From 588cce7e7e7b280f6f93b401a46626db83ba0799 Mon Sep 17 00:00:00 2001 From: alxvov Date: Thu, 27 Jun 2019 09:30:10 +0000 Subject: [PATCH 01/74] add min_spin_oso (just a copy of min_spin) --- src/min_spin_oso.cpp | 333 +++++++++++++++++++++++++++++++++++++++++++ src/min_spin_oso.h | 59 ++++++++ 2 files changed, 392 insertions(+) create mode 100644 src/min_spin_oso.cpp create mode 100644 src/min_spin_oso.h diff --git a/src/min_spin_oso.cpp b/src/min_spin_oso.cpp new file mode 100644 index 0000000000..a97d7b40a1 --- /dev/null +++ b/src/min_spin_oso.cpp @@ -0,0 +1,333 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + 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. +------------------------------------------------------------------------- */ + +/* ------------------------------------------------------------------------ + Contributing authors: Julien Tranchida (SNL) + + Please cite the related publication: +------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include "min_spin_oso.h" +#include "universe.h" +#include "atom.h" +#include "force.h" +#include "update.h" +#include "output.h" +#include "timer.h" +#include "error.h" +#include "modify.h" +#include "math_special.h" +#include "math_const.h" + +using namespace LAMMPS_NS; +using namespace MathConst; + +// EPS_ENERGY = minimum normalization for energy tolerance + +#define EPS_ENERGY 1.0e-8 + +#define DELAYSTEP 5 + +/* ---------------------------------------------------------------------- */ + +MinSpinOSO::MinSpinOSO(LAMMPS *lmp) : Min(lmp) {} + +/* ---------------------------------------------------------------------- */ + +void MinSpinOSO::init() +{ + alpha_damp = 1.0; + discrete_factor = 10.0; + + Min::init(); + + dts = dt = update->dt; + last_negative = update->ntimestep; +} + +/* ---------------------------------------------------------------------- */ + +void MinSpinOSO::setup_style() +{ + double **v = atom->v; + int nlocal = atom->nlocal; + + // check if the atom/spin style is defined + + if (!atom->sp_flag) + error->all(FLERR,"min/spin_oso requires atom/spin style"); + + for (int i = 0; i < nlocal; i++) + v[i][0] = v[i][1] = v[i][2] = 0.0; +} + +/* ---------------------------------------------------------------------- */ + +int MinSpinOSO::modify_param(int narg, char **arg) +{ + if (strcmp(arg[0],"alpha_damp") == 0) { + if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); + alpha_damp = force->numeric(FLERR,arg[1]); + return 2; + } + if (strcmp(arg[0],"discrete_factor") == 0) { + if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); + discrete_factor = force->numeric(FLERR,arg[1]); + return 2; + } + return 0; +} + +/* ---------------------------------------------------------------------- + set current vector lengths and pointers + called after atoms have migrated +------------------------------------------------------------------------- */ + +void MinSpinOSO::reset_vectors() +{ + // atomic dof + + // size sp is 4N vector + nvec = 4 * atom->nlocal; + if (nvec) spvec = atom->sp[0]; + + nvec = 3 * atom->nlocal; + if (nvec) fmvec = atom->fm[0]; + + if (nvec) xvec = atom->x[0]; + if (nvec) fvec = atom->f[0]; +} + +/* ---------------------------------------------------------------------- + minimization via damped spin dynamics +------------------------------------------------------------------------- */ + +int MinSpinOSO::iterate(int maxiter) +{ + bigint ntimestep; + double fmdotfm; + int flag, flagall; + + for (int iter = 0; iter < maxiter; iter++) { + + if (timer->check_timeout(niter)) + return TIMEOUT; + + ntimestep = ++update->ntimestep; + niter++; + + // optimize timestep accross processes / replicas + // need a force calculation for timestep optimization + + energy_force(0); + dts = evaluate_dt(); + + // apply damped precessional dynamics to the spins + + advance_spins(dts); + + eprevious = ecurrent; + ecurrent = energy_force(0); + neval++; + + //// energy tolerance criterion + //// only check after DELAYSTEP elapsed since velocties reset to 0 + //// sync across replicas if running multi-replica minimization + + if (update->etol > 0.0 && ntimestep-last_negative > DELAYSTEP) { + if (update->multireplica == 0) { + if (fabs(ecurrent-eprevious) < + update->etol * 0.5*(fabs(ecurrent) + fabs(eprevious) + EPS_ENERGY)) + return ETOL; + } else { + if (fabs(ecurrent-eprevious) < + update->etol * 0.5*(fabs(ecurrent) + fabs(eprevious) + EPS_ENERGY)) + flag = 0; + else flag = 1; + MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,universe->uworld); + if (flagall == 0) return ETOL; + } + } + + // magnetic torque tolerance criterion + // sync across replicas if running multi-replica minimization + + if (update->ftol > 0.0) { + fmdotfm = fmnorm_sqr(); + if (update->multireplica == 0) { + if (fmdotfm < update->ftol*update->ftol) return FTOL; + } else { + if (fmdotfm < update->ftol*update->ftol) flag = 0; + else flag = 1; + MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,universe->uworld); + if (flagall == 0) return FTOL; + } + } + + // output for thermo, dump, restart files + + if (output->next == ntimestep) { + timer->stamp(); + output->write(ntimestep); + timer->stamp(Timer::OUTPUT); + } + } + + return MAXITER; +} + +/* ---------------------------------------------------------------------- + evaluate max timestep +---------------------------------------------------------------------- */ + +double MinSpinOSO::evaluate_dt() +{ + double dtmax; + double fmsq; + double fmaxsqone,fmaxsqloc,fmaxsqall; + int nlocal = atom->nlocal; + double **fm = atom->fm; + + // finding max fm on this proc. + + fmsq = fmaxsqone = fmaxsqloc = fmaxsqall = 0.0; + for (int i = 0; i < nlocal; i++) { + fmsq = fm[i][0]*fm[i][0]+fm[i][1]*fm[i][1]+fm[i][2]*fm[i][2]; + fmaxsqone = MAX(fmaxsqone,fmsq); + } + + // finding max fm on this replica + + fmaxsqloc = fmaxsqone; + MPI_Allreduce(&fmaxsqone,&fmaxsqloc,1,MPI_DOUBLE,MPI_MAX,world); + + // finding max fm over all replicas, if necessary + // this communicator would be invalid for multiprocess replicas + + fmaxsqall = fmaxsqloc; + if (update->multireplica == 1) { + fmaxsqall = fmaxsqloc; + MPI_Allreduce(&fmaxsqloc,&fmaxsqall,1,MPI_DOUBLE,MPI_MAX,universe->uworld); + } + + if (fmaxsqall == 0.0) + error->all(FLERR,"Incorrect fmaxsqall calculation"); + + // define max timestep by dividing by the + // inverse of max frequency by discrete_factor + + dtmax = MY_2PI/(discrete_factor*sqrt(fmaxsqall)); + + return dtmax; +} + +/* ---------------------------------------------------------------------- + geometric damped advance of spins +---------------------------------------------------------------------- */ + +void MinSpinOSO::advance_spins(double dts) +{ + int nlocal = atom->nlocal; + double **sp = atom->sp; + double **fm = atom->fm; + double tdampx,tdampy,tdampz; + double msq, scale, fm2, energy, dts2; + double cp[3], g[3]; + + dts2 = dts*dts; + + // loop on all spins on proc. + + for (int i = 0; i < nlocal; i++) { + + // calc. damping torque + + tdampx = -alpha_damp*(fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]); + tdampy = -alpha_damp*(fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); + tdampz = -alpha_damp*(fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); + + // apply advance algorithm (geometric, norm preserving) + + fm2 = (tdampx*tdampx+tdampy*tdampy+tdampz*tdampz); + energy = (sp[i][0]*tdampx)+(sp[i][1]*tdampy)+(sp[i][2]*tdampz); + + cp[0] = tdampy*sp[i][2]-tdampz*sp[i][1]; + cp[1] = tdampz*sp[i][0]-tdampx*sp[i][2]; + cp[2] = tdampx*sp[i][1]-tdampy*sp[i][0]; + + g[0] = sp[i][0]+cp[0]*dts; + g[1] = sp[i][1]+cp[1]*dts; + g[2] = sp[i][2]+cp[2]*dts; + + g[0] += (tdampx*energy-0.5*sp[i][0]*fm2)*0.5*dts2; + g[1] += (tdampy*energy-0.5*sp[i][1]*fm2)*0.5*dts2; + g[2] += (tdampz*energy-0.5*sp[i][2]*fm2)*0.5*dts2; + + g[0] /= (1+0.25*fm2*dts2); + g[1] /= (1+0.25*fm2*dts2); + g[2] /= (1+0.25*fm2*dts2); + + sp[i][0] = g[0]; + sp[i][1] = g[1]; + sp[i][2] = g[2]; + + // renormalization (check if necessary) + + msq = g[0]*g[0] + g[1]*g[1] + g[2]*g[2]; + scale = 1.0/sqrt(msq); + sp[i][0] *= scale; + sp[i][1] *= scale; + sp[i][2] *= scale; + + // no comm. to atoms with same tag + // because no need for simplecticity + } +} + +/* ---------------------------------------------------------------------- + compute and return ||mag. torque||_2^2 +------------------------------------------------------------------------- */ + +double MinSpinOSO::fmnorm_sqr() +{ + int nlocal = atom->nlocal; + double tx,ty,tz; + double **sp = atom->sp; + double **fm = atom->fm; + + // calc. magnetic torques + + double local_norm2_sqr = 0.0; + for (int i = 0; i < nlocal; i++) { + tx = (fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]); + ty = (fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); + tz = (fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); + + local_norm2_sqr += tx*tx + ty*ty + tz*tz; + } + + // no extra atom calc. for spins + + if (nextra_atom) + error->all(FLERR,"extra atom option not available yet"); + + double norm2_sqr = 0.0; + MPI_Allreduce(&local_norm2_sqr,&norm2_sqr,1,MPI_DOUBLE,MPI_SUM,world); + + return norm2_sqr; +} + diff --git a/src/min_spin_oso.h b/src/min_spin_oso.h new file mode 100644 index 0000000000..81ad812e5c --- /dev/null +++ b/src/min_spin_oso.h @@ -0,0 +1,59 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + 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 + +MinimizeStyle(spin_oso, MinSpinOSO) + +#else + +#ifndef LMP_MIN_SPIN_OSO_H +#define LMP_MIN_SPIN_OSO_H + +#include "min.h" + +namespace LAMMPS_NS { + +class MinSpinOSO : public Min { + public: + MinSpinOSO(class LAMMPS *); //? + ~MinSpinOSO() {} //? + void init(); + void setup_style(); + int modify_param(int, char **); + void reset_vectors(); + int iterate(int); + double evaluate_dt(); + void advance_spins(double); + double fmnorm_sqr(); + + private: + + // global and spin timesteps + + double dt; + double dts; + + double alpha_damp; // damping for spin minimization + double discrete_factor; // factor for spin timestep evaluation + + double *spvec; // variables for atomic dof, as 1d vector + double *fmvec; // variables for atomic dof, as 1d vector + + bigint last_negative; +}; + +} + +#endif +#endif From 1eb83136c4a86ad8d65e1d46284d8dc69a4a7858 Mon Sep 17 00:00:00 2001 From: alxvov Date: Thu, 27 Jun 2019 10:59:15 +0000 Subject: [PATCH 02/74] add gradient descent with rotation matrices with adaptive time step (as before) --- src/min_spin_oso.cpp | 149 ++++++++++++++++++++++++++++++------------- 1 file changed, 105 insertions(+), 44 deletions(-) diff --git a/src/min_spin_oso.cpp b/src/min_spin_oso.cpp index a97d7b40a1..c20096ae1c 100644 --- a/src/min_spin_oso.cpp +++ b/src/min_spin_oso.cpp @@ -42,6 +42,9 @@ using namespace MathConst; #define DELAYSTEP 5 +void vm3(const double *m, const double *v, double *out); +void rodrigues_rotation(const double *upp_tr, double *out); + /* ---------------------------------------------------------------------- */ MinSpinOSO::MinSpinOSO(LAMMPS *lmp) : Min(lmp) {} @@ -244,58 +247,33 @@ void MinSpinOSO::advance_spins(double dts) int nlocal = atom->nlocal; double **sp = atom->sp; double **fm = atom->fm; - double tdampx,tdampy,tdampz; - double msq, scale, fm2, energy, dts2; - double cp[3], g[3]; - - dts2 = dts*dts; + double tdampx, tdampy, tdampz; + double f[3]; // upper triag. part of skew-symm. matr. to be exponented + double rot_mat[9]; // exponential of a + double s_new[3]; // loop on all spins on proc. for (int i = 0; i < nlocal; i++) { - // calc. damping torque + // calc. damping torque + tdampx = -alpha_damp*(fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]); + tdampy = -alpha_damp*(fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); + tdampz = -alpha_damp*(fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); - tdampx = -alpha_damp*(fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]); - tdampy = -alpha_damp*(fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); - tdampz = -alpha_damp*(fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); + // calculate rotation matrix + f[0] = tdampz * dts; + f[1] = -tdampy * dts; + f[2] = tdampx * dts; + rodrigues_rotation(f, rot_mat); - // apply advance algorithm (geometric, norm preserving) - - fm2 = (tdampx*tdampx+tdampy*tdampy+tdampz*tdampz); - energy = (sp[i][0]*tdampx)+(sp[i][1]*tdampy)+(sp[i][2]*tdampz); - - cp[0] = tdampy*sp[i][2]-tdampz*sp[i][1]; - cp[1] = tdampz*sp[i][0]-tdampx*sp[i][2]; - cp[2] = tdampx*sp[i][1]-tdampy*sp[i][0]; - - g[0] = sp[i][0]+cp[0]*dts; - g[1] = sp[i][1]+cp[1]*dts; - g[2] = sp[i][2]+cp[2]*dts; - - g[0] += (tdampx*energy-0.5*sp[i][0]*fm2)*0.5*dts2; - g[1] += (tdampy*energy-0.5*sp[i][1]*fm2)*0.5*dts2; - g[2] += (tdampz*energy-0.5*sp[i][2]*fm2)*0.5*dts2; - - g[0] /= (1+0.25*fm2*dts2); - g[1] /= (1+0.25*fm2*dts2); - g[2] /= (1+0.25*fm2*dts2); - - sp[i][0] = g[0]; - sp[i][1] = g[1]; - sp[i][2] = g[2]; - - // renormalization (check if necessary) - - msq = g[0]*g[0] + g[1]*g[1] + g[2]*g[2]; - scale = 1.0/sqrt(msq); - sp[i][0] *= scale; - sp[i][1] *= scale; - sp[i][2] *= scale; - - // no comm. to atoms with same tag - // because no need for simplecticity + // rotate spins + vm3(rot_mat, sp[i], s_new); + sp[i][0] = s_new[0]; + sp[i][1] = s_new[1]; + sp[i][2] = s_new[2]; } + } /* ---------------------------------------------------------------------- @@ -331,3 +309,86 @@ double MinSpinOSO::fmnorm_sqr() return norm2_sqr; } + +void rodrigues_rotation(const double *upp_tr, double *out){ + + /*** + * calculate 3x3 matrix exponential using Rodrigues' formula + * (R. Murray, Z. Li, and S. Shankar Sastry, + * A Mathematical Introduction to + * Robotic Manipulation (1994), p. 28 and 30). + * + * upp_tr - vector x, y, z so that one calculate + * U = exp(A) with A= [[0, x, y], + * [-x, 0, z], + * [-y, -z, 0]] + ***/ + + + if (fabs(upp_tr[0]) < 1.0e-40 && + fabs(upp_tr[1]) < 1.0e-40 && + fabs(upp_tr[2]) < 1.0e-40){ + // if upp_tr is zero, return unity matrix + int k; + int m; + for(k = 0; k < 3; k++){ + for(m = 0; m < 3; m++){ + if (m == k) out[3 * k + m] = 1.0; + else out[3 * k + m] = 0.0; + } + } + return; + } + + double theta = sqrt(upp_tr[0] * upp_tr[0] + + upp_tr[1] * upp_tr[1] + + upp_tr[2] * upp_tr[2]); + + double A = cos(theta); + double B = sin(theta); + double D = 1 - A; + double x = upp_tr[0]/theta; + double y = upp_tr[1]/theta; + double z = upp_tr[2]/theta; + + // diagonal elements of U + out[0] = A + z * z * D; + out[4] = A + y * y * D; + out[8] = A + x * x * D; + + // off diagonal of U + double s1 = -y * z *D; + double s2 = x * z * D; + double s3 = -x * y * D; + + double a1 = x * B; + double a2 = y * B; + double a3 = z * B; + + out[1] = s1 + a1; + out[3] = s1 - a1; + out[2] = s2 + a2; + out[6] = s2 - a2; + out[5] = s3 + a3; + out[7] = s3 - a3; + +} + + +void vm3(const double *m, const double *v, double *out){ + /*** + * out = vector^T x m, + * m -- 3x3 matrix , v -- 3-d vector + ***/ + + int i; + int j; + + for(i = 0; i < 3; i++){ + out[i] *= 0.0; + for(j = 0; j < 3; j++){ + out[i] += *(m + 3 * j + i) * v[j]; + } + } + +} From f7ddf433ef03dc94fcf5e5e50a3d61018abe8e06 Mon Sep 17 00:00:00 2001 From: alxvov Date: Thu, 27 Jun 2019 13:14:27 +0000 Subject: [PATCH 03/74] modify comment --- src/min_spin_oso.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/min_spin_oso.cpp b/src/min_spin_oso.cpp index c20096ae1c..d26a7ffc39 100644 --- a/src/min_spin_oso.cpp +++ b/src/min_spin_oso.cpp @@ -239,7 +239,7 @@ double MinSpinOSO::evaluate_dt() } /* ---------------------------------------------------------------------- - geometric damped advance of spins + rotation of spins along the search direction ---------------------------------------------------------------------- */ void MinSpinOSO::advance_spins(double dts) From 589d0e2a6a53c760937b2b9b19c28f41c90db341 Mon Sep 17 00:00:00 2001 From: alxvov Date: Thu, 27 Jun 2019 16:26:24 +0000 Subject: [PATCH 04/74] add conjugate gradients with OSO --- .../min_spin_oso_cg.cpp} | 148 +++++++++++++----- src/SPIN/min_spin_oso_cg.h | 65 ++++++++ src/min_spin_oso.h | 59 ------- 3 files changed, 177 insertions(+), 95 deletions(-) rename src/{min_spin_oso.cpp => SPIN/min_spin_oso_cg.cpp} (72%) create mode 100644 src/SPIN/min_spin_oso_cg.h delete mode 100644 src/min_spin_oso.h diff --git a/src/min_spin_oso.cpp b/src/SPIN/min_spin_oso_cg.cpp similarity index 72% rename from src/min_spin_oso.cpp rename to src/SPIN/min_spin_oso_cg.cpp index d26a7ffc39..9f43442e27 100644 --- a/src/min_spin_oso.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -21,7 +21,7 @@ #include #include #include -#include "min_spin_oso.h" +#include "min_spin_oso_cg.h" #include "universe.h" #include "atom.h" #include "force.h" @@ -47,24 +47,24 @@ void rodrigues_rotation(const double *upp_tr, double *out); /* ---------------------------------------------------------------------- */ -MinSpinOSO::MinSpinOSO(LAMMPS *lmp) : Min(lmp) {} +MinSpinOSO_CG::MinSpinOSO_CG(LAMMPS *lmp) : Min(lmp) {} /* ---------------------------------------------------------------------- */ -void MinSpinOSO::init() +void MinSpinOSO_CG::init() { - alpha_damp = 1.0; - discrete_factor = 10.0; + alpha_damp = 1.0; + discrete_factor = 10.0; - Min::init(); + Min::init(); - dts = dt = update->dt; - last_negative = update->ntimestep; + dts = dt = update->dt; + last_negative = update->ntimestep; } /* ---------------------------------------------------------------------- */ -void MinSpinOSO::setup_style() +void MinSpinOSO_CG::setup_style() { double **v = atom->v; int nlocal = atom->nlocal; @@ -72,7 +72,7 @@ void MinSpinOSO::setup_style() // check if the atom/spin style is defined if (!atom->sp_flag) - error->all(FLERR,"min/spin_oso requires atom/spin style"); + error->all(FLERR,"min/spin_oso_cg requires atom/spin style"); for (int i = 0; i < nlocal; i++) v[i][0] = v[i][1] = v[i][2] = 0.0; @@ -80,7 +80,7 @@ void MinSpinOSO::setup_style() /* ---------------------------------------------------------------------- */ -int MinSpinOSO::modify_param(int narg, char **arg) +int MinSpinOSO_CG::modify_param(int narg, char **arg) { if (strcmp(arg[0],"alpha_damp") == 0) { if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); @@ -100,7 +100,7 @@ int MinSpinOSO::modify_param(int narg, char **arg) called after atoms have migrated ------------------------------------------------------------------------- */ -void MinSpinOSO::reset_vectors() +void MinSpinOSO_CG::reset_vectors() { // atomic dof @@ -119,13 +119,19 @@ void MinSpinOSO::reset_vectors() minimization via damped spin dynamics ------------------------------------------------------------------------- */ -int MinSpinOSO::iterate(int maxiter) +int MinSpinOSO_CG::iterate(int maxiter) { - bigint ntimestep; - double fmdotfm; - int flag, flagall; + bigint ntimestep; + double fmdotfm; + int flag, flagall; - for (int iter = 0; iter < maxiter; iter++) { + // not sure it is best place to allocate memory + int nlocal = atom->nlocal; + g = (double *) calloc(3*nlocal, sizeof(double)); + p = (double *) calloc(3*nlocal, sizeof(double)); + g_old = (double *) calloc(3*nlocal, sizeof(double)); + + for (int iter = 0; iter < maxiter; iter++) { if (timer->check_timeout(niter)) return TIMEOUT; @@ -139,9 +145,9 @@ int MinSpinOSO::iterate(int maxiter) energy_force(0); dts = evaluate_dt(); - // apply damped precessional dynamics to the spins - - advance_spins(dts); + calc_gradients(dts); + calc_search_direction(iter); + advance_spins(); eprevious = ecurrent; ecurrent = energy_force(0); @@ -190,6 +196,10 @@ int MinSpinOSO::iterate(int maxiter) } } + free(p); + free(g); + free(g_old); + return MAXITER; } @@ -197,7 +207,7 @@ int MinSpinOSO::iterate(int maxiter) evaluate max timestep ---------------------------------------------------------------------- */ -double MinSpinOSO::evaluate_dt() +double MinSpinOSO_CG::evaluate_dt() { double dtmax; double fmsq; @@ -238,35 +248,101 @@ double MinSpinOSO::evaluate_dt() return dtmax; } +/* ---------------------------------------------------------------------- + calculate gradients +---------------------------------------------------------------------- */ + +void MinSpinOSO_CG::calc_gradients(double dts) +{ + int nlocal = atom->nlocal; + double **sp = atom->sp; + double **fm = atom->fm; + double tdampx, tdampy, tdampz; + // loop on all spins on proc. + + for (int i = 0; i < nlocal; i++) { + + // calc. damping torque + tdampx = -alpha_damp*(fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]); + tdampy = -alpha_damp*(fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); + tdampz = -alpha_damp*(fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); + + // calculate rotation matrix + g[3 * i + 0] = -tdampz * dts; + g[3 * i + 1] = tdampy * dts; + g[3 * i + 2] = -tdampx * dts; + } +} + +void MinSpinOSO_CG::calc_search_direction(int iter) +{ + int nlocal = atom->nlocal; + double g2old = 0.0; + double g2 = 0.0; + double beta = 0.0; + + double g2_global= 0.0; + double g2old_global= 0.0; + + // for some reason on a second iteration g_old = 0 + // so we make to iterations as steepest descent + if (iter <= 2 || iter % 5 == 0){ + // steepest descent direction + for (int i = 0; i < nlocal; i++) { + for (int j = 0; j < 3; j++){ + p[3 * i + j] = -g[3 * i + j]; + g_old[3 * i + j] = g[3 * i + j]; + } + } + } else{ + // conjugate direction + for (int i = 0; i < nlocal; i++) { + for (int j = 0; j < 3; j++){ + g2old += g_old[3 * i + j] * g_old[3 * i + j]; + g2 += g[3 * i + j] * g[3 * i + j]; + + } + } + + // now we need to collect/broadcast beta on this replica + // different replica can have different beta for now. + // need to check what is beta for GNEB + MPI_Allreduce(&g2, &g2_global, 1, MPI_DOUBLE, MPI_SUM, world); + MPI_Allreduce(&g2old, &g2old_global, 1, MPI_DOUBLE, MPI_SUM, world); + + beta = g2_global / g2old_global; + + //calculate conjugate direction + for (int i = 0; i < nlocal; i++) { + for (int j = 0; j < 3; j++){ + p[3 * i + j] = beta * p[3 * i + j] - g[3 * i + j]; + g_old[3 * i + j] = g[3 * i + j]; + } + } + + } + +} + + /* ---------------------------------------------------------------------- rotation of spins along the search direction ---------------------------------------------------------------------- */ -void MinSpinOSO::advance_spins(double dts) +void MinSpinOSO_CG::advance_spins() { int nlocal = atom->nlocal; double **sp = atom->sp; double **fm = atom->fm; double tdampx, tdampy, tdampz; - double f[3]; // upper triag. part of skew-symm. matr. to be exponented + // double f[3]; // upper triag. part of skew-symm. matr. to be exponented double rot_mat[9]; // exponential of a double s_new[3]; // loop on all spins on proc. for (int i = 0; i < nlocal; i++) { - - // calc. damping torque - tdampx = -alpha_damp*(fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]); - tdampy = -alpha_damp*(fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); - tdampz = -alpha_damp*(fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); - - // calculate rotation matrix - f[0] = tdampz * dts; - f[1] = -tdampy * dts; - f[2] = tdampx * dts; - rodrigues_rotation(f, rot_mat); - + rodrigues_rotation(p + 3 * i, rot_mat); // rotate spins vm3(rot_mat, sp[i], s_new); sp[i][0] = s_new[0]; @@ -280,7 +356,7 @@ void MinSpinOSO::advance_spins(double dts) compute and return ||mag. torque||_2^2 ------------------------------------------------------------------------- */ -double MinSpinOSO::fmnorm_sqr() +double MinSpinOSO_CG::fmnorm_sqr() { int nlocal = atom->nlocal; double tx,ty,tz; diff --git a/src/SPIN/min_spin_oso_cg.h b/src/SPIN/min_spin_oso_cg.h new file mode 100644 index 0000000000..fa0b591c21 --- /dev/null +++ b/src/SPIN/min_spin_oso_cg.h @@ -0,0 +1,65 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + 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 + +MinimizeStyle(spin_oso_cg, MinSpinOSO_CG) + +#else + +#ifndef LMP_MIN_SPIN_OSO_CG_H +#define LMP_MIN_SPIN_OSO_CG_H + +#include "min.h" + +namespace LAMMPS_NS { + +class MinSpinOSO_CG : public Min { + +public: + MinSpinOSO_CG(class LAMMPS *); //? + ~MinSpinOSO_CG() {} //? + void init(); + void setup_style(); + int modify_param(int, char **); + void reset_vectors(); + int iterate(int); + double evaluate_dt(); + void advance_spins(); + double fmnorm_sqr(); + void calc_gradients(double); + void calc_search_direction(int); + +private: + // global and spin timesteps + + double dt; + double dts; + + double alpha_damp; // damping for spin minimization + double discrete_factor; // factor for spin timestep evaluation + + double *spvec; // variables for atomic dof, as 1d vector + double *fmvec; // variables for atomic dof, as 1d vector + + double *g_old; // gradient vector + double *g; // gradient vector + double *p; // search direction vector + + bigint last_negative; +}; + +} + +#endif +#endif diff --git a/src/min_spin_oso.h b/src/min_spin_oso.h deleted file mode 100644 index 81ad812e5c..0000000000 --- a/src/min_spin_oso.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -*- c++ -*- ---------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov - - 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 - -MinimizeStyle(spin_oso, MinSpinOSO) - -#else - -#ifndef LMP_MIN_SPIN_OSO_H -#define LMP_MIN_SPIN_OSO_H - -#include "min.h" - -namespace LAMMPS_NS { - -class MinSpinOSO : public Min { - public: - MinSpinOSO(class LAMMPS *); //? - ~MinSpinOSO() {} //? - void init(); - void setup_style(); - int modify_param(int, char **); - void reset_vectors(); - int iterate(int); - double evaluate_dt(); - void advance_spins(double); - double fmnorm_sqr(); - - private: - - // global and spin timesteps - - double dt; - double dts; - - double alpha_damp; // damping for spin minimization - double discrete_factor; // factor for spin timestep evaluation - - double *spvec; // variables for atomic dof, as 1d vector - double *fmvec; // variables for atomic dof, as 1d vector - - bigint last_negative; -}; - -} - -#endif -#endif From 630ce7b96247b3d8bf23f54c83c04fef8da79c61 Mon Sep 17 00:00:00 2001 From: alxvov Date: Thu, 27 Jun 2019 16:31:24 +0000 Subject: [PATCH 05/74] add contributing authors --- src/SPIN/min_spin_oso_cg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index 9f43442e27..b36e5f280f 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -12,7 +12,7 @@ ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------ - Contributing authors: Julien Tranchida (SNL) + Contributing authors: Julien Tranchida (SNL), Aleksei Ivanov (UI) Please cite the related publication: ------------------------------------------------------------------------- */ From 2520eab46d844bda3e30111d1c8f06d94a009a82 Mon Sep 17 00:00:00 2001 From: alxvov Date: Thu, 27 Jun 2019 16:41:19 +0000 Subject: [PATCH 06/74] small typo --- src/SPIN/min_spin_oso_cg.cpp | 13 ++++++------- src/SPIN/min_spin_oso_cg.h | 4 ++-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index b36e5f280f..9c084d9684 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -145,7 +145,7 @@ int MinSpinOSO_CG::iterate(int maxiter) energy_force(0); dts = evaluate_dt(); - calc_gradients(dts); + calc_gradient(dts); calc_search_direction(iter); advance_spins(); @@ -252,7 +252,7 @@ double MinSpinOSO_CG::evaluate_dt() calculate gradients ---------------------------------------------------------------------- */ -void MinSpinOSO_CG::calc_gradients(double dts) +void MinSpinOSO_CG::calc_gradient(double dts) { int nlocal = atom->nlocal; double **sp = atom->sp; @@ -267,7 +267,7 @@ void MinSpinOSO_CG::calc_gradients(double dts) tdampy = -alpha_damp*(fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); tdampz = -alpha_damp*(fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); - // calculate rotation matrix + // calculate gradients g[3 * i + 0] = -tdampz * dts; g[3 * i + 1] = tdampy * dts; g[3 * i + 2] = -tdampx * dts; @@ -285,7 +285,7 @@ void MinSpinOSO_CG::calc_search_direction(int iter) double g2old_global= 0.0; // for some reason on a second iteration g_old = 0 - // so we make to iterations as steepest descent + // so we make two iterations as steepest descent if (iter <= 2 || iter % 5 == 0){ // steepest descent direction for (int i = 0; i < nlocal; i++) { @@ -312,7 +312,7 @@ void MinSpinOSO_CG::calc_search_direction(int iter) beta = g2_global / g2old_global; - //calculate conjugate direction + // calculate conjugate direction for (int i = 0; i < nlocal; i++) { for (int j = 0; j < 3; j++){ p[3 * i + j] = beta * p[3 * i + j] - g[3 * i + j]; @@ -335,8 +335,7 @@ void MinSpinOSO_CG::advance_spins() double **sp = atom->sp; double **fm = atom->fm; double tdampx, tdampy, tdampz; - // double f[3]; // upper triag. part of skew-symm. matr. to be exponented - double rot_mat[9]; // exponential of a + double rot_mat[9]; // exponential of matrix made of search direction double s_new[3]; // loop on all spins on proc. diff --git a/src/SPIN/min_spin_oso_cg.h b/src/SPIN/min_spin_oso_cg.h index fa0b591c21..a2ecf53e55 100644 --- a/src/SPIN/min_spin_oso_cg.h +++ b/src/SPIN/min_spin_oso_cg.h @@ -37,7 +37,7 @@ public: double evaluate_dt(); void advance_spins(); double fmnorm_sqr(); - void calc_gradients(double); + void calc_gradient(double); void calc_search_direction(int); private: @@ -52,7 +52,7 @@ private: double *spvec; // variables for atomic dof, as 1d vector double *fmvec; // variables for atomic dof, as 1d vector - double *g_old; // gradient vector + double *g_old; // gradient vector at previous iteration double *g; // gradient vector double *p; // search direction vector From 3e8ab7cbb00f42745794afa5205ed4cafbea24f6 Mon Sep 17 00:00:00 2001 From: julient31 Date: Thu, 27 Jun 2019 15:15:57 -0600 Subject: [PATCH 07/74] Commit JT 062719 - cleaned code and setup LAMMPS format and indentation - added src/min_spin_oso_cg.h/cpp to .gitignore --- src/.gitignore | 2 + src/SPIN/min_spin_oso_cg.cpp | 340 ++++++++++++++++++----------------- src/SPIN/min_spin_oso_cg.h | 23 +-- 3 files changed, 193 insertions(+), 172 deletions(-) diff --git a/src/.gitignore b/src/.gitignore index c79c958e6d..0d802981f9 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -161,6 +161,8 @@ /fix_setforce_spin.h /min_spin.cpp /min_spin.h +/min_spin_oso_cg.cpp +/min_spin_oso_cg.h /neb_spin.cpp /neb_spin.h /pair_spin.cpp diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index 9c084d9684..c09d12dbc8 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -12,9 +12,13 @@ ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------ - Contributing authors: Julien Tranchida (SNL), Aleksei Ivanov (UI) + Contributing authors: Aleksei Ivanov (UI) + Julien Tranchida (SNL) Please cite the related publication: + Ivanov, A. V., Uzdin, V. M., & Jónsson, H. (2019). Fast and Robust + Algorithm for the Minimisation of the Energy of Spin Systems. arXiv + preprint arXiv:1904.02669. ------------------------------------------------------------------------- */ #include @@ -24,6 +28,7 @@ #include "min_spin_oso_cg.h" #include "universe.h" #include "atom.h" +#include "citeme.h" #include "force.h" #include "update.h" #include "output.h" @@ -36,30 +41,40 @@ using namespace LAMMPS_NS; using namespace MathConst; +static const char cite_minstyle_spin_oso_cg[] = + "min_style spin/oso_cg command:\n\n" + "@article{ivanov2019fast,\n" + "title={Fast and Robust Algorithm for the Minimisation of the Energy of " + "Spin Systems},\n" + "author={Ivanov, A. V and Uzdin, V. M. and J{\'o}nsson, H.},\n" + "journal={arXiv preprint arXiv:1904.02669},\n" + "year={2019}\n" + "}\n\n"; + // EPS_ENERGY = minimum normalization for energy tolerance #define EPS_ENERGY 1.0e-8 #define DELAYSTEP 5 -void vm3(const double *m, const double *v, double *out); -void rodrigues_rotation(const double *upp_tr, double *out); /* ---------------------------------------------------------------------- */ -MinSpinOSO_CG::MinSpinOSO_CG(LAMMPS *lmp) : Min(lmp) {} +MinSpinOSO_CG::MinSpinOSO_CG(LAMMPS *lmp) : Min(lmp) { + if (lmp->citeme) lmp->citeme->add(cite_minstyle_spin_oso_cg); +} /* ---------------------------------------------------------------------- */ void MinSpinOSO_CG::init() { - alpha_damp = 1.0; - discrete_factor = 10.0; + alpha_damp = 1.0; + discrete_factor = 10.0; - Min::init(); + Min::init(); - dts = dt = update->dt; - last_negative = update->ntimestep; + dts = dt = update->dt; + last_negative = update->ntimestep; } /* ---------------------------------------------------------------------- */ @@ -121,34 +136,34 @@ void MinSpinOSO_CG::reset_vectors() int MinSpinOSO_CG::iterate(int maxiter) { - bigint ntimestep; - double fmdotfm; - int flag, flagall; + bigint ntimestep; + double fmdotfm; + int flag, flagall; - // not sure it is best place to allocate memory - int nlocal = atom->nlocal; - g = (double *) calloc(3*nlocal, sizeof(double)); - p = (double *) calloc(3*nlocal, sizeof(double)); - g_old = (double *) calloc(3*nlocal, sizeof(double)); - - for (int iter = 0; iter < maxiter; iter++) { + // not sure it is best place to allocate memory + int nlocal = atom->nlocal; + g = (double *) calloc(3*nlocal, sizeof(double)); + p = (double *) calloc(3*nlocal, sizeof(double)); + g_old = (double *) calloc(3*nlocal, sizeof(double)); + for (int iter = 0; iter < maxiter; iter++) { + if (timer->check_timeout(niter)) return TIMEOUT; - + ntimestep = ++update->ntimestep; niter++; - + // optimize timestep accross processes / replicas // need a force calculation for timestep optimization - + energy_force(0); dts = evaluate_dt(); - + calc_gradient(dts); calc_search_direction(iter); advance_spins(); - + eprevious = ecurrent; ecurrent = energy_force(0); neval++; @@ -156,7 +171,7 @@ int MinSpinOSO_CG::iterate(int maxiter) //// energy tolerance criterion //// only check after DELAYSTEP elapsed since velocties reset to 0 //// sync across replicas if running multi-replica minimization - + if (update->etol > 0.0 && ntimestep-last_negative > DELAYSTEP) { if (update->multireplica == 0) { if (fabs(ecurrent-eprevious) < @@ -196,9 +211,9 @@ int MinSpinOSO_CG::iterate(int maxiter) } } - free(p); - free(g); - free(g_old); + free(p); + free(g); + free(g_old); return MAXITER; } @@ -254,76 +269,80 @@ double MinSpinOSO_CG::evaluate_dt() void MinSpinOSO_CG::calc_gradient(double dts) { - int nlocal = atom->nlocal; - double **sp = atom->sp; - double **fm = atom->fm; - double tdampx, tdampy, tdampz; - // loop on all spins on proc. + int nlocal = atom->nlocal; + double **sp = atom->sp; + double **fm = atom->fm; + double tdampx, tdampy, tdampz; + + // loop on all spins on proc. - for (int i = 0; i < nlocal; i++) { + for (int i = 0; i < nlocal; i++) { + + // calc. damping torque + + tdampx = -alpha_damp*(fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]); + tdampy = -alpha_damp*(fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); + tdampz = -alpha_damp*(fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); - // calc. damping torque - tdampx = -alpha_damp*(fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]); - tdampy = -alpha_damp*(fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); - tdampz = -alpha_damp*(fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); - - // calculate gradients - g[3 * i + 0] = -tdampz * dts; - g[3 * i + 1] = tdampy * dts; - g[3 * i + 2] = -tdampx * dts; - } + // calculate gradients + + g[3 * i + 0] = -tdampz * dts; + g[3 * i + 1] = tdampy * dts; + g[3 * i + 2] = -tdampx * dts; + } } +/* ---------------------------------------------------------------------- + search direction +---------------------------------------------------------------------- */ + void MinSpinOSO_CG::calc_search_direction(int iter) { - int nlocal = atom->nlocal; - double g2old = 0.0; - double g2 = 0.0; - double beta = 0.0; + int nlocal = atom->nlocal; + double g2old = 0.0; + double g2 = 0.0; + double beta = 0.0; - double g2_global= 0.0; - double g2old_global= 0.0; - - // for some reason on a second iteration g_old = 0 - // so we make two iterations as steepest descent - if (iter <= 2 || iter % 5 == 0){ - // steepest descent direction - for (int i = 0; i < nlocal; i++) { - for (int j = 0; j < 3; j++){ - p[3 * i + j] = -g[3 * i + j]; - g_old[3 * i + j] = g[3 * i + j]; - } - } - } else{ - // conjugate direction - for (int i = 0; i < nlocal; i++) { - for (int j = 0; j < 3; j++){ - g2old += g_old[3 * i + j] * g_old[3 * i + j]; - g2 += g[3 * i + j] * g[3 * i + j]; - - } - } - - // now we need to collect/broadcast beta on this replica - // different replica can have different beta for now. - // need to check what is beta for GNEB - MPI_Allreduce(&g2, &g2_global, 1, MPI_DOUBLE, MPI_SUM, world); - MPI_Allreduce(&g2old, &g2old_global, 1, MPI_DOUBLE, MPI_SUM, world); - - beta = g2_global / g2old_global; - - // calculate conjugate direction - for (int i = 0; i < nlocal; i++) { - for (int j = 0; j < 3; j++){ - p[3 * i + j] = beta * p[3 * i + j] - g[3 * i + j]; - g_old[3 * i + j] = g[3 * i + j]; - } - } + double g2_global= 0.0; + double g2old_global= 0.0; + // for some reason on a second iteration g_old = 0 + // so we make two iterations as steepest descent + + if (iter <= 2 || iter % 5 == 0){ // steepest descent direction + for (int i = 0; i < nlocal; i++) { + for (int j = 0; j < 3; j++){ + p[3 * i + j] = -g[3 * i + j]; + g_old[3 * i + j] = g[3 * i + j]; + } + } + } else { // conjugate direction + for (int i = 0; i < nlocal; i++) { + for (int j = 0; j < 3; j++){ + g2old += g_old[3 * i + j] * g_old[3 * i + j]; + g2 += g[3 * i + j] * g[3 * i + j]; + } } -} + // now we need to collect/broadcast beta on this replica + // different replica can have different beta for now. + // need to check what is beta for GNEB + + MPI_Allreduce(&g2, &g2_global, 1, MPI_DOUBLE, MPI_SUM, world); + MPI_Allreduce(&g2old, &g2old_global, 1, MPI_DOUBLE, MPI_SUM, world); + beta = g2_global / g2old_global; + + // calculate conjugate direction + + for (int i = 0; i < nlocal; i++) { + for (int j = 0; j < 3; j++){ + p[3 * i + j] = beta * p[3 * i + j] - g[3 * i + j]; + g_old[3 * i + j] = g[3 * i + j]; + } + } + } +} /* ---------------------------------------------------------------------- rotation of spins along the search direction @@ -341,14 +360,15 @@ void MinSpinOSO_CG::advance_spins() // loop on all spins on proc. for (int i = 0; i < nlocal; i++) { - rodrigues_rotation(p + 3 * i, rot_mat); - // rotate spins - vm3(rot_mat, sp[i], s_new); - sp[i][0] = s_new[0]; - sp[i][1] = s_new[1]; - sp[i][2] = s_new[2]; + rodrigues_rotation(p + 3 * i, rot_mat); + + // rotate spins + + vm3(rot_mat, sp[i], s_new); + sp[i][0] = s_new[0]; + sp[i][1] = s_new[1]; + sp[i][2] = s_new[2]; } - } /* ---------------------------------------------------------------------- @@ -384,86 +404,82 @@ double MinSpinOSO_CG::fmnorm_sqr() return norm2_sqr; } +/* ---------------------------------------------------------------------- + calculate 3x3 matrix exponential using Rodrigues' formula + (R. Murray, Z. Li, and S. Shankar Sastry, + A Mathematical Introduction to + Robotic Manipulation (1994), p. 28 and 30). + + upp_tr - vector x, y, z so that one calculate + U = exp(A) with A= [[0, x, y], + [-x, 0, z], + [-y, -z, 0]] +------------------------------------------------------------------------- */ -void rodrigues_rotation(const double *upp_tr, double *out){ +void MinSpinOSO_CG::rodrigues_rotation(const double *upp_tr, double *out) +{ - /*** - * calculate 3x3 matrix exponential using Rodrigues' formula - * (R. Murray, Z. Li, and S. Shankar Sastry, - * A Mathematical Introduction to - * Robotic Manipulation (1994), p. 28 and 30). - * - * upp_tr - vector x, y, z so that one calculate - * U = exp(A) with A= [[0, x, y], - * [-x, 0, z], - * [-y, -z, 0]] - ***/ - - - if (fabs(upp_tr[0]) < 1.0e-40 && - fabs(upp_tr[1]) < 1.0e-40 && - fabs(upp_tr[2]) < 1.0e-40){ - // if upp_tr is zero, return unity matrix - int k; - int m; - for(k = 0; k < 3; k++){ - for(m = 0; m < 3; m++){ - if (m == k) out[3 * k + m] = 1.0; - else out[3 * k + m] = 0.0; - } - } - return; + if (fabs(upp_tr[0]) < 1.0e-40 && + fabs(upp_tr[1]) < 1.0e-40 && + fabs(upp_tr[2]) < 1.0e-40){ + + // if upp_tr is zero, return unity matrix + for(int k = 0; k < 3; k++){ + for(int m = 0; m < 3; m++){ + if (m == k) out[3 * k + m] = 1.0; + else out[3 * k + m] = 0.0; + } } + return; + } - double theta = sqrt(upp_tr[0] * upp_tr[0] + - upp_tr[1] * upp_tr[1] + - upp_tr[2] * upp_tr[2]); + double theta = sqrt(upp_tr[0] * upp_tr[0] + + upp_tr[1] * upp_tr[1] + + upp_tr[2] * upp_tr[2]); - double A = cos(theta); - double B = sin(theta); - double D = 1 - A; - double x = upp_tr[0]/theta; - double y = upp_tr[1]/theta; - double z = upp_tr[2]/theta; + double A = cos(theta); + double B = sin(theta); + double D = 1 - A; + double x = upp_tr[0]/theta; + double y = upp_tr[1]/theta; + double z = upp_tr[2]/theta; - // diagonal elements of U - out[0] = A + z * z * D; - out[4] = A + y * y * D; - out[8] = A + x * x * D; + // diagonal elements of U + + out[0] = A + z * z * D; + out[4] = A + y * y * D; + out[8] = A + x * x * D; - // off diagonal of U - double s1 = -y * z *D; - double s2 = x * z * D; - double s3 = -x * y * D; + // off diagonal of U + + double s1 = -y * z *D; + double s2 = x * z * D; + double s3 = -x * y * D; - double a1 = x * B; - double a2 = y * B; - double a3 = z * B; + double a1 = x * B; + double a2 = y * B; + double a3 = z * B; - out[1] = s1 + a1; - out[3] = s1 - a1; - out[2] = s2 + a2; - out[6] = s2 - a2; - out[5] = s3 + a3; - out[7] = s3 - a3; + out[1] = s1 + a1; + out[3] = s1 - a1; + out[2] = s2 + a2; + out[6] = s2 - a2; + out[5] = s3 + a3; + out[7] = s3 - a3; } +/* ---------------------------------------------------------------------- + out = vector^T x m, + m -- 3x3 matrix , v -- 3-d vector +------------------------------------------------------------------------- */ -void vm3(const double *m, const double *v, double *out){ - /*** - * out = vector^T x m, - * m -- 3x3 matrix , v -- 3-d vector - ***/ - - int i; - int j; - - for(i = 0; i < 3; i++){ - out[i] *= 0.0; - for(j = 0; j < 3; j++){ - out[i] += *(m + 3 * j + i) * v[j]; - } +void MinSpinOSO_CG::vm3(const double *m, const double *v, double *out) +{ + for(int i = 0; i < 3; i++){ + out[i] *= 0.0; + for(int j = 0; j < 3; j++){ + out[i] += *(m + 3 * j + i) * v[j]; } - + } } diff --git a/src/SPIN/min_spin_oso_cg.h b/src/SPIN/min_spin_oso_cg.h index a2ecf53e55..8cff52431c 100644 --- a/src/SPIN/min_spin_oso_cg.h +++ b/src/SPIN/min_spin_oso_cg.h @@ -13,7 +13,7 @@ #ifdef MINIMIZE_CLASS -MinimizeStyle(spin_oso_cg, MinSpinOSO_CG) +MinimizeStyle(spin/oso_cg, MinSpinOSO_CG) #else @@ -27,8 +27,8 @@ namespace LAMMPS_NS { class MinSpinOSO_CG : public Min { public: - MinSpinOSO_CG(class LAMMPS *); //? - ~MinSpinOSO_CG() {} //? + MinSpinOSO_CG(class LAMMPS *); + ~MinSpinOSO_CG() {} void init(); void setup_style(); int modify_param(int, char **); @@ -46,15 +46,18 @@ private: double dt; double dts; - double alpha_damp; // damping for spin minimization - double discrete_factor; // factor for spin timestep evaluation + double alpha_damp; // damping for spin minimization + double discrete_factor; // factor for spin timestep evaluation - double *spvec; // variables for atomic dof, as 1d vector - double *fmvec; // variables for atomic dof, as 1d vector + double *spvec; // variables for atomic dof, as 1d vector + double *fmvec; // variables for atomic dof, as 1d vector - double *g_old; // gradient vector at previous iteration - double *g; // gradient vector - double *p; // search direction vector + double *g_old; // gradient vector at previous iteration + double *g; // gradient vector + double *p; // search direction vector + + void vm3(const double *m, const double *v, double *out); + void rodrigues_rotation(const double *upp_tr, double *out); bigint last_negative; }; From 5c8e81241aba49399ef221bc841ccdc249cc08c1 Mon Sep 17 00:00:00 2001 From: julient31 Date: Fri, 28 Jun 2019 10:49:21 -0600 Subject: [PATCH 08/74] Commit JT 062819 - modified memory allocation --- src/SPIN/fix_nve_spin.h | 2 +- src/SPIN/min_spin_oso_cg.cpp | 90 ++++++++++++++++++++++-------------- src/SPIN/min_spin_oso_cg.h | 11 +++-- 3 files changed, 63 insertions(+), 40 deletions(-) diff --git a/src/SPIN/fix_nve_spin.h b/src/SPIN/fix_nve_spin.h index 4800575c06..89cd617e0b 100644 --- a/src/SPIN/fix_nve_spin.h +++ b/src/SPIN/fix_nve_spin.h @@ -54,7 +54,7 @@ friend class PairSpin; double dtv, dtf, dts; // velocity, force, and spin timesteps - int nlocal_max; // max value of nlocal (for lists size) + int nlocal_max; // max value of nlocal (for size of lists) int pair_spin_flag; // magnetic pair flags int long_spin_flag; // magnetic long-range flag diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index c09d12dbc8..d6bca32a40 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -34,6 +34,7 @@ #include "output.h" #include "timer.h" #include "error.h" +#include "memory.h" #include "modify.h" #include "math_special.h" #include "math_const.h" @@ -60,8 +61,20 @@ static const char cite_minstyle_spin_oso_cg[] = /* ---------------------------------------------------------------------- */ -MinSpinOSO_CG::MinSpinOSO_CG(LAMMPS *lmp) : Min(lmp) { +MinSpinOSO_CG::MinSpinOSO_CG(LAMMPS *lmp) : + Min(lmp), g_old(NULL), g_cur(NULL), p_s(NULL) +{ if (lmp->citeme) lmp->citeme->add(cite_minstyle_spin_oso_cg); + nlocal_max = 0; +} + +/* ---------------------------------------------------------------------- */ + +MinSpinOSO_CG::~MinSpinOSO_CG() +{ + memory->destroy(g_old); + memory->destroy(g_cur); + memory->destroy(p_s); } /* ---------------------------------------------------------------------- */ @@ -75,6 +88,13 @@ void MinSpinOSO_CG::init() dts = dt = update->dt; last_negative = update->ntimestep; + + // allocate tables + + nlocal_max = atom->nlocal; + memory->grow(g_old,3*nlocal_max,"min/spin/oso/cg:g_old"); + memory->grow(g_cur,3*nlocal_max,"min/spin/oso/cg:g_cur"); + memory->grow(p_s,3*nlocal_max,"min/spin/oso/cg:p_s"); } /* ---------------------------------------------------------------------- */ @@ -134,17 +154,21 @@ void MinSpinOSO_CG::reset_vectors() minimization via damped spin dynamics ------------------------------------------------------------------------- */ +// g_old g_cur p_s + int MinSpinOSO_CG::iterate(int maxiter) { + int nlocal = atom->nlocal; bigint ntimestep; double fmdotfm; int flag, flagall; - // not sure it is best place to allocate memory - int nlocal = atom->nlocal; - g = (double *) calloc(3*nlocal, sizeof(double)); - p = (double *) calloc(3*nlocal, sizeof(double)); - g_old = (double *) calloc(3*nlocal, sizeof(double)); + if (nlocal_max < nlocal) { + nlocal_max = nlocal; + memory->grow(g_old,3*nlocal_max,"min/spin/oso/cg:g_old"); + memory->grow(g_cur,3*nlocal_max,"min/spin/oso/cg:g_cur"); + memory->grow(p_s,3*nlocal_max,"min/spin/oso/cg:p_s"); + } for (int iter = 0; iter < maxiter; iter++) { @@ -211,10 +235,6 @@ int MinSpinOSO_CG::iterate(int maxiter) } } - free(p); - free(g); - free(g_old); - return MAXITER; } @@ -286,9 +306,9 @@ void MinSpinOSO_CG::calc_gradient(double dts) // calculate gradients - g[3 * i + 0] = -tdampz * dts; - g[3 * i + 1] = tdampy * dts; - g[3 * i + 2] = -tdampx * dts; + g_cur[3 * i + 0] = -tdampz * dts; + g_cur[3 * i + 1] = tdampy * dts; + g_cur[3 * i + 2] = -tdampx * dts; } } @@ -312,15 +332,15 @@ void MinSpinOSO_CG::calc_search_direction(int iter) if (iter <= 2 || iter % 5 == 0){ // steepest descent direction for (int i = 0; i < nlocal; i++) { for (int j = 0; j < 3; j++){ - p[3 * i + j] = -g[3 * i + j]; - g_old[3 * i + j] = g[3 * i + j]; + p_s[3 * i + j] = -g_cur[3 * i + j]; + g_old[3 * i + j] = g_cur[3 * i + j]; } } } else { // conjugate direction for (int i = 0; i < nlocal; i++) { for (int j = 0; j < 3; j++){ g2old += g_old[3 * i + j] * g_old[3 * i + j]; - g2 += g[3 * i + j] * g[3 * i + j]; + g2 += g_cur[3 * i + j] * g_cur[3 * i + j]; } } @@ -337,8 +357,8 @@ void MinSpinOSO_CG::calc_search_direction(int iter) for (int i = 0; i < nlocal; i++) { for (int j = 0; j < 3; j++){ - p[3 * i + j] = beta * p[3 * i + j] - g[3 * i + j]; - g_old[3 * i + j] = g[3 * i + j]; + p_s[3 * i + j] = beta * p_s[3 * i + j] - g_cur[3 * i + j]; + g_old[3 * i + j] = g_cur[3 * i + j]; } } } @@ -360,7 +380,7 @@ void MinSpinOSO_CG::advance_spins() // loop on all spins on proc. for (int i = 0; i < nlocal; i++) { - rodrigues_rotation(p + 3 * i, rot_mat); + rodrigues_rotation(p_s + 3 * i, rot_mat); // rotate spins @@ -418,6 +438,8 @@ double MinSpinOSO_CG::fmnorm_sqr() void MinSpinOSO_CG::rodrigues_rotation(const double *upp_tr, double *out) { + double theta,A,B,D,x,y,z; + double s1,s2,s3,a1,a2,a3; if (fabs(upp_tr[0]) < 1.0e-40 && fabs(upp_tr[1]) < 1.0e-40 && @@ -433,16 +455,16 @@ void MinSpinOSO_CG::rodrigues_rotation(const double *upp_tr, double *out) return; } - double theta = sqrt(upp_tr[0] * upp_tr[0] + - upp_tr[1] * upp_tr[1] + - upp_tr[2] * upp_tr[2]); + theta = sqrt(upp_tr[0] * upp_tr[0] + + upp_tr[1] * upp_tr[1] + + upp_tr[2] * upp_tr[2]); - double A = cos(theta); - double B = sin(theta); - double D = 1 - A; - double x = upp_tr[0]/theta; - double y = upp_tr[1]/theta; - double z = upp_tr[2]/theta; + A = cos(theta); + B = sin(theta); + D = 1 - A; + x = upp_tr[0]/theta; + y = upp_tr[1]/theta; + z = upp_tr[2]/theta; // diagonal elements of U @@ -452,13 +474,13 @@ void MinSpinOSO_CG::rodrigues_rotation(const double *upp_tr, double *out) // off diagonal of U - double s1 = -y * z *D; - double s2 = x * z * D; - double s3 = -x * y * D; + s1 = -y * z *D; + s2 = x * z * D; + s3 = -x * y * D; - double a1 = x * B; - double a2 = y * B; - double a3 = z * B; + a1 = x * B; + a2 = y * B; + a3 = z * B; out[1] = s1 + a1; out[3] = s1 - a1; diff --git a/src/SPIN/min_spin_oso_cg.h b/src/SPIN/min_spin_oso_cg.h index 8cff52431c..a791754836 100644 --- a/src/SPIN/min_spin_oso_cg.h +++ b/src/SPIN/min_spin_oso_cg.h @@ -28,7 +28,7 @@ class MinSpinOSO_CG : public Min { public: MinSpinOSO_CG(class LAMMPS *); - ~MinSpinOSO_CG() {} + virtual ~MinSpinOSO_CG(); void init(); void setup_style(); int modify_param(int, char **); @@ -43,6 +43,7 @@ public: private: // global and spin timesteps + int nlocal_max; // max value of nlocal (for size of lists) double dt; double dts; @@ -53,11 +54,11 @@ private: double *fmvec; // variables for atomic dof, as 1d vector double *g_old; // gradient vector at previous iteration - double *g; // gradient vector - double *p; // search direction vector + double *g_cur; // current gradient vector + double *p_s; // search direction vector - void vm3(const double *m, const double *v, double *out); - void rodrigues_rotation(const double *upp_tr, double *out); + void vm3(const double *, const double *, double *); + void rodrigues_rotation(const double *, double *); bigint last_negative; }; From 61b12a09f2c3f81e520aa788721985f762d50ced Mon Sep 17 00:00:00 2001 From: alxvov Date: Mon, 1 Jul 2019 08:01:11 +0000 Subject: [PATCH 09/74] added lbfgs --- src/SPIN/min_spin_oso_lbfgs.cpp | 577 ++++++++++++++++++++++++++++++++ src/SPIN/min_spin_oso_lbfgs.h | 73 ++++ 2 files changed, 650 insertions(+) create mode 100644 src/SPIN/min_spin_oso_lbfgs.cpp create mode 100644 src/SPIN/min_spin_oso_lbfgs.h diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp new file mode 100644 index 0000000000..f0a4fcbd87 --- /dev/null +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -0,0 +1,577 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + 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. +------------------------------------------------------------------------- */ + +/* ------------------------------------------------------------------------ + Contributing authors: Aleksei Ivanov (UI) + Julien Tranchida (SNL) + + Please cite the related publication: + Ivanov, A. V., Uzdin, V. M., & Jónsson, H. (2019). Fast and Robust + Algorithm for the Minimisation of the Energy of Spin Systems. arXiv + preprint arXiv:1904.02669. +------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include "min_spin_oso_lbfgs.h" +#include "universe.h" +#include "atom.h" +#include "citeme.h" +#include "force.h" +#include "update.h" +#include "output.h" +#include "timer.h" +#include "error.h" +#include "modify.h" +#include "math_special.h" +#include "math_const.h" + +#include +using namespace std; + +using namespace LAMMPS_NS; +using namespace MathConst; + +static const char cite_minstyle_spin_oso_lbfgs[] = + "min_style spin/oso_lbfgs command:\n\n" + "@article{ivanov2019fast,\n" + "title={Fast and Robust Algorithm for the Minimisation of the Energy of " + "Spin Systems},\n" + "author={Ivanov, A. V and Uzdin, V. M. and J{\'o}nsson, H.},\n" + "journal={arXiv preprint arXiv:1904.02669},\n" + "year={2019}\n" + "}\n\n"; + +// EPS_ENERGY = minimum normalization for energy tolerance + +#define EPS_ENERGY 1.0e-8 + +#define DELAYSTEP 5 + + +/* ---------------------------------------------------------------------- */ + +MinSpinOSO_LBFGS::MinSpinOSO_LBFGS(LAMMPS *lmp) : Min(lmp) { + if (lmp->citeme) lmp->citeme->add(cite_minstyle_spin_oso_lbfgs); +} + +/* ---------------------------------------------------------------------- */ + +void MinSpinOSO_LBFGS::init() +{ + alpha_damp = 1.0; + discrete_factor = 10.0; + num_mem = 3; + + Min::init(); + + dts = dt = update->dt; + last_negative = update->ntimestep; +} + +/* ---------------------------------------------------------------------- */ + +void MinSpinOSO_LBFGS::setup_style() +{ + double **v = atom->v; + int nlocal = atom->nlocal; + + // check if the atom/spin style is defined + + if (!atom->sp_flag) + error->all(FLERR,"min/spin_oso_lbfgs requires atom/spin style"); + + for (int i = 0; i < nlocal; i++) + v[i][0] = v[i][1] = v[i][2] = 0.0; +} + +/* ---------------------------------------------------------------------- */ + +int MinSpinOSO_LBFGS::modify_param(int narg, char **arg) +{ + if (strcmp(arg[0],"alpha_damp") == 0) { + if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); + alpha_damp = force->numeric(FLERR,arg[1]); + return 2; + } + if (strcmp(arg[0],"discrete_factor") == 0) { + if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); + discrete_factor = force->numeric(FLERR,arg[1]); + return 2; + } + return 0; +} + +/* ---------------------------------------------------------------------- + set current vector lengths and pointers + called after atoms have migrated +------------------------------------------------------------------------- */ + +void MinSpinOSO_LBFGS::reset_vectors() +{ + // atomic dof + + // size sp is 4N vector + nvec = 4 * atom->nlocal; + if (nvec) spvec = atom->sp[0]; + + nvec = 3 * atom->nlocal; + if (nvec) fmvec = atom->fm[0]; + + if (nvec) xvec = atom->x[0]; + if (nvec) fvec = atom->f[0]; +} + +/* ---------------------------------------------------------------------- + minimization via damped spin dynamics +------------------------------------------------------------------------- */ + +int MinSpinOSO_LBFGS::iterate(int maxiter) +{ + bigint ntimestep; + double fmdotfm; + int flag, flagall; + + // not sure it is best place to allocate memory + int nlocal = atom->nlocal; + g = (double *) calloc(3*nlocal, sizeof(double)); + p = (double *) calloc(3*nlocal, sizeof(double)); + g_old = (double *) calloc(3*nlocal, sizeof(double)); + rho = (double *) calloc(num_mem, sizeof(double)); + ds = (double **) calloc(num_mem, sizeof(double *)); + dy = (double **) calloc(num_mem, sizeof(double *)); + for (int k = 0; k < num_mem; k++){ + ds[k] = (double *) calloc(3*nlocal, sizeof(double)); + dy[k] = (double *) calloc(3*nlocal, sizeof(double)); + } + + for (int iter = 0; iter < maxiter; iter++) { + + if (timer->check_timeout(niter)) + return TIMEOUT; + + ntimestep = ++update->ntimestep; + niter++; + + // optimize timestep accross processes / replicas + // need a force calculation for timestep optimization + + energy_force(0); + // dts = evaluate_dt(); + // dts = 1.0; + calc_gradient(1.0); + calc_search_direction(iter); + advance_spins(); + + eprevious = ecurrent; + ecurrent = energy_force(0); + neval++; + + //// energy tolerance criterion + //// only check after DELAYSTEP elapsed since velocties reset to 0 + //// sync across replicas if running multi-replica minimization + + if (update->etol > 0.0 && ntimestep-last_negative > DELAYSTEP) { + if (update->multireplica == 0) { + if (fabs(ecurrent-eprevious) < + update->etol * 0.5*(fabs(ecurrent) + fabs(eprevious) + EPS_ENERGY)) + return ETOL; + } else { + if (fabs(ecurrent-eprevious) < + update->etol * 0.5*(fabs(ecurrent) + fabs(eprevious) + EPS_ENERGY)) + flag = 0; + else flag = 1; + MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,universe->uworld); + if (flagall == 0) return ETOL; + } + } + + // magnetic torque tolerance criterion + // sync across replicas if running multi-replica minimization + + if (update->ftol > 0.0) { + fmdotfm = fmnorm_sqr(); + if (update->multireplica == 0) { + if (fmdotfm < update->ftol*update->ftol) return FTOL; + } else { + if (fmdotfm < update->ftol*update->ftol) flag = 0; + else flag = 1; + MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,universe->uworld); + if (flagall == 0) return FTOL; + } + } + + // output for thermo, dump, restart files + + if (output->next == ntimestep) { + timer->stamp(); + output->write(ntimestep); + timer->stamp(Timer::OUTPUT); + } + } + + free(p); + free(g); + free(g_old); + for (int k = 0; k < num_mem; k++){ + free(ds[k]); + free(dy[k]); + } + free(ds); + free(dy); + free(rho); + + return MAXITER; +} + +/* ---------------------------------------------------------------------- + evaluate max timestep +---------------------------------------------------------------------- */ + +double MinSpinOSO_LBFGS::evaluate_dt() +{ + double dtmax; + double fmsq; + double fmaxsqone,fmaxsqloc,fmaxsqall; + int nlocal = atom->nlocal; + double **fm = atom->fm; + + // finding max fm on this proc. + + fmsq = fmaxsqone = fmaxsqloc = fmaxsqall = 0.0; + for (int i = 0; i < nlocal; i++) { + fmsq = fm[i][0]*fm[i][0]+fm[i][1]*fm[i][1]+fm[i][2]*fm[i][2]; + fmaxsqone = MAX(fmaxsqone,fmsq); + } + + // finding max fm on this replica + + fmaxsqloc = fmaxsqone; + MPI_Allreduce(&fmaxsqone,&fmaxsqloc,1,MPI_DOUBLE,MPI_MAX,world); + + // finding max fm over all replicas, if necessary + // this communicator would be invalid for multiprocess replicas + + fmaxsqall = fmaxsqloc; + if (update->multireplica == 1) { + fmaxsqall = fmaxsqloc; + MPI_Allreduce(&fmaxsqloc,&fmaxsqall,1,MPI_DOUBLE,MPI_MAX,universe->uworld); + } + + if (fmaxsqall == 0.0) + error->all(FLERR,"Incorrect fmaxsqall calculation"); + + // define max timestep by dividing by the + // inverse of max frequency by discrete_factor + + dtmax = MY_2PI/(discrete_factor*sqrt(fmaxsqall)); + + return dtmax; +} + +/* ---------------------------------------------------------------------- + calculate gradients +---------------------------------------------------------------------- */ + +void MinSpinOSO_LBFGS::calc_gradient(double dts) +{ + int nlocal = atom->nlocal; + double **sp = atom->sp; + double **fm = atom->fm; + double tdampx, tdampy, tdampz; + + // loop on all spins on proc. + + for (int i = 0; i < nlocal; i++) { + + // calc. damping torque + + tdampx = -alpha_damp*(fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]); + tdampy = -alpha_damp*(fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); + tdampz = -alpha_damp*(fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); + + // calculate gradients + + g[3 * i + 0] = -tdampz * dts; + g[3 * i + 1] = tdampy * dts; + g[3 * i + 2] = -tdampx * dts; + } +} + +/* ---------------------------------------------------------------------- + search direction +---------------------------------------------------------------------- */ + +void MinSpinOSO_LBFGS::calc_search_direction(int iter) +{ + int nlocal = atom->nlocal; + + double dyds = 0.0; + double sq = 0.0; + double yy = 0.0; + double yr = 0.0; + double beta = 0.0; + + double dyds_global = 0.0; + double sq_global = 0.0; + double yy_global = 0.0; + double yr_global = 0.0; + double beta_global = 0.0; + + int m_index = iter % num_mem; // memory index + int c_ind = 0; + double *q; + double *alpha; + + q = (double *) calloc(3*nlocal, sizeof(double)); + alpha = (double *) calloc(num_mem, sizeof(double)); + + // for some reason on a second iteration g_old = 0 + // so we make two iterations as steepest descent + + if (iter == 0){ // steepest descent direction + for (int i = 0; i < 3 * nlocal; i++) { + p[i] = -g[i]; + g_old[i] = g[i]; + ds[m_index][i] = 0.0; + dy[m_index][i] = 0.0; + + } + } else { + dyds = 0.0; + for (int i = 0; i < 3 * nlocal; i++) { + ds[m_index][i] = p[i]; + dy[m_index][i] = g[i] - g_old[i]; + dyds += ds[m_index][i] * dy[m_index][i]; + } +// MPI_Allreduce(&dyds, &dyds_global, 1, MPI_DOUBLE, MPI_SUM, world); + if (fabs(dyds) > 1.0e-60) rho[m_index] = 1.0 / dyds; + else rho[m_index] = 1.0e60; + + // set the q vector + + for (int i = 0; i < 3 * nlocal; i++) { + q[i] = g[i]; + } + + // loop over last m indecies + for(int k = num_mem - 1; k > -1; k--) { + // this loop should run from the newest memory to the oldest one. + + c_ind = (k + m_index + 1) % num_mem; + + // dot product between dg and q + + sq = 0.0; + for (int i = 0; i < 3 * nlocal; i++) { + sq += ds[c_ind][i] * q[i]; + } + + // update alpha + + alpha[c_ind] = rho[c_ind] * sq; + + // update q + + for (int i = 0; i < 3 * nlocal; i++) { + q[i] -= alpha[c_ind] * dy[c_ind][i]; + } + } + + // dot product between dg with itself + yy = 0.0; + for (int i = 0; i < 3 * nlocal; i++) { + yy += dy[m_index][i] * dy[m_index][i]; + } + + // calculate now search direction + + if (fabs(yy) > 1.0e-60) { + for (int i = 0; i < 3 * nlocal; i++) { + p[i] = q[i] / (rho[m_index] * yy); + } + }else{ + for (int i = 0; i < 3 * nlocal; i++) { + p[i] = q[i] * 1.0e60; + } + } + + for (int k = 0; k < num_mem; k++){ + // this loop should run from the oldest memory to the newest one. + + if (iter < num_mem) c_ind = k; + else c_ind = (k + m_index + 1) % num_mem; + + // dot product between p and da + yr = 0.0; + for (int i = 0; i < 3 * nlocal; i++) { + yr += dy[c_ind][i] * p[i]; + } + + beta = rho[c_ind] * yr; + for (int i = 0; i < 3 * nlocal; i++) { + p[i] += ds[c_ind][i] * (alpha[c_ind] - beta); + } + } + for (int i = 0; i < 3 * nlocal; i++) { + p[i] = -1.0 * p[i]; + g_old[i] = g[i]; + } + } + + free(q); + free(alpha); + +} + +/* ---------------------------------------------------------------------- + rotation of spins along the search direction +---------------------------------------------------------------------- */ + +void MinSpinOSO_LBFGS::advance_spins() +{ + int nlocal = atom->nlocal; + double **sp = atom->sp; + double **fm = atom->fm; + double tdampx, tdampy, tdampz; + double rot_mat[9]; // exponential of matrix made of search direction + double s_new[3]; + + // loop on all spins on proc. + + for (int i = 0; i < nlocal; i++) { + rodrigues_rotation(p + 3 * i, rot_mat); + + // rotate spins + + vm3(rot_mat, sp[i], s_new); + sp[i][0] = s_new[0]; + sp[i][1] = s_new[1]; + sp[i][2] = s_new[2]; + } +} + +/* ---------------------------------------------------------------------- + compute and return ||mag. torque||_2^2 +------------------------------------------------------------------------- */ + +double MinSpinOSO_LBFGS::fmnorm_sqr() +{ + int nlocal = atom->nlocal; + double tx,ty,tz; + double **sp = atom->sp; + double **fm = atom->fm; + + // calc. magnetic torques + + double local_norm2_sqr = 0.0; + for (int i = 0; i < nlocal; i++) { + tx = (fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]); + ty = (fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); + tz = (fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); + + local_norm2_sqr += tx*tx + ty*ty + tz*tz; + } + + // no extra atom calc. for spins + + if (nextra_atom) + error->all(FLERR,"extra atom option not available yet"); + + double norm2_sqr = 0.0; + MPI_Allreduce(&local_norm2_sqr,&norm2_sqr,1,MPI_DOUBLE,MPI_SUM,world); + + return norm2_sqr; +} + +/* ---------------------------------------------------------------------- + calculate 3x3 matrix exponential using Rodrigues' formula + (R. Murray, Z. Li, and S. Shankar Sastry, + A Mathematical Introduction to + Robotic Manipulation (1994), p. 28 and 30). + + upp_tr - vector x, y, z so that one calculate + U = exp(A) with A= [[0, x, y], + [-x, 0, z], + [-y, -z, 0]] +------------------------------------------------------------------------- */ + +void MinSpinOSO_LBFGS::rodrigues_rotation(const double *upp_tr, double *out) +{ + + if (fabs(upp_tr[0]) < 1.0e-40 && + fabs(upp_tr[1]) < 1.0e-40 && + fabs(upp_tr[2]) < 1.0e-40){ + + // if upp_tr is zero, return unity matrix + for(int k = 0; k < 3; k++){ + for(int m = 0; m < 3; m++){ + if (m == k) out[3 * k + m] = 1.0; + else out[3 * k + m] = 0.0; + } + } + return; + } + + double theta = sqrt(upp_tr[0] * upp_tr[0] + + upp_tr[1] * upp_tr[1] + + upp_tr[2] * upp_tr[2]); + + double A = cos(theta); + double B = sin(theta); + double D = 1 - A; + double x = upp_tr[0]/theta; + double y = upp_tr[1]/theta; + double z = upp_tr[2]/theta; + + // diagonal elements of U + + out[0] = A + z * z * D; + out[4] = A + y * y * D; + out[8] = A + x * x * D; + + // off diagonal of U + + double s1 = -y * z *D; + double s2 = x * z * D; + double s3 = -x * y * D; + + double a1 = x * B; + double a2 = y * B; + double a3 = z * B; + + out[1] = s1 + a1; + out[3] = s1 - a1; + out[2] = s2 + a2; + out[6] = s2 - a2; + out[5] = s3 + a3; + out[7] = s3 - a3; + +} + +/* ---------------------------------------------------------------------- + out = vector^T x m, + m -- 3x3 matrix , v -- 3-d vector +------------------------------------------------------------------------- */ + +void MinSpinOSO_LBFGS::vm3(const double *m, const double *v, double *out) +{ + for(int i = 0; i < 3; i++){ + out[i] *= 0.0; + for(int j = 0; j < 3; j++){ + out[i] += *(m + 3 * j + i) * v[j]; + } + } +} diff --git a/src/SPIN/min_spin_oso_lbfgs.h b/src/SPIN/min_spin_oso_lbfgs.h new file mode 100644 index 0000000000..0a06824382 --- /dev/null +++ b/src/SPIN/min_spin_oso_lbfgs.h @@ -0,0 +1,73 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + 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 + +MinimizeStyle(spin/oso_lbfgs, MinSpinOSO_LBFGS) + +#else + +#ifndef LMP_MIN_SPIN_OSO_LBFGS_H +#define LMP_MIN_SPIN_OSO_LBFGS_H + +#include "min.h" + +namespace LAMMPS_NS { + +class MinSpinOSO_LBFGS : public Min { + +public: + MinSpinOSO_LBFGS(class LAMMPS *); + ~MinSpinOSO_LBFGS() {} + void init(); + void setup_style(); + int modify_param(int, char **); + void reset_vectors(); + int iterate(int); + double evaluate_dt(); + void advance_spins(); + double fmnorm_sqr(); + void calc_gradient(double); + void calc_search_direction(int); + +private: + // global and spin timesteps + + double dt; + double dts; + + double alpha_damp; // damping for spin minimization + double discrete_factor; // factor for spin timestep evaluation + + double *spvec; // variables for atomic dof, as 1d vector + double *fmvec; // variables for atomic dof, as 1d vector + + double *g; // gradient vector + double *g_old; // gradient vector at previous step + double *p; // search direction vector + double **ds; // change in rotation matrix between two iterations, da + double **dy; // change in gradients between two iterations, dg + double *rho; // estimation of curvature + int num_mem; // number of stored steps + + + void vm3(const double *m, const double *v, double *out); + void rodrigues_rotation(const double *upp_tr, double *out); + + bigint last_negative; +}; + +} + +#endif +#endif From 89ecd5d9f9e3daa9fb62430a883e896c3c5235e1 Mon Sep 17 00:00:00 2001 From: alxvov Date: Mon, 1 Jul 2019 08:35:41 +0000 Subject: [PATCH 10/74] get rid off double loops in cg --- src/SPIN/min_spin_oso_cg.cpp | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index d6bca32a40..0c628f7567 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -329,19 +329,15 @@ void MinSpinOSO_CG::calc_search_direction(int iter) // for some reason on a second iteration g_old = 0 // so we make two iterations as steepest descent - if (iter <= 2 || iter % 5 == 0){ // steepest descent direction - for (int i = 0; i < nlocal; i++) { - for (int j = 0; j < 3; j++){ - p_s[3 * i + j] = -g_cur[3 * i + j]; - g_old[3 * i + j] = g_cur[3 * i + j]; - } + if (iter == 0 || iter % 5 == 0){ // steepest descent direction + for (int i = 0; i < 3 * nlocal; i++) { + p_s[i] = -g_cur[i]; + g_old[i] = g_cur[i]; } } else { // conjugate direction - for (int i = 0; i < nlocal; i++) { - for (int j = 0; j < 3; j++){ - g2old += g_old[3 * i + j] * g_old[3 * i + j]; - g2 += g_cur[3 * i + j] * g_cur[3 * i + j]; - } + for (int i = 0; i < 3 * nlocal; i++) { + g2old += g_old[i] * g_old[i]; + g2 += g_cur[i] * g_cur[i]; } // now we need to collect/broadcast beta on this replica @@ -355,11 +351,9 @@ void MinSpinOSO_CG::calc_search_direction(int iter) // calculate conjugate direction - for (int i = 0; i < nlocal; i++) { - for (int j = 0; j < 3; j++){ - p_s[3 * i + j] = beta * p_s[3 * i + j] - g_cur[3 * i + j]; - g_old[3 * i + j] = g_cur[3 * i + j]; - } + for (int i = 0; i < 3 * nlocal; i++) { + p_s[i] = beta * p_s[i] - g_cur[i]; + g_old[i] = g_cur[i]; } } } @@ -385,9 +379,7 @@ void MinSpinOSO_CG::advance_spins() // rotate spins vm3(rot_mat, sp[i], s_new); - sp[i][0] = s_new[0]; - sp[i][1] = s_new[1]; - sp[i][2] = s_new[2]; + for (int j = 0; j < 3; j++) sp[i][j] = s_new[j]; } } From 0f2997533a258ca0869c57ca3c67b309b1d538d7 Mon Sep 17 00:00:00 2001 From: alxvov Date: Mon, 1 Jul 2019 08:36:44 +0000 Subject: [PATCH 11/74] get rid off double loops in cg --- src/SPIN/min_spin_oso_cg.cpp | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index d6bca32a40..5ea5ad8b6d 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -326,22 +326,15 @@ void MinSpinOSO_CG::calc_search_direction(int iter) double g2_global= 0.0; double g2old_global= 0.0; - // for some reason on a second iteration g_old = 0 - // so we make two iterations as steepest descent - - if (iter <= 2 || iter % 5 == 0){ // steepest descent direction - for (int i = 0; i < nlocal; i++) { - for (int j = 0; j < 3; j++){ - p_s[3 * i + j] = -g_cur[3 * i + j]; - g_old[3 * i + j] = g_cur[3 * i + j]; - } + if (iter == 0 || iter % 5 == 0){ // steepest descent direction + for (int i = 0; i < 3 * nlocal; i++) { + p_s[i] = -g_cur[i]; + g_old[i] = g_cur[i]; } } else { // conjugate direction - for (int i = 0; i < nlocal; i++) { - for (int j = 0; j < 3; j++){ - g2old += g_old[3 * i + j] * g_old[3 * i + j]; - g2 += g_cur[3 * i + j] * g_cur[3 * i + j]; - } + for (int i = 0; i < 3 * nlocal; i++) { + g2old += g_old[i] * g_old[i]; + g2 += g_cur[i] * g_cur[i]; } // now we need to collect/broadcast beta on this replica @@ -355,11 +348,9 @@ void MinSpinOSO_CG::calc_search_direction(int iter) // calculate conjugate direction - for (int i = 0; i < nlocal; i++) { - for (int j = 0; j < 3; j++){ - p_s[3 * i + j] = beta * p_s[3 * i + j] - g_cur[3 * i + j]; - g_old[3 * i + j] = g_cur[3 * i + j]; - } + for (int i = 0; i < 3 * nlocal; i++) { + p_s[i] = beta * p_s[i] - g_cur[i]; + g_old[i] = g_cur[i]; } } } From 5f74f6ddfa9aac318a00c17e1afd59f5d3438f15 Mon Sep 17 00:00:00 2001 From: alxvov Date: Mon, 1 Jul 2019 08:38:44 +0000 Subject: [PATCH 12/74] delete irrelevant comment --- src/SPIN/min_spin_oso_cg.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index 0c628f7567..4449832f54 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -326,9 +326,6 @@ void MinSpinOSO_CG::calc_search_direction(int iter) double g2_global= 0.0; double g2old_global= 0.0; - // for some reason on a second iteration g_old = 0 - // so we make two iterations as steepest descent - if (iter == 0 || iter % 5 == 0){ // steepest descent direction for (int i = 0; i < 3 * nlocal; i++) { p_s[i] = -g_cur[i]; From 6a2a4d5cfb00c51de71e4f59288a73b739cb2da9 Mon Sep 17 00:00:00 2001 From: alxvov Date: Mon, 1 Jul 2019 08:58:31 +0000 Subject: [PATCH 13/74] parallelisation of lbfgs --- src/SPIN/min_spin_oso_lbfgs.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index f0a4fcbd87..f21245899b 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -356,8 +356,8 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) dy[m_index][i] = g[i] - g_old[i]; dyds += ds[m_index][i] * dy[m_index][i]; } -// MPI_Allreduce(&dyds, &dyds_global, 1, MPI_DOUBLE, MPI_SUM, world); - if (fabs(dyds) > 1.0e-60) rho[m_index] = 1.0 / dyds; + MPI_Allreduce(&dyds, &dyds_global, 1, MPI_DOUBLE, MPI_SUM, world); + if (fabs(dyds) > 1.0e-60) rho[m_index] = 1.0 / dyds_global; else rho[m_index] = 1.0e60; // set the q vector @@ -378,10 +378,11 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) for (int i = 0; i < 3 * nlocal; i++) { sq += ds[c_ind][i] * q[i]; } + MPI_Allreduce(&sq, &sq_global, 1, MPI_DOUBLE, MPI_SUM, world); // update alpha - alpha[c_ind] = rho[c_ind] * sq; + alpha[c_ind] = rho[c_ind] * sq_global; // update q @@ -395,12 +396,13 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) for (int i = 0; i < 3 * nlocal; i++) { yy += dy[m_index][i] * dy[m_index][i]; } + MPI_Allreduce(&yy, &yy_global, 1, MPI_DOUBLE, MPI_SUM, world); - // calculate now search direction + // calculate now search direction - if (fabs(yy) > 1.0e-60) { + if (fabs(yy_global) > 1.0e-60) { for (int i = 0; i < 3 * nlocal; i++) { - p[i] = q[i] / (rho[m_index] * yy); + p[i] = q[i] / (rho[m_index] * yy_global); } }else{ for (int i = 0; i < 3 * nlocal; i++) { @@ -419,8 +421,9 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) for (int i = 0; i < 3 * nlocal; i++) { yr += dy[c_ind][i] * p[i]; } + MPI_Allreduce(&yr, &yr_global, 1, MPI_DOUBLE, MPI_SUM, world); - beta = rho[c_ind] * yr; + beta = rho[c_ind] * yr_global; for (int i = 0; i < 3 * nlocal; i++) { p[i] += ds[c_ind][i] * (alpha[c_ind] - beta); } @@ -514,7 +517,7 @@ void MinSpinOSO_LBFGS::rodrigues_rotation(const double *upp_tr, double *out) if (fabs(upp_tr[0]) < 1.0e-40 && fabs(upp_tr[1]) < 1.0e-40 && fabs(upp_tr[2]) < 1.0e-40){ - + // if upp_tr is zero, return unity matrix for(int k = 0; k < 3; k++){ for(int m = 0; m < 3; m++){ @@ -537,13 +540,13 @@ void MinSpinOSO_LBFGS::rodrigues_rotation(const double *upp_tr, double *out) double z = upp_tr[2]/theta; // diagonal elements of U - + out[0] = A + z * z * D; out[4] = A + y * y * D; out[8] = A + x * x * D; // off diagonal of U - + double s1 = -y * z *D; double s2 = x * z * D; double s3 = -x * y * D; From 0a0e85ac46b335e0df5242ee1b635a39adddc1a1 Mon Sep 17 00:00:00 2001 From: alxvov Date: Mon, 1 Jul 2019 09:03:17 +0000 Subject: [PATCH 14/74] rodr. rot. as in cg --- src/SPIN/min_spin_oso_lbfgs.cpp | 38 +++++++++++++++++---------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index f21245899b..d200e07f4a 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -513,6 +513,8 @@ double MinSpinOSO_LBFGS::fmnorm_sqr() void MinSpinOSO_LBFGS::rodrigues_rotation(const double *upp_tr, double *out) { + double theta,A,B,D,x,y,z; + double s1,s2,s3,a1,a2,a3; if (fabs(upp_tr[0]) < 1.0e-40 && fabs(upp_tr[1]) < 1.0e-40 && @@ -521,23 +523,23 @@ void MinSpinOSO_LBFGS::rodrigues_rotation(const double *upp_tr, double *out) // if upp_tr is zero, return unity matrix for(int k = 0; k < 3; k++){ for(int m = 0; m < 3; m++){ - if (m == k) out[3 * k + m] = 1.0; - else out[3 * k + m] = 0.0; - } + if (m == k) out[3 * k + m] = 1.0; + else out[3 * k + m] = 0.0; + } } return; } - double theta = sqrt(upp_tr[0] * upp_tr[0] + - upp_tr[1] * upp_tr[1] + - upp_tr[2] * upp_tr[2]); + theta = sqrt(upp_tr[0] * upp_tr[0] + + upp_tr[1] * upp_tr[1] + + upp_tr[2] * upp_tr[2]); - double A = cos(theta); - double B = sin(theta); - double D = 1 - A; - double x = upp_tr[0]/theta; - double y = upp_tr[1]/theta; - double z = upp_tr[2]/theta; + A = cos(theta); + B = sin(theta); + D = 1 - A; + x = upp_tr[0]/theta; + y = upp_tr[1]/theta; + z = upp_tr[2]/theta; // diagonal elements of U @@ -547,13 +549,13 @@ void MinSpinOSO_LBFGS::rodrigues_rotation(const double *upp_tr, double *out) // off diagonal of U - double s1 = -y * z *D; - double s2 = x * z * D; - double s3 = -x * y * D; + s1 = -y * z *D; + s2 = x * z * D; + s3 = -x * y * D; - double a1 = x * B; - double a2 = y * B; - double a3 = z * B; + a1 = x * B; + a2 = y * B; + a3 = z * B; out[1] = s1 + a1; out[3] = s1 - a1; From 1d64d78f240b3bc8a26872ba1cb78b5a83772b45 Mon Sep 17 00:00:00 2001 From: alxvov Date: Mon, 1 Jul 2019 09:40:14 +0000 Subject: [PATCH 15/74] handle memory in a right way --- src/SPIN/min_spin_oso_lbfgs.cpp | 93 ++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 41 deletions(-) diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index d200e07f4a..1143786d73 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -34,13 +34,11 @@ #include "output.h" #include "timer.h" #include "error.h" +#include "memory.h" #include "modify.h" #include "math_special.h" #include "math_const.h" -#include -using namespace std; - using namespace LAMMPS_NS; using namespace MathConst; @@ -63,8 +61,23 @@ static const char cite_minstyle_spin_oso_lbfgs[] = /* ---------------------------------------------------------------------- */ -MinSpinOSO_LBFGS::MinSpinOSO_LBFGS(LAMMPS *lmp) : Min(lmp) { +MinSpinOSO_LBFGS::MinSpinOSO_LBFGS(LAMMPS *lmp) : + Min(lmp), g_old(NULL), g_cur(NULL), p_s(NULL), ds(NULL), dy(NULL), rho(NULL) +{ if (lmp->citeme) lmp->citeme->add(cite_minstyle_spin_oso_lbfgs); + nlocal_max = 0; +} + +/* ---------------------------------------------------------------------- */ + +MinSpinOSO_LBFGS::~MinSpinOSO_LBFGS() +{ + memory->destroy(g_old); + memory->destroy(g_cur); + memory->destroy(p_s); + memory->destroy(ds); + memory->destroy(dy); + memory->destroy(rho); } /* ---------------------------------------------------------------------- */ @@ -79,6 +92,17 @@ void MinSpinOSO_LBFGS::init() dts = dt = update->dt; last_negative = update->ntimestep; + + // allocate tables + + nlocal_max = atom->nlocal; + memory->grow(g_old,3*nlocal_max,"min/spin/oso/lbfgs:g_old"); + memory->grow(g_cur,3*nlocal_max,"min/spin/oso/lbfgs:g_cur"); + memory->grow(p_s,3*nlocal_max,"min/spin/oso/lbfgs:p_s"); + memory->grow(rho,num_mem,"min/spin/oso/lbfgs:rho"); + memory->grow(ds,num_mem,3*nlocal_max,"min/spin/oso/lbfgs:ds"); + memory->grow(dy,num_mem,3*nlocal_max,"min/spin/oso/lbfgs:dy"); + } /* ---------------------------------------------------------------------- */ @@ -140,21 +164,19 @@ void MinSpinOSO_LBFGS::reset_vectors() int MinSpinOSO_LBFGS::iterate(int maxiter) { + int nlocal = atom->nlocal; bigint ntimestep; double fmdotfm; int flag, flagall; - // not sure it is best place to allocate memory - int nlocal = atom->nlocal; - g = (double *) calloc(3*nlocal, sizeof(double)); - p = (double *) calloc(3*nlocal, sizeof(double)); - g_old = (double *) calloc(3*nlocal, sizeof(double)); - rho = (double *) calloc(num_mem, sizeof(double)); - ds = (double **) calloc(num_mem, sizeof(double *)); - dy = (double **) calloc(num_mem, sizeof(double *)); - for (int k = 0; k < num_mem; k++){ - ds[k] = (double *) calloc(3*nlocal, sizeof(double)); - dy[k] = (double *) calloc(3*nlocal, sizeof(double)); + if (nlocal_max < nlocal) { + nlocal_max = nlocal; + memory->grow(g_old,3*nlocal_max,"min/spin/oso/cg:g_old"); + memory->grow(g_cur,3*nlocal_max,"min/spin/oso/cg:g_cur"); + memory->grow(p_s,3*nlocal_max,"min/spin/oso/cg:p_s"); + memory->grow(rho,num_mem,"min/spin/oso/lbfgs:rho"); + memory->grow(ds,num_mem,3*nlocal_max,"min/spin/oso/lbfgs:ds"); + memory->grow(dy,num_mem,3*nlocal_max,"min/spin/oso/lbfgs:dy"); } for (int iter = 0; iter < maxiter; iter++) { @@ -222,17 +244,6 @@ int MinSpinOSO_LBFGS::iterate(int maxiter) } } - free(p); - free(g); - free(g_old); - for (int k = 0; k < num_mem; k++){ - free(ds[k]); - free(dy[k]); - } - free(ds); - free(dy); - free(rho); - return MAXITER; } @@ -304,9 +315,9 @@ void MinSpinOSO_LBFGS::calc_gradient(double dts) // calculate gradients - g[3 * i + 0] = -tdampz * dts; - g[3 * i + 1] = tdampy * dts; - g[3 * i + 2] = -tdampx * dts; + g_cur[3 * i + 0] = -tdampz * dts; + g_cur[3 * i + 1] = tdampy * dts; + g_cur[3 * i + 2] = -tdampx * dts; } } @@ -343,8 +354,8 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) if (iter == 0){ // steepest descent direction for (int i = 0; i < 3 * nlocal; i++) { - p[i] = -g[i]; - g_old[i] = g[i]; + p_s[i] = -g_cur[i]; + g_old[i] = g_cur[i]; ds[m_index][i] = 0.0; dy[m_index][i] = 0.0; @@ -352,8 +363,8 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) } else { dyds = 0.0; for (int i = 0; i < 3 * nlocal; i++) { - ds[m_index][i] = p[i]; - dy[m_index][i] = g[i] - g_old[i]; + ds[m_index][i] = p_s[i]; + dy[m_index][i] = g_cur[i] - g_old[i]; dyds += ds[m_index][i] * dy[m_index][i]; } MPI_Allreduce(&dyds, &dyds_global, 1, MPI_DOUBLE, MPI_SUM, world); @@ -363,7 +374,7 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) // set the q vector for (int i = 0; i < 3 * nlocal; i++) { - q[i] = g[i]; + q[i] = g_cur[i]; } // loop over last m indecies @@ -402,11 +413,11 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) if (fabs(yy_global) > 1.0e-60) { for (int i = 0; i < 3 * nlocal; i++) { - p[i] = q[i] / (rho[m_index] * yy_global); + p_s[i] = q[i] / (rho[m_index] * yy_global); } }else{ for (int i = 0; i < 3 * nlocal; i++) { - p[i] = q[i] * 1.0e60; + p_s[i] = q[i] * 1.0e60; } } @@ -419,18 +430,18 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) // dot product between p and da yr = 0.0; for (int i = 0; i < 3 * nlocal; i++) { - yr += dy[c_ind][i] * p[i]; + yr += dy[c_ind][i] * p_s[i]; } MPI_Allreduce(&yr, &yr_global, 1, MPI_DOUBLE, MPI_SUM, world); beta = rho[c_ind] * yr_global; for (int i = 0; i < 3 * nlocal; i++) { - p[i] += ds[c_ind][i] * (alpha[c_ind] - beta); + p_s[i] += ds[c_ind][i] * (alpha[c_ind] - beta); } } for (int i = 0; i < 3 * nlocal; i++) { - p[i] = -1.0 * p[i]; - g_old[i] = g[i]; + p_s[i] = -1.0 * p_s[i]; + g_old[i] = g_cur[i]; } } @@ -455,7 +466,7 @@ void MinSpinOSO_LBFGS::advance_spins() // loop on all spins on proc. for (int i = 0; i < nlocal; i++) { - rodrigues_rotation(p + 3 * i, rot_mat); + rodrigues_rotation(p_s + 3 * i, rot_mat); // rotate spins From 56c34e42670b7b2c079d462e480f17afe4508cb1 Mon Sep 17 00:00:00 2001 From: alxvov Date: Mon, 1 Jul 2019 09:41:34 +0000 Subject: [PATCH 16/74] merge memory alloc for lbfgs --- src/SPIN/min_spin_oso_lbfgs.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/SPIN/min_spin_oso_lbfgs.h b/src/SPIN/min_spin_oso_lbfgs.h index 0a06824382..3aa326142c 100644 --- a/src/SPIN/min_spin_oso_lbfgs.h +++ b/src/SPIN/min_spin_oso_lbfgs.h @@ -28,7 +28,7 @@ class MinSpinOSO_LBFGS : public Min { public: MinSpinOSO_LBFGS(class LAMMPS *); - ~MinSpinOSO_LBFGS() {} + virtual ~MinSpinOSO_LBFGS(); void init(); void setup_style(); int modify_param(int, char **); @@ -43,6 +43,7 @@ public: private: // global and spin timesteps + int nlocal_max; // max value of nlocal (for size of lists) double dt; double dts; @@ -52,9 +53,9 @@ private: double *spvec; // variables for atomic dof, as 1d vector double *fmvec; // variables for atomic dof, as 1d vector - double *g; // gradient vector + double *g_cur; // current gradient vector double *g_old; // gradient vector at previous step - double *p; // search direction vector + double *p_s; // search direction vector double **ds; // change in rotation matrix between two iterations, da double **dy; // change in gradients between two iterations, dg double *rho; // estimation of curvature From 924c610ebe69ae10656cd9ba70cc05f2723c900f Mon Sep 17 00:00:00 2001 From: alxvov Date: Mon, 1 Jul 2019 09:45:05 +0000 Subject: [PATCH 17/74] use for loop --- src/SPIN/min_spin_oso_lbfgs.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index 1143786d73..f3643168a4 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -471,9 +471,7 @@ void MinSpinOSO_LBFGS::advance_spins() // rotate spins vm3(rot_mat, sp[i], s_new); - sp[i][0] = s_new[0]; - sp[i][1] = s_new[1]; - sp[i][2] = s_new[2]; + for (int j = 0; j < 3; j++) sp[i][j] = s_new[j]; } } From 398f33d4072576e9237744f95709982c1e6c895a Mon Sep 17 00:00:00 2001 From: alxvov Date: Tue, 2 Jul 2019 16:36:06 +0000 Subject: [PATCH 18/74] added cubic line search --- src/SPIN/min_spin_oso_lbfgs_ls.cpp | 717 +++++++++++++++++++++++++++++ src/SPIN/min_spin_oso_lbfgs_ls.h | 84 ++++ 2 files changed, 801 insertions(+) create mode 100644 src/SPIN/min_spin_oso_lbfgs_ls.cpp create mode 100644 src/SPIN/min_spin_oso_lbfgs_ls.h diff --git a/src/SPIN/min_spin_oso_lbfgs_ls.cpp b/src/SPIN/min_spin_oso_lbfgs_ls.cpp new file mode 100644 index 0000000000..f054755129 --- /dev/null +++ b/src/SPIN/min_spin_oso_lbfgs_ls.cpp @@ -0,0 +1,717 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + 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. +------------------------------------------------------------------------- */ + +/* ------------------------------------------------------------------------ + Contributing authors: Aleksei Ivanov (UI) + Julien Tranchida (SNL) + + Please cite the related publication: + Ivanov, A. V., Uzdin, V. M., & Jónsson, H. (2019). Fast and Robust + Algorithm for the Minimisation of the Energy of Spin Systems. arXiv + preprint arXiv:1904.02669. +------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include "min_spin_oso_lbfgs_ls.h" +#include "universe.h" +#include "atom.h" +#include "citeme.h" +#include "force.h" +#include "update.h" +#include "output.h" +#include "timer.h" +#include "error.h" +#include "memory.h" +#include "modify.h" +#include "math_special.h" +#include "math_const.h" +#include + + +using namespace LAMMPS_NS; +using namespace MathConst; + +static const char cite_minstyle_spin_oso_lbfgs_ls[] = + "min_style spin/oso_lbfgs_ls command:\n\n" + "@article{ivanov2019fast,\n" + "title={Fast and Robust Algorithm for the Minimisation of the Energy of " + "Spin Systems},\n" + "author={Ivanov, A. V and Uzdin, V. M. and J{\'o}nsson, H.},\n" + "journal={arXiv preprint arXiv:1904.02669},\n" + "year={2019}\n" + "}\n\n"; + +// EPS_ENERGY = minimum normalization for energy tolerance + +#define EPS_ENERGY 1.0e-8 + +#define DELAYSTEP 5 + + +/* ---------------------------------------------------------------------- */ + +MinSpinOSO_LBFGS_LS::MinSpinOSO_LBFGS_LS(LAMMPS *lmp) : + Min(lmp), g_old(NULL), g_cur(NULL), p_s(NULL), ds(NULL), dy(NULL), rho(NULL) +{ + if (lmp->citeme) lmp->citeme->add(cite_minstyle_spin_oso_lbfgs_ls); + nlocal_max = 0; +} + +/* ---------------------------------------------------------------------- */ + +MinSpinOSO_LBFGS_LS::~MinSpinOSO_LBFGS_LS() +{ + memory->destroy(g_old); + memory->destroy(g_cur); + memory->destroy(p_s); + memory->destroy(ds); + memory->destroy(dy); + memory->destroy(rho); + memory->destroy(sp_copy); +} + +/* ---------------------------------------------------------------------- */ + +void MinSpinOSO_LBFGS_LS::init() +{ + alpha_damp = 1.0; + discrete_factor = 10.0; + num_mem = 3; + der_e_cur = 0.0; + der_e_pr = 0.0; + use_line_search = 1; + + Min::init(); + + dts = dt = update->dt; + last_negative = update->ntimestep; + + // allocate tables + + nlocal_max = atom->nlocal; + memory->grow(g_old,3*nlocal_max,"min/spin/oso/lbfgs_ls:g_old"); + memory->grow(g_cur,3*nlocal_max,"min/spin/oso/lbfgs_ls:g_cur"); + memory->grow(p_s,3*nlocal_max,"min/spin/oso/lbfgs_ls:p_s"); + memory->grow(rho,num_mem,"min/spin/oso/lbfgs_ls:rho"); + memory->grow(ds,num_mem,3*nlocal_max,"min/spin/oso/lbfgs_ls:ds"); + memory->grow(dy,num_mem,3*nlocal_max,"min/spin/oso/lbfgs_ls:dy"); + memory->grow(sp_copy,nlocal_max,3,"min/spin/oso/lbfgs_ls:sp_copy"); + +} + +/* ---------------------------------------------------------------------- */ + +void MinSpinOSO_LBFGS_LS::setup_style() +{ + double **v = atom->v; + int nlocal = atom->nlocal; + + // check if the atom/spin style is defined + + if (!atom->sp_flag) + error->all(FLERR,"min/spin_oso_lbfgs_ls requires atom/spin style"); + + for (int i = 0; i < nlocal; i++) + v[i][0] = v[i][1] = v[i][2] = 0.0; +} + +/* ---------------------------------------------------------------------- */ + +int MinSpinOSO_LBFGS_LS::modify_param(int narg, char **arg) +{ + if (strcmp(arg[0],"alpha_damp") == 0) { + if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); + alpha_damp = force->numeric(FLERR,arg[1]); + return 2; + } + if (strcmp(arg[0],"discrete_factor") == 0) { + if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); + discrete_factor = force->numeric(FLERR,arg[1]); + return 2; + } + return 0; +} + +/* ---------------------------------------------------------------------- + set current vector lengths and pointers + called after atoms have migrated +------------------------------------------------------------------------- */ + +void MinSpinOSO_LBFGS_LS::reset_vectors() +{ + // atomic dof + + // size sp is 4N vector + nvec = 4 * atom->nlocal; + if (nvec) spvec = atom->sp[0]; + + nvec = 3 * atom->nlocal; + if (nvec) fmvec = atom->fm[0]; + + if (nvec) xvec = atom->x[0]; + if (nvec) fvec = atom->f[0]; +} + +/* ---------------------------------------------------------------------- + minimization via damped spin dynamics +------------------------------------------------------------------------- */ + +int MinSpinOSO_LBFGS_LS::iterate(int maxiter) +{ + int nlocal = atom->nlocal; + bigint ntimestep; + double fmdotfm; + int flag, flagall; + double **sp = atom->sp; + + if (nlocal_max < nlocal) { + nlocal_max = nlocal; + memory->grow(g_old,3*nlocal_max,"min/spin/oso/lbfgs_ls:g_old"); + memory->grow(g_cur,3*nlocal_max,"min/spin/oso/lbfgs_ls:g_cur"); + memory->grow(p_s,3*nlocal_max,"min/spin/oso/lbfgs_ls:p_s"); + memory->grow(rho,num_mem,"min/spin/oso/lbfgs_ls:rho"); + memory->grow(ds,num_mem,3*nlocal_max,"min/spin/oso/lbfgs_ls:ds"); + memory->grow(dy,num_mem,3*nlocal_max,"min/spin/oso/lbfgs_ls:dy"); + memory->grow(sp_copy,nlocal_max,3,"min/spin/oso/lbfgs_ls:sp_copy"); + } + + + for (int iter = 0; iter < maxiter; iter++) { + + if (timer->check_timeout(niter)) + return TIMEOUT; + + ntimestep = ++update->ntimestep; + niter++; + + // optimize timestep accross processes / replicas + // need a force calculation for timestep optimization + + if (iter == 0){ + ecurrent = energy_force(0); + calc_gradient(1.0); + neval++; + }else{ + } + calc_search_direction(iter); + + if (use_line_search) { + der_e_cur = 0.0; + for (int i = 0; i < 3 * nlocal; i++) { + der_e_cur += g_cur[i] * p_s[i]; + } + } + + if (use_line_search){ + // here we need to do line search + for (int i = 0; i < nlocal; i++) { + for (int j = 0; j < 3; j++) sp_copy[i][j] = sp[i][j]; + } + eprevious = ecurrent; + der_e_pr = der_e_cur; + + calc_and_make_step(0.0, 1.0, 0); + } + else{ + advance_spins(); + eprevious = ecurrent; + ecurrent = energy_force(0); + neval++; + } + + //// energy tolerance criterion + //// only check after DELAYSTEP elapsed since velocties reset to 0 + //// sync across replicas if running multi-replica minimization + + if (update->etol > 0.0 && ntimestep-last_negative > DELAYSTEP) { + if (update->multireplica == 0) { + if (fabs(ecurrent-eprevious) < + update->etol * 0.5*(fabs(ecurrent) + fabs(eprevious) + EPS_ENERGY)) + return ETOL; + } else { + if (fabs(ecurrent-eprevious) < + update->etol * 0.5*(fabs(ecurrent) + fabs(eprevious) + EPS_ENERGY)) + flag = 0; + else flag = 1; + MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,universe->uworld); + if (flagall == 0) return ETOL; + } + } + + // magnetic torque tolerance criterion + // sync across replicas if running multi-replica minimization + + if (update->ftol > 0.0) { + fmdotfm = fmnorm_sqr(); + if (update->multireplica == 0) { + if (fmdotfm < update->ftol*update->ftol) return FTOL; + } else { + if (fmdotfm < update->ftol*update->ftol) flag = 0; + else flag = 1; + MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,universe->uworld); + if (flagall == 0) return FTOL; + } + } + + // output for thermo, dump, restart files + + if (output->next == ntimestep) { + timer->stamp(); + output->write(ntimestep); + timer->stamp(Timer::OUTPUT); + } + } + + return MAXITER; +} + +/* ---------------------------------------------------------------------- + evaluate max timestep +---------------------------------------------------------------------- */ + +double MinSpinOSO_LBFGS_LS::evaluate_dt() +{ + double dtmax; + double fmsq; + double fmaxsqone,fmaxsqloc,fmaxsqall; + int nlocal = atom->nlocal; + double **fm = atom->fm; + + // finding max fm on this proc. + + fmsq = fmaxsqone = fmaxsqloc = fmaxsqall = 0.0; + for (int i = 0; i < nlocal; i++) { + fmsq = fm[i][0]*fm[i][0]+fm[i][1]*fm[i][1]+fm[i][2]*fm[i][2]; + fmaxsqone = MAX(fmaxsqone,fmsq); + } + + // finding max fm on this replica + + fmaxsqloc = fmaxsqone; + MPI_Allreduce(&fmaxsqone,&fmaxsqloc,1,MPI_DOUBLE,MPI_MAX,world); + + // finding max fm over all replicas, if necessary + // this communicator would be invalid for multiprocess replicas + + fmaxsqall = fmaxsqloc; + if (update->multireplica == 1) { + fmaxsqall = fmaxsqloc; + MPI_Allreduce(&fmaxsqloc,&fmaxsqall,1,MPI_DOUBLE,MPI_MAX,universe->uworld); + } + + if (fmaxsqall == 0.0) + error->all(FLERR,"Incorrect fmaxsqall calculation"); + + // define max timestep by dividing by the + // inverse of max frequency by discrete_factor + + dtmax = MY_2PI/(discrete_factor*sqrt(fmaxsqall)); + + return dtmax; +} + +/* ---------------------------------------------------------------------- + calculate gradients +---------------------------------------------------------------------- */ + +void MinSpinOSO_LBFGS_LS::calc_gradient(double dts) +{ + int nlocal = atom->nlocal; + double **sp = atom->sp; + double **fm = atom->fm; + double tdampx, tdampy, tdampz; + + // loop on all spins on proc. + + for (int i = 0; i < nlocal; i++) { + + // calc. damping torque + + tdampx = -alpha_damp*(fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]); + tdampy = -alpha_damp*(fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); + tdampz = -alpha_damp*(fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); + + // calculate gradients + + g_cur[3 * i + 0] = -tdampz * dts; + g_cur[3 * i + 1] = tdampy * dts; + g_cur[3 * i + 2] = -tdampx * dts; + } +} + +/* ---------------------------------------------------------------------- + search direction +---------------------------------------------------------------------- */ + +void MinSpinOSO_LBFGS_LS::calc_search_direction(int iter) +{ + int nlocal = atom->nlocal; + + double dyds = 0.0; + double sq = 0.0; + double yy = 0.0; + double yr = 0.0; + double beta = 0.0; + + double dyds_global = 0.0; + double sq_global = 0.0; + double yy_global = 0.0; + double yr_global = 0.0; + double beta_global = 0.0; + + int m_index = iter % num_mem; // memory index + int c_ind = 0; + double *q; + double *alpha; + + q = (double *) calloc(3*nlocal, sizeof(double)); + alpha = (double *) calloc(num_mem, sizeof(double)); + + // for some reason on a second iteration g_old = 0 + // so we make two iterations as steepest descent + + if (iter == 0){ // steepest descent direction + for (int i = 0; i < 3 * nlocal; i++) { + p_s[i] = -g_cur[i]; + g_old[i] = g_cur[i]; + ds[m_index][i] = 0.0; + dy[m_index][i] = 0.0; + + } + } else { + dyds = 0.0; + for (int i = 0; i < 3 * nlocal; i++) { + ds[m_index][i] = p_s[i]; + dy[m_index][i] = g_cur[i] - g_old[i]; + dyds += ds[m_index][i] * dy[m_index][i]; + } + MPI_Allreduce(&dyds, &dyds_global, 1, MPI_DOUBLE, MPI_SUM, world); + if (fabs(dyds) > 1.0e-60) rho[m_index] = 1.0 / dyds_global; + else rho[m_index] = 1.0e60; + + // set the q vector + + for (int i = 0; i < 3 * nlocal; i++) { + q[i] = g_cur[i]; + } + + // loop over last m indecies + for(int k = num_mem - 1; k > -1; k--) { + // this loop should run from the newest memory to the oldest one. + + c_ind = (k + m_index + 1) % num_mem; + + // dot product between dg and q + + sq = 0.0; + for (int i = 0; i < 3 * nlocal; i++) { + sq += ds[c_ind][i] * q[i]; + } + MPI_Allreduce(&sq, &sq_global, 1, MPI_DOUBLE, MPI_SUM, world); + + // update alpha + + alpha[c_ind] = rho[c_ind] * sq_global; + + // update q + + for (int i = 0; i < 3 * nlocal; i++) { + q[i] -= alpha[c_ind] * dy[c_ind][i]; + } + } + + // dot product between dg with itself + yy = 0.0; + for (int i = 0; i < 3 * nlocal; i++) { + yy += dy[m_index][i] * dy[m_index][i]; + } + MPI_Allreduce(&yy, &yy_global, 1, MPI_DOUBLE, MPI_SUM, world); + + // calculate now search direction + + if (fabs(yy_global) > 1.0e-60) { + for (int i = 0; i < 3 * nlocal; i++) { + p_s[i] = q[i] / (rho[m_index] * yy_global); + } + }else{ + for (int i = 0; i < 3 * nlocal; i++) { + p_s[i] = q[i] * 1.0e60; + } + } + + for (int k = 0; k < num_mem; k++){ + // this loop should run from the oldest memory to the newest one. + + if (iter < num_mem) c_ind = k; + else c_ind = (k + m_index + 1) % num_mem; + + // dot product between p and da + yr = 0.0; + for (int i = 0; i < 3 * nlocal; i++) { + yr += dy[c_ind][i] * p_s[i]; + } + MPI_Allreduce(&yr, &yr_global, 1, MPI_DOUBLE, MPI_SUM, world); + + beta = rho[c_ind] * yr_global; + for (int i = 0; i < 3 * nlocal; i++) { + p_s[i] += ds[c_ind][i] * (alpha[c_ind] - beta); + } + } + for (int i = 0; i < 3 * nlocal; i++) { + p_s[i] = -1.0 * p_s[i]; + g_old[i] = g_cur[i]; + } + } + + free(q); + free(alpha); + +} + +/* ---------------------------------------------------------------------- + rotation of spins along the search direction +---------------------------------------------------------------------- */ + +void MinSpinOSO_LBFGS_LS::advance_spins() +{ + int nlocal = atom->nlocal; + double **sp = atom->sp; + double **fm = atom->fm; + double tdampx, tdampy, tdampz; + double rot_mat[9]; // exponential of matrix made of search direction + double s_new[3]; + + // loop on all spins on proc. + + for (int i = 0; i < nlocal; i++) { + rodrigues_rotation(p_s + 3 * i, rot_mat); + + // rotate spins + + vm3(rot_mat, sp[i], s_new); + for (int j = 0; j < 3; j++) sp[i][j] = s_new[j]; + } +} + +/* ---------------------------------------------------------------------- + compute and return ||mag. torque||_2^2 +------------------------------------------------------------------------- */ + +double MinSpinOSO_LBFGS_LS::fmnorm_sqr() +{ + int nlocal = atom->nlocal; + double tx,ty,tz; + double **sp = atom->sp; + double **fm = atom->fm; + + // calc. magnetic torques + + double local_norm2_sqr = 0.0; + for (int i = 0; i < nlocal; i++) { + tx = (fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]); + ty = (fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); + tz = (fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); + + local_norm2_sqr += tx*tx + ty*ty + tz*tz; + } + + // no extra atom calc. for spins + + if (nextra_atom) + error->all(FLERR,"extra atom option not available yet"); + + double norm2_sqr = 0.0; + MPI_Allreduce(&local_norm2_sqr,&norm2_sqr,1,MPI_DOUBLE,MPI_SUM,world); + + return norm2_sqr; +} + +/* ---------------------------------------------------------------------- + calculate 3x3 matrix exponential using Rodrigues' formula + (R. Murray, Z. Li, and S. Shankar Sastry, + A Mathematical Introduction to + Robotic Manipulation (1994), p. 28 and 30). + + upp_tr - vector x, y, z so that one calculate + U = exp(A) with A= [[0, x, y], + [-x, 0, z], + [-y, -z, 0]] +------------------------------------------------------------------------- */ + +void MinSpinOSO_LBFGS_LS::rodrigues_rotation(const double *upp_tr, double *out) +{ + double theta,A,B,D,x,y,z; + double s1,s2,s3,a1,a2,a3; + + if (fabs(upp_tr[0]) < 1.0e-40 && + fabs(upp_tr[1]) < 1.0e-40 && + fabs(upp_tr[2]) < 1.0e-40){ + + // if upp_tr is zero, return unity matrix + for(int k = 0; k < 3; k++){ + for(int m = 0; m < 3; m++){ + if (m == k) out[3 * k + m] = 1.0; + else out[3 * k + m] = 0.0; + } + } + return; + } + + theta = sqrt(upp_tr[0] * upp_tr[0] + + upp_tr[1] * upp_tr[1] + + upp_tr[2] * upp_tr[2]); + + A = cos(theta); + B = sin(theta); + D = 1 - A; + x = upp_tr[0]/theta; + y = upp_tr[1]/theta; + z = upp_tr[2]/theta; + + // diagonal elements of U + + out[0] = A + z * z * D; + out[4] = A + y * y * D; + out[8] = A + x * x * D; + + // off diagonal of U + + s1 = -y * z *D; + s2 = x * z * D; + s3 = -x * y * D; + + a1 = x * B; + a2 = y * B; + a3 = z * B; + + out[1] = s1 + a1; + out[3] = s1 - a1; + out[2] = s2 + a2; + out[6] = s2 - a2; + out[5] = s3 + a3; + out[7] = s3 - a3; + +} + +/* ---------------------------------------------------------------------- + out = vector^T x m, + m -- 3x3 matrix , v -- 3-d vector +------------------------------------------------------------------------- */ + +void MinSpinOSO_LBFGS_LS::vm3(const double *m, const double *v, double *out) +{ + for(int i = 0; i < 3; i++){ + out[i] *= 0.0; + for(int j = 0; j < 3; j++){ + out[i] += *(m + 3 * j + i) * v[j]; + } + } +} + + +void MinSpinOSO_LBFGS_LS::make_step(double c, double *energy_and_der) +{ + double p_scaled[3]; + int nlocal = atom->nlocal; + double rot_mat[9]; // exponential of matrix made of search direction + double s_new[3]; + double **sp = atom->sp; + + for (int i = 0; i < nlocal; i++) { + + // scale the search direction + + for (int j = 0; j < 3; j++) p_scaled[j] = c * p_s[3 * i + j]; + + // calculate rotation matrix + + rodrigues_rotation(p_scaled, rot_mat); + + // rotate spins + + vm3(rot_mat, sp[i], s_new); + for (int j = 0; j < 3; j++) sp[i][j] = s_new[j]; + } + + ecurrent = energy_force(0); + calc_gradient(1.0); + neval++; + der_e_cur = 0.0; + for (int i = 0; i < 3 * nlocal; i++) { + der_e_cur += g_cur[i] * p_s[i]; + } + energy_and_der[0] = ecurrent; + energy_and_der[1] = der_e_cur; +} + + +int MinSpinOSO_LBFGS_LS::calc_and_make_step(double a, double b, int index) +{ + double e_and_d[2] = {0.0, 0.0}; + double alpha, c1, c2, c3; + double **sp = atom->sp; + int nlocal = atom->nlocal; + + make_step(b, e_and_d); + ecurrent = e_and_d[0]; + der_e_cur = e_and_d[1]; + index++; + + if (awc(der_e_pr, eprevious, e_and_d[1], e_and_d[0]) || index == 3){ + + for (int i = 0; i < 3 * nlocal; i++) { + p_s[i] = b * p_s[i]; + } + return 1; + } + else{ + double r, f0, f1, df0, df1; + r = b - a; + f0 = eprevious; + f1 = ecurrent; + df0 = der_e_pr; + df1 = der_e_cur; + + c1 = -2.0*(f1-f0)/(r*r*r)+(df1+df0)/(r*r); + c2 = 3.0*(f1-f0)/(r*r)-(df1+2.0*df0)/(r); + c3 = df0; + + alpha = (-c2 + sqrt(c2*c2 - 3.0*c1*c3))/(3.0*c1); + if (alpha < 0.0) alpha = r/2.0; + + for (int i = 0; i < nlocal; i++) { + for (int j = 0; j < 3; j++) sp[i][j] = sp_copy[i][j]; + } + calc_and_make_step(0.0, alpha, index); + } + + return 0; + +} + + +int MinSpinOSO_LBFGS_LS::awc(double der_phi_0, double phi_0, double der_phi_j, double phi_j){ + + double eps = 1.0e-6; + double delta = 0.1; + double sigma = 0.9; + + if ((phi_j <= phi_0 + eps * fabs(phi_0)) && + ((2.0*delta - 1.0) * der_phi_0 >= der_phi_j >= sigma * der_phi_0)) + return 1; + else + return 0; +} diff --git a/src/SPIN/min_spin_oso_lbfgs_ls.h b/src/SPIN/min_spin_oso_lbfgs_ls.h new file mode 100644 index 0000000000..3e0e608ecb --- /dev/null +++ b/src/SPIN/min_spin_oso_lbfgs_ls.h @@ -0,0 +1,84 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + 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 + +MinimizeStyle(spin/oso_lbfgs_ls, MinSpinOSO_LBFGS_LS) + +#else + +#ifndef LMP_MIN_SPIN_OSO_LBFGS_LS_H +#define LMP_MIN_SPIN_OSO_LBFGS_LS_H + +#include "min.h" + +namespace LAMMPS_NS { + +class MinSpinOSO_LBFGS_LS : public Min { + +public: + MinSpinOSO_LBFGS_LS(class LAMMPS *); + virtual ~MinSpinOSO_LBFGS_LS(); + void init(); + void setup_style(); + int modify_param(int, char **); + void reset_vectors(); + int iterate(int); + double evaluate_dt(); + void advance_spins(); + double fmnorm_sqr(); + void calc_gradient(double); + void calc_search_direction(int); + +private: + // global and spin timesteps + + int nlocal_max; // max value of nlocal (for size of lists) + double dt; + double dts; + + double alpha_damp; // damping for spin minimization + double discrete_factor; // factor for spin timestep evaluation + + double *spvec; // variables for atomic dof, as 1d vector + double *fmvec; // variables for atomic dof, as 1d vector + + double *g_cur; // current gradient vector + double *g_old; // gradient vector at previous step + double *p_s; // search direction vector + double **ds; // change in rotation matrix between two iterations, da + double **dy; // change in gradients between two iterations, dg + double *rho; // estimation of curvature + double **sp_copy; // copy of the spins + + int num_mem; // number of stored steps + + double der_e_cur; // current derivative along search dir. + double der_e_pr; // previous derivative along search dir. + + int use_line_search; // use line search or not. + + + void vm3(const double *, const double *, double *); + void rodrigues_rotation(const double *, double *); + int calc_and_make_step(double, double, int); + int awc(double, double, double, double); + void make_step(double, double *); + + bigint last_negative; +}; + +} + +#endif +#endif From ee8d3ced31fb88bc0356fd55e52053106495ad0a Mon Sep 17 00:00:00 2001 From: alxvov Date: Tue, 2 Jul 2019 16:39:27 +0000 Subject: [PATCH 19/74] change cg to lbfgs in oso_lbfgs --- src/SPIN/min_spin_oso_lbfgs.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index f3643168a4..2283a55e51 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -171,9 +171,9 @@ int MinSpinOSO_LBFGS::iterate(int maxiter) if (nlocal_max < nlocal) { nlocal_max = nlocal; - memory->grow(g_old,3*nlocal_max,"min/spin/oso/cg:g_old"); - memory->grow(g_cur,3*nlocal_max,"min/spin/oso/cg:g_cur"); - memory->grow(p_s,3*nlocal_max,"min/spin/oso/cg:p_s"); + memory->grow(g_old,3*nlocal_max,"min/spin/oso/lbfgs:g_old"); + memory->grow(g_cur,3*nlocal_max,"min/spin/oso/lbfgs:g_cur"); + memory->grow(p_s,3*nlocal_max,"min/spin/oso/lbfgs:p_s"); memory->grow(rho,num_mem,"min/spin/oso/lbfgs:rho"); memory->grow(ds,num_mem,3*nlocal_max,"min/spin/oso/lbfgs:ds"); memory->grow(dy,num_mem,3*nlocal_max,"min/spin/oso/lbfgs:dy"); From fd5bc857b24f3d62944c45f0d55542deba473aeb Mon Sep 17 00:00:00 2001 From: alxvov Date: Tue, 2 Jul 2019 17:03:15 +0000 Subject: [PATCH 20/74] calculate energy in the beginning only once --- src/SPIN/min_spin.cpp | 2 +- src/SPIN/min_spin_oso_cg.cpp | 4 ++-- src/SPIN/min_spin_oso_lbfgs.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SPIN/min_spin.cpp b/src/SPIN/min_spin.cpp index 2bddc110e7..2277281e80 100644 --- a/src/SPIN/min_spin.cpp +++ b/src/SPIN/min_spin.cpp @@ -133,7 +133,7 @@ int MinSpin::iterate(int maxiter) // optimize timestep accross processes / replicas // need a force calculation for timestep optimization - energy_force(0); + if (iter == 0) energy_force(0); dts = evaluate_dt(); // apply damped precessional dynamics to the spins diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index 4449832f54..9ed2cb96ea 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -180,8 +180,8 @@ int MinSpinOSO_CG::iterate(int maxiter) // optimize timestep accross processes / replicas // need a force calculation for timestep optimization - - energy_force(0); + + if (iter == 0) energy_force(0); dts = evaluate_dt(); calc_gradient(dts); diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index 2283a55e51..b54c42ebfd 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -190,7 +190,7 @@ int MinSpinOSO_LBFGS::iterate(int maxiter) // optimize timestep accross processes / replicas // need a force calculation for timestep optimization - energy_force(0); + if (iter == 0) energy_force(0); // dts = evaluate_dt(); // dts = 1.0; calc_gradient(1.0); From 44ca54fa25cc90f772c352ee0bfa75bad687a16e Mon Sep 17 00:00:00 2001 From: alxvov Date: Tue, 2 Jul 2019 17:06:53 +0000 Subject: [PATCH 21/74] a bit more comments --- src/SPIN/min_spin_oso_cg.cpp | 7 +++++-- src/SPIN/min_spin_oso_lbfgs.cpp | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index 9ed2cb96ea..8d03ada45d 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -12,7 +12,7 @@ ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------ - Contributing authors: Aleksei Ivanov (UI) + Contributing authors: Aleksei Ivanov (University of Iceland) Julien Tranchida (SNL) Please cite the related publication: @@ -313,7 +313,10 @@ void MinSpinOSO_CG::calc_gradient(double dts) } /* ---------------------------------------------------------------------- - search direction + search direction: + The Fletcher-Reeves conj. grad. method + See Jorge Nocedal and Stephen J. Wright 'Numerical + Optimization' Second Edition, 2006 (p. 121) ---------------------------------------------------------------------- */ void MinSpinOSO_CG::calc_search_direction(int iter) diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index b54c42ebfd..81c36d5e32 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -12,7 +12,7 @@ ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------ - Contributing authors: Aleksei Ivanov (UI) + Contributing authors: Aleksei Ivanov (University of Iceland) Julien Tranchida (SNL) Please cite the related publication: @@ -322,7 +322,10 @@ void MinSpinOSO_LBFGS::calc_gradient(double dts) } /* ---------------------------------------------------------------------- - search direction + search direction: + Limited-memory BFGS. + See Jorge Nocedal and Stephen J. Wright 'Numerical + Optimization' Second Edition, 2006 (p. 177) ---------------------------------------------------------------------- */ void MinSpinOSO_LBFGS::calc_search_direction(int iter) From e3ed8d856209b3f7116f82b3077660ad4c2893ba Mon Sep 17 00:00:00 2001 From: alxvov Date: Tue, 2 Jul 2019 18:02:22 +0000 Subject: [PATCH 22/74] parallelisation of lbfgs, change indentation, more comments --- src/SPIN/min_spin_oso_lbfgs_ls.cpp | 140 ++++++++++++++++------------- 1 file changed, 79 insertions(+), 61 deletions(-) diff --git a/src/SPIN/min_spin_oso_lbfgs_ls.cpp b/src/SPIN/min_spin_oso_lbfgs_ls.cpp index f054755129..38a557266e 100644 --- a/src/SPIN/min_spin_oso_lbfgs_ls.cpp +++ b/src/SPIN/min_spin_oso_lbfgs_ls.cpp @@ -12,7 +12,7 @@ ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------ - Contributing authors: Aleksei Ivanov (UI) + Contributing authors: Aleksei Ivanov (University of Iceland) Julien Tranchida (SNL) Please cite the related publication: @@ -176,6 +176,7 @@ int MinSpinOSO_LBFGS_LS::iterate(int maxiter) double fmdotfm; int flag, flagall; double **sp = atom->sp; + double der_e_cur_global = 0.0; if (nlocal_max < nlocal) { nlocal_max = nlocal; @@ -213,6 +214,8 @@ int MinSpinOSO_LBFGS_LS::iterate(int maxiter) for (int i = 0; i < 3 * nlocal; i++) { der_e_cur += g_cur[i] * p_s[i]; } + MPI_Allreduce(&der_e_cur, &der_e_cur_global, 1, MPI_DOUBLE, MPI_SUM, world); + der_e_cur = der_e_cur_global; } if (use_line_search){ @@ -353,7 +356,10 @@ void MinSpinOSO_LBFGS_LS::calc_gradient(double dts) } /* ---------------------------------------------------------------------- - search direction + search direction: + Limited-memory BFGS. + See Jorge Nocedal and Stephen J. Wright 'Numerical + Optimization' Second Edition, 2006 (p. 177) ---------------------------------------------------------------------- */ void MinSpinOSO_LBFGS_LS::calc_search_direction(int iter) @@ -624,26 +630,26 @@ void MinSpinOSO_LBFGS_LS::vm3(const double *m, const double *v, double *out) void MinSpinOSO_LBFGS_LS::make_step(double c, double *energy_and_der) { - double p_scaled[3]; - int nlocal = atom->nlocal; - double rot_mat[9]; // exponential of matrix made of search direction - double s_new[3]; - double **sp = atom->sp; + double p_scaled[3]; + int nlocal = atom->nlocal; + double rot_mat[9]; // exponential of matrix made of search direction + double s_new[3]; + double **sp = atom->sp; + double der_e_cur_global = 0.0;; - for (int i = 0; i < nlocal; i++) { + for (int i = 0; i < nlocal; i++) { + // scale the search direction - // scale the search direction + for (int j = 0; j < 3; j++) p_scaled[j] = c * p_s[3 * i + j]; - for (int j = 0; j < 3; j++) p_scaled[j] = c * p_s[3 * i + j]; + // calculate rotation matrix - // calculate rotation matrix + rodrigues_rotation(p_scaled, rot_mat); - rodrigues_rotation(p_scaled, rot_mat); + // rotate spins - // rotate spins - - vm3(rot_mat, sp[i], s_new); - for (int j = 0; j < 3; j++) sp[i][j] = s_new[j]; + vm3(rot_mat, sp[i], s_new); + for (int j = 0; j < 3; j++) sp[i][j] = s_new[j]; } ecurrent = energy_force(0); @@ -653,65 +659,77 @@ void MinSpinOSO_LBFGS_LS::make_step(double c, double *energy_and_der) for (int i = 0; i < 3 * nlocal; i++) { der_e_cur += g_cur[i] * p_s[i]; } + MPI_Allreduce(&der_e_cur, &der_e_cur_global, 1, MPI_DOUBLE, MPI_SUM, world); + der_e_cur = der_e_cur_global; + energy_and_der[0] = ecurrent; energy_and_der[1] = der_e_cur; } +/* ---------------------------------------------------------------------- + Calculate step length which satisfies approximate Wolfe conditions + using the cubic interpolation +------------------------------------------------------------------------- */ int MinSpinOSO_LBFGS_LS::calc_and_make_step(double a, double b, int index) { - double e_and_d[2] = {0.0, 0.0}; - double alpha, c1, c2, c3; - double **sp = atom->sp; - int nlocal = atom->nlocal; + double e_and_d[2] = {0.0, 0.0}; + double alpha, c1, c2, c3; + double **sp = atom->sp; + int nlocal = atom->nlocal; - make_step(b, e_and_d); - ecurrent = e_and_d[0]; - der_e_cur = e_and_d[1]; - index++; + make_step(b, e_and_d); + ecurrent = e_and_d[0]; + der_e_cur = e_and_d[1]; + index++; - if (awc(der_e_pr, eprevious, e_and_d[1], e_and_d[0]) || index == 3){ + if (awc(der_e_pr, eprevious, e_and_d[1], e_and_d[0]) || index == 3){ + MPI_Bcast(&b,1,MPI_DOUBLE,0,world); - for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = b * p_s[i]; - } - return 1; + for (int i = 0; i < 3 * nlocal; i++) { + p_s[i] = b * p_s[i]; + } + return 1; + } + else{ + double r, f0, f1, df0, df1; + r = b - a; + f0 = eprevious; + f1 = ecurrent; + df0 = der_e_pr; + df1 = der_e_cur; + + c1 = -2.0*(f1-f0)/(r*r*r)+(df1+df0)/(r*r); + c2 = 3.0*(f1-f0)/(r*r)-(df1+2.0*df0)/(r); + c3 = df0; + + // f(x) = c1 x^3 + c2 x^2 + c3 x^1 + c4 + // has minimum at alpha below. We do not check boundaries. + + alpha = (-c2 + sqrt(c2*c2 - 3.0*c1*c3))/(3.0*c1); + if (alpha < 0.0) alpha = r/2.0; + + for (int i = 0; i < nlocal; i++) { + for (int j = 0; j < 3; j++) sp[i][j] = sp_copy[i][j]; } - else{ - double r, f0, f1, df0, df1; - r = b - a; - f0 = eprevious; - f1 = ecurrent; - df0 = der_e_pr; - df1 = der_e_cur; - - c1 = -2.0*(f1-f0)/(r*r*r)+(df1+df0)/(r*r); - c2 = 3.0*(f1-f0)/(r*r)-(df1+2.0*df0)/(r); - c3 = df0; - - alpha = (-c2 + sqrt(c2*c2 - 3.0*c1*c3))/(3.0*c1); - if (alpha < 0.0) alpha = r/2.0; - - for (int i = 0; i < nlocal; i++) { - for (int j = 0; j < 3; j++) sp[i][j] = sp_copy[i][j]; - } - calc_and_make_step(0.0, alpha, index); - } - - return 0; + calc_and_make_step(0.0, alpha, index); + } + return 0; } - - +/* ---------------------------------------------------------------------- + Approximate Wolfe conditions: + William W. Hager and Hongchao Zhang + SIAM J. optim., 16(1), 170-192. (23 pages) +------------------------------------------------------------------------- */ int MinSpinOSO_LBFGS_LS::awc(double der_phi_0, double phi_0, double der_phi_j, double phi_j){ - double eps = 1.0e-6; - double delta = 0.1; - double sigma = 0.9; + double eps = 1.0e-6; + double delta = 0.1; + double sigma = 0.9; - if ((phi_j <= phi_0 + eps * fabs(phi_0)) && - ((2.0*delta - 1.0) * der_phi_0 >= der_phi_j >= sigma * der_phi_0)) - return 1; - else - return 0; + if ((phi_j <= phi_0 + eps * fabs(phi_0)) && ((2.0*delta - 1.0) * der_phi_0 >= der_phi_j >= sigma * der_phi_0)) + return 1; + else + return 0; } From 66a50419734d343a246ab5ce5a91ea327c4f8ab8 Mon Sep 17 00:00:00 2001 From: julient31 Date: Tue, 2 Jul 2019 16:02:36 -0600 Subject: [PATCH 23/74] Commit1 JT 060219 - added all min/spin tests in src/SPIN/neb_spin.cpp - added lbfgs to .gitignore - commit before pull/merge --- src/.gitignore | 2 ++ src/SPIN/min_spin_oso_lbfgs.cpp | 14 +++++++------- src/SPIN/neb_spin.cpp | 5 +++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/.gitignore b/src/.gitignore index 0d802981f9..f0ac3a1ff9 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -163,6 +163,8 @@ /min_spin.h /min_spin_oso_cg.cpp /min_spin_oso_cg.h +/min_spin_oso_lbfgs.cpp +/min_spin_oso_lbfgs.h /neb_spin.cpp /neb_spin.h /pair_spin.cpp diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index f3643168a4..23cb3718c8 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -361,12 +361,12 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) } } else { - dyds = 0.0; - for (int i = 0; i < 3 * nlocal; i++) { - ds[m_index][i] = p_s[i]; - dy[m_index][i] = g_cur[i] - g_old[i]; - dyds += ds[m_index][i] * dy[m_index][i]; - } + dyds = 0.0; + for (int i = 0; i < 3 * nlocal; i++) { + ds[m_index][i] = p_s[i]; + dy[m_index][i] = g_cur[i] - g_old[i]; + dyds += ds[m_index][i] * dy[m_index][i]; + } MPI_Allreduce(&dyds, &dyds_global, 1, MPI_DOUBLE, MPI_SUM, world); if (fabs(dyds) > 1.0e-60) rho[m_index] = 1.0 / dyds_global; else rho[m_index] = 1.0e60; @@ -409,7 +409,7 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) } MPI_Allreduce(&yy, &yy_global, 1, MPI_DOUBLE, MPI_SUM, world); - // calculate now search direction + // calculate now search direction if (fabs(yy_global) > 1.0e-60) { for (int i = 0; i < 3 * nlocal; i++) { diff --git a/src/SPIN/neb_spin.cpp b/src/SPIN/neb_spin.cpp index 126cfb09e3..9ab461cbe6 100644 --- a/src/SPIN/neb_spin.cpp +++ b/src/SPIN/neb_spin.cpp @@ -50,6 +50,7 @@ #include "memory.h" #include "error.h" #include "math_const.h" +#include "utils.h" using namespace LAMMPS_NS; using namespace MathConst; @@ -194,8 +195,8 @@ void NEBSpin::run() if (update->minimize->searchflag) error->all(FLERR,"NEBSpin requires damped dynamics minimizer"); - if (strcmp(update->minimize_style,"spin") != 0) - error->all(FLERR,"NEBSpin requires spin minimizer"); + if (!utils::strmatch(update->minimize_style,"^spin")) + error->all(FLERR,"NEBSpin requires a spin minimizer"); // setup regular NEBSpin minimization From 8452afb5120c03dfe941afa6a484b98b7e1c5347 Mon Sep 17 00:00:00 2001 From: alxvov Date: Wed, 3 Jul 2019 11:38:31 +0000 Subject: [PATCH 24/74] compare dyds_global instead --- src/SPIN/min_spin_oso_lbfgs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index 83d537030c..e8ac915d8b 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -371,7 +371,7 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) dyds += ds[m_index][i] * dy[m_index][i]; } MPI_Allreduce(&dyds, &dyds_global, 1, MPI_DOUBLE, MPI_SUM, world); - if (fabs(dyds) > 1.0e-60) rho[m_index] = 1.0 / dyds_global; + if (fabs(dyds_global) > 1.0e-60) rho[m_index] = 1.0 / dyds_global; else rho[m_index] = 1.0e60; // set the q vector From eaa542b6e78c828756fd83ff82aba113ea36504a Mon Sep 17 00:00:00 2001 From: alxvov Date: Wed, 3 Jul 2019 11:59:54 +0000 Subject: [PATCH 25/74] scale initial gradients with adaptive time step in the beggining, try to use global parameters for lbfgs --- src/SPIN/min_spin_oso_lbfgs.cpp | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index e8ac915d8b..a598601532 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -190,10 +190,13 @@ int MinSpinOSO_LBFGS::iterate(int maxiter) // optimize timestep accross processes / replicas // need a force calculation for timestep optimization - if (iter == 0) energy_force(0); - // dts = evaluate_dt(); - // dts = 1.0; - calc_gradient(1.0); + if (iter == 0){ + energy_force(0); + dts = evaluate_dt(); + } + else dts = 1.0; + + calc_gradient(dts); calc_search_direction(iter); advance_spins(); @@ -371,6 +374,11 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) dyds += ds[m_index][i] * dy[m_index][i]; } MPI_Allreduce(&dyds, &dyds_global, 1, MPI_DOUBLE, MPI_SUM, world); + if (update->multireplica == 1) { + dyds = dyds_global; + MPI_Allreduce(&dyds_global,&dyds,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + } + if (fabs(dyds_global) > 1.0e-60) rho[m_index] = 1.0 / dyds_global; else rho[m_index] = 1.0e60; @@ -393,6 +401,10 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) sq += ds[c_ind][i] * q[i]; } MPI_Allreduce(&sq, &sq_global, 1, MPI_DOUBLE, MPI_SUM, world); + if (update->multireplica == 1) { + sq = sq_global; + MPI_Allreduce(&sq_global,&sq,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + } // update alpha @@ -411,6 +423,10 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) yy += dy[m_index][i] * dy[m_index][i]; } MPI_Allreduce(&yy, &yy_global, 1, MPI_DOUBLE, MPI_SUM, world); + if (update->multireplica == 1) { + yy = yy_global; + MPI_Allreduce(&yy_global,&yy,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + } // calculate now search direction @@ -435,7 +451,12 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) for (int i = 0; i < 3 * nlocal; i++) { yr += dy[c_ind][i] * p_s[i]; } + MPI_Allreduce(&yr, &yr_global, 1, MPI_DOUBLE, MPI_SUM, world); + if (update->multireplica == 1) { + yr = yr_global; + MPI_Allreduce(&yr_global,&yr,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + } beta = rho[c_ind] * yr_global; for (int i = 0; i < 3 * nlocal; i++) { From 48cc0293ffe7129370163ac8c0aa4c3e5c953e3d Mon Sep 17 00:00:00 2001 From: alxvov Date: Wed, 3 Jul 2019 12:01:21 +0000 Subject: [PATCH 26/74] if g2 zero then beta is also zero --- src/SPIN/min_spin_oso_cg.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index 8d03ada45d..52bf48d228 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -326,9 +326,8 @@ void MinSpinOSO_CG::calc_search_direction(int iter) double g2 = 0.0; double beta = 0.0; - double g2_global= 0.0; - double g2old_global= 0.0; - + double g2_global = 0.0; + double g2old_global = 0.0; if (iter == 0 || iter % 5 == 0){ // steepest descent direction for (int i = 0; i < 3 * nlocal; i++) { p_s[i] = -g_cur[i]; @@ -347,8 +346,16 @@ void MinSpinOSO_CG::calc_search_direction(int iter) MPI_Allreduce(&g2, &g2_global, 1, MPI_DOUBLE, MPI_SUM, world); MPI_Allreduce(&g2old, &g2old_global, 1, MPI_DOUBLE, MPI_SUM, world); - beta = g2_global / g2old_global; + // we don't know yet if we need this. Needs to be tested with multiple replica. + // if (update->multireplica == 1) { + // g2 = g2_global; + // g2old = g2old_global; + // MPI_Allreduce(&g2,&g2_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + // MPI_Allreduce(&g2old,&g2old_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + // } + if (fabs(g2_global) < 1.0e-40) beta = 0.0; + else beta = g2_global / g2old_global; // calculate conjugate direction for (int i = 0; i < 3 * nlocal; i++) { From 87fd17a4d2ce411cfbcff15d1cdd2bc41550570d Mon Sep 17 00:00:00 2001 From: alxvov Date: Wed, 3 Jul 2019 14:54:02 +0000 Subject: [PATCH 27/74] global dot products --- src/SPIN/min_spin_oso_lbfgs_ls.cpp | 37 +++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/SPIN/min_spin_oso_lbfgs_ls.cpp b/src/SPIN/min_spin_oso_lbfgs_ls.cpp index 38a557266e..2e124466ac 100644 --- a/src/SPIN/min_spin_oso_lbfgs_ls.cpp +++ b/src/SPIN/min_spin_oso_lbfgs_ls.cpp @@ -216,6 +216,9 @@ int MinSpinOSO_LBFGS_LS::iterate(int maxiter) } MPI_Allreduce(&der_e_cur, &der_e_cur_global, 1, MPI_DOUBLE, MPI_SUM, world); der_e_cur = der_e_cur_global; + if (update->multireplica == 1) { + MPI_Allreduce(&der_e_cur_global,&der_e_cur,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + } } if (use_line_search){ @@ -388,7 +391,7 @@ void MinSpinOSO_LBFGS_LS::calc_search_direction(int iter) // for some reason on a second iteration g_old = 0 // so we make two iterations as steepest descent - + if (iter == 0){ // steepest descent direction for (int i = 0; i < 3 * nlocal; i++) { p_s[i] = -g_cur[i]; @@ -405,7 +408,12 @@ void MinSpinOSO_LBFGS_LS::calc_search_direction(int iter) dyds += ds[m_index][i] * dy[m_index][i]; } MPI_Allreduce(&dyds, &dyds_global, 1, MPI_DOUBLE, MPI_SUM, world); - if (fabs(dyds) > 1.0e-60) rho[m_index] = 1.0 / dyds_global; + if (update->multireplica == 1) { + dyds = dyds_global; + MPI_Allreduce(&dyds_global,&dyds,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + } + + if (fabs(dyds_global) > 1.0e-60) rho[m_index] = 1.0 / dyds_global; else rho[m_index] = 1.0e60; // set the q vector @@ -427,7 +435,10 @@ void MinSpinOSO_LBFGS_LS::calc_search_direction(int iter) sq += ds[c_ind][i] * q[i]; } MPI_Allreduce(&sq, &sq_global, 1, MPI_DOUBLE, MPI_SUM, world); - + if (update->multireplica == 1) { + sq = sq_global; + MPI_Allreduce(&sq_global,&sq,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + } // update alpha alpha[c_ind] = rho[c_ind] * sq_global; @@ -445,8 +456,12 @@ void MinSpinOSO_LBFGS_LS::calc_search_direction(int iter) yy += dy[m_index][i] * dy[m_index][i]; } MPI_Allreduce(&yy, &yy_global, 1, MPI_DOUBLE, MPI_SUM, world); + if (update->multireplica == 1) { + yy = yy_global; + MPI_Allreduce(&yy_global,&yy,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + } - // calculate now search direction + // calculate now search direction if (fabs(yy_global) > 1.0e-60) { for (int i = 0; i < 3 * nlocal; i++) { @@ -470,6 +485,10 @@ void MinSpinOSO_LBFGS_LS::calc_search_direction(int iter) yr += dy[c_ind][i] * p_s[i]; } MPI_Allreduce(&yr, &yr_global, 1, MPI_DOUBLE, MPI_SUM, world); + if (update->multireplica == 1) { + yr = yr_global; + MPI_Allreduce(&yr_global,&yr,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + } beta = rho[c_ind] * yr_global; for (int i = 0; i < 3 * nlocal; i++) { @@ -661,6 +680,9 @@ void MinSpinOSO_LBFGS_LS::make_step(double c, double *energy_and_der) } MPI_Allreduce(&der_e_cur, &der_e_cur_global, 1, MPI_DOUBLE, MPI_SUM, world); der_e_cur = der_e_cur_global; + if (update->multireplica == 1) { + MPI_Allreduce(&der_e_cur_global,&der_e_cur,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + } energy_and_der[0] = ecurrent; energy_and_der[1] = der_e_cur; @@ -685,10 +707,9 @@ int MinSpinOSO_LBFGS_LS::calc_and_make_step(double a, double b, int index) if (awc(der_e_pr, eprevious, e_and_d[1], e_and_d[0]) || index == 3){ MPI_Bcast(&b,1,MPI_DOUBLE,0,world); - - for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = b * p_s[i]; - } + for (int i = 0; i < 3 * nlocal; i++) { + p_s[i] = b * p_s[i]; + } return 1; } else{ From 747245ee907151deb6cd691f9d53b43972f033d3 Mon Sep 17 00:00:00 2001 From: alxvov Date: Wed, 3 Jul 2019 15:06:53 +0000 Subject: [PATCH 28/74] sum beta over all replicas in cg. Good for GNEB --- src/SPIN/min_spin_oso_cg.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index 52bf48d228..1b4e33ace3 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -346,13 +346,13 @@ void MinSpinOSO_CG::calc_search_direction(int iter) MPI_Allreduce(&g2, &g2_global, 1, MPI_DOUBLE, MPI_SUM, world); MPI_Allreduce(&g2old, &g2old_global, 1, MPI_DOUBLE, MPI_SUM, world); - // we don't know yet if we need this. Needs to be tested with multiple replica. - // if (update->multireplica == 1) { - // g2 = g2_global; - // g2old = g2old_global; - // MPI_Allreduce(&g2,&g2_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); - // MPI_Allreduce(&g2old,&g2old_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); - // } + // Sum over all replicas. Good for GNEB. + if (update->multireplica == 1) { + g2 = g2_global; + g2old = g2old_global; + MPI_Allreduce(&g2,&g2_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + MPI_Allreduce(&g2old,&g2old_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + } if (fabs(g2_global) < 1.0e-40) beta = 0.0; else beta = g2_global / g2old_global; From fb63c5a7085f3f5d6362f4cf3515bcd9666e469d Mon Sep 17 00:00:00 2001 From: julient31 Date: Wed, 3 Jul 2019 09:37:43 -0600 Subject: [PATCH 29/74] Commit1 JT 070319 - commit before pull --- src/SPIN/min_spin_oso_cg.cpp | 8 ++++---- src/SPIN/neb_spin.cpp | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index 52bf48d228..094ae376aa 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -154,8 +154,6 @@ void MinSpinOSO_CG::reset_vectors() minimization via damped spin dynamics ------------------------------------------------------------------------- */ -// g_old g_cur p_s - int MinSpinOSO_CG::iterate(int maxiter) { int nlocal = atom->nlocal; @@ -163,6 +161,8 @@ int MinSpinOSO_CG::iterate(int maxiter) double fmdotfm; int flag, flagall; + // grow tables if nlocal increased + if (nlocal_max < nlocal) { nlocal_max = nlocal; memory->grow(g_old,3*nlocal_max,"min/spin/oso/cg:g_old"); @@ -354,8 +354,8 @@ void MinSpinOSO_CG::calc_search_direction(int iter) // MPI_Allreduce(&g2old,&g2old_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); // } - if (fabs(g2_global) < 1.0e-40) beta = 0.0; - else beta = g2_global / g2old_global; + //if (fabs(g2_global) < 1.0e-40) beta = 0.0; + //else beta = g2_global / g2old_global; // calculate conjugate direction for (int i = 0; i < 3 * nlocal; i++) { diff --git a/src/SPIN/neb_spin.cpp b/src/SPIN/neb_spin.cpp index 9ab461cbe6..12d1d2a956 100644 --- a/src/SPIN/neb_spin.cpp +++ b/src/SPIN/neb_spin.cpp @@ -252,6 +252,8 @@ void NEBSpin::run() timer->init(); timer->barrier_start(); + // if(ireplica != 0 && ireplica != nreplica -1) + while (update->minimize->niter < n1steps) { update->minimize->run(nevery); print_status(); From 526e0da0a90bdd55458892a959b1bf1c60ce6204 Mon Sep 17 00:00:00 2001 From: alxvov Date: Wed, 3 Jul 2019 15:41:29 +0000 Subject: [PATCH 30/74] reduce correctly over the universe --- src/SPIN/min_spin_oso_lbfgs.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index a598601532..5604f99752 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -376,7 +376,7 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) MPI_Allreduce(&dyds, &dyds_global, 1, MPI_DOUBLE, MPI_SUM, world); if (update->multireplica == 1) { dyds = dyds_global; - MPI_Allreduce(&dyds_global,&dyds,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + MPI_Allreduce(&dyds, &dyds_global, 1,MPI_DOUBLE,MPI_SUM,universe->uworld); } if (fabs(dyds_global) > 1.0e-60) rho[m_index] = 1.0 / dyds_global; @@ -403,7 +403,7 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) MPI_Allreduce(&sq, &sq_global, 1, MPI_DOUBLE, MPI_SUM, world); if (update->multireplica == 1) { sq = sq_global; - MPI_Allreduce(&sq_global,&sq,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + MPI_Allreduce(&sq,&sq_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); } // update alpha @@ -425,7 +425,7 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) MPI_Allreduce(&yy, &yy_global, 1, MPI_DOUBLE, MPI_SUM, world); if (update->multireplica == 1) { yy = yy_global; - MPI_Allreduce(&yy_global,&yy,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + MPI_Allreduce(&yy,&yy_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); } // calculate now search direction @@ -455,7 +455,7 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) MPI_Allreduce(&yr, &yr_global, 1, MPI_DOUBLE, MPI_SUM, world); if (update->multireplica == 1) { yr = yr_global; - MPI_Allreduce(&yr_global,&yr,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + MPI_Allreduce(&yr,&yr_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); } beta = rho[c_ind] * yr_global; From 99e58d889cdf3ba9794cd97b5315b891120b165b Mon Sep 17 00:00:00 2001 From: julient31 Date: Wed, 3 Jul 2019 10:48:11 -0600 Subject: [PATCH 31/74] Commit2 JT 070319 - fixing first and last images in oso_lbfgs.cpp --- src/SPIN/min_spin_oso_lbfgs.cpp | 20 +++++++++++++++++++- src/SPIN/min_spin_oso_lbfgs.h | 5 +++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index 5604f99752..a14bf7c4fd 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -39,6 +39,8 @@ #include "math_special.h" #include "math_const.h" +#include "universe.h" + using namespace LAMMPS_NS; using namespace MathConst; @@ -66,6 +68,13 @@ MinSpinOSO_LBFGS::MinSpinOSO_LBFGS(LAMMPS *lmp) : { if (lmp->citeme) lmp->citeme->add(cite_minstyle_spin_oso_lbfgs); nlocal_max = 0; + + // nreplica = number of partitions + // ireplica = which world I am in universe + + nreplica = universe->nworlds; + ireplica = universe->iworld; + } /* ---------------------------------------------------------------------- */ @@ -198,7 +207,16 @@ int MinSpinOSO_LBFGS::iterate(int maxiter) calc_gradient(dts); calc_search_direction(iter); - advance_spins(); + + // to be checked + // if gneb calc., nreplica > 0 + // then advance spins only if intermediate replica + // otherwise (simple minimization), advance spins + + if (nreplica > 0) { + if(ireplica != 0 && ireplica != nreplica-1) + advance_spins(); + } else advance_spins(); eprevious = ecurrent; ecurrent = energy_force(0); diff --git a/src/SPIN/min_spin_oso_lbfgs.h b/src/SPIN/min_spin_oso_lbfgs.h index 3aa326142c..3fc1d625dd 100644 --- a/src/SPIN/min_spin_oso_lbfgs.h +++ b/src/SPIN/min_spin_oso_lbfgs.h @@ -41,6 +41,11 @@ public: void calc_search_direction(int); private: + + + // test + int ireplica,nreplica; + // global and spin timesteps int nlocal_max; // max value of nlocal (for size of lists) From 3c3c7899b4fdceb378c206870ee4e93ff76711df Mon Sep 17 00:00:00 2001 From: alxvov Date: Wed, 3 Jul 2019 19:33:24 +0000 Subject: [PATCH 32/74] use local iteration counter, needed for neb --- src/SPIN/min_spin_oso_cg.cpp | 13 ++++++++----- src/SPIN/min_spin_oso_cg.h | 3 ++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index 1b4e33ace3..8f2ba0623b 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -83,7 +83,7 @@ void MinSpinOSO_CG::init() { alpha_damp = 1.0; discrete_factor = 10.0; - + local_iter = 0; Min::init(); dts = dt = update->dt; @@ -164,6 +164,7 @@ int MinSpinOSO_CG::iterate(int maxiter) int flag, flagall; if (nlocal_max < nlocal) { + local_iter = 0; nlocal_max = nlocal; memory->grow(g_old,3*nlocal_max,"min/spin/oso/cg:g_old"); memory->grow(g_cur,3*nlocal_max,"min/spin/oso/cg:g_cur"); @@ -181,11 +182,11 @@ int MinSpinOSO_CG::iterate(int maxiter) // optimize timestep accross processes / replicas // need a force calculation for timestep optimization - if (iter == 0) energy_force(0); + if (local_iter == 0) energy_force(0); dts = evaluate_dt(); calc_gradient(dts); - calc_search_direction(iter); + calc_search_direction(); advance_spins(); eprevious = ecurrent; @@ -319,7 +320,7 @@ void MinSpinOSO_CG::calc_gradient(double dts) Optimization' Second Edition, 2006 (p. 121) ---------------------------------------------------------------------- */ -void MinSpinOSO_CG::calc_search_direction(int iter) +void MinSpinOSO_CG::calc_search_direction() { int nlocal = atom->nlocal; double g2old = 0.0; @@ -328,7 +329,7 @@ void MinSpinOSO_CG::calc_search_direction(int iter) double g2_global = 0.0; double g2old_global = 0.0; - if (iter == 0 || iter % 5 == 0){ // steepest descent direction + if (local_iter == 0 || local_iter % 5 == 0){ // steepest descent direction for (int i = 0; i < 3 * nlocal; i++) { p_s[i] = -g_cur[i]; g_old[i] = g_cur[i]; @@ -363,6 +364,8 @@ void MinSpinOSO_CG::calc_search_direction(int iter) g_old[i] = g_cur[i]; } } + + local_iter++; } /* ---------------------------------------------------------------------- diff --git a/src/SPIN/min_spin_oso_cg.h b/src/SPIN/min_spin_oso_cg.h index a791754836..3a3d24f078 100644 --- a/src/SPIN/min_spin_oso_cg.h +++ b/src/SPIN/min_spin_oso_cg.h @@ -38,7 +38,7 @@ public: void advance_spins(); double fmnorm_sqr(); void calc_gradient(double); - void calc_search_direction(int); + void calc_search_direction(); private: // global and spin timesteps @@ -56,6 +56,7 @@ private: double *g_old; // gradient vector at previous iteration double *g_cur; // current gradient vector double *p_s; // search direction vector + int local_iter; // number of times we call search_direction void vm3(const double *, const double *, double *); void rodrigues_rotation(const double *, double *); From 95cf85f1b932acc983ab826c90cdcc78e3991751 Mon Sep 17 00:00:00 2001 From: alxvov Date: Wed, 3 Jul 2019 21:12:04 +0000 Subject: [PATCH 33/74] bug: forget to calculate beta.. --- src/SPIN/min_spin_oso_cg.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index 6ae2518986..d8535b19c4 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -355,10 +355,9 @@ void MinSpinOSO_CG::calc_search_direction() MPI_Allreduce(&g2old,&g2old_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); } - //if (fabs(g2_global) < 1.0e-40) beta = 0.0; - //else beta = g2_global / g2old_global; + if (fabs(g2_global) < 1.0e-60) beta = 0.0; + else beta = g2_global / g2old_global; // calculate conjugate direction - for (int i = 0; i < 3 * nlocal; i++) { p_s[i] = beta * p_s[i] - g_cur[i]; g_old[i] = g_cur[i]; From e85bdd17d3a2980f1987f2770c1958c8bbcd8015 Mon Sep 17 00:00:00 2001 From: alxvov Date: Thu, 4 Jul 2019 15:31:18 +0000 Subject: [PATCH 34/74] introduce cutoff step. make lbfgs stable --- src/SPIN/min_spin_oso_lbfgs.cpp | 107 +++++++++++++++++++++++++------- src/SPIN/min_spin_oso_lbfgs.h | 12 ++-- 2 files changed, 92 insertions(+), 27 deletions(-) diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index a14bf7c4fd..09948ac3e5 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -38,7 +38,6 @@ #include "modify.h" #include "math_special.h" #include "math_const.h" - #include "universe.h" using namespace LAMMPS_NS; @@ -96,6 +95,8 @@ void MinSpinOSO_LBFGS::init() alpha_damp = 1.0; discrete_factor = 10.0; num_mem = 3; + local_iter = 0; + maxepsrot = MY_2PI / (200.0); Min::init(); @@ -180,6 +181,7 @@ int MinSpinOSO_LBFGS::iterate(int maxiter) if (nlocal_max < nlocal) { nlocal_max = nlocal; + local_iter = 0; memory->grow(g_old,3*nlocal_max,"min/spin/oso/lbfgs:g_old"); memory->grow(g_cur,3*nlocal_max,"min/spin/oso/lbfgs:g_cur"); memory->grow(p_s,3*nlocal_max,"min/spin/oso/lbfgs:p_s"); @@ -198,26 +200,26 @@ int MinSpinOSO_LBFGS::iterate(int maxiter) // optimize timestep accross processes / replicas // need a force calculation for timestep optimization - - if (iter == 0){ - energy_force(0); - dts = evaluate_dt(); - } - else dts = 1.0; + if (local_iter == 0) energy_force(0); + // to be checked + // if gneb calc., nreplica > 1 + // then calculate gradients of intermediate replicas - calc_gradient(dts); + if (nreplica > 1) { + if(ireplica != 0 && ireplica != nreplica-1) + calc_gradient(1.0); + } else calc_gradient(1.0); calc_search_direction(iter); // to be checked - // if gneb calc., nreplica > 0 + // if gneb calc., nreplica > 1 // then advance spins only if intermediate replica // otherwise (simple minimization), advance spins - if (nreplica > 0) { + if (nreplica > 1) { if(ireplica != 0 && ireplica != nreplica-1) advance_spins(); } else advance_spins(); - eprevious = ecurrent; ecurrent = energy_force(0); neval++; @@ -307,7 +309,7 @@ double MinSpinOSO_LBFGS::evaluate_dt() // define max timestep by dividing by the // inverse of max frequency by discrete_factor - + // std::cout << fmaxsqall << "\n"; dtmax = MY_2PI/(discrete_factor*sqrt(fmaxsqall)); return dtmax; @@ -365,20 +367,31 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) double yr_global = 0.0; double beta_global = 0.0; - int m_index = iter % num_mem; // memory index + int m_index = local_iter % num_mem; // memory index int c_ind = 0; double *q; double *alpha; + double factor; + double scaling; + + if (nreplica > 1) { + if (ireplica == 0 || ireplica == nreplica - 1) { + factor = 0.0; + } + else factor = 1.0; + }else{ + factor = 1.0; + } + q = (double *) calloc(3*nlocal, sizeof(double)); alpha = (double *) calloc(num_mem, sizeof(double)); - // for some reason on a second iteration g_old = 0 - // so we make two iterations as steepest descent - - if (iter == 0){ // steepest descent direction + if (local_iter == 0){ // steepest descent direction + + scaling = maximum_rotation(g_cur); for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = -g_cur[i]; + p_s[i] = - g_cur[i] * factor * scaling; g_old[i] = g_cur[i]; ds[m_index][i] = 0.0; dy[m_index][i] = 0.0; @@ -392,7 +405,9 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) dyds += ds[m_index][i] * dy[m_index][i]; } MPI_Allreduce(&dyds, &dyds_global, 1, MPI_DOUBLE, MPI_SUM, world); + if (update->multireplica == 1) { + dyds_global *= factor; dyds = dyds_global; MPI_Allreduce(&dyds, &dyds_global, 1,MPI_DOUBLE,MPI_SUM,universe->uworld); } @@ -400,6 +415,17 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) if (fabs(dyds_global) > 1.0e-60) rho[m_index] = 1.0 / dyds_global; else rho[m_index] = 1.0e60; + if (rho[m_index] < 0.0){ + local_iter = 0; + for (int k = 0; k < num_mem; k++){ + for (int i = 0; i < nlocal; i ++){ + ds[k][i] = 0.0; + dy[k][i] = 0.0; + } + } + return calc_search_direction(0); + } + // set the q vector for (int i = 0; i < 3 * nlocal; i++) { @@ -420,6 +446,7 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) } MPI_Allreduce(&sq, &sq_global, 1, MPI_DOUBLE, MPI_SUM, world); if (update->multireplica == 1) { + sq_global *= factor; sq = sq_global; MPI_Allreduce(&sq,&sq_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); } @@ -442,19 +469,22 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) } MPI_Allreduce(&yy, &yy_global, 1, MPI_DOUBLE, MPI_SUM, world); if (update->multireplica == 1) { + yy_global *= factor; yy = yy_global; MPI_Allreduce(&yy,&yy_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); } // calculate now search direction - if (fabs(yy_global) > 1.0e-60) { + double devis = rho[m_index] * yy_global; + + if (fabs(devis) > 1.0e-60) { for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = q[i] / (rho[m_index] * yy_global); + p_s[i] = factor * q[i] / devis; } }else{ for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = q[i] * 1.0e60; + p_s[i] = factor * q[i] * 1.0e60; } } @@ -472,6 +502,7 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) MPI_Allreduce(&yr, &yr_global, 1, MPI_DOUBLE, MPI_SUM, world); if (update->multireplica == 1) { + yr_global *= factor; yr = yr_global; MPI_Allreduce(&yr,&yr_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); } @@ -481,12 +512,14 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) p_s[i] += ds[c_ind][i] * (alpha[c_ind] - beta); } } + scaling = maximum_rotation(p_s); for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = -1.0 * p_s[i]; + p_s[i] = - factor * p_s[i] * scaling; g_old[i] = g_cur[i]; } } + local_iter++; free(q); free(alpha); @@ -631,3 +664,33 @@ void MinSpinOSO_LBFGS::vm3(const double *m, const double *v, double *out) } } } + +double MinSpinOSO_LBFGS::maximum_rotation(double *p) +{ + double norm, norm_global, scaling, alpha; + int nlocal = atom->nlocal; + int ntotal = 0; + + norm = 0.0; + for (int i = 0; i < 3 * nlocal; i++) norm += p[i] * p[i]; + + MPI_Allreduce(&norm,&norm_global,1,MPI_DOUBLE,MPI_SUM,world); + if (update->multireplica == 1) { + norm = norm_global; + MPI_Allreduce(&norm,&norm_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + } + + MPI_Allreduce(&nlocal,&ntotal,1,MPI_INT,MPI_SUM,world); + if (update->multireplica == 1) { + nlocal = ntotal; + MPI_Allreduce(&nlocal,&ntotal,1,MPI_INT,MPI_SUM,universe->uworld); + } + + scaling = (maxepsrot * sqrt((double) ntotal / norm_global)); + + if (scaling < 1.0) alpha = scaling; + else alpha = 1.0; + + return alpha; +} + diff --git a/src/SPIN/min_spin_oso_lbfgs.h b/src/SPIN/min_spin_oso_lbfgs.h index 3fc1d625dd..dfc4ec06ff 100644 --- a/src/SPIN/min_spin_oso_lbfgs.h +++ b/src/SPIN/min_spin_oso_lbfgs.h @@ -38,8 +38,8 @@ public: void advance_spins(); double fmnorm_sqr(); void calc_gradient(double); - void calc_search_direction(int); - + void calc_search_direction(int); + double maximum_rotation(double *); private: @@ -64,11 +64,13 @@ private: double **ds; // change in rotation matrix between two iterations, da double **dy; // change in gradients between two iterations, dg double *rho; // estimation of curvature - int num_mem; // number of stored steps + int num_mem; // number of stored steps + int local_iter; // number of times we call search_direction + double maxepsrot; - void vm3(const double *m, const double *v, double *out); - void rodrigues_rotation(const double *upp_tr, double *out); + void vm3(const double *, const double *, double *); + void rodrigues_rotation(const double *, double *); bigint last_negative; }; From f3985c853edace460556d87ff22ed81de884cb25 Mon Sep 17 00:00:00 2001 From: alxvov Date: Thu, 4 Jul 2019 18:19:57 +0000 Subject: [PATCH 35/74] local iter instead of iter --- src/SPIN/min_spin_oso_lbfgs.cpp | 12 ++++++------ src/SPIN/min_spin_oso_lbfgs.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index 09948ac3e5..9687f2f64d 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -96,7 +96,7 @@ void MinSpinOSO_LBFGS::init() discrete_factor = 10.0; num_mem = 3; local_iter = 0; - maxepsrot = MY_2PI / (200.0); + maxepsrot = MY_2PI / (100.0); Min::init(); @@ -209,7 +209,7 @@ int MinSpinOSO_LBFGS::iterate(int maxiter) if(ireplica != 0 && ireplica != nreplica-1) calc_gradient(1.0); } else calc_gradient(1.0); - calc_search_direction(iter); + calc_search_direction(); // to be checked // if gneb calc., nreplica > 1 @@ -351,7 +351,7 @@ void MinSpinOSO_LBFGS::calc_gradient(double dts) Optimization' Second Edition, 2006 (p. 177) ---------------------------------------------------------------------- */ -void MinSpinOSO_LBFGS::calc_search_direction(int iter) +void MinSpinOSO_LBFGS::calc_search_direction() { int nlocal = atom->nlocal; @@ -418,12 +418,12 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) if (rho[m_index] < 0.0){ local_iter = 0; for (int k = 0; k < num_mem; k++){ - for (int i = 0; i < nlocal; i ++){ + for (int i = 0; i < nlocal; i ++){ ds[k][i] = 0.0; dy[k][i] = 0.0; } } - return calc_search_direction(0); + return calc_search_direction(); } // set the q vector @@ -491,7 +491,7 @@ void MinSpinOSO_LBFGS::calc_search_direction(int iter) for (int k = 0; k < num_mem; k++){ // this loop should run from the oldest memory to the newest one. - if (iter < num_mem) c_ind = k; + if (local_iter < num_mem) c_ind = k; else c_ind = (k + m_index + 1) % num_mem; // dot product between p and da diff --git a/src/SPIN/min_spin_oso_lbfgs.h b/src/SPIN/min_spin_oso_lbfgs.h index dfc4ec06ff..c0f8dc484d 100644 --- a/src/SPIN/min_spin_oso_lbfgs.h +++ b/src/SPIN/min_spin_oso_lbfgs.h @@ -38,7 +38,7 @@ public: void advance_spins(); double fmnorm_sqr(); void calc_gradient(double); - void calc_search_direction(int); + void calc_search_direction(); double maximum_rotation(double *); private: From 79f8e422f9f8ee044db5b9e5cb7cee6b637e3dff Mon Sep 17 00:00:00 2001 From: alxvov Date: Thu, 4 Jul 2019 18:21:07 +0000 Subject: [PATCH 36/74] indentation --- src/SPIN/min_spin_oso_lbfgs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index 9687f2f64d..fd83e7b460 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -418,7 +418,7 @@ void MinSpinOSO_LBFGS::calc_search_direction() if (rho[m_index] < 0.0){ local_iter = 0; for (int k = 0; k < num_mem; k++){ - for (int i = 0; i < nlocal; i ++){ + for (int i = 0; i < nlocal; i ++){ ds[k][i] = 0.0; dy[k][i] = 0.0; } From bb325a335ed3c8a8e612142aff2547461a3c35d3 Mon Sep 17 00:00:00 2001 From: julient31 Date: Wed, 10 Jul 2019 09:52:39 -0600 Subject: [PATCH 37/74] Commit1 JT 070919 - test energy/torque modif with etotal --- src/SPIN/pair_spin_dmi.cpp | 8 ++++---- src/SPIN/pair_spin_exchange.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/SPIN/pair_spin_dmi.cpp b/src/SPIN/pair_spin_dmi.cpp index 41430d230f..817d933698 100644 --- a/src/SPIN/pair_spin_dmi.cpp +++ b/src/SPIN/pair_spin_dmi.cpp @@ -317,7 +317,7 @@ void PairSpinDmi::compute(int eflag, int vflag) if (eflag) { evdwl -= (spi[0]*fmi[0] + spi[1]*fmi[1] + spi[2]*fmi[2]); - evdwl *= hbar; + evdwl *= 0.5*hbar; } else evdwl = 0.0; if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair, @@ -431,9 +431,9 @@ void PairSpinDmi::compute_dmi(int i, int j, double eij[3], double fmi[3], double dmiy = eij[2]*v_dmx[itype][jtype] - eij[0]*v_dmz[itype][jtype]; dmiz = eij[0]*v_dmy[itype][jtype] - eij[1]*v_dmx[itype][jtype]; - fmi[0] -= (dmiy*spj[2] - dmiz*spj[1]); - fmi[1] -= (dmiz*spj[0] - dmix*spj[2]); - fmi[2] -= (dmix*spj[1] - dmiy*spj[0]); + fmi[0] -= 2.0*(dmiy*spj[2] - dmiz*spj[1]); + fmi[1] -= 2.0*(dmiz*spj[0] - dmix*spj[2]); + fmi[2] -= 2.0*(dmix*spj[1] - dmiy*spj[0]); } /* ---------------------------------------------------------------------- diff --git a/src/SPIN/pair_spin_exchange.cpp b/src/SPIN/pair_spin_exchange.cpp index 93b6d9501e..721002acba 100644 --- a/src/SPIN/pair_spin_exchange.cpp +++ b/src/SPIN/pair_spin_exchange.cpp @@ -300,7 +300,7 @@ void PairSpinExchange::compute(int eflag, int vflag) if (eflag) { evdwl -= (spi[0]*fmi[0] + spi[1]*fmi[1] + spi[2]*fmi[2]); - evdwl *= hbar; + evdwl *= 0.5*hbar; } else evdwl = 0.0; if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair, @@ -409,9 +409,9 @@ void PairSpinExchange::compute_exchange(int i, int j, double rsq, double fmi[3], Jex *= (1.0-J2[itype][jtype]*ra); Jex *= exp(-ra); - fmi[0] += Jex*spj[0]; - fmi[1] += Jex*spj[1]; - fmi[2] += Jex*spj[2]; + fmi[0] += 2.0*Jex*spj[0]; + fmi[1] += 2.0*Jex*spj[1]; + fmi[2] += 2.0*Jex*spj[2]; } /* ---------------------------------------------------------------------- From 2b2a9e775eed2d8991d776e3f50afd9f678f130c Mon Sep 17 00:00:00 2001 From: alxvov Date: Thu, 11 Jul 2019 08:24:28 +0000 Subject: [PATCH 38/74] fix memory, add sp_copy --- src/SPIN/min_spin_oso_lbfgs_ls.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPIN/min_spin_oso_lbfgs_ls.cpp b/src/SPIN/min_spin_oso_lbfgs_ls.cpp index 2e124466ac..0d9c2d7c51 100644 --- a/src/SPIN/min_spin_oso_lbfgs_ls.cpp +++ b/src/SPIN/min_spin_oso_lbfgs_ls.cpp @@ -64,7 +64,7 @@ static const char cite_minstyle_spin_oso_lbfgs_ls[] = /* ---------------------------------------------------------------------- */ MinSpinOSO_LBFGS_LS::MinSpinOSO_LBFGS_LS(LAMMPS *lmp) : - Min(lmp), g_old(NULL), g_cur(NULL), p_s(NULL), ds(NULL), dy(NULL), rho(NULL) + Min(lmp), g_old(NULL), g_cur(NULL), p_s(NULL), ds(NULL), dy(NULL), rho(NULL), sp_copy(NULL) { if (lmp->citeme) lmp->citeme->add(cite_minstyle_spin_oso_lbfgs_ls); nlocal_max = 0; From 6238ad321228ef4320dc0f006b30f6e150ed7890 Mon Sep 17 00:00:00 2001 From: alxvov Date: Thu, 11 Jul 2019 14:18:42 +0000 Subject: [PATCH 39/74] local iterator, broadcast more --- src/SPIN/min_spin_oso_lbfgs_ls.cpp | 100 ++++++++++++++++++++--------- src/SPIN/min_spin_oso_lbfgs_ls.h | 6 +- 2 files changed, 75 insertions(+), 31 deletions(-) diff --git a/src/SPIN/min_spin_oso_lbfgs_ls.cpp b/src/SPIN/min_spin_oso_lbfgs_ls.cpp index 0d9c2d7c51..e1a6ae99d5 100644 --- a/src/SPIN/min_spin_oso_lbfgs_ls.cpp +++ b/src/SPIN/min_spin_oso_lbfgs_ls.cpp @@ -38,6 +38,7 @@ #include "modify.h" #include "math_special.h" #include "math_const.h" +#include "universe.h" #include @@ -68,6 +69,13 @@ MinSpinOSO_LBFGS_LS::MinSpinOSO_LBFGS_LS(LAMMPS *lmp) : { if (lmp->citeme) lmp->citeme->add(cite_minstyle_spin_oso_lbfgs_ls); nlocal_max = 0; + + // nreplica = number of partitions + // ireplica = which world I am in universe + + nreplica = universe->nworlds; + ireplica = universe->iworld; + } /* ---------------------------------------------------------------------- */ @@ -90,6 +98,7 @@ void MinSpinOSO_LBFGS_LS::init() alpha_damp = 1.0; discrete_factor = 10.0; num_mem = 3; + local_iter = 0; der_e_cur = 0.0; der_e_pr = 0.0; use_line_search = 1; @@ -189,7 +198,6 @@ int MinSpinOSO_LBFGS_LS::iterate(int maxiter) memory->grow(sp_copy,nlocal_max,3,"min/spin/oso/lbfgs_ls:sp_copy"); } - for (int iter = 0; iter < maxiter; iter++) { if (timer->check_timeout(niter)) @@ -201,13 +209,12 @@ int MinSpinOSO_LBFGS_LS::iterate(int maxiter) // optimize timestep accross processes / replicas // need a force calculation for timestep optimization - if (iter == 0){ + if (local_iter == 0){ ecurrent = energy_force(0); calc_gradient(1.0); neval++; - }else{ } - calc_search_direction(iter); + calc_search_direction(); if (use_line_search) { der_e_cur = 0.0; @@ -365,7 +372,7 @@ void MinSpinOSO_LBFGS_LS::calc_gradient(double dts) Optimization' Second Edition, 2006 (p. 177) ---------------------------------------------------------------------- */ -void MinSpinOSO_LBFGS_LS::calc_search_direction(int iter) +void MinSpinOSO_LBFGS_LS::calc_search_direction() { int nlocal = atom->nlocal; @@ -381,41 +388,64 @@ void MinSpinOSO_LBFGS_LS::calc_search_direction(int iter) double yr_global = 0.0; double beta_global = 0.0; - int m_index = iter % num_mem; // memory index + int m_index = local_iter % num_mem; // memory index int c_ind = 0; double *q; double *alpha; + double factor; + + if (nreplica > 1) { + if (ireplica == 0 || ireplica == nreplica - 1) { + factor = 0.0; + } + else factor = 1.0; + }else{ + factor = 1.0; + } + q = (double *) calloc(3*nlocal, sizeof(double)); alpha = (double *) calloc(num_mem, sizeof(double)); - // for some reason on a second iteration g_old = 0 - // so we make two iterations as steepest descent - - if (iter == 0){ // steepest descent direction + if (local_iter == 0){ // steepest descent direction for (int i = 0; i < 3 * nlocal; i++) { p_s[i] = -g_cur[i]; g_old[i] = g_cur[i]; - ds[m_index][i] = 0.0; - dy[m_index][i] = 0.0; - + for (int k = 0; k < num_mem; k++){ + ds[k][i] = 0.0; + dy[k][i] = 0.0; + rho[k] = 0.0; + } } } else { - dyds = 0.0; - for (int i = 0; i < 3 * nlocal; i++) { - ds[m_index][i] = p_s[i]; - dy[m_index][i] = g_cur[i] - g_old[i]; - dyds += ds[m_index][i] * dy[m_index][i]; - } + dyds = 0.0; + for (int i = 0; i < 3 * nlocal; i++) { + ds[m_index][i] = p_s[i]; + dy[m_index][i] = g_cur[i] - g_old[i]; + dyds += ds[m_index][i] * dy[m_index][i]; + } MPI_Allreduce(&dyds, &dyds_global, 1, MPI_DOUBLE, MPI_SUM, world); + if (update->multireplica == 1) { + dyds_global *= factor; dyds = dyds_global; - MPI_Allreduce(&dyds_global,&dyds,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + MPI_Allreduce(&dyds, &dyds_global, 1,MPI_DOUBLE,MPI_SUM,universe->uworld); } - if (fabs(dyds_global) > 1.0e-60) rho[m_index] = 1.0 / dyds_global; + if (fabs(dyds_global) > 1.0e-60) rho[m_index] = 1.0 / dyds_global; else rho[m_index] = 1.0e60; + if (rho[m_index] < 0.0){ + local_iter = 0; + for (int k = 0; k < num_mem; k++){ + for (int i = 0; i < nlocal; i ++){ + ds[k][i] = 0.0; + dy[k][i] = 0.0; + } + } + return calc_search_direction(); + } + // set the q vector for (int i = 0; i < 3 * nlocal; i++) { @@ -436,9 +466,11 @@ void MinSpinOSO_LBFGS_LS::calc_search_direction(int iter) } MPI_Allreduce(&sq, &sq_global, 1, MPI_DOUBLE, MPI_SUM, world); if (update->multireplica == 1) { + sq_global *= factor; sq = sq_global; - MPI_Allreduce(&sq_global,&sq,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + MPI_Allreduce(&sq,&sq_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); } + // update alpha alpha[c_ind] = rho[c_ind] * sq_global; @@ -457,26 +489,29 @@ void MinSpinOSO_LBFGS_LS::calc_search_direction(int iter) } MPI_Allreduce(&yy, &yy_global, 1, MPI_DOUBLE, MPI_SUM, world); if (update->multireplica == 1) { + yy_global *= factor; yy = yy_global; - MPI_Allreduce(&yy_global,&yy,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + MPI_Allreduce(&yy,&yy_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); } // calculate now search direction - if (fabs(yy_global) > 1.0e-60) { + double devis = rho[m_index] * yy_global; + + if (fabs(devis) > 1.0e-60) { for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = q[i] / (rho[m_index] * yy_global); + p_s[i] = factor * q[i] / devis; } }else{ for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = q[i] * 1.0e60; + p_s[i] = factor * q[i] * 1.0e60; } } for (int k = 0; k < num_mem; k++){ // this loop should run from the oldest memory to the newest one. - if (iter < num_mem) c_ind = k; + if (local_iter < num_mem) c_ind = k; else c_ind = (k + m_index + 1) % num_mem; // dot product between p and da @@ -484,10 +519,12 @@ void MinSpinOSO_LBFGS_LS::calc_search_direction(int iter) for (int i = 0; i < 3 * nlocal; i++) { yr += dy[c_ind][i] * p_s[i]; } + MPI_Allreduce(&yr, &yr_global, 1, MPI_DOUBLE, MPI_SUM, world); if (update->multireplica == 1) { + yr_global *= factor; yr = yr_global; - MPI_Allreduce(&yr_global,&yr,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + MPI_Allreduce(&yr,&yr_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); } beta = rho[c_ind] * yr_global; @@ -496,11 +533,12 @@ void MinSpinOSO_LBFGS_LS::calc_search_direction(int iter) } } for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = -1.0 * p_s[i]; + p_s[i] = - factor * p_s[i]; g_old[i] = g_cur[i]; } } + local_iter++; free(q); free(alpha); @@ -705,7 +743,7 @@ int MinSpinOSO_LBFGS_LS::calc_and_make_step(double a, double b, int index) der_e_cur = e_and_d[1]; index++; - if (awc(der_e_pr, eprevious, e_and_d[1], e_and_d[0]) || index == 3){ + if (awc(der_e_pr, eprevious, e_and_d[1], e_and_d[0]) || index == 5){ MPI_Bcast(&b,1,MPI_DOUBLE,0,world); for (int i = 0; i < 3 * nlocal; i++) { p_s[i] = b * p_s[i]; @@ -728,6 +766,8 @@ int MinSpinOSO_LBFGS_LS::calc_and_make_step(double a, double b, int index) // has minimum at alpha below. We do not check boundaries. alpha = (-c2 + sqrt(c2*c2 - 3.0*c1*c3))/(3.0*c1); + MPI_Bcast(&alpha,1,MPI_DOUBLE,0,world); + if (alpha < 0.0) alpha = r/2.0; for (int i = 0; i < nlocal; i++) { diff --git a/src/SPIN/min_spin_oso_lbfgs_ls.h b/src/SPIN/min_spin_oso_lbfgs_ls.h index 3e0e608ecb..eeaf20adf4 100644 --- a/src/SPIN/min_spin_oso_lbfgs_ls.h +++ b/src/SPIN/min_spin_oso_lbfgs_ls.h @@ -38,9 +38,12 @@ public: void advance_spins(); double fmnorm_sqr(); void calc_gradient(double); - void calc_search_direction(int); + void calc_search_direction(); private: + // test + int ireplica,nreplica; + // global and spin timesteps int nlocal_max; // max value of nlocal (for size of lists) @@ -62,6 +65,7 @@ private: double **sp_copy; // copy of the spins int num_mem; // number of stored steps + int local_iter; double der_e_cur; // current derivative along search dir. double der_e_pr; // previous derivative along search dir. From 45516e329eaa69686823b26394541c077068f9f2 Mon Sep 17 00:00:00 2001 From: alxvov Date: Fri, 19 Jul 2019 09:30:02 +0000 Subject: [PATCH 40/74] delete unused variables and function --- src/SPIN/min_spin_oso_lbfgs_ls.cpp | 174 ++++++++++------------------- src/SPIN/min_spin_oso_lbfgs_ls.h | 15 +-- 2 files changed, 62 insertions(+), 127 deletions(-) diff --git a/src/SPIN/min_spin_oso_lbfgs_ls.cpp b/src/SPIN/min_spin_oso_lbfgs_ls.cpp index e1a6ae99d5..5896ba9a9f 100644 --- a/src/SPIN/min_spin_oso_lbfgs_ls.cpp +++ b/src/SPIN/min_spin_oso_lbfgs_ls.cpp @@ -75,6 +75,7 @@ MinSpinOSO_LBFGS_LS::MinSpinOSO_LBFGS_LS(LAMMPS *lmp) : nreplica = universe->nworlds; ireplica = universe->iworld; + use_line_search = 1; } @@ -88,24 +89,21 @@ MinSpinOSO_LBFGS_LS::~MinSpinOSO_LBFGS_LS() memory->destroy(ds); memory->destroy(dy); memory->destroy(rho); - memory->destroy(sp_copy); + if (use_line_search) + memory->destroy(sp_copy); } /* ---------------------------------------------------------------------- */ void MinSpinOSO_LBFGS_LS::init() { - alpha_damp = 1.0; - discrete_factor = 10.0; num_mem = 3; local_iter = 0; der_e_cur = 0.0; der_e_pr = 0.0; - use_line_search = 1; Min::init(); - dts = dt = update->dt; last_negative = update->ntimestep; // allocate tables @@ -117,7 +115,8 @@ void MinSpinOSO_LBFGS_LS::init() memory->grow(rho,num_mem,"min/spin/oso/lbfgs_ls:rho"); memory->grow(ds,num_mem,3*nlocal_max,"min/spin/oso/lbfgs_ls:ds"); memory->grow(dy,num_mem,3*nlocal_max,"min/spin/oso/lbfgs_ls:dy"); - memory->grow(sp_copy,nlocal_max,3,"min/spin/oso/lbfgs_ls:sp_copy"); + if (use_line_search) + memory->grow(sp_copy,nlocal_max,3,"min/spin/oso/lbfgs_ls:sp_copy"); } @@ -141,14 +140,10 @@ void MinSpinOSO_LBFGS_LS::setup_style() int MinSpinOSO_LBFGS_LS::modify_param(int narg, char **arg) { - if (strcmp(arg[0],"alpha_damp") == 0) { + + if (strcmp(arg[0],"line_search") == 0) { if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); - alpha_damp = force->numeric(FLERR,arg[1]); - return 2; - } - if (strcmp(arg[0],"discrete_factor") == 0) { - if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); - discrete_factor = force->numeric(FLERR,arg[1]); + use_line_search = force->numeric(FLERR,arg[1]); return 2; } return 0; @@ -185,7 +180,7 @@ int MinSpinOSO_LBFGS_LS::iterate(int maxiter) double fmdotfm; int flag, flagall; double **sp = atom->sp; - double der_e_cur_global = 0.0; + double der_e_cur_tmp = 0.0; if (nlocal_max < nlocal) { nlocal_max = nlocal; @@ -195,7 +190,8 @@ int MinSpinOSO_LBFGS_LS::iterate(int maxiter) memory->grow(rho,num_mem,"min/spin/oso/lbfgs_ls:rho"); memory->grow(ds,num_mem,3*nlocal_max,"min/spin/oso/lbfgs_ls:ds"); memory->grow(dy,num_mem,3*nlocal_max,"min/spin/oso/lbfgs_ls:dy"); - memory->grow(sp_copy,nlocal_max,3,"min/spin/oso/lbfgs_ls:sp_copy"); + if (use_line_search) + memory->grow(sp_copy,nlocal_max,3,"min/spin/oso/lbfgs_ls:sp_copy"); } for (int iter = 0; iter < maxiter; iter++) { @@ -211,34 +207,35 @@ int MinSpinOSO_LBFGS_LS::iterate(int maxiter) if (local_iter == 0){ ecurrent = energy_force(0); - calc_gradient(1.0); + calc_gradient(); neval++; } calc_search_direction(); if (use_line_search) { + + // here we need to do line search + der_e_cur = 0.0; for (int i = 0; i < 3 * nlocal; i++) { der_e_cur += g_cur[i] * p_s[i]; } - MPI_Allreduce(&der_e_cur, &der_e_cur_global, 1, MPI_DOUBLE, MPI_SUM, world); - der_e_cur = der_e_cur_global; + MPI_Allreduce(&der_e_cur,&der_e_cur_tmp,1,MPI_DOUBLE,MPI_SUM,world); + der_e_cur = der_e_cur_tmp; if (update->multireplica == 1) { - MPI_Allreduce(&der_e_cur_global,&der_e_cur,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + MPI_Allreduce(&der_e_cur_tmp,&der_e_cur,1,MPI_DOUBLE,MPI_SUM,universe->uworld); } - } - - if (use_line_search){ - // here we need to do line search for (int i = 0; i < nlocal; i++) { for (int j = 0; j < 3; j++) sp_copy[i][j] = sp[i][j]; } eprevious = ecurrent; der_e_pr = der_e_cur; - calc_and_make_step(0.0, 1.0, 0); } else{ + + // here we don't do line search + advance_spins(); eprevious = ecurrent; ecurrent = energy_force(0); @@ -291,56 +288,11 @@ int MinSpinOSO_LBFGS_LS::iterate(int maxiter) return MAXITER; } -/* ---------------------------------------------------------------------- - evaluate max timestep ----------------------------------------------------------------------- */ - -double MinSpinOSO_LBFGS_LS::evaluate_dt() -{ - double dtmax; - double fmsq; - double fmaxsqone,fmaxsqloc,fmaxsqall; - int nlocal = atom->nlocal; - double **fm = atom->fm; - - // finding max fm on this proc. - - fmsq = fmaxsqone = fmaxsqloc = fmaxsqall = 0.0; - for (int i = 0; i < nlocal; i++) { - fmsq = fm[i][0]*fm[i][0]+fm[i][1]*fm[i][1]+fm[i][2]*fm[i][2]; - fmaxsqone = MAX(fmaxsqone,fmsq); - } - - // finding max fm on this replica - - fmaxsqloc = fmaxsqone; - MPI_Allreduce(&fmaxsqone,&fmaxsqloc,1,MPI_DOUBLE,MPI_MAX,world); - - // finding max fm over all replicas, if necessary - // this communicator would be invalid for multiprocess replicas - - fmaxsqall = fmaxsqloc; - if (update->multireplica == 1) { - fmaxsqall = fmaxsqloc; - MPI_Allreduce(&fmaxsqloc,&fmaxsqall,1,MPI_DOUBLE,MPI_MAX,universe->uworld); - } - - if (fmaxsqall == 0.0) - error->all(FLERR,"Incorrect fmaxsqall calculation"); - - // define max timestep by dividing by the - // inverse of max frequency by discrete_factor - - dtmax = MY_2PI/(discrete_factor*sqrt(fmaxsqall)); - - return dtmax; -} - /* ---------------------------------------------------------------------- calculate gradients ---------------------------------------------------------------------- */ -void MinSpinOSO_LBFGS_LS::calc_gradient(double dts) +void MinSpinOSO_LBFGS_LS::calc_gradient() { int nlocal = atom->nlocal; double **sp = atom->sp; @@ -351,17 +303,11 @@ void MinSpinOSO_LBFGS_LS::calc_gradient(double dts) for (int i = 0; i < nlocal; i++) { - // calc. damping torque - - tdampx = -alpha_damp*(fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]); - tdampy = -alpha_damp*(fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); - tdampz = -alpha_damp*(fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); - // calculate gradients - g_cur[3 * i + 0] = -tdampz * dts; - g_cur[3 * i + 1] = tdampy * dts; - g_cur[3 * i + 2] = -tdampx * dts; + g_cur[3 * i + 0] = (fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); + g_cur[3 * i + 1] = -(fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); + g_cur[3 * i + 2] = (fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]); } } @@ -438,7 +384,7 @@ void MinSpinOSO_LBFGS_LS::calc_search_direction() if (rho[m_index] < 0.0){ local_iter = 0; for (int k = 0; k < num_mem; k++){ - for (int i = 0; i < nlocal; i ++){ + for (int i = 0; i < nlocal; i ++){ ds[k][i] = 0.0; dy[k][i] = 0.0; } @@ -464,7 +410,7 @@ void MinSpinOSO_LBFGS_LS::calc_search_direction() for (int i = 0; i < 3 * nlocal; i++) { sq += ds[c_ind][i] * q[i]; } - MPI_Allreduce(&sq, &sq_global, 1, MPI_DOUBLE, MPI_SUM, world); + MPI_Allreduce(&sq,&sq_global,1,MPI_DOUBLE,MPI_SUM,world); if (update->multireplica == 1) { sq_global *= factor; sq = sq_global; @@ -487,7 +433,7 @@ void MinSpinOSO_LBFGS_LS::calc_search_direction() for (int i = 0; i < 3 * nlocal; i++) { yy += dy[m_index][i] * dy[m_index][i]; } - MPI_Allreduce(&yy, &yy_global, 1, MPI_DOUBLE, MPI_SUM, world); + MPI_Allreduce(&yy,&yy_global,1,MPI_DOUBLE,MPI_SUM,world); if (update->multireplica == 1) { yy_global *= factor; yy = yy_global; @@ -520,7 +466,7 @@ void MinSpinOSO_LBFGS_LS::calc_search_direction() yr += dy[c_ind][i] * p_s[i]; } - MPI_Allreduce(&yr, &yr_global, 1, MPI_DOUBLE, MPI_SUM, world); + MPI_Allreduce(&yr,&yr_global,1,MPI_DOUBLE,MPI_SUM,world); if (update->multireplica == 1) { yr_global *= factor; yr = yr_global; @@ -580,15 +526,11 @@ double MinSpinOSO_LBFGS_LS::fmnorm_sqr() double **sp = atom->sp; double **fm = atom->fm; - // calc. magnetic torques + // calc. magnetic torques norm double local_norm2_sqr = 0.0; - for (int i = 0; i < nlocal; i++) { - tx = (fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]); - ty = (fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); - tz = (fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); - - local_norm2_sqr += tx*tx + ty*ty + tz*tz; + for (int i = 0; i < 3 * nlocal; i++) { + local_norm2_sqr += g_cur[i]*g_cur[i]; } // no extra atom calc. for spins @@ -678,9 +620,8 @@ void MinSpinOSO_LBFGS_LS::vm3(const double *m, const double *v, double *out) { for(int i = 0; i < 3; i++){ out[i] *= 0.0; - for(int j = 0; j < 3; j++){ - out[i] += *(m + 3 * j + i) * v[j]; - } + for(int j = 0; j < 3; j++) + out[i] += *(m + 3 * j + i) * v[j]; } } @@ -692,9 +633,10 @@ void MinSpinOSO_LBFGS_LS::make_step(double c, double *energy_and_der) double rot_mat[9]; // exponential of matrix made of search direction double s_new[3]; double **sp = atom->sp; - double der_e_cur_global = 0.0;; + double der_e_cur_tmp = 0.0;; for (int i = 0; i < nlocal; i++) { + // scale the search direction for (int j = 0; j < 3; j++) p_scaled[j] = c * p_s[3 * i + j]; @@ -707,23 +649,23 @@ void MinSpinOSO_LBFGS_LS::make_step(double c, double *energy_and_der) vm3(rot_mat, sp[i], s_new); for (int j = 0; j < 3; j++) sp[i][j] = s_new[j]; - } + } - ecurrent = energy_force(0); - calc_gradient(1.0); - neval++; - der_e_cur = 0.0; - for (int i = 0; i < 3 * nlocal; i++) { - der_e_cur += g_cur[i] * p_s[i]; - } - MPI_Allreduce(&der_e_cur, &der_e_cur_global, 1, MPI_DOUBLE, MPI_SUM, world); - der_e_cur = der_e_cur_global; - if (update->multireplica == 1) { - MPI_Allreduce(&der_e_cur_global,&der_e_cur,1,MPI_DOUBLE,MPI_SUM,universe->uworld); - } + ecurrent = energy_force(0); + calc_gradient(); + neval++; + der_e_cur = 0.0; + for (int i = 0; i < 3 * nlocal; i++) { + der_e_cur += g_cur[i] * p_s[i]; + } + MPI_Allreduce(&der_e_cur,&der_e_cur_tmp, 1, MPI_DOUBLE, MPI_SUM, world); + der_e_cur = der_e_cur_tmp; + if (update->multireplica == 1) { + MPI_Allreduce(&der_e_cur_tmp,&der_e_cur,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + } - energy_and_der[0] = ecurrent; - energy_and_der[1] = der_e_cur; + energy_and_der[0] = ecurrent; + energy_and_der[1] = der_e_cur; } /* ---------------------------------------------------------------------- @@ -733,17 +675,17 @@ void MinSpinOSO_LBFGS_LS::make_step(double c, double *energy_and_der) int MinSpinOSO_LBFGS_LS::calc_and_make_step(double a, double b, int index) { - double e_and_d[2] = {0.0, 0.0}; - double alpha, c1, c2, c3; + double e_and_d[2] = {0.0,0.0}; + double alpha,c1,c2,c3; double **sp = atom->sp; int nlocal = atom->nlocal; - make_step(b, e_and_d); + make_step(b,e_and_d); ecurrent = e_and_d[0]; der_e_cur = e_and_d[1]; index++; - if (awc(der_e_pr, eprevious, e_and_d[1], e_and_d[0]) || index == 5){ + if (awc(der_e_pr,eprevious,e_and_d[1],e_and_d[0]) || index == 5){ MPI_Bcast(&b,1,MPI_DOUBLE,0,world); for (int i = 0; i < 3 * nlocal; i++) { p_s[i] = b * p_s[i]; @@ -751,7 +693,7 @@ int MinSpinOSO_LBFGS_LS::calc_and_make_step(double a, double b, int index) return 1; } else{ - double r, f0, f1, df0, df1; + double r,f0,f1,df0,df1; r = b - a; f0 = eprevious; f1 = ecurrent; @@ -778,18 +720,20 @@ int MinSpinOSO_LBFGS_LS::calc_and_make_step(double a, double b, int index) return 0; } + /* ---------------------------------------------------------------------- Approximate Wolfe conditions: William W. Hager and Hongchao Zhang SIAM J. optim., 16(1), 170-192. (23 pages) ------------------------------------------------------------------------- */ + int MinSpinOSO_LBFGS_LS::awc(double der_phi_0, double phi_0, double der_phi_j, double phi_j){ double eps = 1.0e-6; double delta = 0.1; double sigma = 0.9; - if ((phi_j <= phi_0 + eps * fabs(phi_0)) && ((2.0*delta - 1.0) * der_phi_0 >= der_phi_j >= sigma * der_phi_0)) + if ((phi_j<=phi_0+eps*fabs(phi_0)) && ((2.0*delta-1.0) * der_phi_0>=der_phi_j>=sigma*der_phi_0)) return 1; else return 0; diff --git a/src/SPIN/min_spin_oso_lbfgs_ls.h b/src/SPIN/min_spin_oso_lbfgs_ls.h index eeaf20adf4..876e34f9c9 100644 --- a/src/SPIN/min_spin_oso_lbfgs_ls.h +++ b/src/SPIN/min_spin_oso_lbfgs_ls.h @@ -34,24 +34,15 @@ public: int modify_param(int, char **); void reset_vectors(); int iterate(int); - double evaluate_dt(); void advance_spins(); double fmnorm_sqr(); - void calc_gradient(double); + void calc_gradient(); void calc_search_direction(); private: - // test - int ireplica,nreplica; - - // global and spin timesteps + int ireplica,nreplica; // for neb int nlocal_max; // max value of nlocal (for size of lists) - double dt; - double dts; - - double alpha_damp; // damping for spin minimization - double discrete_factor; // factor for spin timestep evaluation double *spvec; // variables for atomic dof, as 1d vector double *fmvec; // variables for atomic dof, as 1d vector @@ -65,7 +56,7 @@ private: double **sp_copy; // copy of the spins int num_mem; // number of stored steps - int local_iter; + int local_iter; // for neb double der_e_cur; // current derivative along search dir. double der_e_pr; // previous derivative along search dir. From 7514eea9a7112a3962ff208178570125e4d9bb4c Mon Sep 17 00:00:00 2001 From: alxvov Date: Fri, 19 Jul 2019 11:47:24 +0000 Subject: [PATCH 41/74] no line search option too --- src/SPIN/min_spin_oso_lbfgs_ls.cpp | 115 ++++++++++++++++++++--------- src/SPIN/min_spin_oso_lbfgs_ls.h | 6 +- 2 files changed, 83 insertions(+), 38 deletions(-) diff --git a/src/SPIN/min_spin_oso_lbfgs_ls.cpp b/src/SPIN/min_spin_oso_lbfgs_ls.cpp index 5896ba9a9f..ddacd3e207 100644 --- a/src/SPIN/min_spin_oso_lbfgs_ls.cpp +++ b/src/SPIN/min_spin_oso_lbfgs_ls.cpp @@ -76,6 +76,7 @@ MinSpinOSO_LBFGS_LS::MinSpinOSO_LBFGS_LS(LAMMPS *lmp) : nreplica = universe->nworlds; ireplica = universe->iworld; use_line_search = 1; + maxepsrot = MY_2PI / (100.0); } @@ -146,6 +147,13 @@ int MinSpinOSO_LBFGS_LS::modify_param(int narg, char **arg) use_line_search = force->numeric(FLERR,arg[1]); return 2; } + if (strcmp(arg[0],"discrete_factor") == 0) { + if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); + double discrete_factor; + discrete_factor = force->numeric(FLERR,arg[1]); + maxepsrot = MY_2PI / discrete_factor; + return 2; + } return 0; } @@ -184,6 +192,7 @@ int MinSpinOSO_LBFGS_LS::iterate(int maxiter) if (nlocal_max < nlocal) { nlocal_max = nlocal; + local_iter = 0; memory->grow(g_old,3*nlocal_max,"min/spin/oso/lbfgs_ls:g_old"); memory->grow(g_cur,3*nlocal_max,"min/spin/oso/lbfgs_ls:g_cur"); memory->grow(p_s,3*nlocal_max,"min/spin/oso/lbfgs_ls:p_s"); @@ -195,7 +204,7 @@ int MinSpinOSO_LBFGS_LS::iterate(int maxiter) } for (int iter = 0; iter < maxiter; iter++) { - + if (timer->check_timeout(niter)) return TIMEOUT; @@ -205,17 +214,13 @@ int MinSpinOSO_LBFGS_LS::iterate(int maxiter) // optimize timestep accross processes / replicas // need a force calculation for timestep optimization - if (local_iter == 0){ - ecurrent = energy_force(0); - calc_gradient(); - neval++; - } - calc_search_direction(); + if (local_iter == 0) + ecurrent = energy_force(0); if (use_line_search) { // here we need to do line search - + calc_search_direction(); der_e_cur = 0.0; for (int i = 0; i < 3 * nlocal; i++) { der_e_cur += g_cur[i] * p_s[i]; @@ -235,8 +240,22 @@ int MinSpinOSO_LBFGS_LS::iterate(int maxiter) else{ // here we don't do line search + // but use cutoff rotation angle + // if gneb calc., nreplica > 1 + // then calculate gradients and advance spins + // of intermediate replicas only + if (nreplica > 1) { + if(ireplica != 0 && ireplica != nreplica-1) + calc_gradient(); + calc_search_direction(); advance_spins(); + } else{ + calc_gradient(); + calc_search_direction(); + advance_spins(); + } + neval++; eprevious = ecurrent; ecurrent = energy_force(0); neval++; @@ -265,7 +284,7 @@ int MinSpinOSO_LBFGS_LS::iterate(int maxiter) // sync across replicas if running multi-replica minimization if (update->ftol > 0.0) { - fmdotfm = fmnorm_sqr(); + fmdotfm = fmnorm2(); if (update->multireplica == 0) { if (fmdotfm < update->ftol*update->ftol) return FTOL; } else { @@ -340,7 +359,9 @@ void MinSpinOSO_LBFGS_LS::calc_search_direction() double *alpha; double factor; + double scaling = 1.0; + // for multiple replica do not move end points if (nreplica > 1) { if (ireplica == 0 || ireplica == nreplica - 1) { factor = 0.0; @@ -354,9 +375,14 @@ void MinSpinOSO_LBFGS_LS::calc_search_direction() alpha = (double *) calloc(num_mem, sizeof(double)); if (local_iter == 0){ // steepest descent direction + + //if no line search then calculate maximum rotation + if (use_line_search == 0) + scaling = maximum_rotation(g_cur); + for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = -g_cur[i]; - g_old[i] = g_cur[i]; + p_s[i] = -g_cur[i] * factor * scaling;; + g_old[i] = g_cur[i] * factor; for (int k = 0; k < num_mem; k++){ ds[k][i] = 0.0; dy[k][i] = 0.0; @@ -478,9 +504,11 @@ void MinSpinOSO_LBFGS_LS::calc_search_direction() p_s[i] += ds[c_ind][i] * (alpha[c_ind] - beta); } } + if (use_line_search == 0) + scaling = maximum_rotation(p_s); for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = - factor * p_s[i]; - g_old[i] = g_cur[i]; + p_s[i] = - factor * p_s[i] * scaling; + g_old[i] = g_cur[i] * factor; } } @@ -516,32 +544,21 @@ void MinSpinOSO_LBFGS_LS::advance_spins() } /* ---------------------------------------------------------------------- - compute and return ||mag. torque||_2^2 + compute and return ||mag. torque||_2^2 / N ------------------------------------------------------------------------- */ -double MinSpinOSO_LBFGS_LS::fmnorm_sqr() -{ +double MinSpinOSO_LBFGS_LS::fmnorm2() { + double norm2, norm2_global; int nlocal = atom->nlocal; - double tx,ty,tz; - double **sp = atom->sp; - double **fm = atom->fm; + int ntotal = 0; - // calc. magnetic torques norm - - double local_norm2_sqr = 0.0; - for (int i = 0; i < 3 * nlocal; i++) { - local_norm2_sqr += g_cur[i]*g_cur[i]; - } - - // no extra atom calc. for spins - - if (nextra_atom) - error->all(FLERR,"extra atom option not available yet"); - - double norm2_sqr = 0.0; - MPI_Allreduce(&local_norm2_sqr,&norm2_sqr,1,MPI_DOUBLE,MPI_SUM,world); - - return norm2_sqr; + norm2 = 0.0; + for (int i = 0; i < 3 * nlocal; i++) norm2 += g_cur[i] * g_cur[i]; + MPI_Allreduce(&norm2, &norm2_global, 1, MPI_DOUBLE, MPI_SUM, world); + MPI_Allreduce(&nlocal, &ntotal, 1, MPI_INT, MPI_SUM, world); + double ans = norm2_global / (double) ntotal; + MPI_Bcast(&ans, 1, MPI_DOUBLE, 0, world); + return ans; } /* ---------------------------------------------------------------------- @@ -738,3 +755,31 @@ int MinSpinOSO_LBFGS_LS::awc(double der_phi_0, double phi_0, double der_phi_j, d else return 0; } + +double MinSpinOSO_LBFGS_LS::maximum_rotation(double *p) +{ + double norm2,norm2_global,scaling,alpha; + int nlocal = atom->nlocal; + int ntotal = 0; + + norm2 = 0.0; + for (int i = 0; i < 3 * nlocal; i++) norm2 += p[i] * p[i]; + + MPI_Allreduce(&norm2,&norm2_global,1,MPI_DOUBLE,MPI_SUM,world); + if (update->multireplica == 1) { + norm2 = norm2_global; + MPI_Allreduce(&norm2,&norm2_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + } + MPI_Allreduce(&nlocal,&ntotal,1,MPI_INT,MPI_SUM,world); + if (update->multireplica == 1) { + nlocal = ntotal; + MPI_Allreduce(&nlocal,&ntotal,1,MPI_INT,MPI_SUM,universe->uworld); + } + + scaling = (maxepsrot * sqrt((double) ntotal / norm2_global)); + + if (scaling < 1.0) alpha = scaling; + else alpha = 1.0; + + return alpha; +} \ No newline at end of file diff --git a/src/SPIN/min_spin_oso_lbfgs_ls.h b/src/SPIN/min_spin_oso_lbfgs_ls.h index 876e34f9c9..a253808923 100644 --- a/src/SPIN/min_spin_oso_lbfgs_ls.h +++ b/src/SPIN/min_spin_oso_lbfgs_ls.h @@ -35,10 +35,10 @@ public: void reset_vectors(); int iterate(int); void advance_spins(); - double fmnorm_sqr(); + double fmnorm2(); void calc_gradient(); void calc_search_direction(); - + double maximum_rotation(double *); private: int ireplica,nreplica; // for neb @@ -62,7 +62,7 @@ private: double der_e_pr; // previous derivative along search dir. int use_line_search; // use line search or not. - + double maxepsrot; void vm3(const double *, const double *, double *); void rodrigues_rotation(const double *, double *); From ad713d39a41107601c7337ac281627057c2c451c Mon Sep 17 00:00:00 2001 From: alxvov Date: Fri, 19 Jul 2019 11:58:39 +0000 Subject: [PATCH 42/74] rename min_spin_oso_lbfgs_ls -> min_spin_oso_lbfgs --- src/SPIN/min_spin_oso_lbfgs.cpp | 365 +++++++++----- src/SPIN/min_spin_oso_lbfgs.h | 32 +- src/SPIN/min_spin_oso_lbfgs_ls.cpp | 785 ----------------------------- src/SPIN/min_spin_oso_lbfgs_ls.h | 79 --- 4 files changed, 241 insertions(+), 1020 deletions(-) delete mode 100644 src/SPIN/min_spin_oso_lbfgs_ls.cpp delete mode 100644 src/SPIN/min_spin_oso_lbfgs_ls.h diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index fd83e7b460..7f716da63d 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -63,16 +63,18 @@ static const char cite_minstyle_spin_oso_lbfgs[] = /* ---------------------------------------------------------------------- */ MinSpinOSO_LBFGS::MinSpinOSO_LBFGS(LAMMPS *lmp) : - Min(lmp), g_old(NULL), g_cur(NULL), p_s(NULL), ds(NULL), dy(NULL), rho(NULL) + Min(lmp), g_old(NULL), g_cur(NULL), p_s(NULL), ds(NULL), dy(NULL), rho(NULL), sp_copy(NULL) { if (lmp->citeme) lmp->citeme->add(cite_minstyle_spin_oso_lbfgs); nlocal_max = 0; - + // nreplica = number of partitions // ireplica = which world I am in universe nreplica = universe->nworlds; ireplica = universe->iworld; + use_line_search = 1; + maxepsrot = MY_2PI / (100.0); } @@ -86,21 +88,21 @@ MinSpinOSO_LBFGS::~MinSpinOSO_LBFGS() memory->destroy(ds); memory->destroy(dy); memory->destroy(rho); + if (use_line_search) + memory->destroy(sp_copy); } /* ---------------------------------------------------------------------- */ void MinSpinOSO_LBFGS::init() { - alpha_damp = 1.0; - discrete_factor = 10.0; num_mem = 3; local_iter = 0; - maxepsrot = MY_2PI / (100.0); + der_e_cur = 0.0; + der_e_pr = 0.0; Min::init(); - dts = dt = update->dt; last_negative = update->ntimestep; // allocate tables @@ -112,6 +114,8 @@ void MinSpinOSO_LBFGS::init() memory->grow(rho,num_mem,"min/spin/oso/lbfgs:rho"); memory->grow(ds,num_mem,3*nlocal_max,"min/spin/oso/lbfgs:ds"); memory->grow(dy,num_mem,3*nlocal_max,"min/spin/oso/lbfgs:dy"); + if (use_line_search) + memory->grow(sp_copy,nlocal_max,3,"min/spin/oso/lbfgs:sp_copy"); } @@ -135,14 +139,17 @@ void MinSpinOSO_LBFGS::setup_style() int MinSpinOSO_LBFGS::modify_param(int narg, char **arg) { - if (strcmp(arg[0],"alpha_damp") == 0) { + + if (strcmp(arg[0],"line_search") == 0) { if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); - alpha_damp = force->numeric(FLERR,arg[1]); + use_line_search = force->numeric(FLERR,arg[1]); return 2; } if (strcmp(arg[0],"discrete_factor") == 0) { if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); + double discrete_factor; discrete_factor = force->numeric(FLERR,arg[1]); + maxepsrot = MY_2PI / discrete_factor; return 2; } return 0; @@ -178,6 +185,8 @@ int MinSpinOSO_LBFGS::iterate(int maxiter) bigint ntimestep; double fmdotfm; int flag, flagall; + double **sp = atom->sp; + double der_e_cur_tmp = 0.0; if (nlocal_max < nlocal) { nlocal_max = nlocal; @@ -188,10 +197,12 @@ int MinSpinOSO_LBFGS::iterate(int maxiter) memory->grow(rho,num_mem,"min/spin/oso/lbfgs:rho"); memory->grow(ds,num_mem,3*nlocal_max,"min/spin/oso/lbfgs:ds"); memory->grow(dy,num_mem,3*nlocal_max,"min/spin/oso/lbfgs:dy"); + if (use_line_search) + memory->grow(sp_copy,nlocal_max,3,"min/spin/oso/lbfgs:sp_copy"); } for (int iter = 0; iter < maxiter; iter++) { - + if (timer->check_timeout(niter)) return TIMEOUT; @@ -200,29 +211,53 @@ int MinSpinOSO_LBFGS::iterate(int maxiter) // optimize timestep accross processes / replicas // need a force calculation for timestep optimization - if (local_iter == 0) energy_force(0); - // to be checked - // if gneb calc., nreplica > 1 - // then calculate gradients of intermediate replicas - if (nreplica > 1) { + if (local_iter == 0) + ecurrent = energy_force(0); + + if (use_line_search) { + + // here we need to do line search + calc_search_direction(); + der_e_cur = 0.0; + for (int i = 0; i < 3 * nlocal; i++) { + der_e_cur += g_cur[i] * p_s[i]; + } + MPI_Allreduce(&der_e_cur,&der_e_cur_tmp,1,MPI_DOUBLE,MPI_SUM,world); + der_e_cur = der_e_cur_tmp; + if (update->multireplica == 1) { + MPI_Allreduce(&der_e_cur_tmp,&der_e_cur,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + } + for (int i = 0; i < nlocal; i++) { + for (int j = 0; j < 3; j++) sp_copy[i][j] = sp[i][j]; + } + eprevious = ecurrent; + der_e_pr = der_e_cur; + calc_and_make_step(0.0, 1.0, 0); + } + else{ + + // here we don't do line search + // but use cutoff rotation angle + // if gneb calc., nreplica > 1 + // then calculate gradients and advance spins + // of intermediate replicas only + + if (nreplica > 1) { if(ireplica != 0 && ireplica != nreplica-1) - calc_gradient(1.0); - } else calc_gradient(1.0); - calc_search_direction(); - - // to be checked - // if gneb calc., nreplica > 1 - // then advance spins only if intermediate replica - // otherwise (simple minimization), advance spins - - if (nreplica > 1) { - if(ireplica != 0 && ireplica != nreplica-1) - advance_spins(); - } else advance_spins(); - eprevious = ecurrent; - ecurrent = energy_force(0); - neval++; + calc_gradient(); + calc_search_direction(); + advance_spins(); + } else{ + calc_gradient(); + calc_search_direction(); + advance_spins(); + } + neval++; + eprevious = ecurrent; + ecurrent = energy_force(0); + neval++; + } //// energy tolerance criterion //// only check after DELAYSTEP elapsed since velocties reset to 0 @@ -247,7 +282,7 @@ int MinSpinOSO_LBFGS::iterate(int maxiter) // sync across replicas if running multi-replica minimization if (update->ftol > 0.0) { - fmdotfm = fmnorm_sqr(); + fmdotfm = fmnorm2(); if (update->multireplica == 0) { if (fmdotfm < update->ftol*update->ftol) return FTOL; } else { @@ -270,56 +305,11 @@ int MinSpinOSO_LBFGS::iterate(int maxiter) return MAXITER; } -/* ---------------------------------------------------------------------- - evaluate max timestep ----------------------------------------------------------------------- */ - -double MinSpinOSO_LBFGS::evaluate_dt() -{ - double dtmax; - double fmsq; - double fmaxsqone,fmaxsqloc,fmaxsqall; - int nlocal = atom->nlocal; - double **fm = atom->fm; - - // finding max fm on this proc. - - fmsq = fmaxsqone = fmaxsqloc = fmaxsqall = 0.0; - for (int i = 0; i < nlocal; i++) { - fmsq = fm[i][0]*fm[i][0]+fm[i][1]*fm[i][1]+fm[i][2]*fm[i][2]; - fmaxsqone = MAX(fmaxsqone,fmsq); - } - - // finding max fm on this replica - - fmaxsqloc = fmaxsqone; - MPI_Allreduce(&fmaxsqone,&fmaxsqloc,1,MPI_DOUBLE,MPI_MAX,world); - - // finding max fm over all replicas, if necessary - // this communicator would be invalid for multiprocess replicas - - fmaxsqall = fmaxsqloc; - if (update->multireplica == 1) { - fmaxsqall = fmaxsqloc; - MPI_Allreduce(&fmaxsqloc,&fmaxsqall,1,MPI_DOUBLE,MPI_MAX,universe->uworld); - } - - if (fmaxsqall == 0.0) - error->all(FLERR,"Incorrect fmaxsqall calculation"); - - // define max timestep by dividing by the - // inverse of max frequency by discrete_factor - // std::cout << fmaxsqall << "\n"; - dtmax = MY_2PI/(discrete_factor*sqrt(fmaxsqall)); - - return dtmax; -} - /* ---------------------------------------------------------------------- calculate gradients ---------------------------------------------------------------------- */ -void MinSpinOSO_LBFGS::calc_gradient(double dts) +void MinSpinOSO_LBFGS::calc_gradient() { int nlocal = atom->nlocal; double **sp = atom->sp; @@ -330,17 +320,11 @@ void MinSpinOSO_LBFGS::calc_gradient(double dts) for (int i = 0; i < nlocal; i++) { - // calc. damping torque - - tdampx = -alpha_damp*(fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]); - tdampy = -alpha_damp*(fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); - tdampz = -alpha_damp*(fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); - // calculate gradients - g_cur[3 * i + 0] = -tdampz * dts; - g_cur[3 * i + 1] = tdampy * dts; - g_cur[3 * i + 2] = -tdampx * dts; + g_cur[3 * i + 0] = (fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); + g_cur[3 * i + 1] = -(fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); + g_cur[3 * i + 2] = (fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]); } } @@ -373,8 +357,9 @@ void MinSpinOSO_LBFGS::calc_search_direction() double *alpha; double factor; - double scaling; + double scaling = 1.0; + // for multiple replica do not move end points if (nreplica > 1) { if (ireplica == 0 || ireplica == nreplica - 1) { factor = 0.0; @@ -388,14 +373,19 @@ void MinSpinOSO_LBFGS::calc_search_direction() alpha = (double *) calloc(num_mem, sizeof(double)); if (local_iter == 0){ // steepest descent direction - - scaling = maximum_rotation(g_cur); - for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = - g_cur[i] * factor * scaling; - g_old[i] = g_cur[i]; - ds[m_index][i] = 0.0; - dy[m_index][i] = 0.0; + //if no line search then calculate maximum rotation + if (use_line_search == 0) + scaling = maximum_rotation(g_cur); + + for (int i = 0; i < 3 * nlocal; i++) { + p_s[i] = -g_cur[i] * factor * scaling;; + g_old[i] = g_cur[i] * factor; + for (int k = 0; k < num_mem; k++){ + ds[k][i] = 0.0; + dy[k][i] = 0.0; + rho[k] = 0.0; + } } } else { dyds = 0.0; @@ -418,7 +408,7 @@ void MinSpinOSO_LBFGS::calc_search_direction() if (rho[m_index] < 0.0){ local_iter = 0; for (int k = 0; k < num_mem; k++){ - for (int i = 0; i < nlocal; i ++){ + for (int i = 0; i < nlocal; i ++){ ds[k][i] = 0.0; dy[k][i] = 0.0; } @@ -444,7 +434,7 @@ void MinSpinOSO_LBFGS::calc_search_direction() for (int i = 0; i < 3 * nlocal; i++) { sq += ds[c_ind][i] * q[i]; } - MPI_Allreduce(&sq, &sq_global, 1, MPI_DOUBLE, MPI_SUM, world); + MPI_Allreduce(&sq,&sq_global,1,MPI_DOUBLE,MPI_SUM,world); if (update->multireplica == 1) { sq_global *= factor; sq = sq_global; @@ -467,7 +457,7 @@ void MinSpinOSO_LBFGS::calc_search_direction() for (int i = 0; i < 3 * nlocal; i++) { yy += dy[m_index][i] * dy[m_index][i]; } - MPI_Allreduce(&yy, &yy_global, 1, MPI_DOUBLE, MPI_SUM, world); + MPI_Allreduce(&yy,&yy_global,1,MPI_DOUBLE,MPI_SUM,world); if (update->multireplica == 1) { yy_global *= factor; yy = yy_global; @@ -500,7 +490,7 @@ void MinSpinOSO_LBFGS::calc_search_direction() yr += dy[c_ind][i] * p_s[i]; } - MPI_Allreduce(&yr, &yr_global, 1, MPI_DOUBLE, MPI_SUM, world); + MPI_Allreduce(&yr,&yr_global,1,MPI_DOUBLE,MPI_SUM,world); if (update->multireplica == 1) { yr_global *= factor; yr = yr_global; @@ -512,10 +502,11 @@ void MinSpinOSO_LBFGS::calc_search_direction() p_s[i] += ds[c_ind][i] * (alpha[c_ind] - beta); } } - scaling = maximum_rotation(p_s); + if (use_line_search == 0) + scaling = maximum_rotation(p_s); for (int i = 0; i < 3 * nlocal; i++) { p_s[i] = - factor * p_s[i] * scaling; - g_old[i] = g_cur[i]; + g_old[i] = g_cur[i] * factor; } } @@ -551,36 +542,21 @@ void MinSpinOSO_LBFGS::advance_spins() } /* ---------------------------------------------------------------------- - compute and return ||mag. torque||_2^2 + compute and return ||mag. torque||_2^2 / N ------------------------------------------------------------------------- */ -double MinSpinOSO_LBFGS::fmnorm_sqr() -{ +double MinSpinOSO_LBFGS::fmnorm2() { + double norm2, norm2_global; int nlocal = atom->nlocal; - double tx,ty,tz; - double **sp = atom->sp; - double **fm = atom->fm; + int ntotal = 0; - // calc. magnetic torques - - double local_norm2_sqr = 0.0; - for (int i = 0; i < nlocal; i++) { - tx = (fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]); - ty = (fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); - tz = (fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); - - local_norm2_sqr += tx*tx + ty*ty + tz*tz; - } - - // no extra atom calc. for spins - - if (nextra_atom) - error->all(FLERR,"extra atom option not available yet"); - - double norm2_sqr = 0.0; - MPI_Allreduce(&local_norm2_sqr,&norm2_sqr,1,MPI_DOUBLE,MPI_SUM,world); - - return norm2_sqr; + norm2 = 0.0; + for (int i = 0; i < 3 * nlocal; i++) norm2 += g_cur[i] * g_cur[i]; + MPI_Allreduce(&norm2, &norm2_global, 1, MPI_DOUBLE, MPI_SUM, world); + MPI_Allreduce(&nlocal, &ntotal, 1, MPI_INT, MPI_SUM, world); + double ans = norm2_global / (double) ntotal; + MPI_Bcast(&ans, 1, MPI_DOUBLE, 0, world); + return ans; } /* ---------------------------------------------------------------------- @@ -659,38 +635,149 @@ void MinSpinOSO_LBFGS::vm3(const double *m, const double *v, double *out) { for(int i = 0; i < 3; i++){ out[i] *= 0.0; - for(int j = 0; j < 3; j++){ - out[i] += *(m + 3 * j + i) * v[j]; - } + for(int j = 0; j < 3; j++) + out[i] += *(m + 3 * j + i) * v[j]; } } + +void MinSpinOSO_LBFGS::make_step(double c, double *energy_and_der) +{ + double p_scaled[3]; + int nlocal = atom->nlocal; + double rot_mat[9]; // exponential of matrix made of search direction + double s_new[3]; + double **sp = atom->sp; + double der_e_cur_tmp = 0.0;; + + for (int i = 0; i < nlocal; i++) { + + // scale the search direction + + for (int j = 0; j < 3; j++) p_scaled[j] = c * p_s[3 * i + j]; + + // calculate rotation matrix + + rodrigues_rotation(p_scaled, rot_mat); + + // rotate spins + + vm3(rot_mat, sp[i], s_new); + for (int j = 0; j < 3; j++) sp[i][j] = s_new[j]; + } + + ecurrent = energy_force(0); + calc_gradient(); + neval++; + der_e_cur = 0.0; + for (int i = 0; i < 3 * nlocal; i++) { + der_e_cur += g_cur[i] * p_s[i]; + } + MPI_Allreduce(&der_e_cur,&der_e_cur_tmp, 1, MPI_DOUBLE, MPI_SUM, world); + der_e_cur = der_e_cur_tmp; + if (update->multireplica == 1) { + MPI_Allreduce(&der_e_cur_tmp,&der_e_cur,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + } + + energy_and_der[0] = ecurrent; + energy_and_der[1] = der_e_cur; +} + +/* ---------------------------------------------------------------------- + Calculate step length which satisfies approximate Wolfe conditions + using the cubic interpolation +------------------------------------------------------------------------- */ + +int MinSpinOSO_LBFGS::calc_and_make_step(double a, double b, int index) +{ + double e_and_d[2] = {0.0,0.0}; + double alpha,c1,c2,c3; + double **sp = atom->sp; + int nlocal = atom->nlocal; + + make_step(b,e_and_d); + ecurrent = e_and_d[0]; + der_e_cur = e_and_d[1]; + index++; + + if (awc(der_e_pr,eprevious,e_and_d[1],e_and_d[0]) || index == 5){ + MPI_Bcast(&b,1,MPI_DOUBLE,0,world); + for (int i = 0; i < 3 * nlocal; i++) { + p_s[i] = b * p_s[i]; + } + return 1; + } + else{ + double r,f0,f1,df0,df1; + r = b - a; + f0 = eprevious; + f1 = ecurrent; + df0 = der_e_pr; + df1 = der_e_cur; + + c1 = -2.0*(f1-f0)/(r*r*r)+(df1+df0)/(r*r); + c2 = 3.0*(f1-f0)/(r*r)-(df1+2.0*df0)/(r); + c3 = df0; + + // f(x) = c1 x^3 + c2 x^2 + c3 x^1 + c4 + // has minimum at alpha below. We do not check boundaries. + + alpha = (-c2 + sqrt(c2*c2 - 3.0*c1*c3))/(3.0*c1); + MPI_Bcast(&alpha,1,MPI_DOUBLE,0,world); + + if (alpha < 0.0) alpha = r/2.0; + + for (int i = 0; i < nlocal; i++) { + for (int j = 0; j < 3; j++) sp[i][j] = sp_copy[i][j]; + } + calc_and_make_step(0.0, alpha, index); + } + + return 0; +} + +/* ---------------------------------------------------------------------- + Approximate Wolfe conditions: + William W. Hager and Hongchao Zhang + SIAM J. optim., 16(1), 170-192. (23 pages) +------------------------------------------------------------------------- */ + +int MinSpinOSO_LBFGS::awc(double der_phi_0, double phi_0, double der_phi_j, double phi_j){ + + double eps = 1.0e-6; + double delta = 0.1; + double sigma = 0.9; + + if ((phi_j<=phi_0+eps*fabs(phi_0)) && ((2.0*delta-1.0) * der_phi_0>=der_phi_j>=sigma*der_phi_0)) + return 1; + else + return 0; +} + double MinSpinOSO_LBFGS::maximum_rotation(double *p) { - double norm, norm_global, scaling, alpha; + double norm2,norm2_global,scaling,alpha; int nlocal = atom->nlocal; int ntotal = 0; - norm = 0.0; - for (int i = 0; i < 3 * nlocal; i++) norm += p[i] * p[i]; + norm2 = 0.0; + for (int i = 0; i < 3 * nlocal; i++) norm2 += p[i] * p[i]; - MPI_Allreduce(&norm,&norm_global,1,MPI_DOUBLE,MPI_SUM,world); + MPI_Allreduce(&norm2,&norm2_global,1,MPI_DOUBLE,MPI_SUM,world); if (update->multireplica == 1) { - norm = norm_global; - MPI_Allreduce(&norm,&norm_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + norm2 = norm2_global; + MPI_Allreduce(&norm2,&norm2_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); } - MPI_Allreduce(&nlocal,&ntotal,1,MPI_INT,MPI_SUM,world); if (update->multireplica == 1) { nlocal = ntotal; MPI_Allreduce(&nlocal,&ntotal,1,MPI_INT,MPI_SUM,universe->uworld); } - scaling = (maxepsrot * sqrt((double) ntotal / norm_global)); + scaling = (maxepsrot * sqrt((double) ntotal / norm2_global)); if (scaling < 1.0) alpha = scaling; else alpha = 1.0; return alpha; -} - +} \ No newline at end of file diff --git a/src/SPIN/min_spin_oso_lbfgs.h b/src/SPIN/min_spin_oso_lbfgs.h index c0f8dc484d..91c900f244 100644 --- a/src/SPIN/min_spin_oso_lbfgs.h +++ b/src/SPIN/min_spin_oso_lbfgs.h @@ -24,7 +24,7 @@ MinimizeStyle(spin/oso_lbfgs, MinSpinOSO_LBFGS) namespace LAMMPS_NS { -class MinSpinOSO_LBFGS : public Min { +class MinSpinOSO_LBFGS: public Min { public: MinSpinOSO_LBFGS(class LAMMPS *); @@ -34,26 +34,15 @@ public: int modify_param(int, char **); void reset_vectors(); int iterate(int); - double evaluate_dt(); void advance_spins(); - double fmnorm_sqr(); - void calc_gradient(double); + double fmnorm2(); + void calc_gradient(); void calc_search_direction(); double maximum_rotation(double *); private: - - - // test - int ireplica,nreplica; - - // global and spin timesteps + int ireplica,nreplica; // for neb int nlocal_max; // max value of nlocal (for size of lists) - double dt; - double dts; - - double alpha_damp; // damping for spin minimization - double discrete_factor; // factor for spin timestep evaluation double *spvec; // variables for atomic dof, as 1d vector double *fmvec; // variables for atomic dof, as 1d vector @@ -64,13 +53,22 @@ private: double **ds; // change in rotation matrix between two iterations, da double **dy; // change in gradients between two iterations, dg double *rho; // estimation of curvature - int num_mem; // number of stored steps - int local_iter; // number of times we call search_direction + double **sp_copy; // copy of the spins + int num_mem; // number of stored steps + int local_iter; // for neb + + double der_e_cur; // current derivative along search dir. + double der_e_pr; // previous derivative along search dir. + + int use_line_search; // use line search or not. double maxepsrot; void vm3(const double *, const double *, double *); void rodrigues_rotation(const double *, double *); + int calc_and_make_step(double, double, int); + int awc(double, double, double, double); + void make_step(double, double *); bigint last_negative; }; diff --git a/src/SPIN/min_spin_oso_lbfgs_ls.cpp b/src/SPIN/min_spin_oso_lbfgs_ls.cpp deleted file mode 100644 index ddacd3e207..0000000000 --- a/src/SPIN/min_spin_oso_lbfgs_ls.cpp +++ /dev/null @@ -1,785 +0,0 @@ -/* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov - - 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. -------------------------------------------------------------------------- */ - -/* ------------------------------------------------------------------------ - Contributing authors: Aleksei Ivanov (University of Iceland) - Julien Tranchida (SNL) - - Please cite the related publication: - Ivanov, A. V., Uzdin, V. M., & Jónsson, H. (2019). Fast and Robust - Algorithm for the Minimisation of the Energy of Spin Systems. arXiv - preprint arXiv:1904.02669. -------------------------------------------------------------------------- */ - -#include -#include -#include -#include -#include "min_spin_oso_lbfgs_ls.h" -#include "universe.h" -#include "atom.h" -#include "citeme.h" -#include "force.h" -#include "update.h" -#include "output.h" -#include "timer.h" -#include "error.h" -#include "memory.h" -#include "modify.h" -#include "math_special.h" -#include "math_const.h" -#include "universe.h" -#include - - -using namespace LAMMPS_NS; -using namespace MathConst; - -static const char cite_minstyle_spin_oso_lbfgs_ls[] = - "min_style spin/oso_lbfgs_ls command:\n\n" - "@article{ivanov2019fast,\n" - "title={Fast and Robust Algorithm for the Minimisation of the Energy of " - "Spin Systems},\n" - "author={Ivanov, A. V and Uzdin, V. M. and J{\'o}nsson, H.},\n" - "journal={arXiv preprint arXiv:1904.02669},\n" - "year={2019}\n" - "}\n\n"; - -// EPS_ENERGY = minimum normalization for energy tolerance - -#define EPS_ENERGY 1.0e-8 - -#define DELAYSTEP 5 - - -/* ---------------------------------------------------------------------- */ - -MinSpinOSO_LBFGS_LS::MinSpinOSO_LBFGS_LS(LAMMPS *lmp) : - Min(lmp), g_old(NULL), g_cur(NULL), p_s(NULL), ds(NULL), dy(NULL), rho(NULL), sp_copy(NULL) -{ - if (lmp->citeme) lmp->citeme->add(cite_minstyle_spin_oso_lbfgs_ls); - nlocal_max = 0; - - // nreplica = number of partitions - // ireplica = which world I am in universe - - nreplica = universe->nworlds; - ireplica = universe->iworld; - use_line_search = 1; - maxepsrot = MY_2PI / (100.0); - -} - -/* ---------------------------------------------------------------------- */ - -MinSpinOSO_LBFGS_LS::~MinSpinOSO_LBFGS_LS() -{ - memory->destroy(g_old); - memory->destroy(g_cur); - memory->destroy(p_s); - memory->destroy(ds); - memory->destroy(dy); - memory->destroy(rho); - if (use_line_search) - memory->destroy(sp_copy); -} - -/* ---------------------------------------------------------------------- */ - -void MinSpinOSO_LBFGS_LS::init() -{ - num_mem = 3; - local_iter = 0; - der_e_cur = 0.0; - der_e_pr = 0.0; - - Min::init(); - - last_negative = update->ntimestep; - - // allocate tables - - nlocal_max = atom->nlocal; - memory->grow(g_old,3*nlocal_max,"min/spin/oso/lbfgs_ls:g_old"); - memory->grow(g_cur,3*nlocal_max,"min/spin/oso/lbfgs_ls:g_cur"); - memory->grow(p_s,3*nlocal_max,"min/spin/oso/lbfgs_ls:p_s"); - memory->grow(rho,num_mem,"min/spin/oso/lbfgs_ls:rho"); - memory->grow(ds,num_mem,3*nlocal_max,"min/spin/oso/lbfgs_ls:ds"); - memory->grow(dy,num_mem,3*nlocal_max,"min/spin/oso/lbfgs_ls:dy"); - if (use_line_search) - memory->grow(sp_copy,nlocal_max,3,"min/spin/oso/lbfgs_ls:sp_copy"); - -} - -/* ---------------------------------------------------------------------- */ - -void MinSpinOSO_LBFGS_LS::setup_style() -{ - double **v = atom->v; - int nlocal = atom->nlocal; - - // check if the atom/spin style is defined - - if (!atom->sp_flag) - error->all(FLERR,"min/spin_oso_lbfgs_ls requires atom/spin style"); - - for (int i = 0; i < nlocal; i++) - v[i][0] = v[i][1] = v[i][2] = 0.0; -} - -/* ---------------------------------------------------------------------- */ - -int MinSpinOSO_LBFGS_LS::modify_param(int narg, char **arg) -{ - - if (strcmp(arg[0],"line_search") == 0) { - if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); - use_line_search = force->numeric(FLERR,arg[1]); - return 2; - } - if (strcmp(arg[0],"discrete_factor") == 0) { - if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); - double discrete_factor; - discrete_factor = force->numeric(FLERR,arg[1]); - maxepsrot = MY_2PI / discrete_factor; - return 2; - } - return 0; -} - -/* ---------------------------------------------------------------------- - set current vector lengths and pointers - called after atoms have migrated -------------------------------------------------------------------------- */ - -void MinSpinOSO_LBFGS_LS::reset_vectors() -{ - // atomic dof - - // size sp is 4N vector - nvec = 4 * atom->nlocal; - if (nvec) spvec = atom->sp[0]; - - nvec = 3 * atom->nlocal; - if (nvec) fmvec = atom->fm[0]; - - if (nvec) xvec = atom->x[0]; - if (nvec) fvec = atom->f[0]; -} - -/* ---------------------------------------------------------------------- - minimization via damped spin dynamics -------------------------------------------------------------------------- */ - -int MinSpinOSO_LBFGS_LS::iterate(int maxiter) -{ - int nlocal = atom->nlocal; - bigint ntimestep; - double fmdotfm; - int flag, flagall; - double **sp = atom->sp; - double der_e_cur_tmp = 0.0; - - if (nlocal_max < nlocal) { - nlocal_max = nlocal; - local_iter = 0; - memory->grow(g_old,3*nlocal_max,"min/spin/oso/lbfgs_ls:g_old"); - memory->grow(g_cur,3*nlocal_max,"min/spin/oso/lbfgs_ls:g_cur"); - memory->grow(p_s,3*nlocal_max,"min/spin/oso/lbfgs_ls:p_s"); - memory->grow(rho,num_mem,"min/spin/oso/lbfgs_ls:rho"); - memory->grow(ds,num_mem,3*nlocal_max,"min/spin/oso/lbfgs_ls:ds"); - memory->grow(dy,num_mem,3*nlocal_max,"min/spin/oso/lbfgs_ls:dy"); - if (use_line_search) - memory->grow(sp_copy,nlocal_max,3,"min/spin/oso/lbfgs_ls:sp_copy"); - } - - for (int iter = 0; iter < maxiter; iter++) { - - if (timer->check_timeout(niter)) - return TIMEOUT; - - ntimestep = ++update->ntimestep; - niter++; - - // optimize timestep accross processes / replicas - // need a force calculation for timestep optimization - - if (local_iter == 0) - ecurrent = energy_force(0); - - if (use_line_search) { - - // here we need to do line search - calc_search_direction(); - der_e_cur = 0.0; - for (int i = 0; i < 3 * nlocal; i++) { - der_e_cur += g_cur[i] * p_s[i]; - } - MPI_Allreduce(&der_e_cur,&der_e_cur_tmp,1,MPI_DOUBLE,MPI_SUM,world); - der_e_cur = der_e_cur_tmp; - if (update->multireplica == 1) { - MPI_Allreduce(&der_e_cur_tmp,&der_e_cur,1,MPI_DOUBLE,MPI_SUM,universe->uworld); - } - for (int i = 0; i < nlocal; i++) { - for (int j = 0; j < 3; j++) sp_copy[i][j] = sp[i][j]; - } - eprevious = ecurrent; - der_e_pr = der_e_cur; - calc_and_make_step(0.0, 1.0, 0); - } - else{ - - // here we don't do line search - // but use cutoff rotation angle - // if gneb calc., nreplica > 1 - // then calculate gradients and advance spins - // of intermediate replicas only - - if (nreplica > 1) { - if(ireplica != 0 && ireplica != nreplica-1) - calc_gradient(); - calc_search_direction(); - advance_spins(); - } else{ - calc_gradient(); - calc_search_direction(); - advance_spins(); - } - neval++; - eprevious = ecurrent; - ecurrent = energy_force(0); - neval++; - } - - //// energy tolerance criterion - //// only check after DELAYSTEP elapsed since velocties reset to 0 - //// sync across replicas if running multi-replica minimization - - if (update->etol > 0.0 && ntimestep-last_negative > DELAYSTEP) { - if (update->multireplica == 0) { - if (fabs(ecurrent-eprevious) < - update->etol * 0.5*(fabs(ecurrent) + fabs(eprevious) + EPS_ENERGY)) - return ETOL; - } else { - if (fabs(ecurrent-eprevious) < - update->etol * 0.5*(fabs(ecurrent) + fabs(eprevious) + EPS_ENERGY)) - flag = 0; - else flag = 1; - MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,universe->uworld); - if (flagall == 0) return ETOL; - } - } - - // magnetic torque tolerance criterion - // sync across replicas if running multi-replica minimization - - if (update->ftol > 0.0) { - fmdotfm = fmnorm2(); - if (update->multireplica == 0) { - if (fmdotfm < update->ftol*update->ftol) return FTOL; - } else { - if (fmdotfm < update->ftol*update->ftol) flag = 0; - else flag = 1; - MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,universe->uworld); - if (flagall == 0) return FTOL; - } - } - - // output for thermo, dump, restart files - - if (output->next == ntimestep) { - timer->stamp(); - output->write(ntimestep); - timer->stamp(Timer::OUTPUT); - } - } - - return MAXITER; -} - -/* ---------------------------------------------------------------------- - calculate gradients ----------------------------------------------------------------------- */ - -void MinSpinOSO_LBFGS_LS::calc_gradient() -{ - int nlocal = atom->nlocal; - double **sp = atom->sp; - double **fm = atom->fm; - double tdampx, tdampy, tdampz; - - // loop on all spins on proc. - - for (int i = 0; i < nlocal; i++) { - - // calculate gradients - - g_cur[3 * i + 0] = (fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); - g_cur[3 * i + 1] = -(fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); - g_cur[3 * i + 2] = (fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]); - } -} - -/* ---------------------------------------------------------------------- - search direction: - Limited-memory BFGS. - See Jorge Nocedal and Stephen J. Wright 'Numerical - Optimization' Second Edition, 2006 (p. 177) ----------------------------------------------------------------------- */ - -void MinSpinOSO_LBFGS_LS::calc_search_direction() -{ - int nlocal = atom->nlocal; - - double dyds = 0.0; - double sq = 0.0; - double yy = 0.0; - double yr = 0.0; - double beta = 0.0; - - double dyds_global = 0.0; - double sq_global = 0.0; - double yy_global = 0.0; - double yr_global = 0.0; - double beta_global = 0.0; - - int m_index = local_iter % num_mem; // memory index - int c_ind = 0; - double *q; - double *alpha; - - double factor; - double scaling = 1.0; - - // for multiple replica do not move end points - if (nreplica > 1) { - if (ireplica == 0 || ireplica == nreplica - 1) { - factor = 0.0; - } - else factor = 1.0; - }else{ - factor = 1.0; - } - - q = (double *) calloc(3*nlocal, sizeof(double)); - alpha = (double *) calloc(num_mem, sizeof(double)); - - if (local_iter == 0){ // steepest descent direction - - //if no line search then calculate maximum rotation - if (use_line_search == 0) - scaling = maximum_rotation(g_cur); - - for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = -g_cur[i] * factor * scaling;; - g_old[i] = g_cur[i] * factor; - for (int k = 0; k < num_mem; k++){ - ds[k][i] = 0.0; - dy[k][i] = 0.0; - rho[k] = 0.0; - } - } - } else { - dyds = 0.0; - for (int i = 0; i < 3 * nlocal; i++) { - ds[m_index][i] = p_s[i]; - dy[m_index][i] = g_cur[i] - g_old[i]; - dyds += ds[m_index][i] * dy[m_index][i]; - } - MPI_Allreduce(&dyds, &dyds_global, 1, MPI_DOUBLE, MPI_SUM, world); - - if (update->multireplica == 1) { - dyds_global *= factor; - dyds = dyds_global; - MPI_Allreduce(&dyds, &dyds_global, 1,MPI_DOUBLE,MPI_SUM,universe->uworld); - } - - if (fabs(dyds_global) > 1.0e-60) rho[m_index] = 1.0 / dyds_global; - else rho[m_index] = 1.0e60; - - if (rho[m_index] < 0.0){ - local_iter = 0; - for (int k = 0; k < num_mem; k++){ - for (int i = 0; i < nlocal; i ++){ - ds[k][i] = 0.0; - dy[k][i] = 0.0; - } - } - return calc_search_direction(); - } - - // set the q vector - - for (int i = 0; i < 3 * nlocal; i++) { - q[i] = g_cur[i]; - } - - // loop over last m indecies - for(int k = num_mem - 1; k > -1; k--) { - // this loop should run from the newest memory to the oldest one. - - c_ind = (k + m_index + 1) % num_mem; - - // dot product between dg and q - - sq = 0.0; - for (int i = 0; i < 3 * nlocal; i++) { - sq += ds[c_ind][i] * q[i]; - } - MPI_Allreduce(&sq,&sq_global,1,MPI_DOUBLE,MPI_SUM,world); - if (update->multireplica == 1) { - sq_global *= factor; - sq = sq_global; - MPI_Allreduce(&sq,&sq_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); - } - - // update alpha - - alpha[c_ind] = rho[c_ind] * sq_global; - - // update q - - for (int i = 0; i < 3 * nlocal; i++) { - q[i] -= alpha[c_ind] * dy[c_ind][i]; - } - } - - // dot product between dg with itself - yy = 0.0; - for (int i = 0; i < 3 * nlocal; i++) { - yy += dy[m_index][i] * dy[m_index][i]; - } - MPI_Allreduce(&yy,&yy_global,1,MPI_DOUBLE,MPI_SUM,world); - if (update->multireplica == 1) { - yy_global *= factor; - yy = yy_global; - MPI_Allreduce(&yy,&yy_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); - } - - // calculate now search direction - - double devis = rho[m_index] * yy_global; - - if (fabs(devis) > 1.0e-60) { - for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = factor * q[i] / devis; - } - }else{ - for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = factor * q[i] * 1.0e60; - } - } - - for (int k = 0; k < num_mem; k++){ - // this loop should run from the oldest memory to the newest one. - - if (local_iter < num_mem) c_ind = k; - else c_ind = (k + m_index + 1) % num_mem; - - // dot product between p and da - yr = 0.0; - for (int i = 0; i < 3 * nlocal; i++) { - yr += dy[c_ind][i] * p_s[i]; - } - - MPI_Allreduce(&yr,&yr_global,1,MPI_DOUBLE,MPI_SUM,world); - if (update->multireplica == 1) { - yr_global *= factor; - yr = yr_global; - MPI_Allreduce(&yr,&yr_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); - } - - beta = rho[c_ind] * yr_global; - for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] += ds[c_ind][i] * (alpha[c_ind] - beta); - } - } - if (use_line_search == 0) - scaling = maximum_rotation(p_s); - for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = - factor * p_s[i] * scaling; - g_old[i] = g_cur[i] * factor; - } - } - - local_iter++; - free(q); - free(alpha); - -} - -/* ---------------------------------------------------------------------- - rotation of spins along the search direction ----------------------------------------------------------------------- */ - -void MinSpinOSO_LBFGS_LS::advance_spins() -{ - int nlocal = atom->nlocal; - double **sp = atom->sp; - double **fm = atom->fm; - double tdampx, tdampy, tdampz; - double rot_mat[9]; // exponential of matrix made of search direction - double s_new[3]; - - // loop on all spins on proc. - - for (int i = 0; i < nlocal; i++) { - rodrigues_rotation(p_s + 3 * i, rot_mat); - - // rotate spins - - vm3(rot_mat, sp[i], s_new); - for (int j = 0; j < 3; j++) sp[i][j] = s_new[j]; - } -} - -/* ---------------------------------------------------------------------- - compute and return ||mag. torque||_2^2 / N -------------------------------------------------------------------------- */ - -double MinSpinOSO_LBFGS_LS::fmnorm2() { - double norm2, norm2_global; - int nlocal = atom->nlocal; - int ntotal = 0; - - norm2 = 0.0; - for (int i = 0; i < 3 * nlocal; i++) norm2 += g_cur[i] * g_cur[i]; - MPI_Allreduce(&norm2, &norm2_global, 1, MPI_DOUBLE, MPI_SUM, world); - MPI_Allreduce(&nlocal, &ntotal, 1, MPI_INT, MPI_SUM, world); - double ans = norm2_global / (double) ntotal; - MPI_Bcast(&ans, 1, MPI_DOUBLE, 0, world); - return ans; -} - -/* ---------------------------------------------------------------------- - calculate 3x3 matrix exponential using Rodrigues' formula - (R. Murray, Z. Li, and S. Shankar Sastry, - A Mathematical Introduction to - Robotic Manipulation (1994), p. 28 and 30). - - upp_tr - vector x, y, z so that one calculate - U = exp(A) with A= [[0, x, y], - [-x, 0, z], - [-y, -z, 0]] -------------------------------------------------------------------------- */ - -void MinSpinOSO_LBFGS_LS::rodrigues_rotation(const double *upp_tr, double *out) -{ - double theta,A,B,D,x,y,z; - double s1,s2,s3,a1,a2,a3; - - if (fabs(upp_tr[0]) < 1.0e-40 && - fabs(upp_tr[1]) < 1.0e-40 && - fabs(upp_tr[2]) < 1.0e-40){ - - // if upp_tr is zero, return unity matrix - for(int k = 0; k < 3; k++){ - for(int m = 0; m < 3; m++){ - if (m == k) out[3 * k + m] = 1.0; - else out[3 * k + m] = 0.0; - } - } - return; - } - - theta = sqrt(upp_tr[0] * upp_tr[0] + - upp_tr[1] * upp_tr[1] + - upp_tr[2] * upp_tr[2]); - - A = cos(theta); - B = sin(theta); - D = 1 - A; - x = upp_tr[0]/theta; - y = upp_tr[1]/theta; - z = upp_tr[2]/theta; - - // diagonal elements of U - - out[0] = A + z * z * D; - out[4] = A + y * y * D; - out[8] = A + x * x * D; - - // off diagonal of U - - s1 = -y * z *D; - s2 = x * z * D; - s3 = -x * y * D; - - a1 = x * B; - a2 = y * B; - a3 = z * B; - - out[1] = s1 + a1; - out[3] = s1 - a1; - out[2] = s2 + a2; - out[6] = s2 - a2; - out[5] = s3 + a3; - out[7] = s3 - a3; - -} - -/* ---------------------------------------------------------------------- - out = vector^T x m, - m -- 3x3 matrix , v -- 3-d vector -------------------------------------------------------------------------- */ - -void MinSpinOSO_LBFGS_LS::vm3(const double *m, const double *v, double *out) -{ - for(int i = 0; i < 3; i++){ - out[i] *= 0.0; - for(int j = 0; j < 3; j++) - out[i] += *(m + 3 * j + i) * v[j]; - } -} - - -void MinSpinOSO_LBFGS_LS::make_step(double c, double *energy_and_der) -{ - double p_scaled[3]; - int nlocal = atom->nlocal; - double rot_mat[9]; // exponential of matrix made of search direction - double s_new[3]; - double **sp = atom->sp; - double der_e_cur_tmp = 0.0;; - - for (int i = 0; i < nlocal; i++) { - - // scale the search direction - - for (int j = 0; j < 3; j++) p_scaled[j] = c * p_s[3 * i + j]; - - // calculate rotation matrix - - rodrigues_rotation(p_scaled, rot_mat); - - // rotate spins - - vm3(rot_mat, sp[i], s_new); - for (int j = 0; j < 3; j++) sp[i][j] = s_new[j]; - } - - ecurrent = energy_force(0); - calc_gradient(); - neval++; - der_e_cur = 0.0; - for (int i = 0; i < 3 * nlocal; i++) { - der_e_cur += g_cur[i] * p_s[i]; - } - MPI_Allreduce(&der_e_cur,&der_e_cur_tmp, 1, MPI_DOUBLE, MPI_SUM, world); - der_e_cur = der_e_cur_tmp; - if (update->multireplica == 1) { - MPI_Allreduce(&der_e_cur_tmp,&der_e_cur,1,MPI_DOUBLE,MPI_SUM,universe->uworld); - } - - energy_and_der[0] = ecurrent; - energy_and_der[1] = der_e_cur; -} - -/* ---------------------------------------------------------------------- - Calculate step length which satisfies approximate Wolfe conditions - using the cubic interpolation -------------------------------------------------------------------------- */ - -int MinSpinOSO_LBFGS_LS::calc_and_make_step(double a, double b, int index) -{ - double e_and_d[2] = {0.0,0.0}; - double alpha,c1,c2,c3; - double **sp = atom->sp; - int nlocal = atom->nlocal; - - make_step(b,e_and_d); - ecurrent = e_and_d[0]; - der_e_cur = e_and_d[1]; - index++; - - if (awc(der_e_pr,eprevious,e_and_d[1],e_and_d[0]) || index == 5){ - MPI_Bcast(&b,1,MPI_DOUBLE,0,world); - for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = b * p_s[i]; - } - return 1; - } - else{ - double r,f0,f1,df0,df1; - r = b - a; - f0 = eprevious; - f1 = ecurrent; - df0 = der_e_pr; - df1 = der_e_cur; - - c1 = -2.0*(f1-f0)/(r*r*r)+(df1+df0)/(r*r); - c2 = 3.0*(f1-f0)/(r*r)-(df1+2.0*df0)/(r); - c3 = df0; - - // f(x) = c1 x^3 + c2 x^2 + c3 x^1 + c4 - // has minimum at alpha below. We do not check boundaries. - - alpha = (-c2 + sqrt(c2*c2 - 3.0*c1*c3))/(3.0*c1); - MPI_Bcast(&alpha,1,MPI_DOUBLE,0,world); - - if (alpha < 0.0) alpha = r/2.0; - - for (int i = 0; i < nlocal; i++) { - for (int j = 0; j < 3; j++) sp[i][j] = sp_copy[i][j]; - } - calc_and_make_step(0.0, alpha, index); - } - - return 0; -} - -/* ---------------------------------------------------------------------- - Approximate Wolfe conditions: - William W. Hager and Hongchao Zhang - SIAM J. optim., 16(1), 170-192. (23 pages) -------------------------------------------------------------------------- */ - -int MinSpinOSO_LBFGS_LS::awc(double der_phi_0, double phi_0, double der_phi_j, double phi_j){ - - double eps = 1.0e-6; - double delta = 0.1; - double sigma = 0.9; - - if ((phi_j<=phi_0+eps*fabs(phi_0)) && ((2.0*delta-1.0) * der_phi_0>=der_phi_j>=sigma*der_phi_0)) - return 1; - else - return 0; -} - -double MinSpinOSO_LBFGS_LS::maximum_rotation(double *p) -{ - double norm2,norm2_global,scaling,alpha; - int nlocal = atom->nlocal; - int ntotal = 0; - - norm2 = 0.0; - for (int i = 0; i < 3 * nlocal; i++) norm2 += p[i] * p[i]; - - MPI_Allreduce(&norm2,&norm2_global,1,MPI_DOUBLE,MPI_SUM,world); - if (update->multireplica == 1) { - norm2 = norm2_global; - MPI_Allreduce(&norm2,&norm2_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); - } - MPI_Allreduce(&nlocal,&ntotal,1,MPI_INT,MPI_SUM,world); - if (update->multireplica == 1) { - nlocal = ntotal; - MPI_Allreduce(&nlocal,&ntotal,1,MPI_INT,MPI_SUM,universe->uworld); - } - - scaling = (maxepsrot * sqrt((double) ntotal / norm2_global)); - - if (scaling < 1.0) alpha = scaling; - else alpha = 1.0; - - return alpha; -} \ No newline at end of file diff --git a/src/SPIN/min_spin_oso_lbfgs_ls.h b/src/SPIN/min_spin_oso_lbfgs_ls.h deleted file mode 100644 index a253808923..0000000000 --- a/src/SPIN/min_spin_oso_lbfgs_ls.h +++ /dev/null @@ -1,79 +0,0 @@ -/* -*- c++ -*- ---------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov - - 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 - -MinimizeStyle(spin/oso_lbfgs_ls, MinSpinOSO_LBFGS_LS) - -#else - -#ifndef LMP_MIN_SPIN_OSO_LBFGS_LS_H -#define LMP_MIN_SPIN_OSO_LBFGS_LS_H - -#include "min.h" - -namespace LAMMPS_NS { - -class MinSpinOSO_LBFGS_LS : public Min { - -public: - MinSpinOSO_LBFGS_LS(class LAMMPS *); - virtual ~MinSpinOSO_LBFGS_LS(); - void init(); - void setup_style(); - int modify_param(int, char **); - void reset_vectors(); - int iterate(int); - void advance_spins(); - double fmnorm2(); - void calc_gradient(); - void calc_search_direction(); - double maximum_rotation(double *); -private: - int ireplica,nreplica; // for neb - - int nlocal_max; // max value of nlocal (for size of lists) - - double *spvec; // variables for atomic dof, as 1d vector - double *fmvec; // variables for atomic dof, as 1d vector - - double *g_cur; // current gradient vector - double *g_old; // gradient vector at previous step - double *p_s; // search direction vector - double **ds; // change in rotation matrix between two iterations, da - double **dy; // change in gradients between two iterations, dg - double *rho; // estimation of curvature - double **sp_copy; // copy of the spins - - int num_mem; // number of stored steps - int local_iter; // for neb - - double der_e_cur; // current derivative along search dir. - double der_e_pr; // previous derivative along search dir. - - int use_line_search; // use line search or not. - double maxepsrot; - - void vm3(const double *, const double *, double *); - void rodrigues_rotation(const double *, double *); - int calc_and_make_step(double, double, int); - int awc(double, double, double, double); - void make_step(double, double *); - - bigint last_negative; -}; - -} - -#endif -#endif From aa5263f729d6cfb996e7b0033c6737b1a6e5d8c9 Mon Sep 17 00:00:00 2001 From: alxvov Date: Fri, 19 Jul 2019 13:46:26 +0000 Subject: [PATCH 43/74] restructure a bit --- src/SPIN/min_spin_oso_lbfgs.h | 47 +++++++++++++++-------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/src/SPIN/min_spin_oso_lbfgs.h b/src/SPIN/min_spin_oso_lbfgs.h index 91c900f244..48d1b47837 100644 --- a/src/SPIN/min_spin_oso_lbfgs.h +++ b/src/SPIN/min_spin_oso_lbfgs.h @@ -25,8 +25,7 @@ MinimizeStyle(spin/oso_lbfgs, MinSpinOSO_LBFGS) namespace LAMMPS_NS { class MinSpinOSO_LBFGS: public Min { - -public: + public: MinSpinOSO_LBFGS(class LAMMPS *); virtual ~MinSpinOSO_LBFGS(); void init(); @@ -34,42 +33,36 @@ public: int modify_param(int, char **); void reset_vectors(); int iterate(int); + private: + int ireplica,nreplica; // for neb + double *spvec; // variables for atomic dof, as 1d vector + double *fmvec; // variables for atomic dof, as 1d vector + double *g_cur; // current gradient vector + double *g_old; // gradient vector at previous step + double *p_s; // search direction vector + double **sp_copy; // copy of the spins + int local_iter; // for neb + int nlocal_max; // max value of nlocal (for size of lists) + void advance_spins(); double fmnorm2(); void calc_gradient(); void calc_search_direction(); double maximum_rotation(double *); -private: - int ireplica,nreplica; // for neb - - int nlocal_max; // max value of nlocal (for size of lists) - - double *spvec; // variables for atomic dof, as 1d vector - double *fmvec; // variables for atomic dof, as 1d vector - - double *g_cur; // current gradient vector - double *g_old; // gradient vector at previous step - double *p_s; // search direction vector - double **ds; // change in rotation matrix between two iterations, da - double **dy; // change in gradients between two iterations, dg - double *rho; // estimation of curvature - double **sp_copy; // copy of the spins - - int num_mem; // number of stored steps - int local_iter; // for neb - - double der_e_cur; // current derivative along search dir. - double der_e_pr; // previous derivative along search dir. - - int use_line_search; // use line search or not. - double maxepsrot; - void vm3(const double *, const double *, double *); void rodrigues_rotation(const double *, double *); int calc_and_make_step(double, double, int); int awc(double, double, double, double); void make_step(double, double *); + double der_e_cur; // current derivative along search dir. + double der_e_pr; // previous derivative along search dir. + int use_line_search; // use line search or not. + double maxepsrot; + double **ds; // change in rotation matrix between two iterations, da + double **dy; // change in gradients between two iterations, dg + double *rho; // estimation of curvature + int num_mem; // number of stored steps bigint last_negative; }; From b31548df2e84ded3b50ebbbd53ae94b2cf912e35 Mon Sep 17 00:00:00 2001 From: alxvov Date: Fri, 19 Jul 2019 16:00:08 +0000 Subject: [PATCH 44/74] convergence criterion based on maximum toque at atom. Minor changes --- src/SPIN/min_spin_oso_lbfgs.cpp | 62 +++++++++++++++++++++------------ src/SPIN/min_spin_oso_lbfgs.h | 2 +- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index 7f716da63d..8d05ea63d8 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -212,25 +212,25 @@ int MinSpinOSO_LBFGS::iterate(int maxiter) // optimize timestep accross processes / replicas // need a force calculation for timestep optimization - if (local_iter == 0) - ecurrent = energy_force(0); - if (use_line_search) { // here we need to do line search + if (local_iter == 0) + calc_gradient(); + calc_search_direction(); der_e_cur = 0.0; - for (int i = 0; i < 3 * nlocal; i++) { + for (int i = 0; i < 3 * nlocal; i++) der_e_cur += g_cur[i] * p_s[i]; - } MPI_Allreduce(&der_e_cur,&der_e_cur_tmp,1,MPI_DOUBLE,MPI_SUM,world); der_e_cur = der_e_cur_tmp; if (update->multireplica == 1) { MPI_Allreduce(&der_e_cur_tmp,&der_e_cur,1,MPI_DOUBLE,MPI_SUM,universe->uworld); } - for (int i = 0; i < nlocal; i++) { - for (int j = 0; j < 3; j++) sp_copy[i][j] = sp[i][j]; - } + for (int i = 0; i < nlocal; i++) + for (int j = 0; j < 3; j++) + sp_copy[i][j] = sp[i][j]; + eprevious = ecurrent; der_e_pr = der_e_cur; calc_and_make_step(0.0, 1.0, 0); @@ -253,7 +253,6 @@ int MinSpinOSO_LBFGS::iterate(int maxiter) calc_search_direction(); advance_spins(); } - neval++; eprevious = ecurrent; ecurrent = energy_force(0); neval++; @@ -282,7 +281,7 @@ int MinSpinOSO_LBFGS::iterate(int maxiter) // sync across replicas if running multi-replica minimization if (update->ftol > 0.0) { - fmdotfm = fmnorm2(); + fmdotfm = max_torque(); if (update->multireplica == 0) { if (fmdotfm < update->ftol*update->ftol) return FTOL; } else { @@ -314,8 +313,7 @@ void MinSpinOSO_LBFGS::calc_gradient() int nlocal = atom->nlocal; double **sp = atom->sp; double **fm = atom->fm; - double tdampx, tdampy, tdampz; - + // loop on all spins on proc. for (int i = 0; i < nlocal; i++) { @@ -542,21 +540,39 @@ void MinSpinOSO_LBFGS::advance_spins() } /* ---------------------------------------------------------------------- - compute and return ||mag. torque||_2^2 / N + compute and return max_i||mag. torque_i||_2 ------------------------------------------------------------------------- */ -double MinSpinOSO_LBFGS::fmnorm2() { - double norm2, norm2_global; +double MinSpinOSO_LBFGS::max_torque() +{ + double fmsq,fmaxsqone,fmaxsqloc,fmaxsqall; int nlocal = atom->nlocal; - int ntotal = 0; - norm2 = 0.0; - for (int i = 0; i < 3 * nlocal; i++) norm2 += g_cur[i] * g_cur[i]; - MPI_Allreduce(&norm2, &norm2_global, 1, MPI_DOUBLE, MPI_SUM, world); - MPI_Allreduce(&nlocal, &ntotal, 1, MPI_INT, MPI_SUM, world); - double ans = norm2_global / (double) ntotal; - MPI_Bcast(&ans, 1, MPI_DOUBLE, 0, world); - return ans; + // finding max fm on this proc. + + fmsq = fmaxsqone = fmaxsqloc = fmaxsqall = 0.0; + for (int i = 0; i < nlocal; i++) { + fmsq = 0.0; + for (int j = 0; j < 3; j++) + fmsq += g_cur[3 * i + j] * g_cur[3 * i + j]; + fmaxsqone = MAX(fmaxsqone,fmsq); + } + + // finding max fm on this replica + + fmaxsqloc = fmaxsqone; + MPI_Allreduce(&fmaxsqone,&fmaxsqloc,1,MPI_DOUBLE,MPI_MAX,world); + + // finding max fm over all replicas, if necessary + // this communicator would be invalid for multiprocess replicas + + fmaxsqall = fmaxsqloc; + if (update->multireplica == 1) { + fmaxsqall = fmaxsqloc; + MPI_Allreduce(&fmaxsqloc,&fmaxsqall,1,MPI_DOUBLE,MPI_MAX,universe->uworld); + } + + return sqrt(fmaxsqall); } /* ---------------------------------------------------------------------- diff --git a/src/SPIN/min_spin_oso_lbfgs.h b/src/SPIN/min_spin_oso_lbfgs.h index 48d1b47837..d74898aa8c 100644 --- a/src/SPIN/min_spin_oso_lbfgs.h +++ b/src/SPIN/min_spin_oso_lbfgs.h @@ -45,7 +45,6 @@ class MinSpinOSO_LBFGS: public Min { int nlocal_max; // max value of nlocal (for size of lists) void advance_spins(); - double fmnorm2(); void calc_gradient(); void calc_search_direction(); double maximum_rotation(double *); @@ -54,6 +53,7 @@ class MinSpinOSO_LBFGS: public Min { int calc_and_make_step(double, double, int); int awc(double, double, double, double); void make_step(double, double *); + double max_torque(); double der_e_cur; // current derivative along search dir. double der_e_pr; // previous derivative along search dir. int use_line_search; // use line search or not. From 3b7bb668aecc3f32d32c1eb4061a112e07536e5b Mon Sep 17 00:00:00 2001 From: alxvov Date: Fri, 19 Jul 2019 16:41:51 +0000 Subject: [PATCH 45/74] conjugate gradients with line search --- src/SPIN/min_spin_oso_cg2.cpp | 665 ++++++++++++++++++++++++++++++++++ src/SPIN/min_spin_oso_cg2.h | 68 ++++ 2 files changed, 733 insertions(+) create mode 100644 src/SPIN/min_spin_oso_cg2.cpp create mode 100644 src/SPIN/min_spin_oso_cg2.h diff --git a/src/SPIN/min_spin_oso_cg2.cpp b/src/SPIN/min_spin_oso_cg2.cpp new file mode 100644 index 0000000000..23873e24f2 --- /dev/null +++ b/src/SPIN/min_spin_oso_cg2.cpp @@ -0,0 +1,665 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + 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. +------------------------------------------------------------------------- */ + +/* ------------------------------------------------------------------------ + Contributing authors: Aleksei Ivanov (University of Iceland) + Julien Tranchida (SNL) + + Please cite the related publication: + Ivanov, A. V., Uzdin, V. M., & Jónsson, H. (2019). Fast and Robust + Algorithm for the Minimisation of the Energy of Spin Systems. arXiv + preprint arXiv:1904.02669. +------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include "min_spin_oso_cg2.h" +#include "universe.h" +#include "atom.h" +#include "citeme.h" +#include "force.h" +#include "update.h" +#include "output.h" +#include "timer.h" +#include "error.h" +#include "memory.h" +#include "modify.h" +#include "math_special.h" +#include "math_const.h" +#include "universe.h" +#include + +using namespace LAMMPS_NS; +using namespace MathConst; + +static const char cite_minstyle_spin_oso_cg2[] = + "min_style spin/oso_cg2 command:\n\n" + "@article{ivanov2019fast,\n" + "title={Fast and Robust Algorithm for the Minimisation of the Energy of " + "Spin Systems},\n" + "author={Ivanov, A. V and Uzdin, V. M. and J{\'o}nsson, H.},\n" + "journal={arXiv preprint arXiv:1904.02669},\n" + "year={2019}\n" + "}\n\n"; + +// EPS_ENERGY = minimum normalization for energy tolerance + +#define EPS_ENERGY 1.0e-8 + +#define DELAYSTEP 5 + + +/* ---------------------------------------------------------------------- */ + +MinSpinOSO_CG2::MinSpinOSO_CG2(LAMMPS *lmp) : + Min(lmp), g_old(NULL), g_cur(NULL), p_s(NULL) +{ + if (lmp->citeme) lmp->citeme->add(cite_minstyle_spin_oso_cg2); + nlocal_max = 0; + + // nreplica = number of partitions + // ireplica = which world I am in universe + + nreplica = universe->nworlds; + ireplica = universe->iworld; + use_line_search = 1; + maxepsrot = MY_2PI / (100.0); + +} + +/* ---------------------------------------------------------------------- */ + +MinSpinOSO_CG2::~MinSpinOSO_CG2() +{ + memory->destroy(g_old); + memory->destroy(g_cur); + memory->destroy(p_s); + if (use_line_search) + memory->destroy(sp_copy); +} + +/* ---------------------------------------------------------------------- */ + +void MinSpinOSO_CG2::init() +{ + local_iter = 0; + der_e_cur = 0.0; + der_e_pr = 0.0; + + Min::init(); + + last_negative = update->ntimestep; + + // allocate tables + + nlocal_max = atom->nlocal; + memory->grow(g_old,3*nlocal_max,"min/spin/oso/cg2:g_old"); + memory->grow(g_cur,3*nlocal_max,"min/spin/oso/cg2:g_cur"); + memory->grow(p_s,3*nlocal_max,"min/spin/oso/cg2:p_s"); + if (use_line_search) + memory->grow(sp_copy,nlocal_max,3,"min/spin/oso/cg2:sp_copy"); +} + +/* ---------------------------------------------------------------------- */ + +void MinSpinOSO_CG2::setup_style() +{ + double **v = atom->v; + int nlocal = atom->nlocal; + + // check if the atom/spin style is defined + + if (!atom->sp_flag) + error->all(FLERR,"min/spin_oso_cg2 requires atom/spin style"); + + for (int i = 0; i < nlocal; i++) + v[i][0] = v[i][1] = v[i][2] = 0.0; +} + +/* ---------------------------------------------------------------------- */ + +int MinSpinOSO_CG2::modify_param(int narg, char **arg) +{ + + if (strcmp(arg[0],"line_search") == 0) { + if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); + use_line_search = force->numeric(FLERR,arg[1]); + return 2; + } + if (strcmp(arg[0],"discrete_factor") == 0) { + if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); + double discrete_factor; + discrete_factor = force->numeric(FLERR,arg[1]); + maxepsrot = MY_2PI / discrete_factor; + return 2; + } + return 0; +} + +/* ---------------------------------------------------------------------- + set current vector lengths and pointers + called after atoms have migrated +------------------------------------------------------------------------- */ + +void MinSpinOSO_CG2::reset_vectors() +{ + // atomic dof + + // size sp is 4N vector + nvec = 4 * atom->nlocal; + if (nvec) spvec = atom->sp[0]; + + nvec = 3 * atom->nlocal; + if (nvec) fmvec = atom->fm[0]; + + if (nvec) xvec = atom->x[0]; + if (nvec) fvec = atom->f[0]; +} + +/* ---------------------------------------------------------------------- + minimization via damped spin dynamics +------------------------------------------------------------------------- */ + +int MinSpinOSO_CG2::iterate(int maxiter) +{ + int nlocal = atom->nlocal; + bigint ntimestep; + double fmdotfm; + int flag, flagall; + double **sp = atom->sp; + double der_e_cur_tmp = 0.0; + + if (nlocal_max < nlocal) { + nlocal_max = nlocal; + local_iter = 0; + nlocal_max = nlocal; + memory->grow(g_old,3*nlocal_max,"min/spin/oso/cg2:g_old"); + memory->grow(g_cur,3*nlocal_max,"min/spin/oso/cg2:g_cur"); + memory->grow(p_s,3*nlocal_max,"min/spin/oso/cg2:p_s"); + if (use_line_search) + memory->grow(sp_copy,nlocal_max,3,"min/spin/oso/cg2:sp_copy"); + } + + for (int iter = 0; iter < maxiter; iter++) { + + if (timer->check_timeout(niter)) + return TIMEOUT; + + ntimestep = ++update->ntimestep; + niter++; + + // optimize timestep accross processes / replicas + // need a force calculation for timestep optimization + + if (use_line_search) { + + // here we need to do line search + if (local_iter == 0) + calc_gradient(); + + calc_search_direction(); + der_e_cur = 0.0; + for (int i = 0; i < 3 * nlocal; i++) + der_e_cur += g_cur[i] * p_s[i]; + MPI_Allreduce(&der_e_cur,&der_e_cur_tmp,1,MPI_DOUBLE,MPI_SUM,world); + der_e_cur = der_e_cur_tmp; + if (update->multireplica == 1) { + MPI_Allreduce(&der_e_cur_tmp,&der_e_cur,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + } + for (int i = 0; i < nlocal; i++) + for (int j = 0; j < 3; j++) + sp_copy[i][j] = sp[i][j]; + + eprevious = ecurrent; + der_e_pr = der_e_cur; + calc_and_make_step(0.0, 1.0, 0); + } + else{ + + // here we don't do line search + // but use cutoff rotation angle + // if gneb calc., nreplica > 1 + // then calculate gradients and advance spins + // of intermediate replicas only + + if (nreplica > 1) { + if(ireplica != 0 && ireplica != nreplica-1) + calc_gradient(); + calc_search_direction(); + advance_spins(); + } else{ + calc_gradient(); + calc_search_direction(); + advance_spins(); + } + eprevious = ecurrent; + ecurrent = energy_force(0); + neval++; + } + + //// energy tolerance criterion + //// only check after DELAYSTEP elapsed since velocties reset to 0 + //// sync across replicas if running multi-replica minimization + + if (update->etol > 0.0 && ntimestep-last_negative > DELAYSTEP) { + if (update->multireplica == 0) { + if (fabs(ecurrent-eprevious) < + update->etol * 0.5*(fabs(ecurrent) + fabs(eprevious) + EPS_ENERGY)) + return ETOL; + } else { + if (fabs(ecurrent-eprevious) < + update->etol * 0.5*(fabs(ecurrent) + fabs(eprevious) + EPS_ENERGY)) + flag = 0; + else flag = 1; + MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,universe->uworld); + if (flagall == 0) return ETOL; + } + } + + // magnetic torque tolerance criterion + // sync across replicas if running multi-replica minimization + + if (update->ftol > 0.0) { + fmdotfm = max_torque(); + if (update->multireplica == 0) { + if (fmdotfm < update->ftol*update->ftol) return FTOL; + } else { + if (fmdotfm < update->ftol*update->ftol) flag = 0; + else flag = 1; + MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,universe->uworld); + if (flagall == 0) return FTOL; + } + } + + // output for thermo, dump, restart files + + if (output->next == ntimestep) { + timer->stamp(); + output->write(ntimestep); + timer->stamp(Timer::OUTPUT); + } + } + + return MAXITER; +} + +/* ---------------------------------------------------------------------- + calculate gradients +---------------------------------------------------------------------- */ + +void MinSpinOSO_CG2::calc_gradient() +{ + int nlocal = atom->nlocal; + double **sp = atom->sp; + double **fm = atom->fm; + double hbar = force->hplanck/MY_2PI; + + // loop on all spins on proc. + + for (int i = 0; i < nlocal; i++) { + + // calculate gradients + + g_cur[3 * i + 0] = (fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]) * hbar; + g_cur[3 * i + 1] = -(fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]) * hbar; + g_cur[3 * i + 2] = (fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]) * hbar; + } +} + + +/* ---------------------------------------------------------------------- + search direction: + The Fletcher-Reeves conj. grad. method + See Jorge Nocedal and Stephen J. Wright 'Numerical + Optimization' Second Edition, 2006 (p. 121) +---------------------------------------------------------------------- */ + +void MinSpinOSO_CG2::calc_search_direction() +{ + int nlocal = atom->nlocal; + double g2old = 0.0; + double g2 = 0.0; + double beta = 0.0; + + double g2_global = 0.0; + double g2old_global = 0.0; + double scaling = 1.0; + + if (use_line_search == 0) + scaling = maximum_rotation(g_cur); + + if (local_iter == 0 || local_iter % 5 == 0){ // steepest descent direction + for (int i = 0; i < 3 * nlocal; i++) { + p_s[i] = -g_cur[i] * scaling; + g_old[i] = g_cur[i]; + } + } else { // conjugate direction + for (int i = 0; i < 3 * nlocal; i++) { + g2old += g_old[i] * g_old[i]; + g2 += g_cur[i] * g_cur[i]; + } + + // now we need to collect/broadcast beta on this replica + // different replica can have different beta for now. + // need to check what is beta for GNEB + + MPI_Allreduce(&g2, &g2_global, 1, MPI_DOUBLE, MPI_SUM, world); + MPI_Allreduce(&g2old, &g2old_global, 1, MPI_DOUBLE, MPI_SUM, world); + + // Sum over all replicas. Good for GNEB. + if (update->multireplica == 1) { + g2 = g2_global; + g2old = g2old_global; + MPI_Allreduce(&g2,&g2_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + MPI_Allreduce(&g2old,&g2old_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + } + + if (fabs(g2_global) < 1.0e-60) beta = 0.0; + else beta = g2_global / g2old_global; + // calculate conjugate direction + for (int i = 0; i < 3 * nlocal; i++) { + p_s[i] = (beta * p_s[i] - g_cur[i])*scaling; + g_old[i] = g_cur[i]; + } + } + + local_iter++; +} + +/* ---------------------------------------------------------------------- + rotation of spins along the search direction +---------------------------------------------------------------------- */ + +void MinSpinOSO_CG2::advance_spins() +{ + int nlocal = atom->nlocal; + double **sp = atom->sp; + double **fm = atom->fm; + double tdampx, tdampy, tdampz; + double rot_mat[9]; // exponential of matrix made of search direction + double s_new[3]; + + // loop on all spins on proc. + + for (int i = 0; i < nlocal; i++) { + rodrigues_rotation(p_s + 3 * i, rot_mat); + + // rotate spins + + vm3(rot_mat, sp[i], s_new); + for (int j = 0; j < 3; j++) sp[i][j] = s_new[j]; + } +} + +/* ---------------------------------------------------------------------- + compute and return max_i||mag. torque_i||_2 +------------------------------------------------------------------------- */ + +double MinSpinOSO_CG2::max_torque() +{ + double fmsq,fmaxsqone,fmaxsqloc,fmaxsqall; + int nlocal = atom->nlocal; + + // finding max fm on this proc. + + fmsq = fmaxsqone = fmaxsqloc = fmaxsqall = 0.0; + for (int i = 0; i < nlocal; i++) { + fmsq = 0.0; + for (int j = 0; j < 3; j++) + fmsq += g_cur[3 * i + j] * g_cur[3 * i + j]; + fmaxsqone = MAX(fmaxsqone,fmsq); + } + + // finding max fm on this replica + + fmaxsqloc = fmaxsqone; + MPI_Allreduce(&fmaxsqone,&fmaxsqloc,1,MPI_DOUBLE,MPI_MAX,world); + + // finding max fm over all replicas, if necessary + // this communicator would be invalid for multiprocess replicas + + fmaxsqall = fmaxsqloc; + if (update->multireplica == 1) { + fmaxsqall = fmaxsqloc; + MPI_Allreduce(&fmaxsqloc,&fmaxsqall,1,MPI_DOUBLE,MPI_MAX,universe->uworld); + } + + return sqrt(fmaxsqall); +} + +/* ---------------------------------------------------------------------- + calculate 3x3 matrix exponential using Rodrigues' formula + (R. Murray, Z. Li, and S. Shankar Sastry, + A Mathematical Introduction to + Robotic Manipulation (1994), p. 28 and 30). + + upp_tr - vector x, y, z so that one calculate + U = exp(A) with A= [[0, x, y], + [-x, 0, z], + [-y, -z, 0]] +------------------------------------------------------------------------- */ + +void MinSpinOSO_CG2::rodrigues_rotation(const double *upp_tr, double *out) +{ + double theta,A,B,D,x,y,z; + double s1,s2,s3,a1,a2,a3; + + if (fabs(upp_tr[0]) < 1.0e-40 && + fabs(upp_tr[1]) < 1.0e-40 && + fabs(upp_tr[2]) < 1.0e-40){ + + // if upp_tr is zero, return unity matrix + for(int k = 0; k < 3; k++){ + for(int m = 0; m < 3; m++){ + if (m == k) out[3 * k + m] = 1.0; + else out[3 * k + m] = 0.0; + } + } + return; + } + + theta = sqrt(upp_tr[0] * upp_tr[0] + + upp_tr[1] * upp_tr[1] + + upp_tr[2] * upp_tr[2]); + + A = cos(theta); + B = sin(theta); + D = 1 - A; + x = upp_tr[0]/theta; + y = upp_tr[1]/theta; + z = upp_tr[2]/theta; + + // diagonal elements of U + + out[0] = A + z * z * D; + out[4] = A + y * y * D; + out[8] = A + x * x * D; + + // off diagonal of U + + s1 = -y * z *D; + s2 = x * z * D; + s3 = -x * y * D; + + a1 = x * B; + a2 = y * B; + a3 = z * B; + + out[1] = s1 + a1; + out[3] = s1 - a1; + out[2] = s2 + a2; + out[6] = s2 - a2; + out[5] = s3 + a3; + out[7] = s3 - a3; + +} + +/* ---------------------------------------------------------------------- + out = vector^T x m, + m -- 3x3 matrix , v -- 3-d vector +------------------------------------------------------------------------- */ + +void MinSpinOSO_CG2::vm3(const double *m, const double *v, double *out) +{ + for(int i = 0; i < 3; i++){ + out[i] *= 0.0; + for(int j = 0; j < 3; j++) + out[i] += *(m + 3 * j + i) * v[j]; + } +} + + +void MinSpinOSO_CG2::make_step(double c, double *energy_and_der) +{ + double p_scaled[3]; + int nlocal = atom->nlocal; + double rot_mat[9]; // exponential of matrix made of search direction + double s_new[3]; + double **sp = atom->sp; + double der_e_cur_tmp = 0.0;; + + for (int i = 0; i < nlocal; i++) { + + // scale the search direction + + for (int j = 0; j < 3; j++) p_scaled[j] = c * p_s[3 * i + j]; + + // calculate rotation matrix + + rodrigues_rotation(p_scaled, rot_mat); + + // rotate spins + + vm3(rot_mat, sp[i], s_new); + for (int j = 0; j < 3; j++) sp[i][j] = s_new[j]; + } + + ecurrent = energy_force(0); + calc_gradient(); + neval++; + der_e_cur = 0.0; + for (int i = 0; i < 3 * nlocal; i++) { + der_e_cur += g_cur[i] * p_s[i]; + } + MPI_Allreduce(&der_e_cur,&der_e_cur_tmp,1,MPI_DOUBLE,MPI_SUM,world); + der_e_cur = der_e_cur_tmp; + if (update->multireplica == 1) { + MPI_Allreduce(&der_e_cur_tmp,&der_e_cur,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + } + + energy_and_der[0] = ecurrent; + energy_and_der[1] = der_e_cur; +} + +/* ---------------------------------------------------------------------- + Calculate step length which satisfies approximate Wolfe conditions + using the cubic interpolation +------------------------------------------------------------------------- */ + +int MinSpinOSO_CG2::calc_and_make_step(double a, double b, int index) +{ + double e_and_d[2] = {0.0,0.0}; + double alpha,c1,c2,c3; + double **sp = atom->sp; + int nlocal = atom->nlocal; + + make_step(b,e_and_d); + ecurrent = e_and_d[0]; + der_e_cur = e_and_d[1]; + index++; + + if (awc(der_e_pr,eprevious,e_and_d[1],e_and_d[0]) || index == 10){ + MPI_Bcast(&b,1,MPI_DOUBLE,0,world); + for (int i = 0; i < 3 * nlocal; i++) { + p_s[i] = b * p_s[i]; + } + return 1; + } + else{ + double r,f0,f1,df0,df1; + r = b - a; + f0 = eprevious; + f1 = ecurrent; + df0 = der_e_pr; + df1 = der_e_cur; + + c1 = -2.0*(f1-f0)/(r*r*r)+(df1+df0)/(r*r); + c2 = 3.0*(f1-f0)/(r*r)-(df1+2.0*df0)/(r); + c3 = df0; + + // f(x) = c1 x^3 + c2 x^2 + c3 x^1 + c4 + // has minimum at alpha below. We do not check boundaries. + + alpha = (-c2 + sqrt(c2*c2 - 3.0*c1*c3))/(3.0*c1); + MPI_Bcast(&alpha,1,MPI_DOUBLE,0,world); + + if (alpha < 0.0) alpha = r/2.0; + + std::cout << alpha << "\n"; + + for (int i = 0; i < nlocal; i++) { + for (int j = 0; j < 3; j++) sp[i][j] = sp_copy[i][j]; + } + calc_and_make_step(0.0, alpha, index); + } + + return 0; +} + +/* ---------------------------------------------------------------------- + Approximate Wolfe conditions: + William W. Hager and Hongchao Zhang + SIAM J. optim., 16(1), 170-192. (23 pages) +------------------------------------------------------------------------- */ + +int MinSpinOSO_CG2::awc(double der_phi_0, double phi_0, double der_phi_j, double phi_j){ + + double eps = 1.0e-6; + double delta = 0.1; + double sigma = 0.9; + + if ((phi_j<=phi_0+eps*fabs(phi_0)) && ((2.0*delta-1.0) * der_phi_0>=der_phi_j>=sigma*der_phi_0)) + return 1; + else + return 0; +} + +double MinSpinOSO_CG2::maximum_rotation(double *p) +{ + double norm2,norm2_global,scaling,alpha; + int nlocal = atom->nlocal; + int ntotal = 0; + + norm2 = 0.0; + for (int i = 0; i < 3 * nlocal; i++) norm2 += p[i] * p[i]; + + MPI_Allreduce(&norm2,&norm2_global,1,MPI_DOUBLE,MPI_SUM,world); + if (update->multireplica == 1) { + norm2 = norm2_global; + MPI_Allreduce(&norm2,&norm2_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + } + MPI_Allreduce(&nlocal,&ntotal,1,MPI_INT,MPI_SUM,world); + if (update->multireplica == 1) { + nlocal = ntotal; + MPI_Allreduce(&nlocal,&ntotal,1,MPI_INT,MPI_SUM,universe->uworld); + } + + scaling = (maxepsrot * sqrt((double) ntotal / norm2_global)); + + if (scaling < 1.0) alpha = scaling; + else alpha = 1.0; + + return alpha; +} \ No newline at end of file diff --git a/src/SPIN/min_spin_oso_cg2.h b/src/SPIN/min_spin_oso_cg2.h new file mode 100644 index 0000000000..c96e82ca8e --- /dev/null +++ b/src/SPIN/min_spin_oso_cg2.h @@ -0,0 +1,68 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + 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 + +MinimizeStyle(spin/oso_cg2, MinSpinOSO_CG2) + +#else + +#ifndef LMP_MIN_SPIN_OSO_CG2_H +#define LMP_MIN_SPIN_OSO_CG2_H + +#include "min.h" + +namespace LAMMPS_NS { + +class MinSpinOSO_CG2: public Min { + public: + MinSpinOSO_CG2(class LAMMPS *); + virtual ~MinSpinOSO_CG2(); + void init(); + void setup_style(); + int modify_param(int, char **); + void reset_vectors(); + int iterate(int); + private: + int ireplica,nreplica; // for neb + double *spvec; // variables for atomic dof, as 1d vector + double *fmvec; // variables for atomic dof, as 1d vector + double *g_cur; // current gradient vector + double *g_old; // gradient vector at previous step + double *p_s; // search direction vector + double **sp_copy; // copy of the spins + int local_iter; // for neb + int nlocal_max; // max value of nlocal (for size of lists) + + void advance_spins(); + void calc_gradient(); + void calc_search_direction(); + double maximum_rotation(double *); + void vm3(const double *, const double *, double *); + void rodrigues_rotation(const double *, double *); + int calc_and_make_step(double, double, int); + int awc(double, double, double, double); + void make_step(double, double *); + double max_torque(); + double der_e_cur; // current derivative along search dir. + double der_e_pr; // previous derivative along search dir. + int use_line_search; // use line search or not. + double maxepsrot; + + bigint last_negative; +}; + +} + +#endif +#endif From 473e64c6b6d2c2ac86db5672075febd12af4385c Mon Sep 17 00:00:00 2001 From: alxvov Date: Mon, 22 Jul 2019 13:49:41 +0000 Subject: [PATCH 46/74] actual gradient of energy, not scaled by hbar. convergence criterion is in eV --- src/SPIN/min_spin_oso_lbfgs.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index 8d05ea63d8..d7e7302e4f 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -313,16 +313,14 @@ void MinSpinOSO_LBFGS::calc_gradient() int nlocal = atom->nlocal; double **sp = atom->sp; double **fm = atom->fm; + double hbar = force->hplanck/MY_2PI; // loop on all spins on proc. for (int i = 0; i < nlocal; i++) { - - // calculate gradients - - g_cur[3 * i + 0] = (fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); - g_cur[3 * i + 1] = -(fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); - g_cur[3 * i + 2] = (fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]); + g_cur[3 * i + 0] = (fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]) * hbar; + g_cur[3 * i + 1] = -(fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]) * hbar; + g_cur[3 * i + 2] = (fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]) * hbar; } } From e4001b01791e9ac1caa54d0c5962886f566afa18 Mon Sep 17 00:00:00 2001 From: alxvov Date: Mon, 22 Jul 2019 14:38:02 +0000 Subject: [PATCH 47/74] change convergence criterion --- src/SPIN/min_spin_oso_cg.cpp | 49 +++++++++++++++++++----------------- src/SPIN/min_spin_oso_cg.h | 10 ++++---- 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index d8535b19c4..fe52ddebe1 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -66,6 +66,8 @@ MinSpinOSO_CG::MinSpinOSO_CG(LAMMPS *lmp) : { if (lmp->citeme) lmp->citeme->add(cite_minstyle_spin_oso_cg); nlocal_max = 0; + alpha_damp = 1.0; + discrete_factor = 10.0; } /* ---------------------------------------------------------------------- */ @@ -81,11 +83,9 @@ MinSpinOSO_CG::~MinSpinOSO_CG() void MinSpinOSO_CG::init() { - alpha_damp = 1.0; - discrete_factor = 10.0; + local_iter = 0; Min::init(); - dts = dt = update->dt; last_negative = update->ntimestep; @@ -216,7 +216,7 @@ int MinSpinOSO_CG::iterate(int maxiter) // sync across replicas if running multi-replica minimization if (update->ftol > 0.0) { - fmdotfm = fmnorm_sqr(); + fmdotfm = max_torque(); if (update->multireplica == 0) { if (fmdotfm < update->ftol*update->ftol) return FTOL; } else { @@ -393,38 +393,41 @@ void MinSpinOSO_CG::advance_spins() } /* ---------------------------------------------------------------------- - compute and return ||mag. torque||_2^2 + compute and return max_i||mag. torque_i||_2 ------------------------------------------------------------------------- */ -double MinSpinOSO_CG::fmnorm_sqr() +double MinSpinOSO_CG::max_torque() { + double fmsq,fmaxsqone,fmaxsqloc,fmaxsqall; int nlocal = atom->nlocal; - double tx,ty,tz; - double **sp = atom->sp; - double **fm = atom->fm; + double hbar = force->hplanck/MY_2PI; - // calc. magnetic torques + // finding max fm on this proc. - double local_norm2_sqr = 0.0; + fmsq = fmaxsqone = fmaxsqloc = fmaxsqall = 0.0; for (int i = 0; i < nlocal; i++) { - tx = (fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]); - ty = (fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); - tz = (fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); - - local_norm2_sqr += tx*tx + ty*ty + tz*tz; + fmsq = 0.0; + for (int j = 0; j < 3; j++) + fmsq += g_cur[3 * i + j] * g_cur[3 * i + j]; + fmaxsqone = MAX(fmaxsqone,fmsq); } - // no extra atom calc. for spins + // finding max fm on this replica - if (nextra_atom) - error->all(FLERR,"extra atom option not available yet"); + fmaxsqloc = fmaxsqone; + MPI_Allreduce(&fmaxsqone,&fmaxsqloc,1,MPI_DOUBLE,MPI_MAX,world); - double norm2_sqr = 0.0; - MPI_Allreduce(&local_norm2_sqr,&norm2_sqr,1,MPI_DOUBLE,MPI_SUM,world); + // finding max fm over all replicas, if necessary + // this communicator would be invalid for multiprocess replicas - return norm2_sqr; + fmaxsqall = fmaxsqloc; + if (update->multireplica == 1) { + fmaxsqall = fmaxsqloc; + MPI_Allreduce(&fmaxsqloc,&fmaxsqall,1,MPI_DOUBLE,MPI_MAX,universe->uworld); + } + + return sqrt(fmaxsqall) * hbar; } - /* ---------------------------------------------------------------------- calculate 3x3 matrix exponential using Rodrigues' formula (R. Murray, Z. Li, and S. Shankar Sastry, diff --git a/src/SPIN/min_spin_oso_cg.h b/src/SPIN/min_spin_oso_cg.h index 3a3d24f078..81bbd2c294 100644 --- a/src/SPIN/min_spin_oso_cg.h +++ b/src/SPIN/min_spin_oso_cg.h @@ -25,8 +25,7 @@ MinimizeStyle(spin/oso_cg, MinSpinOSO_CG) namespace LAMMPS_NS { class MinSpinOSO_CG : public Min { - -public: + public: MinSpinOSO_CG(class LAMMPS *); virtual ~MinSpinOSO_CG(); void init(); @@ -34,18 +33,19 @@ public: int modify_param(int, char **); void reset_vectors(); int iterate(int); + + private: double evaluate_dt(); void advance_spins(); - double fmnorm_sqr(); + double max_torque(); void calc_gradient(double); void calc_search_direction(); -private: // global and spin timesteps - int nlocal_max; // max value of nlocal (for size of lists) double dt; double dts; + int nlocal_max; // max value of nlocal (for size of lists) double alpha_damp; // damping for spin minimization double discrete_factor; // factor for spin timestep evaluation From fabe611c110b1366088369b9e8c5eb56f50aaf04 Mon Sep 17 00:00:00 2001 From: alxvov Date: Mon, 22 Jul 2019 17:26:47 +0000 Subject: [PATCH 48/74] use line search or adaptive time step --- src/SPIN/min_spin_oso_cg.cpp | 3 +- src/SPIN/min_spin_oso_cg2.cpp | 98 ++++++++++++++++++++--------------- src/SPIN/min_spin_oso_cg2.h | 4 ++ 3 files changed, 62 insertions(+), 43 deletions(-) diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index fe52ddebe1..8eb358f86a 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -151,7 +151,7 @@ void MinSpinOSO_CG::reset_vectors() } /* ---------------------------------------------------------------------- - minimization via damped spin dynamics + minimization via orthogonal spin optimisation ------------------------------------------------------------------------- */ int MinSpinOSO_CG::iterate(int maxiter) @@ -428,6 +428,7 @@ double MinSpinOSO_CG::max_torque() return sqrt(fmaxsqall) * hbar; } + /* ---------------------------------------------------------------------- calculate 3x3 matrix exponential using Rodrigues' formula (R. Murray, Z. Li, and S. Shankar Sastry, diff --git a/src/SPIN/min_spin_oso_cg2.cpp b/src/SPIN/min_spin_oso_cg2.cpp index 23873e24f2..52b98eead7 100644 --- a/src/SPIN/min_spin_oso_cg2.cpp +++ b/src/SPIN/min_spin_oso_cg2.cpp @@ -75,7 +75,7 @@ MinSpinOSO_CG2::MinSpinOSO_CG2(LAMMPS *lmp) : nreplica = universe->nworlds; ireplica = universe->iworld; use_line_search = 1; - maxepsrot = MY_2PI / (100.0); + discrete_factor = 10.0; } @@ -100,6 +100,7 @@ void MinSpinOSO_CG2::init() Min::init(); + dts = dt = update->dt; last_negative = update->ntimestep; // allocate tables @@ -140,9 +141,7 @@ int MinSpinOSO_CG2::modify_param(int narg, char **arg) } if (strcmp(arg[0],"discrete_factor") == 0) { if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); - double discrete_factor; discrete_factor = force->numeric(FLERR,arg[1]); - maxepsrot = MY_2PI / discrete_factor; return 2; } return 0; @@ -169,7 +168,7 @@ void MinSpinOSO_CG2::reset_vectors() } /* ---------------------------------------------------------------------- - minimization via damped spin dynamics + minimization via orthogonal spin optimisation ------------------------------------------------------------------------- */ int MinSpinOSO_CG2::iterate(int maxiter) @@ -305,20 +304,21 @@ void MinSpinOSO_CG2::calc_gradient() double **sp = atom->sp; double **fm = atom->fm; double hbar = force->hplanck/MY_2PI; + double factor; + + if (use_line_search) + factor = hbar; + else factor = evaluate_dt(); // loop on all spins on proc. for (int i = 0; i < nlocal; i++) { - - // calculate gradients - - g_cur[3 * i + 0] = (fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]) * hbar; - g_cur[3 * i + 1] = -(fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]) * hbar; - g_cur[3 * i + 2] = (fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]) * hbar; + g_cur[3 * i + 0] = (fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]) * factor; + g_cur[3 * i + 1] = -(fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]) * factor; + g_cur[3 * i + 2] = (fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]) * factor; } } - /* ---------------------------------------------------------------------- search direction: The Fletcher-Reeves conj. grad. method @@ -335,14 +335,10 @@ void MinSpinOSO_CG2::calc_search_direction() double g2_global = 0.0; double g2old_global = 0.0; - double scaling = 1.0; - - if (use_line_search == 0) - scaling = maximum_rotation(g_cur); if (local_iter == 0 || local_iter % 5 == 0){ // steepest descent direction for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = -g_cur[i] * scaling; + p_s[i] = -g_cur[i]; g_old[i] = g_cur[i]; } } else { // conjugate direction @@ -352,11 +348,10 @@ void MinSpinOSO_CG2::calc_search_direction() } // now we need to collect/broadcast beta on this replica - // different replica can have different beta for now. // need to check what is beta for GNEB - MPI_Allreduce(&g2, &g2_global, 1, MPI_DOUBLE, MPI_SUM, world); - MPI_Allreduce(&g2old, &g2old_global, 1, MPI_DOUBLE, MPI_SUM, world); + MPI_Allreduce(&g2,&g2_global,1,MPI_DOUBLE,MPI_SUM,world); + MPI_Allreduce(&g2old,&g2old_global,1,MPI_DOUBLE,MPI_SUM,world); // Sum over all replicas. Good for GNEB. if (update->multireplica == 1) { @@ -365,12 +360,11 @@ void MinSpinOSO_CG2::calc_search_direction() MPI_Allreduce(&g2,&g2_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); MPI_Allreduce(&g2old,&g2old_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); } - if (fabs(g2_global) < 1.0e-60) beta = 0.0; else beta = g2_global / g2old_global; // calculate conjugate direction for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = (beta * p_s[i] - g_cur[i])*scaling; + p_s[i] = (beta * p_s[i] - g_cur[i]); g_old[i] = g_cur[i]; } } @@ -411,6 +405,11 @@ double MinSpinOSO_CG2::max_torque() { double fmsq,fmaxsqone,fmaxsqloc,fmaxsqall; int nlocal = atom->nlocal; + double factor; + double hbar = force->hplanck/MY_2PI; + + if (use_line_search) factor = 1.0; + else factor = hbar; // finding max fm on this proc. @@ -436,7 +435,7 @@ double MinSpinOSO_CG2::max_torque() MPI_Allreduce(&fmaxsqloc,&fmaxsqall,1,MPI_DOUBLE,MPI_MAX,universe->uworld); } - return sqrt(fmaxsqall); + return sqrt(fmaxsqall) * factor; } /* ---------------------------------------------------------------------- @@ -607,8 +606,6 @@ int MinSpinOSO_CG2::calc_and_make_step(double a, double b, int index) if (alpha < 0.0) alpha = r/2.0; - std::cout << alpha << "\n"; - for (int i = 0; i < nlocal; i++) { for (int j = 0; j < 3; j++) sp[i][j] = sp_copy[i][j]; } @@ -636,30 +633,47 @@ int MinSpinOSO_CG2::awc(double der_phi_0, double phi_0, double der_phi_j, double return 0; } -double MinSpinOSO_CG2::maximum_rotation(double *p) +/* ---------------------------------------------------------------------- + evaluate max timestep +---------------------------------------------------------------------- */ + +double MinSpinOSO_CG2::evaluate_dt() { - double norm2,norm2_global,scaling,alpha; + double dtmax; + double fmsq; + double fmaxsqone,fmaxsqloc,fmaxsqall; int nlocal = atom->nlocal; - int ntotal = 0; + double **fm = atom->fm; - norm2 = 0.0; - for (int i = 0; i < 3 * nlocal; i++) norm2 += p[i] * p[i]; + // finding max fm on this proc. - MPI_Allreduce(&norm2,&norm2_global,1,MPI_DOUBLE,MPI_SUM,world); - if (update->multireplica == 1) { - norm2 = norm2_global; - MPI_Allreduce(&norm2,&norm2_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); - } - MPI_Allreduce(&nlocal,&ntotal,1,MPI_INT,MPI_SUM,world); - if (update->multireplica == 1) { - nlocal = ntotal; - MPI_Allreduce(&nlocal,&ntotal,1,MPI_INT,MPI_SUM,universe->uworld); + fmsq = fmaxsqone = fmaxsqloc = fmaxsqall = 0.0; + for (int i = 0; i < nlocal; i++) { + fmsq = fm[i][0]*fm[i][0]+fm[i][1]*fm[i][1]+fm[i][2]*fm[i][2]; + fmaxsqone = MAX(fmaxsqone,fmsq); } - scaling = (maxepsrot * sqrt((double) ntotal / norm2_global)); + // finding max fm on this replica - if (scaling < 1.0) alpha = scaling; - else alpha = 1.0; + fmaxsqloc = fmaxsqone; + MPI_Allreduce(&fmaxsqone,&fmaxsqloc,1,MPI_DOUBLE,MPI_MAX,world); - return alpha; + // finding max fm over all replicas, if necessary + // this communicator would be invalid for multiprocess replicas + + fmaxsqall = fmaxsqloc; + if (update->multireplica == 1) { + fmaxsqall = fmaxsqloc; + MPI_Allreduce(&fmaxsqloc,&fmaxsqall,1,MPI_DOUBLE,MPI_MAX,universe->uworld); + } + + if (fmaxsqall == 0.0) + error->all(FLERR,"Incorrect fmaxsqall calculation"); + + // define max timestep by dividing by the + // inverse of max frequency by discrete_factor + + dtmax = MY_2PI/(discrete_factor*sqrt(fmaxsqall)); + + return dtmax; } \ No newline at end of file diff --git a/src/SPIN/min_spin_oso_cg2.h b/src/SPIN/min_spin_oso_cg2.h index c96e82ca8e..83605f98ed 100644 --- a/src/SPIN/min_spin_oso_cg2.h +++ b/src/SPIN/min_spin_oso_cg2.h @@ -34,6 +34,8 @@ class MinSpinOSO_CG2: public Min { void reset_vectors(); int iterate(int); private: + double dt; // global timestep + double dts; // spin timestep int ireplica,nreplica; // for neb double *spvec; // variables for atomic dof, as 1d vector double *fmvec; // variables for atomic dof, as 1d vector @@ -43,7 +45,9 @@ class MinSpinOSO_CG2: public Min { double **sp_copy; // copy of the spins int local_iter; // for neb int nlocal_max; // max value of nlocal (for size of lists) + double discrete_factor; // factor for spin timestep evaluation + double evaluate_dt(); void advance_spins(); void calc_gradient(); void calc_search_direction(); From 31d2b23f9c8de272051beac63261278bcd6bf411 Mon Sep 17 00:00:00 2001 From: alxvov Date: Mon, 22 Jul 2019 17:53:02 +0000 Subject: [PATCH 49/74] rename cg2 -> cg --- src/SPIN/min_spin_oso_cg.cpp | 660 ++++++++++++++++++++------------- src/SPIN/min_spin_oso_cg.h | 43 +-- src/SPIN/min_spin_oso_cg2.cpp | 679 ---------------------------------- src/SPIN/min_spin_oso_cg2.h | 72 ---- 4 files changed, 435 insertions(+), 1019 deletions(-) delete mode 100644 src/SPIN/min_spin_oso_cg2.cpp delete mode 100644 src/SPIN/min_spin_oso_cg2.h diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index 8eb358f86a..c9f3a59f87 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -38,6 +38,7 @@ #include "modify.h" #include "math_special.h" #include "math_const.h" +#include "universe.h" using namespace LAMMPS_NS; using namespace MathConst; @@ -61,12 +62,18 @@ static const char cite_minstyle_spin_oso_cg[] = /* ---------------------------------------------------------------------- */ -MinSpinOSO_CG::MinSpinOSO_CG(LAMMPS *lmp) : +MinSpinOSO_CG::MinSpinOSO_CG(LAMMPS *lmp) : Min(lmp), g_old(NULL), g_cur(NULL), p_s(NULL) { if (lmp->citeme) lmp->citeme->add(cite_minstyle_spin_oso_cg); nlocal_max = 0; - alpha_damp = 1.0; + + // nreplica = number of partitions + // ireplica = which world I am in universe + + nreplica = universe->nworlds; + ireplica = universe->iworld; + use_line_search = 1; discrete_factor = 10.0; } @@ -77,24 +84,31 @@ MinSpinOSO_CG::~MinSpinOSO_CG() memory->destroy(g_old); memory->destroy(g_cur); memory->destroy(p_s); + if (use_line_search) + memory->destroy(sp_copy); } /* ---------------------------------------------------------------------- */ void MinSpinOSO_CG::init() { - local_iter = 0; + der_e_cur = 0.0; + der_e_pr = 0.0; + Min::init(); + dts = dt = update->dt; last_negative = update->ntimestep; - + // allocate tables nlocal_max = atom->nlocal; memory->grow(g_old,3*nlocal_max,"min/spin/oso/cg:g_old"); memory->grow(g_cur,3*nlocal_max,"min/spin/oso/cg:g_cur"); memory->grow(p_s,3*nlocal_max,"min/spin/oso/cg:p_s"); + if (use_line_search) + memory->grow(sp_copy,nlocal_max,3,"min/spin/oso/cg:sp_copy"); } /* ---------------------------------------------------------------------- */ @@ -117,9 +131,9 @@ void MinSpinOSO_CG::setup_style() int MinSpinOSO_CG::modify_param(int narg, char **arg) { - if (strcmp(arg[0],"alpha_damp") == 0) { + if (strcmp(arg[0],"line_search") == 0) { if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); - alpha_damp = force->numeric(FLERR,arg[1]); + use_line_search = force->numeric(FLERR,arg[1]); return 2; } if (strcmp(arg[0],"discrete_factor") == 0) { @@ -160,19 +174,22 @@ int MinSpinOSO_CG::iterate(int maxiter) bigint ntimestep; double fmdotfm; int flag, flagall; - - // grow tables if nlocal increased + double **sp = atom->sp; + double der_e_cur_tmp = 0.0; if (nlocal_max < nlocal) { + nlocal_max = nlocal; local_iter = 0; nlocal_max = nlocal; memory->grow(g_old,3*nlocal_max,"min/spin/oso/cg:g_old"); memory->grow(g_cur,3*nlocal_max,"min/spin/oso/cg:g_cur"); memory->grow(p_s,3*nlocal_max,"min/spin/oso/cg:p_s"); + if (use_line_search) + memory->grow(sp_copy,nlocal_max,3,"min/spin/oso/cg:sp_copy"); } for (int iter = 0; iter < maxiter; iter++) { - + if (timer->check_timeout(niter)) return TIMEOUT; @@ -182,16 +199,51 @@ int MinSpinOSO_CG::iterate(int maxiter) // optimize timestep accross processes / replicas // need a force calculation for timestep optimization - if (local_iter == 0) energy_force(0); - dts = evaluate_dt(); - - calc_gradient(dts); - calc_search_direction(); - advance_spins(); - - eprevious = ecurrent; - ecurrent = energy_force(0); - neval++; + if (use_line_search) { + + // here we need to do line search + if (local_iter == 0) + calc_gradient(); + + calc_search_direction(); + der_e_cur = 0.0; + for (int i = 0; i < 3 * nlocal; i++) + der_e_cur += g_cur[i] * p_s[i]; + MPI_Allreduce(&der_e_cur,&der_e_cur_tmp,1,MPI_DOUBLE,MPI_SUM,world); + der_e_cur = der_e_cur_tmp; + if (update->multireplica == 1) { + MPI_Allreduce(&der_e_cur_tmp,&der_e_cur,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + } + for (int i = 0; i < nlocal; i++) + for (int j = 0; j < 3; j++) + sp_copy[i][j] = sp[i][j]; + + eprevious = ecurrent; + der_e_pr = der_e_cur; + calc_and_make_step(0.0, 1.0, 0); + } + else{ + + // here we don't do line search + // but use cutoff rotation angle + // if gneb calc., nreplica > 1 + // then calculate gradients and advance spins + // of intermediate replicas only + + if (nreplica > 1) { + if(ireplica != 0 && ireplica != nreplica-1) + calc_gradient(); + calc_search_direction(); + advance_spins(); + } else{ + calc_gradient(); + calc_search_direction(); + advance_spins(); + } + eprevious = ecurrent; + ecurrent = energy_force(0); + neval++; + } //// energy tolerance criterion //// only check after DELAYSTEP elapsed since velocties reset to 0 @@ -239,6 +291,347 @@ int MinSpinOSO_CG::iterate(int maxiter) return MAXITER; } +/* ---------------------------------------------------------------------- + calculate gradients +---------------------------------------------------------------------- */ + +void MinSpinOSO_CG::calc_gradient() +{ + int nlocal = atom->nlocal; + double **sp = atom->sp; + double **fm = atom->fm; + double hbar = force->hplanck/MY_2PI; + double factor; + + if (use_line_search) + factor = hbar; + else factor = evaluate_dt(); + + // loop on all spins on proc. + + for (int i = 0; i < nlocal; i++) { + g_cur[3 * i + 0] = (fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]) * factor; + g_cur[3 * i + 1] = -(fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]) * factor; + g_cur[3 * i + 2] = (fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]) * factor; + } +} + +/* ---------------------------------------------------------------------- + search direction: + The Fletcher-Reeves conj. grad. method + See Jorge Nocedal and Stephen J. Wright 'Numerical + Optimization' Second Edition, 2006 (p. 121) +---------------------------------------------------------------------- */ + +void MinSpinOSO_CG::calc_search_direction() +{ + int nlocal = atom->nlocal; + double g2old = 0.0; + double g2 = 0.0; + double beta = 0.0; + + double g2_global = 0.0; + double g2old_global = 0.0; + + if (local_iter == 0 || local_iter % 5 == 0){ // steepest descent direction + for (int i = 0; i < 3 * nlocal; i++) { + p_s[i] = -g_cur[i]; + g_old[i] = g_cur[i]; + } + } else { // conjugate direction + for (int i = 0; i < 3 * nlocal; i++) { + g2old += g_old[i] * g_old[i]; + g2 += g_cur[i] * g_cur[i]; + } + + // now we need to collect/broadcast beta on this replica + // need to check what is beta for GNEB + + MPI_Allreduce(&g2,&g2_global,1,MPI_DOUBLE,MPI_SUM,world); + MPI_Allreduce(&g2old,&g2old_global,1,MPI_DOUBLE,MPI_SUM,world); + + // Sum over all replicas. Good for GNEB. + if (update->multireplica == 1) { + g2 = g2_global; + g2old = g2old_global; + MPI_Allreduce(&g2,&g2_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + MPI_Allreduce(&g2old,&g2old_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + } + if (fabs(g2_global) < 1.0e-60) beta = 0.0; + else beta = g2_global / g2old_global; + // calculate conjugate direction + for (int i = 0; i < 3 * nlocal; i++) { + p_s[i] = (beta * p_s[i] - g_cur[i]); + g_old[i] = g_cur[i]; + } + } + + local_iter++; +} + +/* ---------------------------------------------------------------------- + rotation of spins along the search direction +---------------------------------------------------------------------- */ + +void MinSpinOSO_CG::advance_spins() +{ + int nlocal = atom->nlocal; + double **sp = atom->sp; + double **fm = atom->fm; + double tdampx, tdampy, tdampz; + double rot_mat[9]; // exponential of matrix made of search direction + double s_new[3]; + + // loop on all spins on proc. + + for (int i = 0; i < nlocal; i++) { + rodrigues_rotation(p_s + 3 * i, rot_mat); + + // rotate spins + + vm3(rot_mat, sp[i], s_new); + for (int j = 0; j < 3; j++) sp[i][j] = s_new[j]; + } +} + +/* ---------------------------------------------------------------------- + compute and return max_i||mag. torque_i||_2 +------------------------------------------------------------------------- */ + +double MinSpinOSO_CG::max_torque() +{ + double fmsq,fmaxsqone,fmaxsqloc,fmaxsqall; + int nlocal = atom->nlocal; + double factor; + double hbar = force->hplanck/MY_2PI; + + if (use_line_search) factor = 1.0; + else factor = hbar; + + // finding max fm on this proc. + + fmsq = fmaxsqone = fmaxsqloc = fmaxsqall = 0.0; + for (int i = 0; i < nlocal; i++) { + fmsq = 0.0; + for (int j = 0; j < 3; j++) + fmsq += g_cur[3 * i + j] * g_cur[3 * i + j]; + fmaxsqone = MAX(fmaxsqone,fmsq); + } + + // finding max fm on this replica + + fmaxsqloc = fmaxsqone; + MPI_Allreduce(&fmaxsqone,&fmaxsqloc,1,MPI_DOUBLE,MPI_MAX,world); + + // finding max fm over all replicas, if necessary + // this communicator would be invalid for multiprocess replicas + + fmaxsqall = fmaxsqloc; + if (update->multireplica == 1) { + fmaxsqall = fmaxsqloc; + MPI_Allreduce(&fmaxsqloc,&fmaxsqall,1,MPI_DOUBLE,MPI_MAX,universe->uworld); + } + + return sqrt(fmaxsqall) * factor; +} + +/* ---------------------------------------------------------------------- + calculate 3x3 matrix exponential using Rodrigues' formula + (R. Murray, Z. Li, and S. Shankar Sastry, + A Mathematical Introduction to + Robotic Manipulation (1994), p. 28 and 30). + + upp_tr - vector x, y, z so that one calculate + U = exp(A) with A= [[0, x, y], + [-x, 0, z], + [-y, -z, 0]] +------------------------------------------------------------------------- */ + +void MinSpinOSO_CG::rodrigues_rotation(const double *upp_tr, double *out) +{ + double theta,A,B,D,x,y,z; + double s1,s2,s3,a1,a2,a3; + + if (fabs(upp_tr[0]) < 1.0e-40 && + fabs(upp_tr[1]) < 1.0e-40 && + fabs(upp_tr[2]) < 1.0e-40){ + + // if upp_tr is zero, return unity matrix + for(int k = 0; k < 3; k++){ + for(int m = 0; m < 3; m++){ + if (m == k) + out[3 * k + m] = 1.0; + else + out[3 * k + m] = 0.0; + } + } + return; + } + + theta = sqrt(upp_tr[0] * upp_tr[0] + + upp_tr[1] * upp_tr[1] + + upp_tr[2] * upp_tr[2]); + + A = cos(theta); + B = sin(theta); + D = 1 - A; + x = upp_tr[0]/theta; + y = upp_tr[1]/theta; + z = upp_tr[2]/theta; + + // diagonal elements of U + + out[0] = A + z * z * D; + out[4] = A + y * y * D; + out[8] = A + x * x * D; + + // off diagonal of U + + s1 = -y * z *D; + s2 = x * z * D; + s3 = -x * y * D; + + a1 = x * B; + a2 = y * B; + a3 = z * B; + + out[1] = s1 + a1; + out[3] = s1 - a1; + out[2] = s2 + a2; + out[6] = s2 - a2; + out[5] = s3 + a3; + out[7] = s3 - a3; + +} + +/* ---------------------------------------------------------------------- + out = vector^T x m, + m -- 3x3 matrix , v -- 3-d vector +------------------------------------------------------------------------- */ + +void MinSpinOSO_CG::vm3(const double *m, const double *v, double *out) +{ + for(int i = 0; i < 3; i++){ + out[i] *= 0.0; + for(int j = 0; j < 3; j++) + out[i] += *(m + 3 * j + i) * v[j]; + } +} + + +void MinSpinOSO_CG::make_step(double c, double *energy_and_der) +{ + double p_scaled[3]; + int nlocal = atom->nlocal; + double rot_mat[9]; // exponential of matrix made of search direction + double s_new[3]; + double **sp = atom->sp; + double der_e_cur_tmp = 0.0;; + + for (int i = 0; i < nlocal; i++) { + + // scale the search direction + + for (int j = 0; j < 3; j++) p_scaled[j] = c * p_s[3 * i + j]; + + // calculate rotation matrix + + rodrigues_rotation(p_scaled, rot_mat); + + // rotate spins + + vm3(rot_mat, sp[i], s_new); + for (int j = 0; j < 3; j++) sp[i][j] = s_new[j]; + } + + ecurrent = energy_force(0); + calc_gradient(); + neval++; + der_e_cur = 0.0; + for (int i = 0; i < 3 * nlocal; i++) { + der_e_cur += g_cur[i] * p_s[i]; + } + MPI_Allreduce(&der_e_cur,&der_e_cur_tmp,1,MPI_DOUBLE,MPI_SUM,world); + der_e_cur = der_e_cur_tmp; + if (update->multireplica == 1) { + MPI_Allreduce(&der_e_cur_tmp,&der_e_cur,1,MPI_DOUBLE,MPI_SUM,universe->uworld); + } + + energy_and_der[0] = ecurrent; + energy_and_der[1] = der_e_cur; +} + +/* ---------------------------------------------------------------------- + Calculate step length which satisfies approximate Wolfe conditions + using the cubic interpolation +------------------------------------------------------------------------- */ + +int MinSpinOSO_CG::calc_and_make_step(double a, double b, int index) +{ + double e_and_d[2] = {0.0,0.0}; + double alpha,c1,c2,c3; + double **sp = atom->sp; + int nlocal = atom->nlocal; + + make_step(b,e_and_d); + ecurrent = e_and_d[0]; + der_e_cur = e_and_d[1]; + index++; + + if (awc(der_e_pr,eprevious,e_and_d[1],e_and_d[0]) || index == 10){ + MPI_Bcast(&b,1,MPI_DOUBLE,0,world); + for (int i = 0; i < 3 * nlocal; i++) { + p_s[i] = b * p_s[i]; + } + return 1; + } + else{ + double r,f0,f1,df0,df1; + r = b - a; + f0 = eprevious; + f1 = ecurrent; + df0 = der_e_pr; + df1 = der_e_cur; + + c1 = -2.0*(f1-f0)/(r*r*r)+(df1+df0)/(r*r); + c2 = 3.0*(f1-f0)/(r*r)-(df1+2.0*df0)/(r); + c3 = df0; + + // f(x) = c1 x^3 + c2 x^2 + c3 x^1 + c4 + // has minimum at alpha below. We do not check boundaries. + + alpha = (-c2 + sqrt(c2*c2 - 3.0*c1*c3))/(3.0*c1); + MPI_Bcast(&alpha,1,MPI_DOUBLE,0,world); + + if (alpha < 0.0) alpha = r/2.0; + + for (int i = 0; i < nlocal; i++) { + for (int j = 0; j < 3; j++) sp[i][j] = sp_copy[i][j]; + } + calc_and_make_step(0.0, alpha, index); + } + + return 0; +} + +/* ---------------------------------------------------------------------- + Approximate Wolfe conditions: + William W. Hager and Hongchao Zhang + SIAM J. optim., 16(1), 170-192. (23 pages) +------------------------------------------------------------------------- */ + +int MinSpinOSO_CG::awc(double der_phi_0, double phi_0, double der_phi_j, double phi_j){ + + double eps = 1.0e-6; + double delta = 0.1; + double sigma = 0.9; + + if ((phi_j<=phi_0+eps*fabs(phi_0)) && ((2.0*delta-1.0) * der_phi_0>=der_phi_j>=sigma*der_phi_0)) + return 1; + else + return 0; +} + /* ---------------------------------------------------------------------- evaluate max timestep ---------------------------------------------------------------------- */ @@ -282,231 +675,4 @@ double MinSpinOSO_CG::evaluate_dt() dtmax = MY_2PI/(discrete_factor*sqrt(fmaxsqall)); return dtmax; -} - -/* ---------------------------------------------------------------------- - calculate gradients ----------------------------------------------------------------------- */ - -void MinSpinOSO_CG::calc_gradient(double dts) -{ - int nlocal = atom->nlocal; - double **sp = atom->sp; - double **fm = atom->fm; - double tdampx, tdampy, tdampz; - - // loop on all spins on proc. - - for (int i = 0; i < nlocal; i++) { - - // calc. damping torque - - tdampx = -alpha_damp*(fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]); - tdampy = -alpha_damp*(fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); - tdampz = -alpha_damp*(fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); - - // calculate gradients - - g_cur[3 * i + 0] = -tdampz * dts; - g_cur[3 * i + 1] = tdampy * dts; - g_cur[3 * i + 2] = -tdampx * dts; - } -} - -/* ---------------------------------------------------------------------- - search direction: - The Fletcher-Reeves conj. grad. method - See Jorge Nocedal and Stephen J. Wright 'Numerical - Optimization' Second Edition, 2006 (p. 121) ----------------------------------------------------------------------- */ - -void MinSpinOSO_CG::calc_search_direction() -{ - int nlocal = atom->nlocal; - double g2old = 0.0; - double g2 = 0.0; - double beta = 0.0; - - double g2_global = 0.0; - double g2old_global = 0.0; - if (local_iter == 0 || local_iter % 5 == 0){ // steepest descent direction - for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = -g_cur[i]; - g_old[i] = g_cur[i]; - } - } else { // conjugate direction - for (int i = 0; i < 3 * nlocal; i++) { - g2old += g_old[i] * g_old[i]; - g2 += g_cur[i] * g_cur[i]; - } - - // now we need to collect/broadcast beta on this replica - // different replica can have different beta for now. - // need to check what is beta for GNEB - - MPI_Allreduce(&g2, &g2_global, 1, MPI_DOUBLE, MPI_SUM, world); - MPI_Allreduce(&g2old, &g2old_global, 1, MPI_DOUBLE, MPI_SUM, world); - - // Sum over all replicas. Good for GNEB. - if (update->multireplica == 1) { - g2 = g2_global; - g2old = g2old_global; - MPI_Allreduce(&g2,&g2_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); - MPI_Allreduce(&g2old,&g2old_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); - } - - if (fabs(g2_global) < 1.0e-60) beta = 0.0; - else beta = g2_global / g2old_global; - // calculate conjugate direction - for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = beta * p_s[i] - g_cur[i]; - g_old[i] = g_cur[i]; - } - } - - local_iter++; -} - -/* ---------------------------------------------------------------------- - rotation of spins along the search direction ----------------------------------------------------------------------- */ - -void MinSpinOSO_CG::advance_spins() -{ - int nlocal = atom->nlocal; - double **sp = atom->sp; - double **fm = atom->fm; - double tdampx, tdampy, tdampz; - double rot_mat[9]; // exponential of matrix made of search direction - double s_new[3]; - - // loop on all spins on proc. - - for (int i = 0; i < nlocal; i++) { - rodrigues_rotation(p_s + 3 * i, rot_mat); - - // rotate spins - - vm3(rot_mat, sp[i], s_new); - for (int j = 0; j < 3; j++) sp[i][j] = s_new[j]; - } -} - -/* ---------------------------------------------------------------------- - compute and return max_i||mag. torque_i||_2 -------------------------------------------------------------------------- */ - -double MinSpinOSO_CG::max_torque() -{ - double fmsq,fmaxsqone,fmaxsqloc,fmaxsqall; - int nlocal = atom->nlocal; - double hbar = force->hplanck/MY_2PI; - - // finding max fm on this proc. - - fmsq = fmaxsqone = fmaxsqloc = fmaxsqall = 0.0; - for (int i = 0; i < nlocal; i++) { - fmsq = 0.0; - for (int j = 0; j < 3; j++) - fmsq += g_cur[3 * i + j] * g_cur[3 * i + j]; - fmaxsqone = MAX(fmaxsqone,fmsq); - } - - // finding max fm on this replica - - fmaxsqloc = fmaxsqone; - MPI_Allreduce(&fmaxsqone,&fmaxsqloc,1,MPI_DOUBLE,MPI_MAX,world); - - // finding max fm over all replicas, if necessary - // this communicator would be invalid for multiprocess replicas - - fmaxsqall = fmaxsqloc; - if (update->multireplica == 1) { - fmaxsqall = fmaxsqloc; - MPI_Allreduce(&fmaxsqloc,&fmaxsqall,1,MPI_DOUBLE,MPI_MAX,universe->uworld); - } - - return sqrt(fmaxsqall) * hbar; -} - -/* ---------------------------------------------------------------------- - calculate 3x3 matrix exponential using Rodrigues' formula - (R. Murray, Z. Li, and S. Shankar Sastry, - A Mathematical Introduction to - Robotic Manipulation (1994), p. 28 and 30). - - upp_tr - vector x, y, z so that one calculate - U = exp(A) with A= [[0, x, y], - [-x, 0, z], - [-y, -z, 0]] -------------------------------------------------------------------------- */ - -void MinSpinOSO_CG::rodrigues_rotation(const double *upp_tr, double *out) -{ - double theta,A,B,D,x,y,z; - double s1,s2,s3,a1,a2,a3; - - if (fabs(upp_tr[0]) < 1.0e-40 && - fabs(upp_tr[1]) < 1.0e-40 && - fabs(upp_tr[2]) < 1.0e-40){ - - // if upp_tr is zero, return unity matrix - for(int k = 0; k < 3; k++){ - for(int m = 0; m < 3; m++){ - if (m == k) out[3 * k + m] = 1.0; - else out[3 * k + m] = 0.0; - } - } - return; - } - - theta = sqrt(upp_tr[0] * upp_tr[0] + - upp_tr[1] * upp_tr[1] + - upp_tr[2] * upp_tr[2]); - - A = cos(theta); - B = sin(theta); - D = 1 - A; - x = upp_tr[0]/theta; - y = upp_tr[1]/theta; - z = upp_tr[2]/theta; - - // diagonal elements of U - - out[0] = A + z * z * D; - out[4] = A + y * y * D; - out[8] = A + x * x * D; - - // off diagonal of U - - s1 = -y * z *D; - s2 = x * z * D; - s3 = -x * y * D; - - a1 = x * B; - a2 = y * B; - a3 = z * B; - - out[1] = s1 + a1; - out[3] = s1 - a1; - out[2] = s2 + a2; - out[6] = s2 - a2; - out[5] = s3 + a3; - out[7] = s3 - a3; - -} - -/* ---------------------------------------------------------------------- - out = vector^T x m, - m -- 3x3 matrix , v -- 3-d vector -------------------------------------------------------------------------- */ - -void MinSpinOSO_CG::vm3(const double *m, const double *v, double *out) -{ - for(int i = 0; i < 3; i++){ - out[i] *= 0.0; - for(int j = 0; j < 3; j++){ - out[i] += *(m + 3 * j + i) * v[j]; - } - } -} +} \ No newline at end of file diff --git a/src/SPIN/min_spin_oso_cg.h b/src/SPIN/min_spin_oso_cg.h index 81bbd2c294..e50d1a69db 100644 --- a/src/SPIN/min_spin_oso_cg.h +++ b/src/SPIN/min_spin_oso_cg.h @@ -24,7 +24,7 @@ MinimizeStyle(spin/oso_cg, MinSpinOSO_CG) namespace LAMMPS_NS { -class MinSpinOSO_CG : public Min { +class MinSpinOSO_CG: public Min { public: MinSpinOSO_CG(class LAMMPS *); virtual ~MinSpinOSO_CG(); @@ -33,33 +33,34 @@ class MinSpinOSO_CG : public Min { int modify_param(int, char **); void reset_vectors(); int iterate(int); - private: - double evaluate_dt(); - void advance_spins(); - double max_torque(); - void calc_gradient(double); - void calc_search_direction(); - - // global and spin timesteps - - double dt; - double dts; - int nlocal_max; // max value of nlocal (for size of lists) - - double alpha_damp; // damping for spin minimization - double discrete_factor; // factor for spin timestep evaluation - + double dt; // global timestep + double dts; // spin timestep + int ireplica,nreplica; // for neb double *spvec; // variables for atomic dof, as 1d vector double *fmvec; // variables for atomic dof, as 1d vector - - double *g_old; // gradient vector at previous iteration - double *g_cur; // current gradient vector + double *g_cur; // current gradient vector + double *g_old; // gradient vector at previous step double *p_s; // search direction vector - int local_iter; // number of times we call search_direction + double **sp_copy; // copy of the spins + int local_iter; // for neb + int nlocal_max; // max value of nlocal (for size of lists) + double discrete_factor; // factor for spin timestep evaluation + double evaluate_dt(); + void advance_spins(); + void calc_gradient(); + void calc_search_direction(); + double maximum_rotation(double *); void vm3(const double *, const double *, double *); void rodrigues_rotation(const double *, double *); + int calc_and_make_step(double, double, int); + int awc(double, double, double, double); + void make_step(double, double *); + double max_torque(); + double der_e_cur; // current derivative along search dir. + double der_e_pr; // previous derivative along search dir. + int use_line_search; // use line search or not. bigint last_negative; }; diff --git a/src/SPIN/min_spin_oso_cg2.cpp b/src/SPIN/min_spin_oso_cg2.cpp deleted file mode 100644 index 52b98eead7..0000000000 --- a/src/SPIN/min_spin_oso_cg2.cpp +++ /dev/null @@ -1,679 +0,0 @@ -/* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov - - 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. -------------------------------------------------------------------------- */ - -/* ------------------------------------------------------------------------ - Contributing authors: Aleksei Ivanov (University of Iceland) - Julien Tranchida (SNL) - - Please cite the related publication: - Ivanov, A. V., Uzdin, V. M., & Jónsson, H. (2019). Fast and Robust - Algorithm for the Minimisation of the Energy of Spin Systems. arXiv - preprint arXiv:1904.02669. -------------------------------------------------------------------------- */ - -#include -#include -#include -#include -#include "min_spin_oso_cg2.h" -#include "universe.h" -#include "atom.h" -#include "citeme.h" -#include "force.h" -#include "update.h" -#include "output.h" -#include "timer.h" -#include "error.h" -#include "memory.h" -#include "modify.h" -#include "math_special.h" -#include "math_const.h" -#include "universe.h" -#include - -using namespace LAMMPS_NS; -using namespace MathConst; - -static const char cite_minstyle_spin_oso_cg2[] = - "min_style spin/oso_cg2 command:\n\n" - "@article{ivanov2019fast,\n" - "title={Fast and Robust Algorithm for the Minimisation of the Energy of " - "Spin Systems},\n" - "author={Ivanov, A. V and Uzdin, V. M. and J{\'o}nsson, H.},\n" - "journal={arXiv preprint arXiv:1904.02669},\n" - "year={2019}\n" - "}\n\n"; - -// EPS_ENERGY = minimum normalization for energy tolerance - -#define EPS_ENERGY 1.0e-8 - -#define DELAYSTEP 5 - - -/* ---------------------------------------------------------------------- */ - -MinSpinOSO_CG2::MinSpinOSO_CG2(LAMMPS *lmp) : - Min(lmp), g_old(NULL), g_cur(NULL), p_s(NULL) -{ - if (lmp->citeme) lmp->citeme->add(cite_minstyle_spin_oso_cg2); - nlocal_max = 0; - - // nreplica = number of partitions - // ireplica = which world I am in universe - - nreplica = universe->nworlds; - ireplica = universe->iworld; - use_line_search = 1; - discrete_factor = 10.0; - -} - -/* ---------------------------------------------------------------------- */ - -MinSpinOSO_CG2::~MinSpinOSO_CG2() -{ - memory->destroy(g_old); - memory->destroy(g_cur); - memory->destroy(p_s); - if (use_line_search) - memory->destroy(sp_copy); -} - -/* ---------------------------------------------------------------------- */ - -void MinSpinOSO_CG2::init() -{ - local_iter = 0; - der_e_cur = 0.0; - der_e_pr = 0.0; - - Min::init(); - - dts = dt = update->dt; - last_negative = update->ntimestep; - - // allocate tables - - nlocal_max = atom->nlocal; - memory->grow(g_old,3*nlocal_max,"min/spin/oso/cg2:g_old"); - memory->grow(g_cur,3*nlocal_max,"min/spin/oso/cg2:g_cur"); - memory->grow(p_s,3*nlocal_max,"min/spin/oso/cg2:p_s"); - if (use_line_search) - memory->grow(sp_copy,nlocal_max,3,"min/spin/oso/cg2:sp_copy"); -} - -/* ---------------------------------------------------------------------- */ - -void MinSpinOSO_CG2::setup_style() -{ - double **v = atom->v; - int nlocal = atom->nlocal; - - // check if the atom/spin style is defined - - if (!atom->sp_flag) - error->all(FLERR,"min/spin_oso_cg2 requires atom/spin style"); - - for (int i = 0; i < nlocal; i++) - v[i][0] = v[i][1] = v[i][2] = 0.0; -} - -/* ---------------------------------------------------------------------- */ - -int MinSpinOSO_CG2::modify_param(int narg, char **arg) -{ - - if (strcmp(arg[0],"line_search") == 0) { - if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); - use_line_search = force->numeric(FLERR,arg[1]); - return 2; - } - if (strcmp(arg[0],"discrete_factor") == 0) { - if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); - discrete_factor = force->numeric(FLERR,arg[1]); - return 2; - } - return 0; -} - -/* ---------------------------------------------------------------------- - set current vector lengths and pointers - called after atoms have migrated -------------------------------------------------------------------------- */ - -void MinSpinOSO_CG2::reset_vectors() -{ - // atomic dof - - // size sp is 4N vector - nvec = 4 * atom->nlocal; - if (nvec) spvec = atom->sp[0]; - - nvec = 3 * atom->nlocal; - if (nvec) fmvec = atom->fm[0]; - - if (nvec) xvec = atom->x[0]; - if (nvec) fvec = atom->f[0]; -} - -/* ---------------------------------------------------------------------- - minimization via orthogonal spin optimisation -------------------------------------------------------------------------- */ - -int MinSpinOSO_CG2::iterate(int maxiter) -{ - int nlocal = atom->nlocal; - bigint ntimestep; - double fmdotfm; - int flag, flagall; - double **sp = atom->sp; - double der_e_cur_tmp = 0.0; - - if (nlocal_max < nlocal) { - nlocal_max = nlocal; - local_iter = 0; - nlocal_max = nlocal; - memory->grow(g_old,3*nlocal_max,"min/spin/oso/cg2:g_old"); - memory->grow(g_cur,3*nlocal_max,"min/spin/oso/cg2:g_cur"); - memory->grow(p_s,3*nlocal_max,"min/spin/oso/cg2:p_s"); - if (use_line_search) - memory->grow(sp_copy,nlocal_max,3,"min/spin/oso/cg2:sp_copy"); - } - - for (int iter = 0; iter < maxiter; iter++) { - - if (timer->check_timeout(niter)) - return TIMEOUT; - - ntimestep = ++update->ntimestep; - niter++; - - // optimize timestep accross processes / replicas - // need a force calculation for timestep optimization - - if (use_line_search) { - - // here we need to do line search - if (local_iter == 0) - calc_gradient(); - - calc_search_direction(); - der_e_cur = 0.0; - for (int i = 0; i < 3 * nlocal; i++) - der_e_cur += g_cur[i] * p_s[i]; - MPI_Allreduce(&der_e_cur,&der_e_cur_tmp,1,MPI_DOUBLE,MPI_SUM,world); - der_e_cur = der_e_cur_tmp; - if (update->multireplica == 1) { - MPI_Allreduce(&der_e_cur_tmp,&der_e_cur,1,MPI_DOUBLE,MPI_SUM,universe->uworld); - } - for (int i = 0; i < nlocal; i++) - for (int j = 0; j < 3; j++) - sp_copy[i][j] = sp[i][j]; - - eprevious = ecurrent; - der_e_pr = der_e_cur; - calc_and_make_step(0.0, 1.0, 0); - } - else{ - - // here we don't do line search - // but use cutoff rotation angle - // if gneb calc., nreplica > 1 - // then calculate gradients and advance spins - // of intermediate replicas only - - if (nreplica > 1) { - if(ireplica != 0 && ireplica != nreplica-1) - calc_gradient(); - calc_search_direction(); - advance_spins(); - } else{ - calc_gradient(); - calc_search_direction(); - advance_spins(); - } - eprevious = ecurrent; - ecurrent = energy_force(0); - neval++; - } - - //// energy tolerance criterion - //// only check after DELAYSTEP elapsed since velocties reset to 0 - //// sync across replicas if running multi-replica minimization - - if (update->etol > 0.0 && ntimestep-last_negative > DELAYSTEP) { - if (update->multireplica == 0) { - if (fabs(ecurrent-eprevious) < - update->etol * 0.5*(fabs(ecurrent) + fabs(eprevious) + EPS_ENERGY)) - return ETOL; - } else { - if (fabs(ecurrent-eprevious) < - update->etol * 0.5*(fabs(ecurrent) + fabs(eprevious) + EPS_ENERGY)) - flag = 0; - else flag = 1; - MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,universe->uworld); - if (flagall == 0) return ETOL; - } - } - - // magnetic torque tolerance criterion - // sync across replicas if running multi-replica minimization - - if (update->ftol > 0.0) { - fmdotfm = max_torque(); - if (update->multireplica == 0) { - if (fmdotfm < update->ftol*update->ftol) return FTOL; - } else { - if (fmdotfm < update->ftol*update->ftol) flag = 0; - else flag = 1; - MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,universe->uworld); - if (flagall == 0) return FTOL; - } - } - - // output for thermo, dump, restart files - - if (output->next == ntimestep) { - timer->stamp(); - output->write(ntimestep); - timer->stamp(Timer::OUTPUT); - } - } - - return MAXITER; -} - -/* ---------------------------------------------------------------------- - calculate gradients ----------------------------------------------------------------------- */ - -void MinSpinOSO_CG2::calc_gradient() -{ - int nlocal = atom->nlocal; - double **sp = atom->sp; - double **fm = atom->fm; - double hbar = force->hplanck/MY_2PI; - double factor; - - if (use_line_search) - factor = hbar; - else factor = evaluate_dt(); - - // loop on all spins on proc. - - for (int i = 0; i < nlocal; i++) { - g_cur[3 * i + 0] = (fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]) * factor; - g_cur[3 * i + 1] = -(fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]) * factor; - g_cur[3 * i + 2] = (fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]) * factor; - } -} - -/* ---------------------------------------------------------------------- - search direction: - The Fletcher-Reeves conj. grad. method - See Jorge Nocedal and Stephen J. Wright 'Numerical - Optimization' Second Edition, 2006 (p. 121) ----------------------------------------------------------------------- */ - -void MinSpinOSO_CG2::calc_search_direction() -{ - int nlocal = atom->nlocal; - double g2old = 0.0; - double g2 = 0.0; - double beta = 0.0; - - double g2_global = 0.0; - double g2old_global = 0.0; - - if (local_iter == 0 || local_iter % 5 == 0){ // steepest descent direction - for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = -g_cur[i]; - g_old[i] = g_cur[i]; - } - } else { // conjugate direction - for (int i = 0; i < 3 * nlocal; i++) { - g2old += g_old[i] * g_old[i]; - g2 += g_cur[i] * g_cur[i]; - } - - // now we need to collect/broadcast beta on this replica - // need to check what is beta for GNEB - - MPI_Allreduce(&g2,&g2_global,1,MPI_DOUBLE,MPI_SUM,world); - MPI_Allreduce(&g2old,&g2old_global,1,MPI_DOUBLE,MPI_SUM,world); - - // Sum over all replicas. Good for GNEB. - if (update->multireplica == 1) { - g2 = g2_global; - g2old = g2old_global; - MPI_Allreduce(&g2,&g2_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); - MPI_Allreduce(&g2old,&g2old_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); - } - if (fabs(g2_global) < 1.0e-60) beta = 0.0; - else beta = g2_global / g2old_global; - // calculate conjugate direction - for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = (beta * p_s[i] - g_cur[i]); - g_old[i] = g_cur[i]; - } - } - - local_iter++; -} - -/* ---------------------------------------------------------------------- - rotation of spins along the search direction ----------------------------------------------------------------------- */ - -void MinSpinOSO_CG2::advance_spins() -{ - int nlocal = atom->nlocal; - double **sp = atom->sp; - double **fm = atom->fm; - double tdampx, tdampy, tdampz; - double rot_mat[9]; // exponential of matrix made of search direction - double s_new[3]; - - // loop on all spins on proc. - - for (int i = 0; i < nlocal; i++) { - rodrigues_rotation(p_s + 3 * i, rot_mat); - - // rotate spins - - vm3(rot_mat, sp[i], s_new); - for (int j = 0; j < 3; j++) sp[i][j] = s_new[j]; - } -} - -/* ---------------------------------------------------------------------- - compute and return max_i||mag. torque_i||_2 -------------------------------------------------------------------------- */ - -double MinSpinOSO_CG2::max_torque() -{ - double fmsq,fmaxsqone,fmaxsqloc,fmaxsqall; - int nlocal = atom->nlocal; - double factor; - double hbar = force->hplanck/MY_2PI; - - if (use_line_search) factor = 1.0; - else factor = hbar; - - // finding max fm on this proc. - - fmsq = fmaxsqone = fmaxsqloc = fmaxsqall = 0.0; - for (int i = 0; i < nlocal; i++) { - fmsq = 0.0; - for (int j = 0; j < 3; j++) - fmsq += g_cur[3 * i + j] * g_cur[3 * i + j]; - fmaxsqone = MAX(fmaxsqone,fmsq); - } - - // finding max fm on this replica - - fmaxsqloc = fmaxsqone; - MPI_Allreduce(&fmaxsqone,&fmaxsqloc,1,MPI_DOUBLE,MPI_MAX,world); - - // finding max fm over all replicas, if necessary - // this communicator would be invalid for multiprocess replicas - - fmaxsqall = fmaxsqloc; - if (update->multireplica == 1) { - fmaxsqall = fmaxsqloc; - MPI_Allreduce(&fmaxsqloc,&fmaxsqall,1,MPI_DOUBLE,MPI_MAX,universe->uworld); - } - - return sqrt(fmaxsqall) * factor; -} - -/* ---------------------------------------------------------------------- - calculate 3x3 matrix exponential using Rodrigues' formula - (R. Murray, Z. Li, and S. Shankar Sastry, - A Mathematical Introduction to - Robotic Manipulation (1994), p. 28 and 30). - - upp_tr - vector x, y, z so that one calculate - U = exp(A) with A= [[0, x, y], - [-x, 0, z], - [-y, -z, 0]] -------------------------------------------------------------------------- */ - -void MinSpinOSO_CG2::rodrigues_rotation(const double *upp_tr, double *out) -{ - double theta,A,B,D,x,y,z; - double s1,s2,s3,a1,a2,a3; - - if (fabs(upp_tr[0]) < 1.0e-40 && - fabs(upp_tr[1]) < 1.0e-40 && - fabs(upp_tr[2]) < 1.0e-40){ - - // if upp_tr is zero, return unity matrix - for(int k = 0; k < 3; k++){ - for(int m = 0; m < 3; m++){ - if (m == k) out[3 * k + m] = 1.0; - else out[3 * k + m] = 0.0; - } - } - return; - } - - theta = sqrt(upp_tr[0] * upp_tr[0] + - upp_tr[1] * upp_tr[1] + - upp_tr[2] * upp_tr[2]); - - A = cos(theta); - B = sin(theta); - D = 1 - A; - x = upp_tr[0]/theta; - y = upp_tr[1]/theta; - z = upp_tr[2]/theta; - - // diagonal elements of U - - out[0] = A + z * z * D; - out[4] = A + y * y * D; - out[8] = A + x * x * D; - - // off diagonal of U - - s1 = -y * z *D; - s2 = x * z * D; - s3 = -x * y * D; - - a1 = x * B; - a2 = y * B; - a3 = z * B; - - out[1] = s1 + a1; - out[3] = s1 - a1; - out[2] = s2 + a2; - out[6] = s2 - a2; - out[5] = s3 + a3; - out[7] = s3 - a3; - -} - -/* ---------------------------------------------------------------------- - out = vector^T x m, - m -- 3x3 matrix , v -- 3-d vector -------------------------------------------------------------------------- */ - -void MinSpinOSO_CG2::vm3(const double *m, const double *v, double *out) -{ - for(int i = 0; i < 3; i++){ - out[i] *= 0.0; - for(int j = 0; j < 3; j++) - out[i] += *(m + 3 * j + i) * v[j]; - } -} - - -void MinSpinOSO_CG2::make_step(double c, double *energy_and_der) -{ - double p_scaled[3]; - int nlocal = atom->nlocal; - double rot_mat[9]; // exponential of matrix made of search direction - double s_new[3]; - double **sp = atom->sp; - double der_e_cur_tmp = 0.0;; - - for (int i = 0; i < nlocal; i++) { - - // scale the search direction - - for (int j = 0; j < 3; j++) p_scaled[j] = c * p_s[3 * i + j]; - - // calculate rotation matrix - - rodrigues_rotation(p_scaled, rot_mat); - - // rotate spins - - vm3(rot_mat, sp[i], s_new); - for (int j = 0; j < 3; j++) sp[i][j] = s_new[j]; - } - - ecurrent = energy_force(0); - calc_gradient(); - neval++; - der_e_cur = 0.0; - for (int i = 0; i < 3 * nlocal; i++) { - der_e_cur += g_cur[i] * p_s[i]; - } - MPI_Allreduce(&der_e_cur,&der_e_cur_tmp,1,MPI_DOUBLE,MPI_SUM,world); - der_e_cur = der_e_cur_tmp; - if (update->multireplica == 1) { - MPI_Allreduce(&der_e_cur_tmp,&der_e_cur,1,MPI_DOUBLE,MPI_SUM,universe->uworld); - } - - energy_and_der[0] = ecurrent; - energy_and_der[1] = der_e_cur; -} - -/* ---------------------------------------------------------------------- - Calculate step length which satisfies approximate Wolfe conditions - using the cubic interpolation -------------------------------------------------------------------------- */ - -int MinSpinOSO_CG2::calc_and_make_step(double a, double b, int index) -{ - double e_and_d[2] = {0.0,0.0}; - double alpha,c1,c2,c3; - double **sp = atom->sp; - int nlocal = atom->nlocal; - - make_step(b,e_and_d); - ecurrent = e_and_d[0]; - der_e_cur = e_and_d[1]; - index++; - - if (awc(der_e_pr,eprevious,e_and_d[1],e_and_d[0]) || index == 10){ - MPI_Bcast(&b,1,MPI_DOUBLE,0,world); - for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = b * p_s[i]; - } - return 1; - } - else{ - double r,f0,f1,df0,df1; - r = b - a; - f0 = eprevious; - f1 = ecurrent; - df0 = der_e_pr; - df1 = der_e_cur; - - c1 = -2.0*(f1-f0)/(r*r*r)+(df1+df0)/(r*r); - c2 = 3.0*(f1-f0)/(r*r)-(df1+2.0*df0)/(r); - c3 = df0; - - // f(x) = c1 x^3 + c2 x^2 + c3 x^1 + c4 - // has minimum at alpha below. We do not check boundaries. - - alpha = (-c2 + sqrt(c2*c2 - 3.0*c1*c3))/(3.0*c1); - MPI_Bcast(&alpha,1,MPI_DOUBLE,0,world); - - if (alpha < 0.0) alpha = r/2.0; - - for (int i = 0; i < nlocal; i++) { - for (int j = 0; j < 3; j++) sp[i][j] = sp_copy[i][j]; - } - calc_and_make_step(0.0, alpha, index); - } - - return 0; -} - -/* ---------------------------------------------------------------------- - Approximate Wolfe conditions: - William W. Hager and Hongchao Zhang - SIAM J. optim., 16(1), 170-192. (23 pages) -------------------------------------------------------------------------- */ - -int MinSpinOSO_CG2::awc(double der_phi_0, double phi_0, double der_phi_j, double phi_j){ - - double eps = 1.0e-6; - double delta = 0.1; - double sigma = 0.9; - - if ((phi_j<=phi_0+eps*fabs(phi_0)) && ((2.0*delta-1.0) * der_phi_0>=der_phi_j>=sigma*der_phi_0)) - return 1; - else - return 0; -} - -/* ---------------------------------------------------------------------- - evaluate max timestep ----------------------------------------------------------------------- */ - -double MinSpinOSO_CG2::evaluate_dt() -{ - double dtmax; - double fmsq; - double fmaxsqone,fmaxsqloc,fmaxsqall; - int nlocal = atom->nlocal; - double **fm = atom->fm; - - // finding max fm on this proc. - - fmsq = fmaxsqone = fmaxsqloc = fmaxsqall = 0.0; - for (int i = 0; i < nlocal; i++) { - fmsq = fm[i][0]*fm[i][0]+fm[i][1]*fm[i][1]+fm[i][2]*fm[i][2]; - fmaxsqone = MAX(fmaxsqone,fmsq); - } - - // finding max fm on this replica - - fmaxsqloc = fmaxsqone; - MPI_Allreduce(&fmaxsqone,&fmaxsqloc,1,MPI_DOUBLE,MPI_MAX,world); - - // finding max fm over all replicas, if necessary - // this communicator would be invalid for multiprocess replicas - - fmaxsqall = fmaxsqloc; - if (update->multireplica == 1) { - fmaxsqall = fmaxsqloc; - MPI_Allreduce(&fmaxsqloc,&fmaxsqall,1,MPI_DOUBLE,MPI_MAX,universe->uworld); - } - - if (fmaxsqall == 0.0) - error->all(FLERR,"Incorrect fmaxsqall calculation"); - - // define max timestep by dividing by the - // inverse of max frequency by discrete_factor - - dtmax = MY_2PI/(discrete_factor*sqrt(fmaxsqall)); - - return dtmax; -} \ No newline at end of file diff --git a/src/SPIN/min_spin_oso_cg2.h b/src/SPIN/min_spin_oso_cg2.h deleted file mode 100644 index 83605f98ed..0000000000 --- a/src/SPIN/min_spin_oso_cg2.h +++ /dev/null @@ -1,72 +0,0 @@ -/* -*- c++ -*- ---------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov - - 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 - -MinimizeStyle(spin/oso_cg2, MinSpinOSO_CG2) - -#else - -#ifndef LMP_MIN_SPIN_OSO_CG2_H -#define LMP_MIN_SPIN_OSO_CG2_H - -#include "min.h" - -namespace LAMMPS_NS { - -class MinSpinOSO_CG2: public Min { - public: - MinSpinOSO_CG2(class LAMMPS *); - virtual ~MinSpinOSO_CG2(); - void init(); - void setup_style(); - int modify_param(int, char **); - void reset_vectors(); - int iterate(int); - private: - double dt; // global timestep - double dts; // spin timestep - int ireplica,nreplica; // for neb - double *spvec; // variables for atomic dof, as 1d vector - double *fmvec; // variables for atomic dof, as 1d vector - double *g_cur; // current gradient vector - double *g_old; // gradient vector at previous step - double *p_s; // search direction vector - double **sp_copy; // copy of the spins - int local_iter; // for neb - int nlocal_max; // max value of nlocal (for size of lists) - double discrete_factor; // factor for spin timestep evaluation - - double evaluate_dt(); - void advance_spins(); - void calc_gradient(); - void calc_search_direction(); - double maximum_rotation(double *); - void vm3(const double *, const double *, double *); - void rodrigues_rotation(const double *, double *); - int calc_and_make_step(double, double, int); - int awc(double, double, double, double); - void make_step(double, double *); - double max_torque(); - double der_e_cur; // current derivative along search dir. - double der_e_pr; // previous derivative along search dir. - int use_line_search; // use line search or not. - double maxepsrot; - - bigint last_negative; -}; - -} - -#endif -#endif From 07f2f5e5266983d3fcec42c5e50ac19ce82903f4 Mon Sep 17 00:00:00 2001 From: alxvov Date: Mon, 22 Jul 2019 18:15:32 +0000 Subject: [PATCH 50/74] no line search for multireplica --- src/SPIN/min_spin_oso_cg.cpp | 10 +++++++++- src/SPIN/min_spin_oso_lbfgs.cpp | 12 ++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index c9f3a59f87..21927d0d31 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -73,7 +73,11 @@ MinSpinOSO_CG::MinSpinOSO_CG(LAMMPS *lmp) : nreplica = universe->nworlds; ireplica = universe->iworld; - use_line_search = 1; + if (nreplica > 1) + use_line_search = 0; // no line search for NEB + else + use_line_search = 1; + discrete_factor = 10.0; } @@ -134,6 +138,10 @@ int MinSpinOSO_CG::modify_param(int narg, char **arg) if (strcmp(arg[0],"line_search") == 0) { if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); use_line_search = force->numeric(FLERR,arg[1]); + + if (nreplica > 1 && use_line_search) + error->all(FLERR,"Illegal fix_modify command, cannot use NEB and line search together"); + return 2; } if (strcmp(arg[0],"discrete_factor") == 0) { diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index d7e7302e4f..eba62f296f 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -73,7 +73,11 @@ MinSpinOSO_LBFGS::MinSpinOSO_LBFGS(LAMMPS *lmp) : nreplica = universe->nworlds; ireplica = universe->iworld; - use_line_search = 1; + if (nreplica > 1) + use_line_search = 0; // no line search for NEB + else + use_line_search = 1; + maxepsrot = MY_2PI / (100.0); } @@ -143,13 +147,17 @@ int MinSpinOSO_LBFGS::modify_param(int narg, char **arg) if (strcmp(arg[0],"line_search") == 0) { if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); use_line_search = force->numeric(FLERR,arg[1]); + + if (nreplica > 1 && use_line_search) + error->all(FLERR,"Illegal fix_modify command, cannot use NEB and line search together"); + return 2; } if (strcmp(arg[0],"discrete_factor") == 0) { if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); double discrete_factor; discrete_factor = force->numeric(FLERR,arg[1]); - maxepsrot = MY_2PI / discrete_factor; + maxepsrot = MY_2PI / (10 * discrete_factor); return 2; } return 0; From 89bfe4acf23eb09e6c9ab04302fb1faef89106de Mon Sep 17 00:00:00 2001 From: alxvov Date: Mon, 22 Jul 2019 18:29:24 +0000 Subject: [PATCH 51/74] change convergence criteria in min_spin --- src/SPIN/min_spin.cpp | 42 +++++++++++++++++++++++++++++++++++++++++- src/SPIN/min_spin.h | 1 + 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/SPIN/min_spin.cpp b/src/SPIN/min_spin.cpp index 2277281e80..9849ba9946 100644 --- a/src/SPIN/min_spin.cpp +++ b/src/SPIN/min_spin.cpp @@ -167,7 +167,7 @@ int MinSpin::iterate(int maxiter) // sync across replicas if running multi-replica minimization if (update->ftol > 0.0) { - fmdotfm = fmnorm_sqr(); + fmdotfm = max_torque(); if (update->multireplica == 0) { if (fmdotfm < update->ftol*update->ftol) return FTOL; } else { @@ -331,3 +331,43 @@ double MinSpin::fmnorm_sqr() return norm2_sqr; } +/* ---------------------------------------------------------------------- + compute and return max_i||mag. torque_i||_2 +------------------------------------------------------------------------- */ + +double MinSpin::max_torque() +{ + double fmsq,fmaxsqone,fmaxsqloc,fmaxsqall; + int nlocal = atom->nlocal; + double hbar = force->hplanck/MY_2PI; + double tx,ty,tz; + double **sp = atom->sp; + double **fm = atom->fm; + + fmsq = fmaxsqone = fmaxsqloc = fmaxsqall = 0.0; + for (int i = 0; i < nlocal; i++) { + tx = fm[i][1] * sp[i][2] - fm[i][2] * sp[i][1]; + ty = fm[i][2] * sp[i][0] - fm[i][0] * sp[i][2]; + tz = fm[i][0] * sp[i][1] - fm[i][1] * sp[i][0]; + fmsq = tx * tx + ty * ty + tz * tz; + fmaxsqone = MAX(fmaxsqone,fmsq); + } + + // finding max fm on this replica + + fmaxsqloc = fmaxsqone; + MPI_Allreduce(&fmaxsqone,&fmaxsqloc,1,MPI_DOUBLE,MPI_MAX,world); + + // finding max fm over all replicas, if necessary + // this communicator would be invalid for multiprocess replicas + + fmaxsqall = fmaxsqloc; + if (update->multireplica == 1) { + fmaxsqall = fmaxsqloc; + MPI_Allreduce(&fmaxsqloc,&fmaxsqall,1,MPI_DOUBLE,MPI_MAX,universe->uworld); + } + + // multiply it by hbar so that units are in eV + + return sqrt(fmaxsqall) * hbar; +} diff --git a/src/SPIN/min_spin.h b/src/SPIN/min_spin.h index fbc624a9cc..d6d49203d5 100644 --- a/src/SPIN/min_spin.h +++ b/src/SPIN/min_spin.h @@ -36,6 +36,7 @@ class MinSpin : public Min { double evaluate_dt(); void advance_spins(double); double fmnorm_sqr(); + double max_torque(); private: From a9a2c7a496b38e4f30f6aa8389e6f7a58e13267c Mon Sep 17 00:00:00 2001 From: alxvov Date: Mon, 22 Jul 2019 18:31:14 +0000 Subject: [PATCH 52/74] no line search as default option for CG --- src/SPIN/min_spin_oso_cg.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index 21927d0d31..843f1e48f1 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -73,10 +73,7 @@ MinSpinOSO_CG::MinSpinOSO_CG(LAMMPS *lmp) : nreplica = universe->nworlds; ireplica = universe->iworld; - if (nreplica > 1) - use_line_search = 0; // no line search for NEB - else - use_line_search = 1; + use_line_search = 0; // no line search as default option for CG discrete_factor = 10.0; } From f0679cff6d87b0133f05833309af9c5d44468a0f Mon Sep 17 00:00:00 2001 From: julient31 Date: Tue, 23 Jul 2019 09:27:15 -0600 Subject: [PATCH 53/74] Commit JT 072319 - added 2 oso examples in examples/SPIN/spinmin - added doc for oso_cg and oso_lbfgs --- doc/src/lammps.book | 1 + doc/src/min_modify.txt | 22 +++++++-- doc/src/min_spin.txt | 36 +++++++++++++-- doc/src/min_style.txt | 19 +++++++- doc/src/minimize.txt | 3 +- doc/src/neb_spin.txt | 6 ++- doc/src/pair_spin_dipole.txt | 5 +- examples/SPIN/spinmin/in.spinmin_cg.bfo | 54 ++++++++++++++++++++++ examples/SPIN/spinmin/in.spinmin_lbfgs.bfo | 54 ++++++++++++++++++++++ src/SPIN/min_spin.cpp | 4 +- src/SPIN/min_spin_oso_cg.cpp | 12 ++--- src/SPIN/min_spin_oso_lbfgs.cpp | 16 +++---- 12 files changed, 200 insertions(+), 32 deletions(-) create mode 100644 examples/SPIN/spinmin/in.spinmin_cg.bfo create mode 100644 examples/SPIN/spinmin/in.spinmin_lbfgs.bfo diff --git a/doc/src/lammps.book b/doc/src/lammps.book index 2738c9b051..8abe9cffa1 100644 --- a/doc/src/lammps.book +++ b/doc/src/lammps.book @@ -647,6 +647,7 @@ pair_sph_lj.html pair_sph_rhosum.html pair_sph_taitwater.html pair_sph_taitwater_morris.html +pair_spin_dipole.html pair_spin_dmi.html pair_spin_exchange.html pair_spin_magelec.html diff --git a/doc/src/min_modify.txt b/doc/src/min_modify.txt index d342e8bf01..da7b593d16 100644 --- a/doc/src/min_modify.txt +++ b/doc/src/min_modify.txt @@ -13,11 +13,11 @@ min_modify command :h3 min_modify keyword values ... :pre one or more keyword/value pairs may be listed :ulb,l -keyword = {dmax} or {line} or {alpha_damp} or {discrete_factor} +keyword = {dmax} or {line} or {alpha_damp} or {discrete_factor} or {spin_cubic} or {spin_none} {dmax} value = max max = maximum distance for line search to move (distance units) - {line} value = {backtrack} or {quadratic} or {forcezero} - backtrack,quadratic,forcezero = style of linesearch to use + {line} value = {backtrack} or {quadratic} or {forcezero} or {spin_cubic} or {spin_none} + backtrack,quadratic,forcezero,spin_cubic,spin_none = style of linesearch to use {alpha_damp} value = damping damping = fictitious Gilbert damping for spin minimization (adim) {discrete_factor} value = factor @@ -80,7 +80,21 @@ See "min_spin"_min_spin.html for more information about those quantities. Default values are {alpha_damp} = 1.0 and {discrete_factor} = 10.0. -[Restrictions:] none +The choice of a line search algorithm for the {spin_oso_cg} and +{spin_oso_lbfgs} can be specified via the {line} keyword. +The {spin_cubic} and {spin_none} only make sense when those two +when one of those two minimization styles is declared. + +The {spin_cubic} keyword activates the line search procedure when +the {spin_oso_cg} algorithm is used. + +The {spin_none} keyword deactivates the line search procedure when +the {spin_oso_lbfgs} algorithm is used. + +[Restrictions:] The line search procedure of styles +{spin_oso_cg} and {spin_oso_lbfgs} cannot be used for magnetic +NEB calculations. See "neb/spin"_neb_spin.html for more +explanation. [Related commands:] diff --git a/doc/src/min_spin.txt b/doc/src/min_spin.txt index 890e324aca..6883a4197c 100644 --- a/doc/src/min_spin.txt +++ b/doc/src/min_spin.txt @@ -6,14 +6,19 @@ :line min_style spin command :h3 +min_style spin_oso_cg command :h3 +min_style spin_oso_lbfgs command :h3 [Syntax:] -min_style spin :pre +min_style spin +min_style spin_oso_cg +min_style spin_oso_lbfgs :pre [Examples:] -min_style spin :pre +min_style spin_oso_lbfgs +min_modify discrete_factor 10.0 line_search 0 :pre [Description:] @@ -46,9 +51,29 @@ definition of this timestep. {discrete_factor} can be defined with the "min_modify"_min_modify.html command. -NOTE: The {spin} style replaces the force tolerance by a torque +Style {spin_oso_cg} defines an orthogonal spin optimization +(OSO) combined to a conjugate gradient (CG) algorithm. +The "min_modify"_min_modify.html command can be used to +couple the {spin_oso_cg} to a line search procedure, and to modify the +discretization factor {discrete_factor}. + +Style {spin_oso_lbfgs} defines an orthogonal spin optimization +(OSO) combined to a limited-memory Broyden-Fletcher-Goldfarb-Shanno +(LBFGS) algorithm. +By default, style {spin_oso_lbfgs} uses a line search procedure. +The "min_modify"_min_modify.html command can be used to +deactivate the line search procedure. + +For more information about styles {spin_oso_cg} and {spin_oso_lbfgs}, +see their implementation reported in "(Ivanov)"_#Ivanov1. + +NOTE: All the {spin} styles replace the force tolerance by a torque tolerance. See "minimize"_minimize.html for more explanation. +NOTE: The {spin_oso_cg} and {spin_oso_lbfgs} styles can be used +for magnetic NEB calculations only if the line search procedure +is deactivated. See "neb/spin"_neb_spin.html for more explanation. + [Restrictions:] This minimization procedure is only applied to spin degrees of @@ -63,3 +88,8 @@ freedom for a frozen lattice configuration. The option defaults are {alpha_damp} = 1.0 and {discrete_factor} = 10.0. + +:line + +:link(Ivanov1) +[(Ivanov)] Ivanov, Uzdin, Jonsson. arXiv preprint arXiv:1904.02669, (2019). diff --git a/doc/src/min_style.txt b/doc/src/min_style.txt index c46c1492b4..081ec17889 100644 --- a/doc/src/min_style.txt +++ b/doc/src/min_style.txt @@ -11,7 +11,8 @@ min_style command :h3 min_style style :pre -style = {cg} or {hftn} or {sd} or {quickmin} or {fire} or {spin} :ul +style = {cg} or {hftn} or {sd} or {quickmin} or {fire} or {spin} +or {spin_oso_cg} or {spin_oso_lbfgs} :ul [Examples:] @@ -64,11 +65,25 @@ a minimization. Style {spin} is a damped spin dynamics with an adaptive timestep. -See the "min/spin"_min_spin.html doc page for more information. + +Style {spin_oso_cg} uses an orthogonal spin optimization (OSO) +combined to a conjugate gradient (CG) approach to minimize spin +configurations. + +Style {spin_oso_lbfgs} uses an orthogonal spin optimization (OSO) +combined to a limited-memory Broyden-Fletcher-Goldfarb-Shanno +(LBFGS) approach to minimize spin configurations. + +See the "min/spin"_min_spin.html doc page for more information +about the {spin}, {spin_oso_cg} and {spin_oso_lbfgs} styles. Either the {quickmin} and {fire} styles are useful in the context of nudged elastic band (NEB) calculations via the "neb"_neb.html command. +Either the {spin}, {spin_oso_cg} and {spin_oso_lbfgs} styles are useful +in the context of magnetic geodesic nudged elastic band (GNEB) calculations +via the "neb/spin"_neb_spin.html command. + NOTE: The damped dynamic minimizers use whatever timestep you have defined via the "timestep"_timestep.html command. Often they will converge more quickly if you use a timestep about 10x larger than you diff --git a/doc/src/minimize.txt b/doc/src/minimize.txt index ecf1ad0fcf..1dc28acdef 100644 --- a/doc/src/minimize.txt +++ b/doc/src/minimize.txt @@ -103,7 +103,8 @@ the line search fails because the step distance backtracks to 0.0 the number of outer iterations or timesteps exceeds {maxiter} the number of total force evaluations exceeds {maxeval} :ul -NOTE: the "minimization style"_min_style.html {spin} replaces +NOTE: the "minimization style"_min_style.html {spin}, +{spin_oso_cg}, and {spin_oso_lbfgs} replace the force tolerance {ftol} by a torque tolerance. The minimization procedure stops if the 2-norm (length) of the global torque vector (defined as the cross product between the diff --git a/doc/src/neb_spin.txt b/doc/src/neb_spin.txt index 7dbd924cd2..46478b1219 100644 --- a/doc/src/neb_spin.txt +++ b/doc/src/neb_spin.txt @@ -172,7 +172,8 @@ command is issued. A NEB calculation proceeds in two stages, each of which is a minimization procedure, performed via damped dynamics. To enable this, you must first define a damped spin dynamics -"min_style"_min_style.html, using the {spin} style (see +"min_style"_min_style.html, using either the {spin}, +{spin_oso_cg}, or {spin_oso_lbfgs} style (see "min_spin"_min_spin.html for more information). The other styles cannot be used, since they relax the lattice degrees of freedom instead of the spins. @@ -358,6 +359,9 @@ This command can only be used if LAMMPS was built with the SPIN package. See the "Build package"_Build_package.html doc page for more info. +The line search procedures of the {spin_oso_cg} and {spin_oso_lbfgs} +minimization styles cannot be used in a GNEB calculation. + :line [Related commands:] diff --git a/doc/src/pair_spin_dipole.txt b/doc/src/pair_spin_dipole.txt index 0d6471e07f..735c71139a 100644 --- a/doc/src/pair_spin_dipole.txt +++ b/doc/src/pair_spin_dipole.txt @@ -25,9 +25,8 @@ pair_coeff * * 10.0 pair_coeff 2 3 8.0 :pre pair_style spin/dipole/long 9.0 -pair_coeff * * 1.0 1.0 -pair_coeff 2 3 1.0 1.0 2.5 4.0 scale 0.5 -pair_coeff 2 3 1.0 1.0 2.5 4.0 :pre +pair_coeff * * 10.0 +pair_coeff 2 3 6.0 :pre [Description:] diff --git a/examples/SPIN/spinmin/in.spinmin_cg.bfo b/examples/SPIN/spinmin/in.spinmin_cg.bfo new file mode 100644 index 0000000000..cd6ec485ad --- /dev/null +++ b/examples/SPIN/spinmin/in.spinmin_cg.bfo @@ -0,0 +1,54 @@ +# bfo in a 3d periodic box + +units metal +dimension 3 +boundary p p f +atom_style spin + +# necessary for the serial algorithm (sametag) +atom_modify map array + +lattice sc 3.96 +region box block 0.0 34.0 0.0 34.0 0.0 1.0 +create_box 1 box +create_atoms 1 box + +# setting mass, mag. moments, and interactions for bcc iron + +mass 1 1.0 +set group all spin/random 11 2.50 + +pair_style hybrid/overlay spin/exchange 6.0 spin/magelec 4.5 spin/dmi 4.5 +pair_coeff * * spin/exchange exchange 6.0 -0.01575 0.0 1.965 +# pair_coeff * * spin/magelec magelec 4.5 0.000109 1.0 1.0 1.0 +pair_coeff * * spin/magelec magelec 4.5 0.00109 1.0 1.0 1.0 +pair_coeff * * spin/dmi dmi 4.5 0.00005 1.0 1.0 1.0 + +neighbor 0.1 bin +neigh_modify every 10 check yes delay 20 + +fix 1 all precession/spin anisotropy 0.0000033 0.0 0.0 1.0 +fix_modify 1 energy yes + +timestep 0.0001 + +compute out_mag all spin +compute out_pe all pe +compute out_ke all ke +compute out_temp all temp + +variable magz equal c_out_mag[3] +variable magnorm equal c_out_mag[4] +variable emag equal c_out_mag[5] +variable tmag equal c_out_mag[6] + +thermo 50 +thermo_style custom step time v_magnorm v_emag v_tmag temp etotal +thermo_modify format float %20.15g + +compute outsp all property/atom spx spy spz sp fmx fmy fmz +dump 1 all custom 50 dump.lammpstrj type x y z c_outsp[1] c_outsp[2] c_outsp[3] c_outsp[4] c_outsp[5] c_outsp[6] c_outsp[7] + +min_style spin/oso_cg +min_modify discrete_factor 10.0 line_search 0 +minimize 1.0e-10 1.0e-10 10000 1000 diff --git a/examples/SPIN/spinmin/in.spinmin_lbfgs.bfo b/examples/SPIN/spinmin/in.spinmin_lbfgs.bfo new file mode 100644 index 0000000000..5db44522e1 --- /dev/null +++ b/examples/SPIN/spinmin/in.spinmin_lbfgs.bfo @@ -0,0 +1,54 @@ +# bfo in a 3d periodic box + +units metal +dimension 3 +boundary p p f +atom_style spin + +# necessary for the serial algorithm (sametag) +atom_modify map array + +lattice sc 3.96 +region box block 0.0 34.0 0.0 34.0 0.0 1.0 +create_box 1 box +create_atoms 1 box + +# setting mass, mag. moments, and interactions for bcc iron + +mass 1 1.0 +set group all spin/random 11 2.50 + +pair_style hybrid/overlay spin/exchange 6.0 spin/magelec 4.5 spin/dmi 4.5 +pair_coeff * * spin/exchange exchange 6.0 -0.01575 0.0 1.965 +#pair_coeff * * spin/magelec magelec 4.5 0.000109 1.0 1.0 1.0 +pair_coeff * * spin/magelec magelec 4.5 0.00109 1.0 1.0 1.0 +pair_coeff * * spin/dmi dmi 4.5 0.00005 1.0 1.0 1.0 + +neighbor 0.1 bin +neigh_modify every 10 check yes delay 20 + +fix 1 all precession/spin anisotropy 0.0000033 0.0 0.0 1.0 +fix_modify 1 energy yes + +timestep 0.0001 + +compute out_mag all spin +compute out_pe all pe +compute out_ke all ke +compute out_temp all temp + +variable magz equal c_out_mag[3] +variable magnorm equal c_out_mag[4] +variable emag equal c_out_mag[5] +variable tmag equal c_out_mag[6] + +thermo 50 +thermo_style custom step time v_magnorm v_emag v_tmag temp etotal +thermo_modify format float %20.15g + +compute outsp all property/atom spx spy spz sp fmx fmy fmz +dump 1 all custom 50 dump.lammpstrj type x y z c_outsp[1] c_outsp[2] c_outsp[3] c_outsp[4] c_outsp[5] c_outsp[6] c_outsp[7] + +min_style spin/oso_lbfgs +min_modify discrete_factor 10.0 line_search 1 +minimize 1.0e-15 1.0e-10 10000 1000 diff --git a/src/SPIN/min_spin.cpp b/src/SPIN/min_spin.cpp index 9849ba9946..f56c9f0d96 100644 --- a/src/SPIN/min_spin.cpp +++ b/src/SPIN/min_spin.cpp @@ -80,12 +80,12 @@ void MinSpin::setup_style() int MinSpin::modify_param(int narg, char **arg) { if (strcmp(arg[0],"alpha_damp") == 0) { - if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); + if (narg < 2) error->all(FLERR,"Illegal min_modify command"); alpha_damp = force->numeric(FLERR,arg[1]); return 2; } if (strcmp(arg[0],"discrete_factor") == 0) { - if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); + if (narg < 2) error->all(FLERR,"Illegal min_modify command"); discrete_factor = force->numeric(FLERR,arg[1]); return 2; } diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index 843f1e48f1..e43c51e3af 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -133,12 +133,10 @@ void MinSpinOSO_CG::setup_style() int MinSpinOSO_CG::modify_param(int narg, char **arg) { if (strcmp(arg[0],"line_search") == 0) { - if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); + if (narg < 2) error->all(FLERR,"Illegal min_modify command"); use_line_search = force->numeric(FLERR,arg[1]); - if (nreplica > 1 && use_line_search) error->all(FLERR,"Illegal fix_modify command, cannot use NEB and line search together"); - return 2; } if (strcmp(arg[0],"discrete_factor") == 0) { @@ -250,9 +248,9 @@ int MinSpinOSO_CG::iterate(int maxiter) neval++; } - //// energy tolerance criterion - //// only check after DELAYSTEP elapsed since velocties reset to 0 - //// sync across replicas if running multi-replica minimization + // energy tolerance criterion + // only check after DELAYSTEP elapsed since velocties reset to 0 + // sync across replicas if running multi-replica minimization if (update->etol > 0.0 && ntimestep-last_negative > DELAYSTEP) { if (update->multireplica == 0) { @@ -680,4 +678,4 @@ double MinSpinOSO_CG::evaluate_dt() dtmax = MY_2PI/(discrete_factor*sqrt(fmaxsqall)); return dtmax; -} \ No newline at end of file +} diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index eba62f296f..0bd128367f 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -145,16 +145,14 @@ int MinSpinOSO_LBFGS::modify_param(int narg, char **arg) { if (strcmp(arg[0],"line_search") == 0) { - if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); + if (narg < 2) error->all(FLERR,"Illegal min_modify command"); use_line_search = force->numeric(FLERR,arg[1]); - if (nreplica > 1 && use_line_search) - error->all(FLERR,"Illegal fix_modify command, cannot use NEB and line search together"); - + error->all(FLERR,"Illegal min_modify command, cannot use NEB and line search together"); return 2; } if (strcmp(arg[0],"discrete_factor") == 0) { - if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); + if (narg < 2) error->all(FLERR,"Illegal min_modify command"); double discrete_factor; discrete_factor = force->numeric(FLERR,arg[1]); maxepsrot = MY_2PI / (10 * discrete_factor); @@ -266,9 +264,9 @@ int MinSpinOSO_LBFGS::iterate(int maxiter) neval++; } - //// energy tolerance criterion - //// only check after DELAYSTEP elapsed since velocties reset to 0 - //// sync across replicas if running multi-replica minimization + // energy tolerance criterion + // only check after DELAYSTEP elapsed since velocties reset to 0 + // sync across replicas if running multi-replica minimization if (update->etol > 0.0 && ntimestep-last_negative > DELAYSTEP) { if (update->multireplica == 0) { @@ -802,4 +800,4 @@ double MinSpinOSO_LBFGS::maximum_rotation(double *p) else alpha = 1.0; return alpha; -} \ No newline at end of file +} From f1c3b9d0bf3fd4f27711e81eb11dbb70d79da5fb Mon Sep 17 00:00:00 2001 From: julient31 Date: Tue, 23 Jul 2019 11:24:52 -0600 Subject: [PATCH 54/74] Commit2 JT 072319 - corrected some mistakes in doc files - modified oso examples to match new line options --- doc/src/min_modify.txt | 10 +++++----- doc/src/min_spin.txt | 5 +++-- doc/src/neb_spin.txt | 4 ++-- examples/SPIN/spinmin/in.spinmin_cg.bfo | 2 +- examples/SPIN/spinmin/in.spinmin_lbfgs.bfo | 2 +- src/SPIN/neb_spin.cpp | 2 +- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/doc/src/min_modify.txt b/doc/src/min_modify.txt index da7b593d16..c59e2b474b 100644 --- a/doc/src/min_modify.txt +++ b/doc/src/min_modify.txt @@ -13,7 +13,7 @@ min_modify command :h3 min_modify keyword values ... :pre one or more keyword/value pairs may be listed :ulb,l -keyword = {dmax} or {line} or {alpha_damp} or {discrete_factor} or {spin_cubic} or {spin_none} +keyword = {dmax} or {line} or {alpha_damp} or {discrete_factor} {dmax} value = max max = maximum distance for line search to move (distance units) {line} value = {backtrack} or {quadratic} or {forcezero} or {spin_cubic} or {spin_none} @@ -81,9 +81,9 @@ quantities. Default values are {alpha_damp} = 1.0 and {discrete_factor} = 10.0. The choice of a line search algorithm for the {spin_oso_cg} and -{spin_oso_lbfgs} can be specified via the {line} keyword. -The {spin_cubic} and {spin_none} only make sense when those two -when one of those two minimization styles is declared. +{spin_oso_lbfgs} styles can be specified via the {line} keyword. +The {spin_cubic} and {spin_none} only make sense when one of those +two minimization styles is declared. The {spin_cubic} keyword activates the line search procedure when the {spin_oso_cg} algorithm is used. @@ -93,7 +93,7 @@ the {spin_oso_lbfgs} algorithm is used. [Restrictions:] The line search procedure of styles {spin_oso_cg} and {spin_oso_lbfgs} cannot be used for magnetic -NEB calculations. See "neb/spin"_neb_spin.html for more +GNEB calculations. See "neb/spin"_neb_spin.html for more explanation. [Related commands:] diff --git a/doc/src/min_spin.txt b/doc/src/min_spin.txt index 6883a4197c..2a85427c56 100644 --- a/doc/src/min_spin.txt +++ b/doc/src/min_spin.txt @@ -18,7 +18,7 @@ min_style spin_oso_lbfgs :pre [Examples:] min_style spin_oso_lbfgs -min_modify discrete_factor 10.0 line_search 0 :pre +min_modify discrete_factor 10.0 line spin_none :pre [Description:] @@ -62,7 +62,8 @@ Style {spin_oso_lbfgs} defines an orthogonal spin optimization (LBFGS) algorithm. By default, style {spin_oso_lbfgs} uses a line search procedure. The "min_modify"_min_modify.html command can be used to -deactivate the line search procedure. +deactivate the line search procedure, and to modify the +discretization factor {discrete_factor}. For more information about styles {spin_oso_cg} and {spin_oso_lbfgs}, see their implementation reported in "(Ivanov)"_#Ivanov1. diff --git a/doc/src/neb_spin.txt b/doc/src/neb_spin.txt index 46478b1219..27e835276e 100644 --- a/doc/src/neb_spin.txt +++ b/doc/src/neb_spin.txt @@ -60,8 +60,8 @@ processors per replica. See the "Howto replica"_Howto_replica.html doc page for further discussion. NOTE: As explained below, a GNEB calculation performs a damped dynamics -minimization across all the replicas. The "spin"_min_spin.html -style minimizer has to be defined in your input script. +minimization across all the replicas. One of the "spin"_min_spin.html +style minimizers has to be defined in your input script. When a GNEB calculation is performed, it is assumed that each replica is running the same system, though LAMMPS does not check for this. diff --git a/examples/SPIN/spinmin/in.spinmin_cg.bfo b/examples/SPIN/spinmin/in.spinmin_cg.bfo index cd6ec485ad..901b04e5fd 100644 --- a/examples/SPIN/spinmin/in.spinmin_cg.bfo +++ b/examples/SPIN/spinmin/in.spinmin_cg.bfo @@ -50,5 +50,5 @@ compute outsp all property/atom spx spy spz sp fmx fmy fmz dump 1 all custom 50 dump.lammpstrj type x y z c_outsp[1] c_outsp[2] c_outsp[3] c_outsp[4] c_outsp[5] c_outsp[6] c_outsp[7] min_style spin/oso_cg -min_modify discrete_factor 10.0 line_search 0 +min_modify discrete_factor 10.0 line spin_cubic minimize 1.0e-10 1.0e-10 10000 1000 diff --git a/examples/SPIN/spinmin/in.spinmin_lbfgs.bfo b/examples/SPIN/spinmin/in.spinmin_lbfgs.bfo index 5db44522e1..4edd1a053e 100644 --- a/examples/SPIN/spinmin/in.spinmin_lbfgs.bfo +++ b/examples/SPIN/spinmin/in.spinmin_lbfgs.bfo @@ -50,5 +50,5 @@ compute outsp all property/atom spx spy spz sp fmx fmy fmz dump 1 all custom 50 dump.lammpstrj type x y z c_outsp[1] c_outsp[2] c_outsp[3] c_outsp[4] c_outsp[5] c_outsp[6] c_outsp[7] min_style spin/oso_lbfgs -min_modify discrete_factor 10.0 line_search 1 +min_modify discrete_factor 10.0 line spin_none minimize 1.0e-15 1.0e-10 10000 1000 diff --git a/src/SPIN/neb_spin.cpp b/src/SPIN/neb_spin.cpp index 12d1d2a956..4fa1f4467b 100644 --- a/src/SPIN/neb_spin.cpp +++ b/src/SPIN/neb_spin.cpp @@ -650,7 +650,7 @@ int NEBSpin::initial_rotation(double *spi, double *sploc, double fraction) kcrossy = kz*spix - kx*spiz; kcrossz = kx*spiy - ky*spix; - kdots = kx*spix + ky*spiz + kz*spiz; + kdots = kx*spix + ky*spiy + kz*spiz; omega = acos(sidotsf); omega *= fraction; From f9ed12be4f0ff547661a6dffe420b67c76655379 Mon Sep 17 00:00:00 2001 From: alxvov Date: Wed, 24 Jul 2019 23:21:07 +0000 Subject: [PATCH 55/74] modify line for spin_cubic, spin_none. edit docs a bit. --- doc/src/min_modify.txt | 12 ++-- doc/src/min_spin.txt | 17 ++++-- doc/src/minimize.txt | 8 +-- doc/src/neb_spin.txt | 6 +- examples/SPIN/spinmin/in.spinmin_cg.bfo | 8 +-- examples/SPIN/spinmin/in.spinmin_lbfgs.bfo | 6 +- src/MAKE/Makefile.serial | 2 +- src/SPIN/min_spin_oso_cg.cpp | 64 +++++++++++----------- src/SPIN/min_spin_oso_cg.h | 4 +- src/SPIN/min_spin_oso_lbfgs.cpp | 48 +++++++--------- src/SPIN/min_spin_oso_lbfgs.h | 2 +- 11 files changed, 89 insertions(+), 88 deletions(-) diff --git a/doc/src/min_modify.txt b/doc/src/min_modify.txt index c59e2b474b..9c4d7c8fcb 100644 --- a/doc/src/min_modify.txt +++ b/doc/src/min_modify.txt @@ -84,12 +84,12 @@ The choice of a line search algorithm for the {spin_oso_cg} and {spin_oso_lbfgs} styles can be specified via the {line} keyword. The {spin_cubic} and {spin_none} only make sense when one of those two minimization styles is declared. - -The {spin_cubic} keyword activates the line search procedure when -the {spin_oso_cg} algorithm is used. - -The {spin_none} keyword deactivates the line search procedure when -the {spin_oso_lbfgs} algorithm is used. +The {spin_cubic} performs the line search based on a cubic interpolation +of the energy along the search direction. The {spin_none} keyword +deactivates the line search procedure. +The {spin_none} is a default value for {line} keyword apart from the case when +single-replica calculations are performed with {spin_oso_lbfgs} that +uses {spin_cubic} line search. [Restrictions:] The line search procedure of styles {spin_oso_cg} and {spin_oso_lbfgs} cannot be used for magnetic diff --git a/doc/src/min_spin.txt b/doc/src/min_spin.txt index 2a85427c56..77dc008b3e 100644 --- a/doc/src/min_spin.txt +++ b/doc/src/min_spin.txt @@ -18,7 +18,7 @@ min_style spin_oso_lbfgs :pre [Examples:] min_style spin_oso_lbfgs -min_modify discrete_factor 10.0 line spin_none :pre +min_modify line spin_none discrete_factor 10.0 :pre [Description:] @@ -55,12 +55,21 @@ Style {spin_oso_cg} defines an orthogonal spin optimization (OSO) combined to a conjugate gradient (CG) algorithm. The "min_modify"_min_modify.html command can be used to couple the {spin_oso_cg} to a line search procedure, and to modify the -discretization factor {discrete_factor}. +discretization factor {discrete_factor}. +By defualt, the style {spin_oso_cg} does not employ line search procedure and +and uses the adaptive time-step technique in the same way as style {spin}. Style {spin_oso_lbfgs} defines an orthogonal spin optimization (OSO) combined to a limited-memory Broyden-Fletcher-Goldfarb-Shanno -(LBFGS) algorithm. -By default, style {spin_oso_lbfgs} uses a line search procedure. +(L-BFGS) algorithm. +By default, style {spin_oso_lbfgs} uses a line search procedure +based on cubic interpolation for +a single-replica calculation, and it does not use line search procedure +for a multireplica calculation (such as in case of GNEB calculation). +If the line search procedure is not used then the discrete factor defines +the maximum root mean squared rotation angle of spins by equation {pi/(5*Kappa)}. +The default value for Kappa is 10. + The "min_modify"_min_modify.html command can be used to deactivate the line search procedure, and to modify the discretization factor {discrete_factor}. diff --git a/doc/src/minimize.txt b/doc/src/minimize.txt index 1dc28acdef..1de925d6c8 100644 --- a/doc/src/minimize.txt +++ b/doc/src/minimize.txt @@ -106,10 +106,10 @@ the number of total force evaluations exceeds {maxeval} :ul NOTE: the "minimization style"_min_style.html {spin}, {spin_oso_cg}, and {spin_oso_lbfgs} replace the force tolerance {ftol} by a torque tolerance. -The minimization procedure stops if the 2-norm (length) of the -global torque vector (defined as the cross product between the -spins and their precession vectors omega) is less than {ftol}, -or if any of the other criteria are met. +The minimization procedure stops if the 2-norm (length) of the torque vector on atom +(defined as the cross product between the +atomic spin and its precession vectors omega) is less than {ftol}, +or if any of the other criteria are met. Torque have the same units as the energy. NOTE: You can also use the "fix halt"_fix_halt.html command to specify a general criterion for exiting a minimization, that is a calculation diff --git a/doc/src/neb_spin.txt b/doc/src/neb_spin.txt index 27e835276e..2fdfda8c66 100644 --- a/doc/src/neb_spin.txt +++ b/doc/src/neb_spin.txt @@ -59,7 +59,7 @@ performance speed-up you would see with one or more physical processors per replica. See the "Howto replica"_Howto_replica.html doc page for further discussion. -NOTE: As explained below, a GNEB calculation performs a damped dynamics +NOTE: As explained below, a GNEB calculation performs a minimization across all the replicas. One of the "spin"_min_spin.html style minimizers has to be defined in your input script. @@ -170,8 +170,8 @@ command is issued. :line A NEB calculation proceeds in two stages, each of which is a -minimization procedure, performed via damped dynamics. To enable -this, you must first define a damped spin dynamics +minimization procedure. To enable +this, you must first define a "min_style"_min_style.html, using either the {spin}, {spin_oso_cg}, or {spin_oso_lbfgs} style (see "min_spin"_min_spin.html for more information). diff --git a/examples/SPIN/spinmin/in.spinmin_cg.bfo b/examples/SPIN/spinmin/in.spinmin_cg.bfo index 901b04e5fd..776079edb8 100644 --- a/examples/SPIN/spinmin/in.spinmin_cg.bfo +++ b/examples/SPIN/spinmin/in.spinmin_cg.bfo @@ -42,13 +42,13 @@ variable magnorm equal c_out_mag[4] variable emag equal c_out_mag[5] variable tmag equal c_out_mag[6] -thermo 50 +thermo 100 thermo_style custom step time v_magnorm v_emag v_tmag temp etotal thermo_modify format float %20.15g compute outsp all property/atom spx spy spz sp fmx fmy fmz dump 1 all custom 50 dump.lammpstrj type x y z c_outsp[1] c_outsp[2] c_outsp[3] c_outsp[4] c_outsp[5] c_outsp[6] c_outsp[7] -min_style spin/oso_cg -min_modify discrete_factor 10.0 line spin_cubic -minimize 1.0e-10 1.0e-10 10000 1000 +min_style spin_oso_cg +# min_modify line spin_none discrete_factor 10.0 +minimize 1.0e-10 1.0e-7 1000 1000 diff --git a/examples/SPIN/spinmin/in.spinmin_lbfgs.bfo b/examples/SPIN/spinmin/in.spinmin_lbfgs.bfo index 4edd1a053e..ca600f1c2b 100644 --- a/examples/SPIN/spinmin/in.spinmin_lbfgs.bfo +++ b/examples/SPIN/spinmin/in.spinmin_lbfgs.bfo @@ -49,6 +49,6 @@ thermo_modify format float %20.15g compute outsp all property/atom spx spy spz sp fmx fmy fmz dump 1 all custom 50 dump.lammpstrj type x y z c_outsp[1] c_outsp[2] c_outsp[3] c_outsp[4] c_outsp[5] c_outsp[6] c_outsp[7] -min_style spin/oso_lbfgs -min_modify discrete_factor 10.0 line spin_none -minimize 1.0e-15 1.0e-10 10000 1000 +min_style spin_oso_lbfgs +min_modify line spin_cubic discrete_factor 10.0 +minimize 1.0e-15 1.0e-7 10000 1000 diff --git a/src/MAKE/Makefile.serial b/src/MAKE/Makefile.serial index 5954d97761..8628d2bb73 100644 --- a/src/MAKE/Makefile.serial +++ b/src/MAKE/Makefile.serial @@ -7,7 +7,7 @@ SHELL = /bin/sh # specify flags and libraries needed for your compiler CC = g++ -CCFLAGS = -g -O3 +CCFLAGS = -g -O3 -Wall SHFLAGS = -fPIC DEPFLAGS = -M diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index e43c51e3af..2bdc00d8ed 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -63,7 +63,7 @@ static const char cite_minstyle_spin_oso_cg[] = /* ---------------------------------------------------------------------- */ MinSpinOSO_CG::MinSpinOSO_CG(LAMMPS *lmp) : - Min(lmp), g_old(NULL), g_cur(NULL), p_s(NULL) + Min(lmp), g_old(NULL), g_cur(NULL), p_s(NULL), sp_copy(NULL) { if (lmp->citeme) lmp->citeme->add(cite_minstyle_spin_oso_cg); nlocal_max = 0; @@ -99,6 +99,13 @@ void MinSpinOSO_CG::init() Min::init(); + if (linestyle == 3 && nreplica == 1){ + use_line_search = 1; + } + else{ + use_line_search = 0; + } + dts = dt = update->dt; last_negative = update->ntimestep; @@ -132,13 +139,6 @@ void MinSpinOSO_CG::setup_style() int MinSpinOSO_CG::modify_param(int narg, char **arg) { - if (strcmp(arg[0],"line_search") == 0) { - if (narg < 2) error->all(FLERR,"Illegal min_modify command"); - use_line_search = force->numeric(FLERR,arg[1]); - if (nreplica > 1 && use_line_search) - error->all(FLERR,"Illegal fix_modify command, cannot use NEB and line search together"); - return 2; - } if (strcmp(arg[0],"discrete_factor") == 0) { if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); discrete_factor = force->numeric(FLERR,arg[1]); @@ -181,7 +181,6 @@ int MinSpinOSO_CG::iterate(int maxiter) double der_e_cur_tmp = 0.0; if (nlocal_max < nlocal) { - nlocal_max = nlocal; local_iter = 0; nlocal_max = nlocal; memory->grow(g_old,3*nlocal_max,"min/spin/oso/cg:g_old"); @@ -205,8 +204,9 @@ int MinSpinOSO_CG::iterate(int maxiter) if (use_line_search) { // here we need to do line search - if (local_iter == 0) + if (local_iter == 0){ calc_gradient(); + } calc_search_direction(); der_e_cur = 0.0; @@ -219,7 +219,7 @@ int MinSpinOSO_CG::iterate(int maxiter) } for (int i = 0; i < nlocal; i++) for (int j = 0; j < 3; j++) - sp_copy[i][j] = sp[i][j]; + sp_copy[i][j] = sp[i][j]; eprevious = ecurrent; der_e_pr = der_e_cur; @@ -228,24 +228,15 @@ int MinSpinOSO_CG::iterate(int maxiter) else{ // here we don't do line search - // but use cutoff rotation angle // if gneb calc., nreplica > 1 // then calculate gradients and advance spins // of intermediate replicas only - - if (nreplica > 1) { - if(ireplica != 0 && ireplica != nreplica-1) calc_gradient(); calc_search_direction(); advance_spins(); - } else{ - calc_gradient(); - calc_search_direction(); - advance_spins(); - } + neval++; eprevious = ecurrent; ecurrent = energy_force(0); - neval++; } // energy tolerance criterion @@ -336,10 +327,18 @@ void MinSpinOSO_CG::calc_search_direction() double g2_global = 0.0; double g2old_global = 0.0; + double factor = 1.0; + + // for multiple replica do not move end points + if (nreplica > 1) + if (ireplica == 0 || ireplica == nreplica - 1) + factor = 0.0; + + if (local_iter == 0 || local_iter % 5 == 0){ // steepest descent direction for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = -g_cur[i]; - g_old[i] = g_cur[i]; + p_s[i] = -g_cur[i] * factor; + g_old[i] = g_cur[i] * factor; } } else { // conjugate direction for (int i = 0; i < 3 * nlocal; i++) { @@ -354,9 +353,9 @@ void MinSpinOSO_CG::calc_search_direction() MPI_Allreduce(&g2old,&g2old_global,1,MPI_DOUBLE,MPI_SUM,world); // Sum over all replicas. Good for GNEB. - if (update->multireplica == 1) { - g2 = g2_global; - g2old = g2old_global; + if (nreplica > 1) { + g2 = g2_global * factor; + g2old = g2old_global * factor; MPI_Allreduce(&g2,&g2_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); MPI_Allreduce(&g2old,&g2old_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); } @@ -364,8 +363,8 @@ void MinSpinOSO_CG::calc_search_direction() else beta = g2_global / g2old_global; // calculate conjugate direction for (int i = 0; i < 3 * nlocal; i++) { - p_s[i] = (beta * p_s[i] - g_cur[i]); - g_old[i] = g_cur[i]; + p_s[i] = (beta * p_s[i] - g_cur[i]) * factor; + g_old[i] = g_cur[i] * factor; } } @@ -380,8 +379,6 @@ void MinSpinOSO_CG::advance_spins() { int nlocal = atom->nlocal; double **sp = atom->sp; - double **fm = atom->fm; - double tdampx, tdampy, tdampz; double rot_mat[9]; // exponential of matrix made of search direction double s_new[3]; @@ -477,7 +474,7 @@ void MinSpinOSO_CG::rodrigues_rotation(const double *upp_tr, double *out) A = cos(theta); B = sin(theta); - D = 1 - A; + D = 1.0 - A; x = upp_tr[0]/theta; y = upp_tr[1]/theta; z = upp_tr[2]/theta; @@ -529,7 +526,7 @@ void MinSpinOSO_CG::make_step(double c, double *energy_and_der) double rot_mat[9]; // exponential of matrix made of search direction double s_new[3]; double **sp = atom->sp; - double der_e_cur_tmp = 0.0;; + double der_e_cur_tmp = 0.0; for (int i = 0; i < nlocal; i++) { @@ -629,7 +626,8 @@ int MinSpinOSO_CG::awc(double der_phi_0, double phi_0, double der_phi_j, double double delta = 0.1; double sigma = 0.9; - if ((phi_j<=phi_0+eps*fabs(phi_0)) && ((2.0*delta-1.0) * der_phi_0>=der_phi_j>=sigma*der_phi_0)) + if ((phi_j<=phi_0+eps*fabs(phi_0)) && + ((2.0*delta-1.0) * der_phi_0>=der_phi_j>=sigma*der_phi_0)) return 1; else return 0; diff --git a/src/SPIN/min_spin_oso_cg.h b/src/SPIN/min_spin_oso_cg.h index e50d1a69db..41253f440f 100644 --- a/src/SPIN/min_spin_oso_cg.h +++ b/src/SPIN/min_spin_oso_cg.h @@ -13,7 +13,7 @@ #ifdef MINIMIZE_CLASS -MinimizeStyle(spin/oso_cg, MinSpinOSO_CG) +MinimizeStyle(spin_oso_cg, MinSpinOSO_CG) #else @@ -39,8 +39,8 @@ class MinSpinOSO_CG: public Min { int ireplica,nreplica; // for neb double *spvec; // variables for atomic dof, as 1d vector double *fmvec; // variables for atomic dof, as 1d vector - double *g_cur; // current gradient vector double *g_old; // gradient vector at previous step + double *g_cur; // current gradient vector double *p_s; // search direction vector double **sp_copy; // copy of the spins int local_iter; // for neb diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index 0bd128367f..6aaeb7ca23 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -107,6 +107,13 @@ void MinSpinOSO_LBFGS::init() Min::init(); + if (linestyle != 4 && nreplica == 1){ + use_line_search = 1; + } + else{ + use_line_search = 0; + } + last_negative = update->ntimestep; // allocate tables @@ -143,14 +150,6 @@ void MinSpinOSO_LBFGS::setup_style() int MinSpinOSO_LBFGS::modify_param(int narg, char **arg) { - - if (strcmp(arg[0],"line_search") == 0) { - if (narg < 2) error->all(FLERR,"Illegal min_modify command"); - use_line_search = force->numeric(FLERR,arg[1]); - if (nreplica > 1 && use_line_search) - error->all(FLERR,"Illegal min_modify command, cannot use NEB and line search together"); - return 2; - } if (strcmp(arg[0],"discrete_factor") == 0) { if (narg < 2) error->all(FLERR,"Illegal min_modify command"); double discrete_factor; @@ -221,8 +220,11 @@ int MinSpinOSO_LBFGS::iterate(int maxiter) if (use_line_search) { // here we need to do line search - if (local_iter == 0) + if (local_iter == 0){ + eprevious = ecurrent; + ecurrent = energy_force(0); calc_gradient(); + } calc_search_direction(); der_e_cur = 0.0; @@ -248,19 +250,11 @@ int MinSpinOSO_LBFGS::iterate(int maxiter) // if gneb calc., nreplica > 1 // then calculate gradients and advance spins // of intermediate replicas only - - if (nreplica > 1) { - if(ireplica != 0 && ireplica != nreplica-1) - calc_gradient(); - calc_search_direction(); - advance_spins(); - } else{ - calc_gradient(); - calc_search_direction(); - advance_spins(); - } eprevious = ecurrent; ecurrent = energy_force(0); + calc_gradient(); + calc_search_direction(); + advance_spins(); neval++; } @@ -398,7 +392,7 @@ void MinSpinOSO_LBFGS::calc_search_direction() } MPI_Allreduce(&dyds, &dyds_global, 1, MPI_DOUBLE, MPI_SUM, world); - if (update->multireplica == 1) { + if (nreplica > 1) { dyds_global *= factor; dyds = dyds_global; MPI_Allreduce(&dyds, &dyds_global, 1,MPI_DOUBLE,MPI_SUM,universe->uworld); @@ -437,7 +431,7 @@ void MinSpinOSO_LBFGS::calc_search_direction() sq += ds[c_ind][i] * q[i]; } MPI_Allreduce(&sq,&sq_global,1,MPI_DOUBLE,MPI_SUM,world); - if (update->multireplica == 1) { + if (nreplica > 1) { sq_global *= factor; sq = sq_global; MPI_Allreduce(&sq,&sq_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); @@ -460,7 +454,7 @@ void MinSpinOSO_LBFGS::calc_search_direction() yy += dy[m_index][i] * dy[m_index][i]; } MPI_Allreduce(&yy,&yy_global,1,MPI_DOUBLE,MPI_SUM,world); - if (update->multireplica == 1) { + if (nreplica > 1) { yy_global *= factor; yy = yy_global; MPI_Allreduce(&yy,&yy_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); @@ -493,7 +487,7 @@ void MinSpinOSO_LBFGS::calc_search_direction() } MPI_Allreduce(&yr,&yr_global,1,MPI_DOUBLE,MPI_SUM,world); - if (update->multireplica == 1) { + if (nreplica > 1) { yr_global *= factor; yr = yr_global; MPI_Allreduce(&yr,&yr_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); @@ -668,7 +662,7 @@ void MinSpinOSO_LBFGS::make_step(double c, double *energy_and_der) double rot_mat[9]; // exponential of matrix made of search direction double s_new[3]; double **sp = atom->sp; - double der_e_cur_tmp = 0.0;; + double der_e_cur_tmp = 0.0; for (int i = 0; i < nlocal; i++) { @@ -784,12 +778,12 @@ double MinSpinOSO_LBFGS::maximum_rotation(double *p) for (int i = 0; i < 3 * nlocal; i++) norm2 += p[i] * p[i]; MPI_Allreduce(&norm2,&norm2_global,1,MPI_DOUBLE,MPI_SUM,world); - if (update->multireplica == 1) { + if (nreplica > 1) { norm2 = norm2_global; MPI_Allreduce(&norm2,&norm2_global,1,MPI_DOUBLE,MPI_SUM,universe->uworld); } MPI_Allreduce(&nlocal,&ntotal,1,MPI_INT,MPI_SUM,world); - if (update->multireplica == 1) { + if (nreplica > 1) { nlocal = ntotal; MPI_Allreduce(&nlocal,&ntotal,1,MPI_INT,MPI_SUM,universe->uworld); } diff --git a/src/SPIN/min_spin_oso_lbfgs.h b/src/SPIN/min_spin_oso_lbfgs.h index d74898aa8c..3071bacc35 100644 --- a/src/SPIN/min_spin_oso_lbfgs.h +++ b/src/SPIN/min_spin_oso_lbfgs.h @@ -13,7 +13,7 @@ #ifdef MINIMIZE_CLASS -MinimizeStyle(spin/oso_lbfgs, MinSpinOSO_LBFGS) +MinimizeStyle(spin_oso_lbfgs, MinSpinOSO_LBFGS) #else From 883f6d1e8d6eb18e7ab520a1a7845ec41f31607a Mon Sep 17 00:00:00 2001 From: julient31 Date: Fri, 26 Jul 2019 09:06:43 -0600 Subject: [PATCH 56/74] Commit1 JT 072619 - corrected warnings in cg and lbfgs - removed unused variables in spin/dipole pair styles --- src/SPIN/min_spin_oso_cg.cpp | 6 ++++-- src/SPIN/min_spin_oso_lbfgs.cpp | 12 ++++++------ src/SPIN/min_spin_oso_lbfgs.h | 20 ++++++++++---------- src/SPIN/pair_spin_dipole_cut.cpp | 2 +- src/SPIN/pair_spin_dipole_long.cpp | 5 +---- 5 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index 2bdc00d8ed..1c91fa1500 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -512,7 +512,8 @@ void MinSpinOSO_CG::rodrigues_rotation(const double *upp_tr, double *out) void MinSpinOSO_CG::vm3(const double *m, const double *v, double *out) { for(int i = 0; i < 3; i++){ - out[i] *= 0.0; + //out[i] *= 0.0; + out[i] = 0.0; for(int j = 0; j < 3; j++) out[i] += *(m + 3 * j + i) * v[j]; } @@ -627,7 +628,8 @@ int MinSpinOSO_CG::awc(double der_phi_0, double phi_0, double der_phi_j, double double sigma = 0.9; if ((phi_j<=phi_0+eps*fabs(phi_0)) && - ((2.0*delta-1.0) * der_phi_0>=der_phi_j>=sigma*der_phi_0)) + ((2.0*delta-1.0) * der_phi_0>=der_phi_j) && + (der_phi_j>=sigma*der_phi_0)) return 1; else return 0; diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index 6aaeb7ca23..b9315d706e 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -63,7 +63,7 @@ static const char cite_minstyle_spin_oso_lbfgs[] = /* ---------------------------------------------------------------------- */ MinSpinOSO_LBFGS::MinSpinOSO_LBFGS(LAMMPS *lmp) : - Min(lmp), g_old(NULL), g_cur(NULL), p_s(NULL), ds(NULL), dy(NULL), rho(NULL), sp_copy(NULL) + Min(lmp), g_old(NULL), g_cur(NULL), p_s(NULL), rho(NULL), ds(NULL), dy(NULL), sp_copy(NULL) { if (lmp->citeme) lmp->citeme->add(cite_minstyle_spin_oso_lbfgs); nlocal_max = 0; @@ -345,7 +345,6 @@ void MinSpinOSO_LBFGS::calc_search_direction() double sq_global = 0.0; double yy_global = 0.0; double yr_global = 0.0; - double beta_global = 0.0; int m_index = local_iter % num_mem; // memory index int c_ind = 0; @@ -520,8 +519,6 @@ void MinSpinOSO_LBFGS::advance_spins() { int nlocal = atom->nlocal; double **sp = atom->sp; - double **fm = atom->fm; - double tdampx, tdampy, tdampz; double rot_mat[9]; // exponential of matrix made of search direction double s_new[3]; @@ -648,7 +645,8 @@ void MinSpinOSO_LBFGS::rodrigues_rotation(const double *upp_tr, double *out) void MinSpinOSO_LBFGS::vm3(const double *m, const double *v, double *out) { for(int i = 0; i < 3; i++){ - out[i] *= 0.0; + //out[i] *= 0.0; + out[i] = 0.0; for(int j = 0; j < 3; j++) out[i] += *(m + 3 * j + i) * v[j]; } @@ -762,7 +760,9 @@ int MinSpinOSO_LBFGS::awc(double der_phi_0, double phi_0, double der_phi_j, doub double delta = 0.1; double sigma = 0.9; - if ((phi_j<=phi_0+eps*fabs(phi_0)) && ((2.0*delta-1.0) * der_phi_0>=der_phi_j>=sigma*der_phi_0)) + if ((phi_j<=phi_0+eps*fabs(phi_0)) && + ((2.0*delta-1.0) * der_phi_0>=der_phi_j) && + (der_phi_j>=sigma*der_phi_0)) return 1; else return 0; diff --git a/src/SPIN/min_spin_oso_lbfgs.h b/src/SPIN/min_spin_oso_lbfgs.h index 3071bacc35..204f6bf058 100644 --- a/src/SPIN/min_spin_oso_lbfgs.h +++ b/src/SPIN/min_spin_oso_lbfgs.h @@ -34,14 +34,13 @@ class MinSpinOSO_LBFGS: public Min { void reset_vectors(); int iterate(int); private: - int ireplica,nreplica; // for neb + int ireplica,nreplica; // for neb double *spvec; // variables for atomic dof, as 1d vector double *fmvec; // variables for atomic dof, as 1d vector - double *g_cur; // current gradient vector - double *g_old; // gradient vector at previous step + double *g_old; // gradient vector at previous step + double *g_cur; // current gradient vector double *p_s; // search direction vector - double **sp_copy; // copy of the spins - int local_iter; // for neb + int local_iter; // for neb int nlocal_max; // max value of nlocal (for size of lists) void advance_spins(); @@ -54,14 +53,15 @@ class MinSpinOSO_LBFGS: public Min { int awc(double, double, double, double); void make_step(double, double *); double max_torque(); - double der_e_cur; // current derivative along search dir. - double der_e_pr; // previous derivative along search dir. - int use_line_search; // use line search or not. + double der_e_cur; // current derivative along search dir. + double der_e_pr; // previous derivative along search dir. + int use_line_search; // use line search or not. double maxepsrot; - double **ds; // change in rotation matrix between two iterations, da - double **dy; // change in gradients between two iterations, dg double *rho; // estimation of curvature + double **ds; // change in rotation matrix between two iterations, da + double **dy; // change in gradients between two iterations, dg + double **sp_copy; // copy of the spins int num_mem; // number of stored steps bigint last_negative; }; diff --git a/src/SPIN/pair_spin_dipole_cut.cpp b/src/SPIN/pair_spin_dipole_cut.cpp index 4ff198488a..e6b9a59ad9 100644 --- a/src/SPIN/pair_spin_dipole_cut.cpp +++ b/src/SPIN/pair_spin_dipole_cut.cpp @@ -323,7 +323,7 @@ void PairSpinDipoleCut::compute(int eflag, int vflag) void PairSpinDipoleCut::compute_single_pair(int ii, double fmi[3]) { int j,jnum,itype,jtype,ntypes; - int *ilist,*jlist,*numneigh,**firstneigh; + int *jlist,*numneigh,**firstneigh; double rsq,rinv,r2inv,r3inv,local_cut2; double xi[3],rij[3],eij[3],spi[4],spj[4]; diff --git a/src/SPIN/pair_spin_dipole_long.cpp b/src/SPIN/pair_spin_dipole_long.cpp index e3575a6a07..febc6f924c 100644 --- a/src/SPIN/pair_spin_dipole_long.cpp +++ b/src/SPIN/pair_spin_dipole_long.cpp @@ -355,10 +355,9 @@ void PairSpinDipoleLong::compute(int eflag, int vflag) void PairSpinDipoleLong::compute_single_pair(int ii, double fmi[3]) { - //int i,j,jj,jnum,itype,jtype; int j,jj,jnum,itype,jtype,ntypes; int k,locflag; - int *ilist,*jlist,*numneigh,**firstneigh; + int *jlist,*numneigh,**firstneigh; double r,rinv,r2inv,rsq,grij,expm2,t,erfc; double local_cut2,pre1,pre2,pre3; double bij[4],xi[3],rij[3],eij[3],spi[4],spj[4]; @@ -368,7 +367,6 @@ void PairSpinDipoleLong::compute_single_pair(int ii, double fmi[3]) double **sp = atom->sp; double **fm_long = atom->fm_long; - ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; @@ -406,7 +404,6 @@ void PairSpinDipoleLong::compute_single_pair(int ii, double fmi[3]) // computation of the exchange interaction // loop over neighbors of atom i - //i = ilist[ii]; xi[0] = x[ii][0]; xi[1] = x[ii][1]; xi[2] = x[ii][2]; From 7e5c293a233b7f8e5b7095559452b92fb4c7eddd Mon Sep 17 00:00:00 2001 From: alxvov Date: Fri, 26 Jul 2019 16:30:38 +0000 Subject: [PATCH 57/74] delete comment. Add line option --- src/SPIN/min_spin_oso_cg.cpp | 1 - src/SPIN/min_spin_oso_lbfgs.cpp | 3 +-- src/min.cpp | 2 ++ 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index 1c91fa1500..f95bffb947 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -512,7 +512,6 @@ void MinSpinOSO_CG::rodrigues_rotation(const double *upp_tr, double *out) void MinSpinOSO_CG::vm3(const double *m, const double *v, double *out) { for(int i = 0; i < 3; i++){ - //out[i] *= 0.0; out[i] = 0.0; for(int j = 0; j < 3; j++) out[i] += *(m + 3 * j + i) * v[j]; diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index b9315d706e..ce459586bf 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -645,7 +645,6 @@ void MinSpinOSO_LBFGS::rodrigues_rotation(const double *upp_tr, double *out) void MinSpinOSO_LBFGS::vm3(const double *m, const double *v, double *out) { for(int i = 0; i < 3; i++){ - //out[i] *= 0.0; out[i] = 0.0; for(int j = 0; j < 3; j++) out[i] += *(m + 3 * j + i) * v[j]; @@ -760,7 +759,7 @@ int MinSpinOSO_LBFGS::awc(double der_phi_0, double phi_0, double der_phi_j, doub double delta = 0.1; double sigma = 0.9; - if ((phi_j<=phi_0+eps*fabs(phi_0)) && + if ((phi_j<=phi_0+eps*fabs(phi_0)) && ((2.0*delta-1.0) * der_phi_0>=der_phi_j) && (der_phi_j>=sigma*der_phi_0)) return 1; diff --git a/src/min.cpp b/src/min.cpp index 2a42a444a0..a903fa98d8 100644 --- a/src/min.cpp +++ b/src/min.cpp @@ -653,6 +653,8 @@ void Min::modify_params(int narg, char **arg) if (strcmp(arg[iarg+1],"backtrack") == 0) linestyle = 0; else if (strcmp(arg[iarg+1],"quadratic") == 0) linestyle = 1; else if (strcmp(arg[iarg+1],"forcezero") == 0) linestyle = 2; + else if (strcmp(arg[iarg+1],"spin_cubic") == 0) linestyle = 3; + else if (strcmp(arg[iarg+1],"spin_none") == 0) linestyle = 4; else error->all(FLERR,"Illegal min_modify command"); iarg += 2; } else { From c5b7a36eebe3f8a886c902d53d71486920ecea2d Mon Sep 17 00:00:00 2001 From: julient31 Date: Fri, 26 Jul 2019 17:33:49 -0600 Subject: [PATCH 58/74] Commit JT 072619 - added a min_style option for norm type (euclidean or Max) - adapted and tested spin minimizers - adapted (net tested) regular minimizers --- src/SPIN/min_spin.cpp | 90 +++++-------------------------- src/SPIN/min_spin.h | 2 - src/SPIN/min_spin_oso_cg.cpp | 94 +++++++++++++-------------------- src/SPIN/min_spin_oso_cg.h | 72 ++++++++++++------------- src/SPIN/min_spin_oso_lbfgs.cpp | 61 ++++++++------------- src/SPIN/min_spin_oso_lbfgs.h | 74 +++++++++++++------------- src/min.cpp | 74 ++++++++++++++++++++++++++ src/min.h | 14 +++-- src/min_cg.cpp | 12 ++++- src/min_fire.cpp | 12 ++++- src/min_hftn.cpp | 4 ++ src/min_quickmin.cpp | 12 ++++- src/min_sd.cpp | 3 +- 13 files changed, 266 insertions(+), 258 deletions(-) diff --git a/src/SPIN/min_spin.cpp b/src/SPIN/min_spin.cpp index f56c9f0d96..d229927c29 100644 --- a/src/SPIN/min_spin.cpp +++ b/src/SPIN/min_spin.cpp @@ -119,7 +119,7 @@ void MinSpin::reset_vectors() int MinSpin::iterate(int maxiter) { bigint ntimestep; - double fmdotfm; + double fmdotfm,fmsq,fmsqall; int flag,flagall; for (int iter = 0; iter < maxiter; iter++) { @@ -166,8 +166,20 @@ int MinSpin::iterate(int maxiter) // magnetic torque tolerance criterion // sync across replicas if running multi-replica minimization + fmdotfm = fmsq = fmsqall = 0.0; if (update->ftol > 0.0) { - fmdotfm = max_torque(); + if (normstyle == 1) { // max torque norm + fmsq = max_torque(); + fmsqall = fmsq; + if (update->multireplica == 0) + MPI_Allreduce(&fmsq,&fmsqall,1,MPI_INT,MPI_MAX,universe->uworld); + } else { // Euclidean torque norm + fmsq = total_torque(); + fmsqall = fmsq; + if (update->multireplica == 0) + MPI_Allreduce(&fmsq,&fmsqall,1,MPI_INT,MPI_SUM,universe->uworld); + } + fmdotfm = fmsqall*fmsqall; if (update->multireplica == 0) { if (fmdotfm < update->ftol*update->ftol) return FTOL; } else { @@ -297,77 +309,3 @@ void MinSpin::advance_spins(double dts) // because no need for simplecticity } } - -/* ---------------------------------------------------------------------- - compute and return ||mag. torque||_2^2 -------------------------------------------------------------------------- */ - -double MinSpin::fmnorm_sqr() -{ - int nlocal = atom->nlocal; - double tx,ty,tz; - double **sp = atom->sp; - double **fm = atom->fm; - - // calc. magnetic torques - - double local_norm2_sqr = 0.0; - for (int i = 0; i < nlocal; i++) { - tx = (fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]); - ty = (fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]); - tz = (fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]); - - local_norm2_sqr += tx*tx + ty*ty + tz*tz; - } - - // no extra atom calc. for spins - - if (nextra_atom) - error->all(FLERR,"extra atom option not available yet"); - - double norm2_sqr = 0.0; - MPI_Allreduce(&local_norm2_sqr,&norm2_sqr,1,MPI_DOUBLE,MPI_SUM,world); - - return norm2_sqr; -} - -/* ---------------------------------------------------------------------- - compute and return max_i||mag. torque_i||_2 -------------------------------------------------------------------------- */ - -double MinSpin::max_torque() -{ - double fmsq,fmaxsqone,fmaxsqloc,fmaxsqall; - int nlocal = atom->nlocal; - double hbar = force->hplanck/MY_2PI; - double tx,ty,tz; - double **sp = atom->sp; - double **fm = atom->fm; - - fmsq = fmaxsqone = fmaxsqloc = fmaxsqall = 0.0; - for (int i = 0; i < nlocal; i++) { - tx = fm[i][1] * sp[i][2] - fm[i][2] * sp[i][1]; - ty = fm[i][2] * sp[i][0] - fm[i][0] * sp[i][2]; - tz = fm[i][0] * sp[i][1] - fm[i][1] * sp[i][0]; - fmsq = tx * tx + ty * ty + tz * tz; - fmaxsqone = MAX(fmaxsqone,fmsq); - } - - // finding max fm on this replica - - fmaxsqloc = fmaxsqone; - MPI_Allreduce(&fmaxsqone,&fmaxsqloc,1,MPI_DOUBLE,MPI_MAX,world); - - // finding max fm over all replicas, if necessary - // this communicator would be invalid for multiprocess replicas - - fmaxsqall = fmaxsqloc; - if (update->multireplica == 1) { - fmaxsqall = fmaxsqloc; - MPI_Allreduce(&fmaxsqloc,&fmaxsqall,1,MPI_DOUBLE,MPI_MAX,universe->uworld); - } - - // multiply it by hbar so that units are in eV - - return sqrt(fmaxsqall) * hbar; -} diff --git a/src/SPIN/min_spin.h b/src/SPIN/min_spin.h index d6d49203d5..f2df81e58c 100644 --- a/src/SPIN/min_spin.h +++ b/src/SPIN/min_spin.h @@ -35,8 +35,6 @@ class MinSpin : public Min { int iterate(int); double evaluate_dt(); void advance_spins(double); - double fmnorm_sqr(); - double max_torque(); private: diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index 1c91fa1500..16a95c5c02 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -29,6 +29,7 @@ #include "universe.h" #include "atom.h" #include "citeme.h" +#include "comm.h" #include "force.h" #include "update.h" #include "output.h" @@ -99,6 +100,13 @@ void MinSpinOSO_CG::init() Min::init(); + // warning if line_search combined to gneb + + if ((nreplica >= 1) && (linestyle != 4) && (comm->me == 0)) + error->warning(FLERR,"Line search incompatible gneb"); + + // set back use_line_search to 0 if more than one replica + if (linestyle == 3 && nreplica == 1){ use_line_search = 1; } @@ -175,7 +183,7 @@ int MinSpinOSO_CG::iterate(int maxiter) { int nlocal = atom->nlocal; bigint ntimestep; - double fmdotfm; + double fmdotfm,fmsq,fmsqall; int flag, flagall; double **sp = atom->sp; double der_e_cur_tmp = 0.0; @@ -261,8 +269,20 @@ int MinSpinOSO_CG::iterate(int maxiter) // magnetic torque tolerance criterion // sync across replicas if running multi-replica minimization + fmdotfm = fmsq = fmsqall = 0.0; if (update->ftol > 0.0) { - fmdotfm = max_torque(); + if (normstyle == 1) { // max torque norm + fmsq = max_torque(); + fmsqall = fmsq; + if (update->multireplica == 0) + MPI_Allreduce(&fmsq,&fmsqall,1,MPI_INT,MPI_MAX,universe->uworld); + } else { // Euclidean torque norm + fmsq = total_torque(); + fmsqall = fmsq; + if (update->multireplica == 0) + MPI_Allreduce(&fmsq,&fmsqall,1,MPI_INT,MPI_SUM,universe->uworld); + } + fmdotfm = fmsqall*fmsqall; if (update->multireplica == 0) { if (fmdotfm < update->ftol*update->ftol) return FTOL; } else { @@ -353,6 +373,7 @@ void MinSpinOSO_CG::calc_search_direction() MPI_Allreduce(&g2old,&g2old_global,1,MPI_DOUBLE,MPI_SUM,world); // Sum over all replicas. Good for GNEB. + if (nreplica > 1) { g2 = g2_global * factor; g2old = g2old_global * factor; @@ -361,7 +382,9 @@ void MinSpinOSO_CG::calc_search_direction() } if (fabs(g2_global) < 1.0e-60) beta = 0.0; else beta = g2_global / g2old_global; + // calculate conjugate direction + for (int i = 0; i < 3 * nlocal; i++) { p_s[i] = (beta * p_s[i] - g_cur[i]) * factor; g_old[i] = g_cur[i] * factor; @@ -379,7 +402,7 @@ void MinSpinOSO_CG::advance_spins() { int nlocal = atom->nlocal; double **sp = atom->sp; - double rot_mat[9]; // exponential of matrix made of search direction + double rot_mat[9]; // exponential of matrix made of search direction double s_new[3]; // loop on all spins on proc. @@ -394,47 +417,6 @@ void MinSpinOSO_CG::advance_spins() } } -/* ---------------------------------------------------------------------- - compute and return max_i||mag. torque_i||_2 -------------------------------------------------------------------------- */ - -double MinSpinOSO_CG::max_torque() -{ - double fmsq,fmaxsqone,fmaxsqloc,fmaxsqall; - int nlocal = atom->nlocal; - double factor; - double hbar = force->hplanck/MY_2PI; - - if (use_line_search) factor = 1.0; - else factor = hbar; - - // finding max fm on this proc. - - fmsq = fmaxsqone = fmaxsqloc = fmaxsqall = 0.0; - for (int i = 0; i < nlocal; i++) { - fmsq = 0.0; - for (int j = 0; j < 3; j++) - fmsq += g_cur[3 * i + j] * g_cur[3 * i + j]; - fmaxsqone = MAX(fmaxsqone,fmsq); - } - - // finding max fm on this replica - - fmaxsqloc = fmaxsqone; - MPI_Allreduce(&fmaxsqone,&fmaxsqloc,1,MPI_DOUBLE,MPI_MAX,world); - - // finding max fm over all replicas, if necessary - // this communicator would be invalid for multiprocess replicas - - fmaxsqall = fmaxsqloc; - if (update->multireplica == 1) { - fmaxsqall = fmaxsqloc; - MPI_Allreduce(&fmaxsqloc,&fmaxsqall,1,MPI_DOUBLE,MPI_MAX,universe->uworld); - } - - return sqrt(fmaxsqall) * factor; -} - /* ---------------------------------------------------------------------- calculate 3x3 matrix exponential using Rodrigues' formula (R. Murray, Z. Li, and S. Shankar Sastry, @@ -456,15 +438,14 @@ void MinSpinOSO_CG::rodrigues_rotation(const double *upp_tr, double *out) fabs(upp_tr[1]) < 1.0e-40 && fabs(upp_tr[2]) < 1.0e-40){ - // if upp_tr is zero, return unity matrix - for(int k = 0; k < 3; k++){ - for(int m = 0; m < 3; m++){ - if (m == k) - out[3 * k + m] = 1.0; - else - out[3 * k + m] = 0.0; + // if upp_tr is zero, return unity matrix + + for(int k = 0; k < 3; k++){ + for(int m = 0; m < 3; m++){ + if (m == k) out[3 * k + m] = 1.0; + else out[3 * k + m] = 0.0; + } } - } return; } @@ -512,13 +493,14 @@ void MinSpinOSO_CG::rodrigues_rotation(const double *upp_tr, double *out) void MinSpinOSO_CG::vm3(const double *m, const double *v, double *out) { for(int i = 0; i < 3; i++){ - //out[i] *= 0.0; out[i] = 0.0; - for(int j = 0; j < 3; j++) - out[i] += *(m + 3 * j + i) * v[j]; + for(int j = 0; j < 3; j++) out[i] += *(m + 3 * j + i) * v[j]; } } +/* ---------------------------------------------------------------------- + advance spins +------------------------------------------------------------------------- */ void MinSpinOSO_CG::make_step(double c, double *energy_and_der) { @@ -586,7 +568,7 @@ int MinSpinOSO_CG::calc_and_make_step(double a, double b, int index) } return 1; } - else{ + else { double r,f0,f1,df0,df1; r = b - a; f0 = eprevious; diff --git a/src/SPIN/min_spin_oso_cg.h b/src/SPIN/min_spin_oso_cg.h index 41253f440f..30d9adf066 100644 --- a/src/SPIN/min_spin_oso_cg.h +++ b/src/SPIN/min_spin_oso_cg.h @@ -25,44 +25,44 @@ MinimizeStyle(spin_oso_cg, MinSpinOSO_CG) namespace LAMMPS_NS { class MinSpinOSO_CG: public Min { - public: - MinSpinOSO_CG(class LAMMPS *); - virtual ~MinSpinOSO_CG(); - void init(); - void setup_style(); - int modify_param(int, char **); - void reset_vectors(); - int iterate(int); - private: - double dt; // global timestep - double dts; // spin timestep - int ireplica,nreplica; // for neb - double *spvec; // variables for atomic dof, as 1d vector - double *fmvec; // variables for atomic dof, as 1d vector - double *g_old; // gradient vector at previous step - double *g_cur; // current gradient vector - double *p_s; // search direction vector - double **sp_copy; // copy of the spins - int local_iter; // for neb - int nlocal_max; // max value of nlocal (for size of lists) - double discrete_factor; // factor for spin timestep evaluation + public: + MinSpinOSO_CG(class LAMMPS *); + virtual ~MinSpinOSO_CG(); + void init(); + void setup_style(); + void reset_vectors(); + int modify_param(int, char **); + int iterate(int); - double evaluate_dt(); - void advance_spins(); - void calc_gradient(); - void calc_search_direction(); - double maximum_rotation(double *); - void vm3(const double *, const double *, double *); - void rodrigues_rotation(const double *, double *); - int calc_and_make_step(double, double, int); - int awc(double, double, double, double); - void make_step(double, double *); - double max_torque(); - double der_e_cur; // current derivative along search dir. - double der_e_pr; // previous derivative along search dir. - int use_line_search; // use line search or not. + private: + int local_iter; // for neb + int nlocal_max; // max value of nlocal (for size of lists) + int use_line_search; // use line search or not. + int ireplica,nreplica; // for neb + double dt; // global timestep + double dts; // spin timestep + double discrete_factor; // factor for spin timestep evaluation + double der_e_cur; // current derivative along search dir. + double der_e_pr; // previous derivative along search dir. + double *spvec; // variables for atomic dof, as 1d vector + double *fmvec; // variables for atomic dof, as 1d vector + double *g_old; // gradient vector at previous step + double *g_cur; // current gradient vector + double *p_s; // search direction vector + double **sp_copy; // copy of the spins - bigint last_negative; + void advance_spins(); + void calc_gradient(); + void calc_search_direction(); + void vm3(const double *, const double *, double *); + void rodrigues_rotation(const double *, double *); + void make_step(double, double *); + int calc_and_make_step(double, double, int); + int awc(double, double, double, double); + double evaluate_dt(); + double maximum_rotation(double *); + + bigint last_negative; }; } diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index b9315d706e..2913ef4101 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -26,9 +26,9 @@ #include #include #include "min_spin_oso_lbfgs.h" -#include "universe.h" #include "atom.h" #include "citeme.h" +#include "comm.h" #include "force.h" #include "update.h" #include "output.h" @@ -107,6 +107,13 @@ void MinSpinOSO_LBFGS::init() Min::init(); + // warning if line_search combined to gneb + + if ((nreplica >= 1) && (linestyle != 4) && (comm->me == 0)) + error->warning(FLERR,"Line search incompatible gneb"); + + // set back use_line_search to 0 if more than one replica + if (linestyle != 4 && nreplica == 1){ use_line_search = 1; } @@ -188,7 +195,7 @@ int MinSpinOSO_LBFGS::iterate(int maxiter) { int nlocal = atom->nlocal; bigint ntimestep; - double fmdotfm; + double fmdotfm,fmsq,fmsqall; int flag, flagall; double **sp = atom->sp; double der_e_cur_tmp = 0.0; @@ -280,8 +287,20 @@ int MinSpinOSO_LBFGS::iterate(int maxiter) // magnetic torque tolerance criterion // sync across replicas if running multi-replica minimization + fmdotfm = fmsq = fmsqall = 0.0; if (update->ftol > 0.0) { - fmdotfm = max_torque(); + if (normstyle == 1) { // max torque norm + fmsq = max_torque(); + fmsqall = fmsq; + if (update->multireplica == 0) + MPI_Allreduce(&fmsq,&fmsqall,1,MPI_INT,MPI_MAX,universe->uworld); + } else { // Euclidean torque norm + fmsq = total_torque(); + fmsqall = fmsq; + if (update->multireplica == 0) + MPI_Allreduce(&fmsq,&fmsqall,1,MPI_INT,MPI_SUM,universe->uworld); + } + fmdotfm = fmsqall*fmsqall; if (update->multireplica == 0) { if (fmdotfm < update->ftol*update->ftol) return FTOL; } else { @@ -534,42 +553,6 @@ void MinSpinOSO_LBFGS::advance_spins() } } -/* ---------------------------------------------------------------------- - compute and return max_i||mag. torque_i||_2 -------------------------------------------------------------------------- */ - -double MinSpinOSO_LBFGS::max_torque() -{ - double fmsq,fmaxsqone,fmaxsqloc,fmaxsqall; - int nlocal = atom->nlocal; - - // finding max fm on this proc. - - fmsq = fmaxsqone = fmaxsqloc = fmaxsqall = 0.0; - for (int i = 0; i < nlocal; i++) { - fmsq = 0.0; - for (int j = 0; j < 3; j++) - fmsq += g_cur[3 * i + j] * g_cur[3 * i + j]; - fmaxsqone = MAX(fmaxsqone,fmsq); - } - - // finding max fm on this replica - - fmaxsqloc = fmaxsqone; - MPI_Allreduce(&fmaxsqone,&fmaxsqloc,1,MPI_DOUBLE,MPI_MAX,world); - - // finding max fm over all replicas, if necessary - // this communicator would be invalid for multiprocess replicas - - fmaxsqall = fmaxsqloc; - if (update->multireplica == 1) { - fmaxsqall = fmaxsqloc; - MPI_Allreduce(&fmaxsqloc,&fmaxsqall,1,MPI_DOUBLE,MPI_MAX,universe->uworld); - } - - return sqrt(fmaxsqall); -} - /* ---------------------------------------------------------------------- calculate 3x3 matrix exponential using Rodrigues' formula (R. Murray, Z. Li, and S. Shankar Sastry, diff --git a/src/SPIN/min_spin_oso_lbfgs.h b/src/SPIN/min_spin_oso_lbfgs.h index 204f6bf058..9bd36afa8b 100644 --- a/src/SPIN/min_spin_oso_lbfgs.h +++ b/src/SPIN/min_spin_oso_lbfgs.h @@ -25,45 +25,45 @@ MinimizeStyle(spin_oso_lbfgs, MinSpinOSO_LBFGS) namespace LAMMPS_NS { class MinSpinOSO_LBFGS: public Min { - public: - MinSpinOSO_LBFGS(class LAMMPS *); - virtual ~MinSpinOSO_LBFGS(); - void init(); - void setup_style(); - int modify_param(int, char **); - void reset_vectors(); - int iterate(int); - private: - int ireplica,nreplica; // for neb - double *spvec; // variables for atomic dof, as 1d vector - double *fmvec; // variables for atomic dof, as 1d vector - double *g_old; // gradient vector at previous step - double *g_cur; // current gradient vector - double *p_s; // search direction vector - int local_iter; // for neb - int nlocal_max; // max value of nlocal (for size of lists) + public: + MinSpinOSO_LBFGS(class LAMMPS *); + virtual ~MinSpinOSO_LBFGS(); + void init(); + void setup_style(); + int modify_param(int, char **); + void reset_vectors(); + int iterate(int); - void advance_spins(); - void calc_gradient(); - void calc_search_direction(); - double maximum_rotation(double *); - void vm3(const double *, const double *, double *); - void rodrigues_rotation(const double *, double *); - int calc_and_make_step(double, double, int); - int awc(double, double, double, double); - void make_step(double, double *); - double max_torque(); - double der_e_cur; // current derivative along search dir. - double der_e_pr; // previous derivative along search dir. - int use_line_search; // use line search or not. - double maxepsrot; + private: + int local_iter; // for neb + int use_line_search; // use line search or not. + int nlocal_max; // max value of nlocal (for size of lists) + int ireplica,nreplica; // for neb + double der_e_cur; // current derivative along search dir. + double der_e_pr; // previous derivative along search dir. + double maxepsrot; + double *spvec; // variables for atomic dof, as 1d vector + double *fmvec; // variables for atomic dof, as 1d vector + double *g_old; // gradient vector at previous step + double *g_cur; // current gradient vector + double *p_s; // search direction vector - double *rho; // estimation of curvature - double **ds; // change in rotation matrix between two iterations, da - double **dy; // change in gradients between two iterations, dg - double **sp_copy; // copy of the spins - int num_mem; // number of stored steps - bigint last_negative; + void advance_spins(); + void calc_gradient(); + void calc_search_direction(); + void vm3(const double *, const double *, double *); + void rodrigues_rotation(const double *, double *); + void make_step(double, double *); + int calc_and_make_step(double, double, int); + int awc(double, double, double, double); + double maximum_rotation(double *); + + double *rho; // estimation of curvature + double **ds; // change in rotation matrix between two iterations, da + double **dy; // change in gradients between two iterations, dg + double **sp_copy; // copy of the spins + int num_mem; // number of stored steps + bigint last_negative; }; } diff --git a/src/min.cpp b/src/min.cpp index 2a42a444a0..e476b1abc8 100644 --- a/src/min.cpp +++ b/src/min.cpp @@ -42,10 +42,12 @@ #include "output.h" #include "thermo.h" #include "timer.h" +#include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; +using namespace MathConst; /* ---------------------------------------------------------------------- */ @@ -54,6 +56,7 @@ Min::Min(LAMMPS *lmp) : Pointers(lmp) dmax = 0.1; searchflag = 0; linestyle = 1; + normstyle = 0; elist_global = elist_atom = NULL; vlist_global = vlist_atom = NULL; @@ -653,6 +656,14 @@ void Min::modify_params(int narg, char **arg) if (strcmp(arg[iarg+1],"backtrack") == 0) linestyle = 0; else if (strcmp(arg[iarg+1],"quadratic") == 0) linestyle = 1; else if (strcmp(arg[iarg+1],"forcezero") == 0) linestyle = 2; + else if (strcmp(arg[iarg+1],"spin_cubic") == 0) linestyle = 3; + else if (strcmp(arg[iarg+1],"spin_none") == 0) linestyle = 4; + else error->all(FLERR,"Illegal min_modify command"); + iarg += 2; + } else if (strcmp(arg[iarg],"norm") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal min_modify command"); + if (strcmp(arg[iarg+1],"euclidean") == 0) normstyle = 0; + else if (strcmp(arg[iarg+1],"max") == 0) normstyle = 1; else error->all(FLERR,"Illegal min_modify command"); iarg += 2; } else { @@ -816,6 +827,69 @@ double Min::fnorm_inf() return norm_inf; } +/* ---------------------------------------------------------------------- + compute and return sum_i||mag. torque_i||_2 (in eV) +------------------------------------------------------------------------- */ + +double Min::total_torque() +{ + double fmsq,ftotsqone,ftotsqall; + int nlocal = atom->nlocal; + double hbar = force->hplanck/MY_2PI; + double tx,ty,tz; + double **sp = atom->sp; + double **fm = atom->fm; + + fmsq = ftotsqone = ftotsqall = 0.0; + for (int i = 0; i < nlocal; i++) { + tx = fm[i][1] * sp[i][2] - fm[i][2] * sp[i][1]; + ty = fm[i][2] * sp[i][0] - fm[i][0] * sp[i][2]; + tz = fm[i][0] * sp[i][1] - fm[i][1] * sp[i][0]; + fmsq = tx * tx + ty * ty + tz * tz; + ftotsqone += fmsq; + } + + // summing all fmsqtot on this replica + + MPI_Allreduce(&ftotsqone,&ftotsqall,1,MPI_DOUBLE,MPI_SUM,world); + + // multiply it by hbar so that units are in eV + + return sqrt(ftotsqall) * hbar; +} + +/* ---------------------------------------------------------------------- + compute and return max_i ||mag. torque_i|| (in eV) +------------------------------------------------------------------------- */ + +double Min::max_torque() +{ + double fmsq,fmaxsqone,fmaxsqall; + int nlocal = atom->nlocal; + double hbar = force->hplanck/MY_2PI; + double tx,ty,tz; + double **sp = atom->sp; + double **fm = atom->fm; + + fmsq = fmaxsqone = fmaxsqall = 0.0; + for (int i = 0; i < nlocal; i++) { + tx = fm[i][1] * sp[i][2] - fm[i][2] * sp[i][1]; + ty = fm[i][2] * sp[i][0] - fm[i][0] * sp[i][2]; + tz = fm[i][0] * sp[i][1] - fm[i][1] * sp[i][0]; + fmsq = tx * tx + ty * ty + tz * tz; + fmaxsqone = MAX(fmaxsqone,fmsq); + } + + // finding max fm on this replica + + fmaxsqall = fmaxsqone; + MPI_Allreduce(&fmaxsqone,&fmaxsqall,1,MPI_DOUBLE,MPI_MAX,world); + + // multiply it by hbar so that units are in eV + + return sqrt(fmaxsqall) * hbar; +} + /* ---------------------------------------------------------------------- possible stop conditions ------------------------------------------------------------------------- */ diff --git a/src/min.h b/src/min.h index a63254231c..e18d0dd677 100644 --- a/src/min.h +++ b/src/min.h @@ -42,6 +42,10 @@ class Min : protected Pointers { double fnorm_sqr(); double fnorm_inf(); + // methods for spin minimizers + double max_torque(); + double total_torque(); + virtual void init_style() {} virtual void setup_style() = 0; virtual void reset_vectors() = 0; @@ -56,8 +60,11 @@ class Min : protected Pointers { int virial_style; // compute virial explicitly or implicitly int external_force_clear; // clear forces locally or externally - double dmax; // max dist to move any atom in one step - int linestyle; // 0 = backtrack, 1 = quadratic, 2 = forcezero + double dmax; // max dist to move any atom in one step + int linestyle; // 0 = backtrack, 1 = quadratic, 2 = forcezero + // 3 = spin_cubic, 4 = spin_none + + int normstyle; // 0 = Euclidean norm, 1 = inf. norm int nelist_global,nelist_atom; // # of PE,virial computes to check int nvlist_global,nvlist_atom; @@ -102,9 +109,6 @@ class Min : protected Pointers { double energy_force(int); void force_clear(); - double compute_force_norm_sqr(); - double compute_force_norm_inf(); - void ev_setup(); void ev_set(bigint); diff --git a/src/min_cg.cpp b/src/min_cg.cpp index 20e8cc30dd..9801e57f4d 100644 --- a/src/min_cg.cpp +++ b/src/min_cg.cpp @@ -37,7 +37,7 @@ MinCG::MinCG(LAMMPS *lmp) : MinLineSearch(lmp) {} int MinCG::iterate(int maxiter) { int i,m,n,fail,ntimestep; - double beta,gg,dot[2],dotall[2]; + double beta,gg,dot[2],dotall[2],fmax,fmaxall; double *fatom,*gatom,*hatom; // nlimit = max # of CG iterations before restarting @@ -87,10 +87,12 @@ int MinCG::iterate(int maxiter) // force tolerance criterion + fmax = fmaxall = 0.0; dot[0] = dot[1] = 0.0; for (i = 0; i < nvec; i++) { dot[0] += fvec[i]*fvec[i]; dot[1] += fvec[i]*g[i]; + fmax = MAX(fmax,fvec[i]*fvec[i]); } if (nextra_atom) for (m = 0; m < nextra_atom; m++) { @@ -100,16 +102,22 @@ int MinCG::iterate(int maxiter) for (i = 0; i < n; i++) { dot[0] += fatom[i]*fatom[i]; dot[1] += fatom[i]*gatom[i]; + fmax = MAX(fmax,fatom[i]*fatom[i]); } } MPI_Allreduce(dot,dotall,2,MPI_DOUBLE,MPI_SUM,world); + MPI_Allreduce(&fmax,&fmaxall,2,MPI_DOUBLE,MPI_MAX,world); if (nextra_global) for (i = 0; i < nextra_global; i++) { dotall[0] += fextra[i]*fextra[i]; dotall[1] += fextra[i]*gextra[i]; } - if (dotall[0] < update->ftol*update->ftol) return FTOL; + if (normstyle == 1) { // max force norm + if (fmax < update->ftol*update->ftol) return FTOL; + } else { // Euclidean force norm + if (dotall[0] < update->ftol*update->ftol) return FTOL; + } // update new search direction h from new f = -Grad(x) and old g // this is Polak-Ribieri formulation diff --git a/src/min_fire.cpp b/src/min_fire.cpp index a50071d562..a0a3bce8ba 100644 --- a/src/min_fire.cpp +++ b/src/min_fire.cpp @@ -80,7 +80,7 @@ void MinFire::reset_vectors() int MinFire::iterate(int maxiter) { bigint ntimestep; - double vmax,vdotf,vdotfall,vdotv,vdotvall,fdotf,fdotfall; + double vmax,vdotf,vdotfall,vdotv,vdotvall,fdotf,fdotfloc,fdotfall; double scale1,scale2; double dtvone,dtv,dtf,dtfm; int flag,flagall; @@ -250,7 +250,15 @@ int MinFire::iterate(int maxiter) // sync across replicas if running multi-replica minimization if (update->ftol > 0.0) { - fdotf = fnorm_sqr(); + if (normstyle == 1) { // max force norm + fdotf = fnorm_inf(); + fdotfloc = fdotf; + MPI_Allreduce(&fdotfloc,&fdotf,1,MPI_INT,MPI_MAX,universe->uworld); + } else { // Euclidean force norm + fdotf = fnorm_sqr(); + fdotfloc = fdotf; + MPI_Allreduce(&fdotfloc,&fdotf,1,MPI_INT,MPI_SUM,universe->uworld); + } if (update->multireplica == 0) { if (fdotf < update->ftol*update->ftol) return FTOL; } else { diff --git a/src/min_hftn.cpp b/src/min_hftn.cpp index 0c834fbeb4..9f8695f151 100644 --- a/src/min_hftn.cpp +++ b/src/min_hftn.cpp @@ -20,6 +20,7 @@ #include #include #include "atom.h" +#include "error.h" #include "fix_minimize.h" #include "min_hftn.h" #include "modify.h" @@ -111,6 +112,9 @@ void MinHFTN::init() { Min::init(); + if (normstyle == 1) + error->all(FLERR,"Incorrect min_modify option"); + for (int i = 1; i < NUM_HFTN_ATOM_BASED_VECTORS; i++) { if (_daExtraGlobal[i] != NULL) delete [] _daExtraGlobal[i]; diff --git a/src/min_quickmin.cpp b/src/min_quickmin.cpp index 8b48816355..d6507cfcde 100644 --- a/src/min_quickmin.cpp +++ b/src/min_quickmin.cpp @@ -76,7 +76,7 @@ void MinQuickMin::reset_vectors() int MinQuickMin::iterate(int maxiter) { bigint ntimestep; - double vmax,vdotf,vdotfall,fdotf,fdotfall,scale; + double vmax,vdotf,vdotfall,fdotf,fdotfloc,fdotfall,scale; double dtvone,dtv,dtf,dtfm; int flag,flagall; @@ -216,7 +216,15 @@ int MinQuickMin::iterate(int maxiter) // sync across replicas if running multi-replica minimization if (update->ftol > 0.0) { - fdotf = fnorm_sqr(); + if (normstyle == 1) { // max force norm + fdotf = fnorm_inf(); + fdotfloc = fdotf; + MPI_Allreduce(&fdotfloc,&fdotf,1,MPI_INT,MPI_MAX,universe->uworld); + } else { // Euclidean force norm + fdotf = fnorm_sqr(); + fdotfloc = fdotf; + MPI_Allreduce(&fdotfloc,&fdotf,1,MPI_INT,MPI_SUM,universe->uworld); + } if (update->multireplica == 0) { if (fdotf < update->ftol*update->ftol) return FTOL; } else { diff --git a/src/min_sd.cpp b/src/min_sd.cpp index 5d44437ca0..60386df82c 100644 --- a/src/min_sd.cpp +++ b/src/min_sd.cpp @@ -79,7 +79,8 @@ int MinSD::iterate(int maxiter) // force tolerance criterion - fdotf = fnorm_sqr(); + if (normstyle == 1) fdotf = fnorm_inf(); // max force norm + else fdotf = fnorm_sqr(); // Euclidean force norm if (fdotf < update->ftol*update->ftol) return FTOL; // set new search direction h to f = -Grad(x) From 1364329432bef1809811b4e188e02520091ed825 Mon Sep 17 00:00:00 2001 From: julient31 Date: Fri, 26 Jul 2019 17:54:04 -0600 Subject: [PATCH 59/74] Commit JT 072619 - draft doc of norm option (doc/src/min_modify.txt) --- doc/src/min_modify.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/src/min_modify.txt b/doc/src/min_modify.txt index 9c4d7c8fcb..ecd4795a8f 100644 --- a/doc/src/min_modify.txt +++ b/doc/src/min_modify.txt @@ -18,6 +18,8 @@ keyword = {dmax} or {line} or {alpha_damp} or {discrete_factor} max = maximum distance for line search to move (distance units) {line} value = {backtrack} or {quadratic} or {forcezero} or {spin_cubic} or {spin_none} backtrack,quadratic,forcezero,spin_cubic,spin_none = style of linesearch to use + {norm} value = {euclidean} or {max} + euclidean,max = style of norm to use {alpha_damp} value = damping damping = fictitious Gilbert damping for spin minimization (adim) {discrete_factor} value = factor @@ -69,6 +71,14 @@ difference of two large values (energy before and energy after) and that difference may be smaller than machine epsilon even if atoms could move in the gradient direction to reduce forces further. +The choice of a norm can be modified for the min styles {fire}, +{quickmin}, {sd}, {spin}, {spin_oso_cg} and {spin_oso_lbfgs} +using the {norm} keyword. +The default {euclidean} norm computes the 2-norm (length) of the +global force vector. The {max} norm computes the maximum value +of the 2-norms of all forces in the system. + + Keywords {alpha_damp} and {discrete_factor} only make sense when a "min_spin"_min_spin.html command is declared. Keyword {alpha_damp} defines an analog of a magnetic Gilbert From 9609c75073130b19856c3bc0e64068e72254e507 Mon Sep 17 00:00:00 2001 From: alxvov Date: Tue, 30 Jul 2019 11:16:40 +0000 Subject: [PATCH 60/74] Use descent condition, and no line search as a default option for all oso --- examples/SPIN/spinmin/in.spinmin_cg.bfo | 2 +- examples/SPIN/spinmin/in.spinmin_lbfgs.bfo | 4 ++-- src/SPIN/min_spin_oso_cg.cpp | 14 ++++---------- src/SPIN/min_spin_oso_cg.h | 2 +- src/SPIN/min_spin_oso_lbfgs.cpp | 21 ++++++--------------- src/SPIN/min_spin_oso_lbfgs.h | 2 +- 6 files changed, 15 insertions(+), 30 deletions(-) diff --git a/examples/SPIN/spinmin/in.spinmin_cg.bfo b/examples/SPIN/spinmin/in.spinmin_cg.bfo index 776079edb8..8c288763c4 100644 --- a/examples/SPIN/spinmin/in.spinmin_cg.bfo +++ b/examples/SPIN/spinmin/in.spinmin_cg.bfo @@ -51,4 +51,4 @@ dump 1 all custom 50 dump.lammpstrj type x y z c_outsp[1] c_outsp[2] c_outsp[3 min_style spin_oso_cg # min_modify line spin_none discrete_factor 10.0 -minimize 1.0e-10 1.0e-7 1000 1000 +minimize 1.0e-10 1.0e-10 10000 10000 diff --git a/examples/SPIN/spinmin/in.spinmin_lbfgs.bfo b/examples/SPIN/spinmin/in.spinmin_lbfgs.bfo index ca600f1c2b..6a9104cc9c 100644 --- a/examples/SPIN/spinmin/in.spinmin_lbfgs.bfo +++ b/examples/SPIN/spinmin/in.spinmin_lbfgs.bfo @@ -50,5 +50,5 @@ compute outsp all property/atom spx spy spz sp fmx fmy fmz dump 1 all custom 50 dump.lammpstrj type x y z c_outsp[1] c_outsp[2] c_outsp[3] c_outsp[4] c_outsp[5] c_outsp[6] c_outsp[7] min_style spin_oso_lbfgs -min_modify line spin_cubic discrete_factor 10.0 -minimize 1.0e-15 1.0e-7 10000 1000 +# min_modify line spin_cubic discrete_factor 10.0 +minimize 1.0e-15 1.0e-10 10000 1000 diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_oso_cg.cpp index 16a95c5c02..f1f2f72436 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_oso_cg.cpp @@ -561,7 +561,7 @@ int MinSpinOSO_CG::calc_and_make_step(double a, double b, int index) der_e_cur = e_and_d[1]; index++; - if (awc(der_e_pr,eprevious,e_and_d[1],e_and_d[0]) || index == 10){ + if (adescent(eprevious,e_and_d[0]) || index == 5){ MPI_Bcast(&b,1,MPI_DOUBLE,0,world); for (int i = 0; i < 3 * nlocal; i++) { p_s[i] = b * p_s[i]; @@ -598,20 +598,14 @@ int MinSpinOSO_CG::calc_and_make_step(double a, double b, int index) } /* ---------------------------------------------------------------------- - Approximate Wolfe conditions: - William W. Hager and Hongchao Zhang - SIAM J. optim., 16(1), 170-192. (23 pages) + Approximate descent ------------------------------------------------------------------------- */ -int MinSpinOSO_CG::awc(double der_phi_0, double phi_0, double der_phi_j, double phi_j){ +int MinSpinOSO_CG::adescent(double phi_0, double phi_j){ double eps = 1.0e-6; - double delta = 0.1; - double sigma = 0.9; - if ((phi_j<=phi_0+eps*fabs(phi_0)) && - ((2.0*delta-1.0) * der_phi_0>=der_phi_j) && - (der_phi_j>=sigma*der_phi_0)) + if (phi_j<=phi_0+eps*fabs(phi_0)) return 1; else return 0; diff --git a/src/SPIN/min_spin_oso_cg.h b/src/SPIN/min_spin_oso_cg.h index 30d9adf066..d6dc7c03d0 100644 --- a/src/SPIN/min_spin_oso_cg.h +++ b/src/SPIN/min_spin_oso_cg.h @@ -58,7 +58,7 @@ class MinSpinOSO_CG: public Min { void rodrigues_rotation(const double *, double *); void make_step(double, double *); int calc_and_make_step(double, double, int); - int awc(double, double, double, double); + int adescent(double, double); double evaluate_dt(); double maximum_rotation(double *); diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_oso_lbfgs.cpp index f850879d1a..8623a8bb29 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_oso_lbfgs.cpp @@ -73,10 +73,7 @@ MinSpinOSO_LBFGS::MinSpinOSO_LBFGS(LAMMPS *lmp) : nreplica = universe->nworlds; ireplica = universe->iworld; - if (nreplica > 1) - use_line_search = 0; // no line search for NEB - else - use_line_search = 1; + use_line_search = 0; // no line search as default option for LBFGS maxepsrot = MY_2PI / (100.0); @@ -114,7 +111,7 @@ void MinSpinOSO_LBFGS::init() // set back use_line_search to 0 if more than one replica - if (linestyle != 4 && nreplica == 1){ + if (linestyle == 3 && nreplica == 1){ use_line_search = 1; } else{ @@ -694,7 +691,7 @@ int MinSpinOSO_LBFGS::calc_and_make_step(double a, double b, int index) der_e_cur = e_and_d[1]; index++; - if (awc(der_e_pr,eprevious,e_and_d[1],e_and_d[0]) || index == 5){ + if (adescent(eprevious,e_and_d[0]) || index == 5){ MPI_Bcast(&b,1,MPI_DOUBLE,0,world); for (int i = 0; i < 3 * nlocal; i++) { p_s[i] = b * p_s[i]; @@ -731,20 +728,14 @@ int MinSpinOSO_LBFGS::calc_and_make_step(double a, double b, int index) } /* ---------------------------------------------------------------------- - Approximate Wolfe conditions: - William W. Hager and Hongchao Zhang - SIAM J. optim., 16(1), 170-192. (23 pages) + Approximate descent ------------------------------------------------------------------------- */ -int MinSpinOSO_LBFGS::awc(double der_phi_0, double phi_0, double der_phi_j, double phi_j){ +int MinSpinOSO_LBFGS::adescent(double phi_0, double phi_j){ double eps = 1.0e-6; - double delta = 0.1; - double sigma = 0.9; - if ((phi_j<=phi_0+eps*fabs(phi_0)) && - ((2.0*delta-1.0) * der_phi_0>=der_phi_j) && - (der_phi_j>=sigma*der_phi_0)) + if (phi_j<=phi_0+eps*fabs(phi_0)) return 1; else return 0; diff --git a/src/SPIN/min_spin_oso_lbfgs.h b/src/SPIN/min_spin_oso_lbfgs.h index 9bd36afa8b..68fa10921e 100644 --- a/src/SPIN/min_spin_oso_lbfgs.h +++ b/src/SPIN/min_spin_oso_lbfgs.h @@ -55,7 +55,7 @@ class MinSpinOSO_LBFGS: public Min { void rodrigues_rotation(const double *, double *); void make_step(double, double *); int calc_and_make_step(double, double, int); - int awc(double, double, double, double); + int adescent(double, double); double maximum_rotation(double *); double *rho; // estimation of curvature From aa3c44ad4af471e3c4cc65734f3abe43179d3b27 Mon Sep 17 00:00:00 2001 From: alxvov Date: Tue, 30 Jul 2019 12:02:10 +0000 Subject: [PATCH 61/74] modify documentation a bit --- doc/src/min_modify.txt | 6 +++--- doc/src/min_spin.txt | 11 +++++------ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/doc/src/min_modify.txt b/doc/src/min_modify.txt index ecd4795a8f..35a02c47c3 100644 --- a/doc/src/min_modify.txt +++ b/doc/src/min_modify.txt @@ -97,9 +97,9 @@ two minimization styles is declared. The {spin_cubic} performs the line search based on a cubic interpolation of the energy along the search direction. The {spin_none} keyword deactivates the line search procedure. -The {spin_none} is a default value for {line} keyword apart from the case when -single-replica calculations are performed with {spin_oso_lbfgs} that -uses {spin_cubic} line search. +The {spin_none} is a default value for {line} keyword for both {spin_oso_lbfgs} +and {spin_oso_cg}. Convergence of {spin_oso_lbfgs} can be more robust if +{spin_cubic} line search is used. [Restrictions:] The line search procedure of styles {spin_oso_cg} and {spin_oso_lbfgs} cannot be used for magnetic diff --git a/doc/src/min_spin.txt b/doc/src/min_spin.txt index 77dc008b3e..20c4cde1d7 100644 --- a/doc/src/min_spin.txt +++ b/doc/src/min_spin.txt @@ -18,7 +18,7 @@ min_style spin_oso_lbfgs :pre [Examples:] min_style spin_oso_lbfgs -min_modify line spin_none discrete_factor 10.0 :pre +min_modify line spin_cubic discrete_factor 10.0 :pre [Description:] @@ -62,16 +62,15 @@ and uses the adaptive time-step technique in the same way as style {spin}. Style {spin_oso_lbfgs} defines an orthogonal spin optimization (OSO) combined to a limited-memory Broyden-Fletcher-Goldfarb-Shanno (L-BFGS) algorithm. -By default, style {spin_oso_lbfgs} uses a line search procedure -based on cubic interpolation for -a single-replica calculation, and it does not use line search procedure -for a multireplica calculation (such as in case of GNEB calculation). +By default, style {spin_oso_lbfgs} does not employ line search procedure. If the line search procedure is not used then the discrete factor defines the maximum root mean squared rotation angle of spins by equation {pi/(5*Kappa)}. The default value for Kappa is 10. +The {spin_cubic} line search can improve +the convergence of the {spin_oso_lbfgs} algorithm. The "min_modify"_min_modify.html command can be used to -deactivate the line search procedure, and to modify the +activate the line search procedure, and to modify the discretization factor {discrete_factor}. For more information about styles {spin_oso_cg} and {spin_oso_lbfgs}, From 74fa4f741571be0bb060462691d76651d10394e8 Mon Sep 17 00:00:00 2001 From: julient31 Date: Tue, 30 Jul 2019 08:58:12 -0600 Subject: [PATCH 62/74] Commit JT 073019 - modified doc doc/src/min_modify.txt - tested lattice minimizers with norm styles --- doc/src/min_modify.txt | 19 +++++++++++-------- doc/src/min_spin.txt | 10 +++++----- doc/src/min_style.txt | 3 +-- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/doc/src/min_modify.txt b/doc/src/min_modify.txt index 35a02c47c3..2056655d40 100644 --- a/doc/src/min_modify.txt +++ b/doc/src/min_modify.txt @@ -13,7 +13,7 @@ min_modify command :h3 min_modify keyword values ... :pre one or more keyword/value pairs may be listed :ulb,l -keyword = {dmax} or {line} or {alpha_damp} or {discrete_factor} +keyword = {dmax} or {line} or {norm} or {alpha_damp} or {discrete_factor} {dmax} value = max max = maximum distance for line search to move (distance units) {line} value = {backtrack} or {quadratic} or {forcezero} or {spin_cubic} or {spin_none} @@ -71,13 +71,12 @@ difference of two large values (energy before and energy after) and that difference may be smaller than machine epsilon even if atoms could move in the gradient direction to reduce forces further. -The choice of a norm can be modified for the min styles {fire}, -{quickmin}, {sd}, {spin}, {spin_oso_cg} and {spin_oso_lbfgs} -using the {norm} keyword. +The choice of a norm can be modified for the min styles {cg}, {sd}, +{quickmin}, {fire}, {spin}, {spin_oso_cg} and {spin_oso_lbfgs} using +the {norm} keyword. The default {euclidean} norm computes the 2-norm (length) of the global force vector. The {max} norm computes the maximum value -of the 2-norms of all forces in the system. - +of the 2-norms across all forces in the system. Keywords {alpha_damp} and {discrete_factor} only make sense when a "min_spin"_min_spin.html command is declared. @@ -88,7 +87,6 @@ Keyword {discrete_factor} defines a discretization factor for the adaptive timestep used in the {spin} minimization. See "min_spin"_min_spin.html for more information about those quantities. -Default values are {alpha_damp} = 1.0 and {discrete_factor} = 10.0. The choice of a line search algorithm for the {spin_oso_cg} and {spin_oso_lbfgs} styles can be specified via the {line} keyword. @@ -112,4 +110,9 @@ explanation. [Default:] -The option defaults are dmax = 0.1 and line = quadratic. +The option defaults are dmax = 0.1, line = quadratic and norm = +euclidean. + +For the {spin}, {spin_oso_cg} and {spin_oso_lbfgs} styles, the +option defaults are alpha_damp = 1.0, discrete_factor = 10.0, +line = spin_none, and norm = euclidean. diff --git a/doc/src/min_spin.txt b/doc/src/min_spin.txt index 20c4cde1d7..575db2dc74 100644 --- a/doc/src/min_spin.txt +++ b/doc/src/min_spin.txt @@ -56,7 +56,7 @@ Style {spin_oso_cg} defines an orthogonal spin optimization The "min_modify"_min_modify.html command can be used to couple the {spin_oso_cg} to a line search procedure, and to modify the discretization factor {discrete_factor}. -By defualt, the style {spin_oso_cg} does not employ line search procedure and +By default, style {spin_oso_cg} does not employ the line search procedure and uses the adaptive time-step technique in the same way as style {spin}. Style {spin_oso_lbfgs} defines an orthogonal spin optimization @@ -66,8 +66,8 @@ By default, style {spin_oso_lbfgs} does not employ line search procedure. If the line search procedure is not used then the discrete factor defines the maximum root mean squared rotation angle of spins by equation {pi/(5*Kappa)}. The default value for Kappa is 10. -The {spin_cubic} line search can improve -the convergence of the {spin_oso_lbfgs} algorithm. +The {spin_cubic} line search can improve the convergence of the +{spin_oso_lbfgs} algorithm. The "min_modify"_min_modify.html command can be used to activate the line search procedure, and to modify the @@ -95,8 +95,8 @@ freedom for a frozen lattice configuration. [Default:] -The option defaults are {alpha_damp} = 1.0 and {discrete_factor} = -10.0. +The option defaults are {alpha_damp} = 1.0, {discrete_factor} = +10.0, {line} = spin_none and {norm} = euclidean. :line diff --git a/doc/src/min_style.txt b/doc/src/min_style.txt index 081ec17889..7c40fd4947 100644 --- a/doc/src/min_style.txt +++ b/doc/src/min_style.txt @@ -11,8 +11,7 @@ min_style command :h3 min_style style :pre -style = {cg} or {hftn} or {sd} or {quickmin} or {fire} or {spin} -or {spin_oso_cg} or {spin_oso_lbfgs} :ul +style = {cg} or {hftn} or {sd} or {quickmin} or {fire} or {spin} or {spin_oso_cg} or {spin_oso_lbfgs} :ul [Examples:] From f4e3186abf95e0b0d6efd165c84a693ca295f448 Mon Sep 17 00:00:00 2001 From: julient31 Date: Tue, 30 Jul 2019 13:10:27 -0600 Subject: [PATCH 63/74] Commit JT 073019 - modified the false_positive file to correct errors - improved the doc page of fix nve/spin --- doc/src/fix_nve_spin.txt | 15 +++++++++++---- doc/src/min_modify.txt | 3 +-- doc/utils/sphinx-config/false_positives.txt | 5 +++++ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/doc/src/fix_nve_spin.txt b/doc/src/fix_nve_spin.txt index 7b382bb6ad..30df484e54 100644 --- a/doc/src/fix_nve_spin.txt +++ b/doc/src/fix_nve_spin.txt @@ -27,10 +27,16 @@ fix 1 all nve/spin lattice no :pre Perform a symplectic integration for the spin or spin-lattice system. -The {lattice} keyword defines if the spins are integrated on a lattice -of fixed atoms (lattice = no), or if atoms are moving (lattice = yes). +The {lattice} keyword defines whether the spins are integrated on a +fixed or moving lattice. -By default (lattice = yes), a spin-lattice integration is performed. +If {lattice}=yes, the equations of motion of the atoms are integrated, +and a combined spin and lattice calculation is performed. +This is the default option. + +If {lattice}=no, the equations of motion of the atoms are not +integrated. The lattice degrees of freedom are frozen, and a +spin dynamics only calculation is performed. The {nve/spin} fix applies a Suzuki-Trotter decomposition to the equations of motion of the spin lattice system, following the scheme: @@ -63,7 +69,8 @@ instead of "array" is also valid. "atom_style spin"_atom_style.html, "fix nve"_fix_nve.html -[Default:] none +[Default:] By default (lattice = yes), a spin-lattice integration is +performed. :line diff --git a/doc/src/min_modify.txt b/doc/src/min_modify.txt index 2056655d40..857c3551aa 100644 --- a/doc/src/min_modify.txt +++ b/doc/src/min_modify.txt @@ -110,8 +110,7 @@ explanation. [Default:] -The option defaults are dmax = 0.1, line = quadratic and norm = -euclidean. +The option defaults are dmax = 0.1, line = quadratic and norm = euclidean. For the {spin}, {spin_oso_cg} and {spin_oso_lbfgs} styles, the option defaults are alpha_damp = 1.0, discrete_factor = 10.0, diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index 1dea229393..417738998e 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -273,6 +273,7 @@ Broadwell Broglie brownian brownw +Broyden Bryantsev Btarget btype @@ -981,6 +982,7 @@ gmask Gmask gneb GNEB +Goldfarb googlemail Gordan GPa @@ -1395,6 +1397,7 @@ Laupretre lavenderblush lawngreen lB +lbfgs lbl LBtype lcbop @@ -2030,6 +2033,7 @@ Orsi ortho orthonormal orthorhombic +oso ot Otype Ouldridge @@ -2493,6 +2497,7 @@ setvel sfftw Sg Shan +Shanno shapex shapey shapez From c71e869a33cdec0c855763a0ce60928cf1149975 Mon Sep 17 00:00:00 2001 From: alxvov Date: Wed, 21 Aug 2019 14:02:34 +0000 Subject: [PATCH 64/74] define params in creator as init is called after modify --- src/SPIN/min_spin.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SPIN/min_spin.cpp b/src/SPIN/min_spin.cpp index c8e0020ef8..947e281b42 100644 --- a/src/SPIN/min_spin.cpp +++ b/src/SPIN/min_spin.cpp @@ -41,15 +41,15 @@ using namespace MathConst; /* ---------------------------------------------------------------------- */ -MinSpin::MinSpin(LAMMPS *lmp) : Min(lmp) {} +MinSpin::MinSpin(LAMMPS *lmp) : Min(lmp) { + alpha_damp = 1.0; + discrete_factor = 10.0; +} /* ---------------------------------------------------------------------- */ void MinSpin::init() { - alpha_damp = 1.0; - discrete_factor = 10.0; - Min::init(); dts = dt = update->dt; From 8ec4e3fc9164fb21a2ceadf5211b3abe7987690f Mon Sep 17 00:00:00 2001 From: julient31 Date: Thu, 22 Aug 2019 10:48:58 -0600 Subject: [PATCH 65/74] Commit JT 082219 - modified min spin names (removed oso from spin/cg and spin/lbfgs) - modified associated option name (from spin_oso_cg to spin/cg, same for lbfgs) - modified .gitignore, doc pages, and examples accordingly --- doc/src/min_modify.txt | 14 ++-- doc/src/min_spin.txt | 26 +++---- doc/src/min_style.txt | 10 +-- doc/src/minimize.txt | 2 +- doc/src/neb_spin.txt | 4 +- examples/SPIN/spinmin/in.spinmin_cg.bfo | 2 +- examples/SPIN/spinmin/in.spinmin_lbfgs.bfo | 2 +- src/.gitignore | 8 +-- .../{min_spin_oso_cg.cpp => min_spin_cg.cpp} | 58 +++++++-------- src/SPIN/{min_spin_oso_cg.h => min_spin_cg.h} | 12 ++-- ..._spin_oso_lbfgs.cpp => min_spin_lbfgs.cpp} | 70 +++++++++---------- ...{min_spin_oso_lbfgs.h => min_spin_lbfgs.h} | 12 ++-- 12 files changed, 110 insertions(+), 110 deletions(-) rename src/SPIN/{min_spin_oso_cg.cpp => min_spin_cg.cpp} (91%) rename src/SPIN/{min_spin_oso_cg.h => min_spin_cg.h} (90%) rename src/SPIN/{min_spin_oso_lbfgs.cpp => min_spin_lbfgs.cpp} (90%) rename src/SPIN/{min_spin_oso_lbfgs.h => min_spin_lbfgs.h} (90%) diff --git a/doc/src/min_modify.txt b/doc/src/min_modify.txt index 857c3551aa..22ee232467 100644 --- a/doc/src/min_modify.txt +++ b/doc/src/min_modify.txt @@ -72,7 +72,7 @@ that difference may be smaller than machine epsilon even if atoms could move in the gradient direction to reduce forces further. The choice of a norm can be modified for the min styles {cg}, {sd}, -{quickmin}, {fire}, {spin}, {spin_oso_cg} and {spin_oso_lbfgs} using +{quickmin}, {fire}, {spin}, {spin/cg} and {spin/lbfgs} using the {norm} keyword. The default {euclidean} norm computes the 2-norm (length) of the global force vector. The {max} norm computes the maximum value @@ -88,19 +88,19 @@ adaptive timestep used in the {spin} minimization. See "min_spin"_min_spin.html for more information about those quantities. -The choice of a line search algorithm for the {spin_oso_cg} and -{spin_oso_lbfgs} styles can be specified via the {line} keyword. +The choice of a line search algorithm for the {spin/cg} and +{spin/lbfgs} styles can be specified via the {line} keyword. The {spin_cubic} and {spin_none} only make sense when one of those two minimization styles is declared. The {spin_cubic} performs the line search based on a cubic interpolation of the energy along the search direction. The {spin_none} keyword deactivates the line search procedure. -The {spin_none} is a default value for {line} keyword for both {spin_oso_lbfgs} -and {spin_oso_cg}. Convergence of {spin_oso_lbfgs} can be more robust if +The {spin_none} is a default value for {line} keyword for both {spin/lbfgs} +and {spin/cg}. Convergence of {spin/lbfgs} can be more robust if {spin_cubic} line search is used. [Restrictions:] The line search procedure of styles -{spin_oso_cg} and {spin_oso_lbfgs} cannot be used for magnetic +{spin/cg} and {spin/lbfgs} cannot be used for magnetic GNEB calculations. See "neb/spin"_neb_spin.html for more explanation. @@ -112,6 +112,6 @@ explanation. The option defaults are dmax = 0.1, line = quadratic and norm = euclidean. -For the {spin}, {spin_oso_cg} and {spin_oso_lbfgs} styles, the +For the {spin}, {spin/cg} and {spin/lbfgs} styles, the option defaults are alpha_damp = 1.0, discrete_factor = 10.0, line = spin_none, and norm = euclidean. diff --git a/doc/src/min_spin.txt b/doc/src/min_spin.txt index 575db2dc74..ba034cfbb9 100644 --- a/doc/src/min_spin.txt +++ b/doc/src/min_spin.txt @@ -6,18 +6,18 @@ :line min_style spin command :h3 -min_style spin_oso_cg command :h3 -min_style spin_oso_lbfgs command :h3 +min_style spin/cg command :h3 +min_style spin/lbfgs command :h3 [Syntax:] min_style spin -min_style spin_oso_cg -min_style spin_oso_lbfgs :pre +min_style spin/cg +min_style spin/lbfgs :pre [Examples:] -min_style spin_oso_lbfgs +min_style spin/lbfgs min_modify line spin_cubic discrete_factor 10.0 :pre [Description:] @@ -51,35 +51,35 @@ definition of this timestep. {discrete_factor} can be defined with the "min_modify"_min_modify.html command. -Style {spin_oso_cg} defines an orthogonal spin optimization +Style {spin/cg} defines an orthogonal spin optimization (OSO) combined to a conjugate gradient (CG) algorithm. The "min_modify"_min_modify.html command can be used to -couple the {spin_oso_cg} to a line search procedure, and to modify the +couple the {spin/cg} to a line search procedure, and to modify the discretization factor {discrete_factor}. -By default, style {spin_oso_cg} does not employ the line search procedure +By default, style {spin/cg} does not employ the line search procedure and uses the adaptive time-step technique in the same way as style {spin}. -Style {spin_oso_lbfgs} defines an orthogonal spin optimization +Style {spin/lbfgs} defines an orthogonal spin optimization (OSO) combined to a limited-memory Broyden-Fletcher-Goldfarb-Shanno (L-BFGS) algorithm. -By default, style {spin_oso_lbfgs} does not employ line search procedure. +By default, style {spin/lbfgs} does not employ line search procedure. If the line search procedure is not used then the discrete factor defines the maximum root mean squared rotation angle of spins by equation {pi/(5*Kappa)}. The default value for Kappa is 10. The {spin_cubic} line search can improve the convergence of the -{spin_oso_lbfgs} algorithm. +{spin/lbfgs} algorithm. The "min_modify"_min_modify.html command can be used to activate the line search procedure, and to modify the discretization factor {discrete_factor}. -For more information about styles {spin_oso_cg} and {spin_oso_lbfgs}, +For more information about styles {spin/cg} and {spin/lbfgs}, see their implementation reported in "(Ivanov)"_#Ivanov1. NOTE: All the {spin} styles replace the force tolerance by a torque tolerance. See "minimize"_minimize.html for more explanation. -NOTE: The {spin_oso_cg} and {spin_oso_lbfgs} styles can be used +NOTE: The {spin/cg} and {spin/lbfgs} styles can be used for magnetic NEB calculations only if the line search procedure is deactivated. See "neb/spin"_neb_spin.html for more explanation. diff --git a/doc/src/min_style.txt b/doc/src/min_style.txt index 7c40fd4947..9613da7b13 100644 --- a/doc/src/min_style.txt +++ b/doc/src/min_style.txt @@ -11,7 +11,7 @@ min_style command :h3 min_style style :pre -style = {cg} or {hftn} or {sd} or {quickmin} or {fire} or {spin} or {spin_oso_cg} or {spin_oso_lbfgs} :ul +style = {cg} or {hftn} or {sd} or {quickmin} or {fire} or {spin} or {spin/cg} or {spin/lbfgs} :ul [Examples:] @@ -65,21 +65,21 @@ a minimization. Style {spin} is a damped spin dynamics with an adaptive timestep. -Style {spin_oso_cg} uses an orthogonal spin optimization (OSO) +Style {spin/cg} uses an orthogonal spin optimization (OSO) combined to a conjugate gradient (CG) approach to minimize spin configurations. -Style {spin_oso_lbfgs} uses an orthogonal spin optimization (OSO) +Style {spin/lbfgs} uses an orthogonal spin optimization (OSO) combined to a limited-memory Broyden-Fletcher-Goldfarb-Shanno (LBFGS) approach to minimize spin configurations. See the "min/spin"_min_spin.html doc page for more information -about the {spin}, {spin_oso_cg} and {spin_oso_lbfgs} styles. +about the {spin}, {spin/cg} and {spin/lbfgs} styles. Either the {quickmin} and {fire} styles are useful in the context of nudged elastic band (NEB) calculations via the "neb"_neb.html command. -Either the {spin}, {spin_oso_cg} and {spin_oso_lbfgs} styles are useful +Either the {spin}, {spin/cg} and {spin/lbfgs} styles are useful in the context of magnetic geodesic nudged elastic band (GNEB) calculations via the "neb/spin"_neb_spin.html command. diff --git a/doc/src/minimize.txt b/doc/src/minimize.txt index 1de925d6c8..bfdc02bedf 100644 --- a/doc/src/minimize.txt +++ b/doc/src/minimize.txt @@ -104,7 +104,7 @@ the number of outer iterations or timesteps exceeds {maxiter} the number of total force evaluations exceeds {maxeval} :ul NOTE: the "minimization style"_min_style.html {spin}, -{spin_oso_cg}, and {spin_oso_lbfgs} replace +{spin/cg}, and {spin/lbfgs} replace the force tolerance {ftol} by a torque tolerance. The minimization procedure stops if the 2-norm (length) of the torque vector on atom (defined as the cross product between the diff --git a/doc/src/neb_spin.txt b/doc/src/neb_spin.txt index 2fdfda8c66..b64df39219 100644 --- a/doc/src/neb_spin.txt +++ b/doc/src/neb_spin.txt @@ -173,7 +173,7 @@ A NEB calculation proceeds in two stages, each of which is a minimization procedure. To enable this, you must first define a "min_style"_min_style.html, using either the {spin}, -{spin_oso_cg}, or {spin_oso_lbfgs} style (see +{spin/cg}, or {spin/lbfgs} style (see "min_spin"_min_spin.html for more information). The other styles cannot be used, since they relax the lattice degrees of freedom instead of the spins. @@ -359,7 +359,7 @@ This command can only be used if LAMMPS was built with the SPIN package. See the "Build package"_Build_package.html doc page for more info. -The line search procedures of the {spin_oso_cg} and {spin_oso_lbfgs} +The line search procedures of the {spin/cg} and {spin/lbfgs} minimization styles cannot be used in a GNEB calculation. :line diff --git a/examples/SPIN/spinmin/in.spinmin_cg.bfo b/examples/SPIN/spinmin/in.spinmin_cg.bfo index 8c288763c4..9d57399a56 100644 --- a/examples/SPIN/spinmin/in.spinmin_cg.bfo +++ b/examples/SPIN/spinmin/in.spinmin_cg.bfo @@ -49,6 +49,6 @@ thermo_modify format float %20.15g compute outsp all property/atom spx spy spz sp fmx fmy fmz dump 1 all custom 50 dump.lammpstrj type x y z c_outsp[1] c_outsp[2] c_outsp[3] c_outsp[4] c_outsp[5] c_outsp[6] c_outsp[7] -min_style spin_oso_cg +min_style spin/cg # min_modify line spin_none discrete_factor 10.0 minimize 1.0e-10 1.0e-10 10000 10000 diff --git a/examples/SPIN/spinmin/in.spinmin_lbfgs.bfo b/examples/SPIN/spinmin/in.spinmin_lbfgs.bfo index 6a9104cc9c..a73b863b11 100644 --- a/examples/SPIN/spinmin/in.spinmin_lbfgs.bfo +++ b/examples/SPIN/spinmin/in.spinmin_lbfgs.bfo @@ -49,6 +49,6 @@ thermo_modify format float %20.15g compute outsp all property/atom spx spy spz sp fmx fmy fmz dump 1 all custom 50 dump.lammpstrj type x y z c_outsp[1] c_outsp[2] c_outsp[3] c_outsp[4] c_outsp[5] c_outsp[6] c_outsp[7] -min_style spin_oso_lbfgs +min_style spin/lbfgs # min_modify line spin_cubic discrete_factor 10.0 minimize 1.0e-15 1.0e-10 10000 1000 diff --git a/src/.gitignore b/src/.gitignore index 595276853c..5848874d94 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -161,10 +161,10 @@ /fix_setforce_spin.h /min_spin.cpp /min_spin.h -/min_spin_oso_cg.cpp -/min_spin_oso_cg.h -/min_spin_oso_lbfgs.cpp -/min_spin_oso_lbfgs.h +/min_spin_cg.cpp +/min_spin_cg.h +/min_spin_lbfgs.cpp +/min_spin_lbfgs.h /neb_spin.cpp /neb_spin.h /pair_spin.cpp diff --git a/src/SPIN/min_spin_oso_cg.cpp b/src/SPIN/min_spin_cg.cpp similarity index 91% rename from src/SPIN/min_spin_oso_cg.cpp rename to src/SPIN/min_spin_cg.cpp index f1f2f72436..322915c0f3 100644 --- a/src/SPIN/min_spin_oso_cg.cpp +++ b/src/SPIN/min_spin_cg.cpp @@ -25,7 +25,7 @@ #include #include #include -#include "min_spin_oso_cg.h" +#include "min_spin_cg.h" #include "universe.h" #include "atom.h" #include "citeme.h" @@ -44,8 +44,8 @@ using namespace LAMMPS_NS; using namespace MathConst; -static const char cite_minstyle_spin_oso_cg[] = - "min_style spin/oso_cg command:\n\n" +static const char cite_minstyle_spin_cg[] = + "min_style spin/cg command:\n\n" "@article{ivanov2019fast,\n" "title={Fast and Robust Algorithm for the Minimisation of the Energy of " "Spin Systems},\n" @@ -63,10 +63,10 @@ static const char cite_minstyle_spin_oso_cg[] = /* ---------------------------------------------------------------------- */ -MinSpinOSO_CG::MinSpinOSO_CG(LAMMPS *lmp) : +MinSpinCG::MinSpinCG(LAMMPS *lmp) : Min(lmp), g_old(NULL), g_cur(NULL), p_s(NULL), sp_copy(NULL) { - if (lmp->citeme) lmp->citeme->add(cite_minstyle_spin_oso_cg); + if (lmp->citeme) lmp->citeme->add(cite_minstyle_spin_cg); nlocal_max = 0; // nreplica = number of partitions @@ -81,7 +81,7 @@ MinSpinOSO_CG::MinSpinOSO_CG(LAMMPS *lmp) : /* ---------------------------------------------------------------------- */ -MinSpinOSO_CG::~MinSpinOSO_CG() +MinSpinCG::~MinSpinCG() { memory->destroy(g_old); memory->destroy(g_cur); @@ -92,7 +92,7 @@ MinSpinOSO_CG::~MinSpinOSO_CG() /* ---------------------------------------------------------------------- */ -void MinSpinOSO_CG::init() +void MinSpinCG::init() { local_iter = 0; der_e_cur = 0.0; @@ -120,16 +120,16 @@ void MinSpinOSO_CG::init() // allocate tables nlocal_max = atom->nlocal; - memory->grow(g_old,3*nlocal_max,"min/spin/oso/cg:g_old"); - memory->grow(g_cur,3*nlocal_max,"min/spin/oso/cg:g_cur"); - memory->grow(p_s,3*nlocal_max,"min/spin/oso/cg:p_s"); + memory->grow(g_old,3*nlocal_max,"min/spin/cg:g_old"); + memory->grow(g_cur,3*nlocal_max,"min/spin/cg:g_cur"); + memory->grow(p_s,3*nlocal_max,"min/spin/cg:p_s"); if (use_line_search) - memory->grow(sp_copy,nlocal_max,3,"min/spin/oso/cg:sp_copy"); + memory->grow(sp_copy,nlocal_max,3,"min/spin/cg:sp_copy"); } /* ---------------------------------------------------------------------- */ -void MinSpinOSO_CG::setup_style() +void MinSpinCG::setup_style() { double **v = atom->v; int nlocal = atom->nlocal; @@ -137,7 +137,7 @@ void MinSpinOSO_CG::setup_style() // check if the atom/spin style is defined if (!atom->sp_flag) - error->all(FLERR,"min/spin_oso_cg requires atom/spin style"); + error->all(FLERR,"min spin/cg requires atom/spin style"); for (int i = 0; i < nlocal; i++) v[i][0] = v[i][1] = v[i][2] = 0.0; @@ -145,7 +145,7 @@ void MinSpinOSO_CG::setup_style() /* ---------------------------------------------------------------------- */ -int MinSpinOSO_CG::modify_param(int narg, char **arg) +int MinSpinCG::modify_param(int narg, char **arg) { if (strcmp(arg[0],"discrete_factor") == 0) { if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); @@ -160,7 +160,7 @@ int MinSpinOSO_CG::modify_param(int narg, char **arg) called after atoms have migrated ------------------------------------------------------------------------- */ -void MinSpinOSO_CG::reset_vectors() +void MinSpinCG::reset_vectors() { // atomic dof @@ -179,7 +179,7 @@ void MinSpinOSO_CG::reset_vectors() minimization via orthogonal spin optimisation ------------------------------------------------------------------------- */ -int MinSpinOSO_CG::iterate(int maxiter) +int MinSpinCG::iterate(int maxiter) { int nlocal = atom->nlocal; bigint ntimestep; @@ -191,11 +191,11 @@ int MinSpinOSO_CG::iterate(int maxiter) if (nlocal_max < nlocal) { local_iter = 0; nlocal_max = nlocal; - memory->grow(g_old,3*nlocal_max,"min/spin/oso/cg:g_old"); - memory->grow(g_cur,3*nlocal_max,"min/spin/oso/cg:g_cur"); - memory->grow(p_s,3*nlocal_max,"min/spin/oso/cg:p_s"); + memory->grow(g_old,3*nlocal_max,"min/spin/cg:g_old"); + memory->grow(g_cur,3*nlocal_max,"min/spin/cg:g_cur"); + memory->grow(p_s,3*nlocal_max,"min/spin/cg:p_s"); if (use_line_search) - memory->grow(sp_copy,nlocal_max,3,"min/spin/oso/cg:sp_copy"); + memory->grow(sp_copy,nlocal_max,3,"min/spin/cg:sp_copy"); } for (int iter = 0; iter < maxiter; iter++) { @@ -309,7 +309,7 @@ int MinSpinOSO_CG::iterate(int maxiter) calculate gradients ---------------------------------------------------------------------- */ -void MinSpinOSO_CG::calc_gradient() +void MinSpinCG::calc_gradient() { int nlocal = atom->nlocal; double **sp = atom->sp; @@ -337,7 +337,7 @@ void MinSpinOSO_CG::calc_gradient() Optimization' Second Edition, 2006 (p. 121) ---------------------------------------------------------------------- */ -void MinSpinOSO_CG::calc_search_direction() +void MinSpinCG::calc_search_direction() { int nlocal = atom->nlocal; double g2old = 0.0; @@ -398,7 +398,7 @@ void MinSpinOSO_CG::calc_search_direction() rotation of spins along the search direction ---------------------------------------------------------------------- */ -void MinSpinOSO_CG::advance_spins() +void MinSpinCG::advance_spins() { int nlocal = atom->nlocal; double **sp = atom->sp; @@ -429,7 +429,7 @@ void MinSpinOSO_CG::advance_spins() [-y, -z, 0]] ------------------------------------------------------------------------- */ -void MinSpinOSO_CG::rodrigues_rotation(const double *upp_tr, double *out) +void MinSpinCG::rodrigues_rotation(const double *upp_tr, double *out) { double theta,A,B,D,x,y,z; double s1,s2,s3,a1,a2,a3; @@ -490,7 +490,7 @@ void MinSpinOSO_CG::rodrigues_rotation(const double *upp_tr, double *out) m -- 3x3 matrix , v -- 3-d vector ------------------------------------------------------------------------- */ -void MinSpinOSO_CG::vm3(const double *m, const double *v, double *out) +void MinSpinCG::vm3(const double *m, const double *v, double *out) { for(int i = 0; i < 3; i++){ out[i] = 0.0; @@ -502,7 +502,7 @@ void MinSpinOSO_CG::vm3(const double *m, const double *v, double *out) advance spins ------------------------------------------------------------------------- */ -void MinSpinOSO_CG::make_step(double c, double *energy_and_der) +void MinSpinCG::make_step(double c, double *energy_and_der) { double p_scaled[3]; int nlocal = atom->nlocal; @@ -549,7 +549,7 @@ void MinSpinOSO_CG::make_step(double c, double *energy_and_der) using the cubic interpolation ------------------------------------------------------------------------- */ -int MinSpinOSO_CG::calc_and_make_step(double a, double b, int index) +int MinSpinCG::calc_and_make_step(double a, double b, int index) { double e_and_d[2] = {0.0,0.0}; double alpha,c1,c2,c3; @@ -601,7 +601,7 @@ int MinSpinOSO_CG::calc_and_make_step(double a, double b, int index) Approximate descent ------------------------------------------------------------------------- */ -int MinSpinOSO_CG::adescent(double phi_0, double phi_j){ +int MinSpinCG::adescent(double phi_0, double phi_j){ double eps = 1.0e-6; @@ -615,7 +615,7 @@ int MinSpinOSO_CG::adescent(double phi_0, double phi_j){ evaluate max timestep ---------------------------------------------------------------------- */ -double MinSpinOSO_CG::evaluate_dt() +double MinSpinCG::evaluate_dt() { double dtmax; double fmsq; diff --git a/src/SPIN/min_spin_oso_cg.h b/src/SPIN/min_spin_cg.h similarity index 90% rename from src/SPIN/min_spin_oso_cg.h rename to src/SPIN/min_spin_cg.h index d6dc7c03d0..0eed7a61e6 100644 --- a/src/SPIN/min_spin_oso_cg.h +++ b/src/SPIN/min_spin_cg.h @@ -13,21 +13,21 @@ #ifdef MINIMIZE_CLASS -MinimizeStyle(spin_oso_cg, MinSpinOSO_CG) +MinimizeStyle(spin/cg, MinSpinCG) #else -#ifndef LMP_MIN_SPIN_OSO_CG_H -#define LMP_MIN_SPIN_OSO_CG_H +#ifndef LMP_MIN_SPIN_CG_H +#define LMP_MIN_SPIN_CG_H #include "min.h" namespace LAMMPS_NS { -class MinSpinOSO_CG: public Min { +class MinSpinCG: public Min { public: - MinSpinOSO_CG(class LAMMPS *); - virtual ~MinSpinOSO_CG(); + MinSpinCG(class LAMMPS *); + virtual ~MinSpinCG(); void init(); void setup_style(); void reset_vectors(); diff --git a/src/SPIN/min_spin_oso_lbfgs.cpp b/src/SPIN/min_spin_lbfgs.cpp similarity index 90% rename from src/SPIN/min_spin_oso_lbfgs.cpp rename to src/SPIN/min_spin_lbfgs.cpp index 8623a8bb29..891dec5c93 100644 --- a/src/SPIN/min_spin_oso_lbfgs.cpp +++ b/src/SPIN/min_spin_lbfgs.cpp @@ -25,7 +25,7 @@ #include #include #include -#include "min_spin_oso_lbfgs.h" +#include "min_spin_lbfgs.h" #include "atom.h" #include "citeme.h" #include "comm.h" @@ -43,8 +43,8 @@ using namespace LAMMPS_NS; using namespace MathConst; -static const char cite_minstyle_spin_oso_lbfgs[] = - "min_style spin/oso_lbfgs command:\n\n" +static const char cite_minstyle_spin_lbfgs[] = + "min_style spin/lbfgs command:\n\n" "@article{ivanov2019fast,\n" "title={Fast and Robust Algorithm for the Minimisation of the Energy of " "Spin Systems},\n" @@ -62,10 +62,10 @@ static const char cite_minstyle_spin_oso_lbfgs[] = /* ---------------------------------------------------------------------- */ -MinSpinOSO_LBFGS::MinSpinOSO_LBFGS(LAMMPS *lmp) : +MinSpinLBFGS::MinSpinLBFGS(LAMMPS *lmp) : Min(lmp), g_old(NULL), g_cur(NULL), p_s(NULL), rho(NULL), ds(NULL), dy(NULL), sp_copy(NULL) { - if (lmp->citeme) lmp->citeme->add(cite_minstyle_spin_oso_lbfgs); + if (lmp->citeme) lmp->citeme->add(cite_minstyle_spin_lbfgs); nlocal_max = 0; // nreplica = number of partitions @@ -81,7 +81,7 @@ MinSpinOSO_LBFGS::MinSpinOSO_LBFGS(LAMMPS *lmp) : /* ---------------------------------------------------------------------- */ -MinSpinOSO_LBFGS::~MinSpinOSO_LBFGS() +MinSpinLBFGS::~MinSpinLBFGS() { memory->destroy(g_old); memory->destroy(g_cur); @@ -95,7 +95,7 @@ MinSpinOSO_LBFGS::~MinSpinOSO_LBFGS() /* ---------------------------------------------------------------------- */ -void MinSpinOSO_LBFGS::init() +void MinSpinLBFGS::init() { num_mem = 3; local_iter = 0; @@ -123,20 +123,20 @@ void MinSpinOSO_LBFGS::init() // allocate tables nlocal_max = atom->nlocal; - memory->grow(g_old,3*nlocal_max,"min/spin/oso/lbfgs:g_old"); - memory->grow(g_cur,3*nlocal_max,"min/spin/oso/lbfgs:g_cur"); - memory->grow(p_s,3*nlocal_max,"min/spin/oso/lbfgs:p_s"); - memory->grow(rho,num_mem,"min/spin/oso/lbfgs:rho"); - memory->grow(ds,num_mem,3*nlocal_max,"min/spin/oso/lbfgs:ds"); - memory->grow(dy,num_mem,3*nlocal_max,"min/spin/oso/lbfgs:dy"); + memory->grow(g_old,3*nlocal_max,"min/spin/lbfgs:g_old"); + memory->grow(g_cur,3*nlocal_max,"min/spin/lbfgs:g_cur"); + memory->grow(p_s,3*nlocal_max,"min/spin/lbfgs:p_s"); + memory->grow(rho,num_mem,"min/spin/lbfgs:rho"); + memory->grow(ds,num_mem,3*nlocal_max,"min/spin/lbfgs:ds"); + memory->grow(dy,num_mem,3*nlocal_max,"min/spin/lbfgs:dy"); if (use_line_search) - memory->grow(sp_copy,nlocal_max,3,"min/spin/oso/lbfgs:sp_copy"); + memory->grow(sp_copy,nlocal_max,3,"min/spin/lbfgs:sp_copy"); } /* ---------------------------------------------------------------------- */ -void MinSpinOSO_LBFGS::setup_style() +void MinSpinLBFGS::setup_style() { double **v = atom->v; int nlocal = atom->nlocal; @@ -144,7 +144,7 @@ void MinSpinOSO_LBFGS::setup_style() // check if the atom/spin style is defined if (!atom->sp_flag) - error->all(FLERR,"min/spin_oso_lbfgs requires atom/spin style"); + error->all(FLERR,"min spin/lbfgs requires atom/spin style"); for (int i = 0; i < nlocal; i++) v[i][0] = v[i][1] = v[i][2] = 0.0; @@ -152,7 +152,7 @@ void MinSpinOSO_LBFGS::setup_style() /* ---------------------------------------------------------------------- */ -int MinSpinOSO_LBFGS::modify_param(int narg, char **arg) +int MinSpinLBFGS::modify_param(int narg, char **arg) { if (strcmp(arg[0],"discrete_factor") == 0) { if (narg < 2) error->all(FLERR,"Illegal min_modify command"); @@ -169,7 +169,7 @@ int MinSpinOSO_LBFGS::modify_param(int narg, char **arg) called after atoms have migrated ------------------------------------------------------------------------- */ -void MinSpinOSO_LBFGS::reset_vectors() +void MinSpinLBFGS::reset_vectors() { // atomic dof @@ -188,7 +188,7 @@ void MinSpinOSO_LBFGS::reset_vectors() minimization via damped spin dynamics ------------------------------------------------------------------------- */ -int MinSpinOSO_LBFGS::iterate(int maxiter) +int MinSpinLBFGS::iterate(int maxiter) { int nlocal = atom->nlocal; bigint ntimestep; @@ -200,14 +200,14 @@ int MinSpinOSO_LBFGS::iterate(int maxiter) if (nlocal_max < nlocal) { nlocal_max = nlocal; local_iter = 0; - memory->grow(g_old,3*nlocal_max,"min/spin/oso/lbfgs:g_old"); - memory->grow(g_cur,3*nlocal_max,"min/spin/oso/lbfgs:g_cur"); - memory->grow(p_s,3*nlocal_max,"min/spin/oso/lbfgs:p_s"); - memory->grow(rho,num_mem,"min/spin/oso/lbfgs:rho"); - memory->grow(ds,num_mem,3*nlocal_max,"min/spin/oso/lbfgs:ds"); - memory->grow(dy,num_mem,3*nlocal_max,"min/spin/oso/lbfgs:dy"); + memory->grow(g_old,3*nlocal_max,"min/spin/lbfgs:g_old"); + memory->grow(g_cur,3*nlocal_max,"min/spin/lbfgs:g_cur"); + memory->grow(p_s,3*nlocal_max,"min/spin/lbfgs:p_s"); + memory->grow(rho,num_mem,"min/spin/lbfgs:rho"); + memory->grow(ds,num_mem,3*nlocal_max,"min/spin/lbfgs:ds"); + memory->grow(dy,num_mem,3*nlocal_max,"min/spin/lbfgs:dy"); if (use_line_search) - memory->grow(sp_copy,nlocal_max,3,"min/spin/oso/lbfgs:sp_copy"); + memory->grow(sp_copy,nlocal_max,3,"min/spin/lbfgs:sp_copy"); } for (int iter = 0; iter < maxiter; iter++) { @@ -324,7 +324,7 @@ int MinSpinOSO_LBFGS::iterate(int maxiter) calculate gradients ---------------------------------------------------------------------- */ -void MinSpinOSO_LBFGS::calc_gradient() +void MinSpinLBFGS::calc_gradient() { int nlocal = atom->nlocal; double **sp = atom->sp; @@ -347,7 +347,7 @@ void MinSpinOSO_LBFGS::calc_gradient() Optimization' Second Edition, 2006 (p. 177) ---------------------------------------------------------------------- */ -void MinSpinOSO_LBFGS::calc_search_direction() +void MinSpinLBFGS::calc_search_direction() { int nlocal = atom->nlocal; @@ -531,7 +531,7 @@ void MinSpinOSO_LBFGS::calc_search_direction() rotation of spins along the search direction ---------------------------------------------------------------------- */ -void MinSpinOSO_LBFGS::advance_spins() +void MinSpinLBFGS::advance_spins() { int nlocal = atom->nlocal; double **sp = atom->sp; @@ -562,7 +562,7 @@ void MinSpinOSO_LBFGS::advance_spins() [-y, -z, 0]] ------------------------------------------------------------------------- */ -void MinSpinOSO_LBFGS::rodrigues_rotation(const double *upp_tr, double *out) +void MinSpinLBFGS::rodrigues_rotation(const double *upp_tr, double *out) { double theta,A,B,D,x,y,z; double s1,s2,s3,a1,a2,a3; @@ -622,7 +622,7 @@ void MinSpinOSO_LBFGS::rodrigues_rotation(const double *upp_tr, double *out) m -- 3x3 matrix , v -- 3-d vector ------------------------------------------------------------------------- */ -void MinSpinOSO_LBFGS::vm3(const double *m, const double *v, double *out) +void MinSpinLBFGS::vm3(const double *m, const double *v, double *out) { for(int i = 0; i < 3; i++){ out[i] = 0.0; @@ -632,7 +632,7 @@ void MinSpinOSO_LBFGS::vm3(const double *m, const double *v, double *out) } -void MinSpinOSO_LBFGS::make_step(double c, double *energy_and_der) +void MinSpinLBFGS::make_step(double c, double *energy_and_der) { double p_scaled[3]; int nlocal = atom->nlocal; @@ -679,7 +679,7 @@ void MinSpinOSO_LBFGS::make_step(double c, double *energy_and_der) using the cubic interpolation ------------------------------------------------------------------------- */ -int MinSpinOSO_LBFGS::calc_and_make_step(double a, double b, int index) +int MinSpinLBFGS::calc_and_make_step(double a, double b, int index) { double e_and_d[2] = {0.0,0.0}; double alpha,c1,c2,c3; @@ -731,7 +731,7 @@ int MinSpinOSO_LBFGS::calc_and_make_step(double a, double b, int index) Approximate descent ------------------------------------------------------------------------- */ -int MinSpinOSO_LBFGS::adescent(double phi_0, double phi_j){ +int MinSpinLBFGS::adescent(double phi_0, double phi_j){ double eps = 1.0e-6; @@ -741,7 +741,7 @@ int MinSpinOSO_LBFGS::adescent(double phi_0, double phi_j){ return 0; } -double MinSpinOSO_LBFGS::maximum_rotation(double *p) +double MinSpinLBFGS::maximum_rotation(double *p) { double norm2,norm2_global,scaling,alpha; int nlocal = atom->nlocal; diff --git a/src/SPIN/min_spin_oso_lbfgs.h b/src/SPIN/min_spin_lbfgs.h similarity index 90% rename from src/SPIN/min_spin_oso_lbfgs.h rename to src/SPIN/min_spin_lbfgs.h index 68fa10921e..cead605b32 100644 --- a/src/SPIN/min_spin_oso_lbfgs.h +++ b/src/SPIN/min_spin_lbfgs.h @@ -13,21 +13,21 @@ #ifdef MINIMIZE_CLASS -MinimizeStyle(spin_oso_lbfgs, MinSpinOSO_LBFGS) +MinimizeStyle(spin/lbfgs, MinSpinLBFGS) #else -#ifndef LMP_MIN_SPIN_OSO_LBFGS_H -#define LMP_MIN_SPIN_OSO_LBFGS_H +#ifndef LMP_MIN_SPIN_LBFGS_H +#define LMP_MIN_SPIN_LBFGS_H #include "min.h" namespace LAMMPS_NS { -class MinSpinOSO_LBFGS: public Min { +class MinSpinLBFGS: public Min { public: - MinSpinOSO_LBFGS(class LAMMPS *); - virtual ~MinSpinOSO_LBFGS(); + MinSpinLBFGS(class LAMMPS *); + virtual ~MinSpinLBFGS(); void init(); void setup_style(); int modify_param(int, char **); From f1563ed9885ecd1ad9e5b914a320969a7ea44504 Mon Sep 17 00:00:00 2001 From: julient31 Date: Tue, 27 Aug 2019 17:44:04 -0600 Subject: [PATCH 66/74] Commit JT 082719 - correcting min_modify.txt --- doc/src/min_modify.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/src/min_modify.txt b/doc/src/min_modify.txt index 22ee232467..06c1f7514f 100644 --- a/doc/src/min_modify.txt +++ b/doc/src/min_modify.txt @@ -99,9 +99,10 @@ The {spin_none} is a default value for {line} keyword for both {spin/lbfgs} and {spin/cg}. Convergence of {spin/lbfgs} can be more robust if {spin_cubic} line search is used. -[Restrictions:] The line search procedure of styles -{spin/cg} and {spin/lbfgs} cannot be used for magnetic -GNEB calculations. See "neb/spin"_neb_spin.html for more +[Restrictions:] + +The line search procedure of styles {spin/cg} and {spin/lbfgs} cannot be +used for magnetic GNEB calculations. See "neb/spin"_neb_spin.html for more explanation. [Related commands:] From 48ea1eecb6fa3494db772069de1529baa7542ea1 Mon Sep 17 00:00:00 2001 From: alxvov Date: Sun, 8 Sep 2019 15:51:54 +0300 Subject: [PATCH 67/74] make as in master --- src/MAKE/Makefile.serial | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MAKE/Makefile.serial b/src/MAKE/Makefile.serial index 8628d2bb73..5954d97761 100644 --- a/src/MAKE/Makefile.serial +++ b/src/MAKE/Makefile.serial @@ -7,7 +7,7 @@ SHELL = /bin/sh # specify flags and libraries needed for your compiler CC = g++ -CCFLAGS = -g -O3 -Wall +CCFLAGS = -g -O3 SHFLAGS = -fPIC DEPFLAGS = -M From 56e1a05287c34188eca387dfee62b935434096fd Mon Sep 17 00:00:00 2001 From: julient31 Date: Mon, 23 Sep 2019 11:12:31 -0600 Subject: [PATCH 68/74] Commit JT 092319 - modified norm input in min_modify - corrected doc/src/min_modify.txt - added expression of the norms - added a min max method in src/min.h --- doc/src/Eqs/norm_max.jpg | Bin 0 -> 9471 bytes doc/src/Eqs/norm_max.tex | 15 ++++++++++ doc/src/Eqs/norm_two.jpg | Bin 0 -> 6048 bytes doc/src/Eqs/norm_two.tex | 15 ++++++++++ doc/src/min_modify.txt | 18 ++++++++---- src/MAKE/Makefile.serial | 2 +- src/min.cpp | 59 +++++++++++++++++++++++++++++++-------- src/min.h | 4 ++- src/min_cg.cpp | 12 ++++---- src/min_fire.cpp | 11 ++------ src/min_hftn.cpp | 2 +- src/min_quickmin.cpp | 11 ++------ src/min_sd.cpp | 6 ++-- 13 files changed, 109 insertions(+), 46 deletions(-) create mode 100644 doc/src/Eqs/norm_max.jpg create mode 100644 doc/src/Eqs/norm_max.tex create mode 100644 doc/src/Eqs/norm_two.jpg create mode 100644 doc/src/Eqs/norm_two.tex diff --git a/doc/src/Eqs/norm_max.jpg b/doc/src/Eqs/norm_max.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c10db9a53144cb3e889eb3c4315352d2ef0c85e8 GIT binary patch literal 9471 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 literal 0 HcmV?d00001 diff --git a/doc/src/Eqs/norm_max.tex b/doc/src/Eqs/norm_max.tex new file mode 100644 index 0000000000..3b2198bdf0 --- /dev/null +++ b/doc/src/Eqs/norm_max.tex @@ -0,0 +1,15 @@ +\documentclass[preview]{standalone} +\usepackage{varwidth} +\usepackage[utf8x]{inputenc} +\usepackage{amsmath, amssymb, graphics, setspace} + +\begin{document} +\begin{varwidth}{50in} + \begin{equation} + % \left| \left| \vec{F} \right| \right|_2 + || \vec{F} ||_{max} + = {\rm max}\left(||\vec{F}_1||, \cdots, ||\vec{F}_N||\right) + \nonumber + \end{equation} +\end{varwidth} +\end{document} diff --git a/doc/src/Eqs/norm_two.jpg b/doc/src/Eqs/norm_two.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5554de32f96a3a16f855b7e5011aa999d3c2819c GIT binary patch literal 6048 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 Wbg?+l1j#1hE)v|+w|Del^uGZ4YjxcK literal 0 HcmV?d00001 diff --git a/doc/src/Eqs/norm_two.tex b/doc/src/Eqs/norm_two.tex new file mode 100644 index 0000000000..d428081a49 --- /dev/null +++ b/doc/src/Eqs/norm_two.tex @@ -0,0 +1,15 @@ +\documentclass[preview]{standalone} +\usepackage{varwidth} +\usepackage[utf8x]{inputenc} +\usepackage{amsmath, amssymb, graphics, setspace} + +\begin{document} +\begin{varwidth}{50in} + \begin{equation} + % \left| \left| \vec{F} \right| \right|_2 + || \vec{F} ||_{2} + = \sqrt{\vec{F}_1+ \cdots + \vec{F}_N} + \nonumber + \end{equation} +\end{varwidth} +\end{document} diff --git a/doc/src/min_modify.txt b/doc/src/min_modify.txt index 06c1f7514f..b941a33559 100644 --- a/doc/src/min_modify.txt +++ b/doc/src/min_modify.txt @@ -18,8 +18,9 @@ keyword = {dmax} or {line} or {norm} or {alpha_damp} or {discrete_factor} max = maximum distance for line search to move (distance units) {line} value = {backtrack} or {quadratic} or {forcezero} or {spin_cubic} or {spin_none} backtrack,quadratic,forcezero,spin_cubic,spin_none = style of linesearch to use - {norm} value = {euclidean} or {max} - euclidean,max = style of norm to use + {norm} value = {two} or {max} + two = Euclidean two-norm (length of 3N vector) + max = max value of across all 3-vectors {alpha_damp} value = damping damping = fictitious Gilbert damping for spin minimization (adim) {discrete_factor} value = factor @@ -74,9 +75,16 @@ could move in the gradient direction to reduce forces further. The choice of a norm can be modified for the min styles {cg}, {sd}, {quickmin}, {fire}, {spin}, {spin/cg} and {spin/lbfgs} using the {norm} keyword. -The default {euclidean} norm computes the 2-norm (length) of the -global force vector. The {max} norm computes the maximum value -of the 2-norms across all forces in the system. +The default {two} norm computes the 2-norm (Euclidean length) of the +global force vector: + +:c,image(Eqs/norm_two.jpg) + +The {max} norm computes the length of the 3-vector force +for each atom (2-norm), and takes the maximum value of those accross +all atoms + +:c,image(Eqs/norm_max.jpg) Keywords {alpha_damp} and {discrete_factor} only make sense when a "min_spin"_min_spin.html command is declared. diff --git a/src/MAKE/Makefile.serial b/src/MAKE/Makefile.serial index 8628d2bb73..5954d97761 100644 --- a/src/MAKE/Makefile.serial +++ b/src/MAKE/Makefile.serial @@ -7,7 +7,7 @@ SHELL = /bin/sh # specify flags and libraries needed for your compiler CC = g++ -CCFLAGS = -g -O3 -Wall +CCFLAGS = -g -O3 SHFLAGS = -fPIC DEPFLAGS = -M diff --git a/src/min.cpp b/src/min.cpp index 31adf58525..33643d4837 100644 --- a/src/min.cpp +++ b/src/min.cpp @@ -49,6 +49,8 @@ using namespace LAMMPS_NS; using namespace MathConst; +enum{TWO,MAX} + /* ---------------------------------------------------------------------- */ Min::Min(LAMMPS *lmp) : Pointers(lmp) @@ -56,7 +58,7 @@ Min::Min(LAMMPS *lmp) : Pointers(lmp) dmax = 0.1; searchflag = 0; linestyle = 1; - normstyle = 0; + normstyle = TWO; elist_global = elist_atom = NULL; vlist_global = vlist_atom = NULL; @@ -662,8 +664,8 @@ void Min::modify_params(int narg, char **arg) iarg += 2; } else if (strcmp(arg[iarg],"norm") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal min_modify command"); - if (strcmp(arg[iarg+1],"euclidean") == 0) normstyle = 0; - else if (strcmp(arg[iarg+1],"max") == 0) normstyle = 1; + if (strcmp(arg[iarg+1],"two") == 0) normstyle = TWO; + else if (strcmp(arg[iarg+1],"max") == 0) normstyle = MAX; else error->all(FLERR,"Illegal min_modify command"); iarg += 2; } else { @@ -827,6 +829,41 @@ double Min::fnorm_inf() return norm_inf; } +/* ---------------------------------------------------------------------- + compute and return ||force||_max (inf norm per-vector) +------------------------------------------------------------------------- */ + +double Min::fnorm_max() +{ + int i,n; + double fdotf,*fatom; + + double local_norm_max = 0.0; + for (i = 0; i < nvec; i+=3) { + fdotf = fvec[i]*fvec[i]+fvec[i+1]*fvec[i+1]+fvec[i+2]*fvec[i+2]; + local_norm_max = MAX(fdotf,local_norm_max); + } + if (nextra_atom) { + for (int m = 0; m < nextra_atom; m++) { + fatom = fextra_atom[m]; + n = extra_nlen[m]; + for (i = 0; i < n; i+=3) + fdotf = fvec[i]*fvec[i]+fvec[i+1]*fvec[i+1]+fvec[i+2]*fvec[i+2]; + local_norm_max = MAX(fdotf,local_norm_max); + } + } + + double norm_max = 0.0; + MPI_Allreduce(&local_norm_max,&norm_max,1,MPI_DOUBLE,MPI_MAX,world); + + if (nextra_global) + for (i = 0; i < n; i+=3) + fdotf = fvec[i]*fvec[i]+fvec[i+1]*fvec[i+1]+fvec[i+2]*fvec[i+2]; + norm_max = MAX(fdotf,norm_max); + + return norm_max; +} + /* ---------------------------------------------------------------------- compute and return sum_i||mag. torque_i||_2 (in eV) ------------------------------------------------------------------------- */ @@ -842,10 +879,10 @@ double Min::total_torque() fmsq = ftotsqone = ftotsqall = 0.0; for (int i = 0; i < nlocal; i++) { - tx = fm[i][1] * sp[i][2] - fm[i][2] * sp[i][1]; - ty = fm[i][2] * sp[i][0] - fm[i][0] * sp[i][2]; - tz = fm[i][0] * sp[i][1] - fm[i][1] * sp[i][0]; - fmsq = tx * tx + ty * ty + tz * tz; + tx = fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]; + ty = fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]; + tz = fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]; + fmsq = tx*tx + ty*ty + tz*tz; ftotsqone += fmsq; } @@ -873,10 +910,10 @@ double Min::max_torque() fmsq = fmaxsqone = fmaxsqall = 0.0; for (int i = 0; i < nlocal; i++) { - tx = fm[i][1] * sp[i][2] - fm[i][2] * sp[i][1]; - ty = fm[i][2] * sp[i][0] - fm[i][0] * sp[i][2]; - tz = fm[i][0] * sp[i][1] - fm[i][1] * sp[i][0]; - fmsq = tx * tx + ty * ty + tz * tz; + tx = fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]; + ty = fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]; + tz = fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]; + fmsq = tx*tx + ty*ty + tz*tz; fmaxsqone = MAX(fmaxsqone,fmsq); } diff --git a/src/min.h b/src/min.h index e18d0dd677..ac7a3c1e9b 100644 --- a/src/min.h +++ b/src/min.h @@ -41,6 +41,7 @@ class Min : protected Pointers { virtual int modify_param(int, char **) {return 0;} double fnorm_sqr(); double fnorm_inf(); + double fnorm_max(); // methods for spin minimizers double max_torque(); @@ -64,7 +65,8 @@ class Min : protected Pointers { int linestyle; // 0 = backtrack, 1 = quadratic, 2 = forcezero // 3 = spin_cubic, 4 = spin_none - int normstyle; // 0 = Euclidean norm, 1 = inf. norm + int normstyle; // TWO or MAX flag for force norm evaluation + // int normstyle; // 0 = Euclidean norm, 1 = inf. norm int nelist_global,nelist_atom; // # of PE,virial computes to check int nvlist_global,nvlist_atom; diff --git a/src/min_cg.cpp b/src/min_cg.cpp index 2267a1ebb6..d98ec0ef97 100644 --- a/src/min_cg.cpp +++ b/src/min_cg.cpp @@ -35,7 +35,7 @@ MinCG::MinCG(LAMMPS *lmp) : MinLineSearch(lmp) {} int MinCG::iterate(int maxiter) { int i,m,n,fail,ntimestep; - double beta,gg,dot[2],dotall[2],fmax,fmaxall; + double beta,gg,dot[2],dotall[2],fmax; double *fatom,*gatom,*hatom; // nlimit = max # of CG iterations before restarting @@ -85,13 +85,12 @@ int MinCG::iterate(int maxiter) // force tolerance criterion - fmax = fmaxall = 0.0; dot[0] = dot[1] = 0.0; for (i = 0; i < nvec; i++) { dot[0] += fvec[i]*fvec[i]; dot[1] += fvec[i]*g[i]; - fmax = MAX(fmax,fvec[i]*fvec[i]); } + if (nextra_atom) for (m = 0; m < nextra_atom; m++) { fatom = fextra_atom[m]; @@ -104,16 +103,17 @@ int MinCG::iterate(int maxiter) } } MPI_Allreduce(dot,dotall,2,MPI_DOUBLE,MPI_SUM,world); - MPI_Allreduce(&fmax,&fmaxall,2,MPI_DOUBLE,MPI_MAX,world); if (nextra_global) for (i = 0; i < nextra_global; i++) { dotall[0] += fextra[i]*fextra[i]; dotall[1] += fextra[i]*gextra[i]; } - if (normstyle == 1) { // max force norm + fmax = 0.0; + if (normstyle == MAX) { // max force norm + fmax = fnorm_max(); if (fmax < update->ftol*update->ftol) return FTOL; - } else { // Euclidean force norm + } else { // Euclidean force 2-norm if (dotall[0] < update->ftol*update->ftol) return FTOL; } diff --git a/src/min_fire.cpp b/src/min_fire.cpp index 5b047ccd0e..dbb7f36148 100644 --- a/src/min_fire.cpp +++ b/src/min_fire.cpp @@ -250,15 +250,8 @@ int MinFire::iterate(int maxiter) // sync across replicas if running multi-replica minimization if (update->ftol > 0.0) { - if (normstyle == 1) { // max force norm - fdotf = fnorm_inf(); - fdotfloc = fdotf; - MPI_Allreduce(&fdotfloc,&fdotf,1,MPI_INT,MPI_MAX,universe->uworld); - } else { // Euclidean force norm - fdotf = fnorm_sqr(); - fdotfloc = fdotf; - MPI_Allreduce(&fdotfloc,&fdotf,1,MPI_INT,MPI_SUM,universe->uworld); - } + if (normstyle == MAX) fdotf = fnorm_inf(); // max force norm + else fdotf = fnorm_sqr(); // Euclidean force 2-norm if (update->multireplica == 0) { if (fdotf < update->ftol*update->ftol) return FTOL; } else { diff --git a/src/min_hftn.cpp b/src/min_hftn.cpp index 3c2cff9205..63432aab63 100644 --- a/src/min_hftn.cpp +++ b/src/min_hftn.cpp @@ -113,7 +113,7 @@ void MinHFTN::init() { Min::init(); - if (normstyle == 1) + if (normstyle == MAX) error->all(FLERR,"Incorrect min_modify option"); for (int i = 1; i < NUM_HFTN_ATOM_BASED_VECTORS; i++) { diff --git a/src/min_quickmin.cpp b/src/min_quickmin.cpp index 3450f7785e..6846aaba0a 100644 --- a/src/min_quickmin.cpp +++ b/src/min_quickmin.cpp @@ -215,15 +215,8 @@ int MinQuickMin::iterate(int maxiter) // sync across replicas if running multi-replica minimization if (update->ftol > 0.0) { - if (normstyle == 1) { // max force norm - fdotf = fnorm_inf(); - fdotfloc = fdotf; - MPI_Allreduce(&fdotfloc,&fdotf,1,MPI_INT,MPI_MAX,universe->uworld); - } else { // Euclidean force norm - fdotf = fnorm_sqr(); - fdotfloc = fdotf; - MPI_Allreduce(&fdotfloc,&fdotf,1,MPI_INT,MPI_SUM,universe->uworld); - } + if (normstyle == MAX) fdotfloc = fnorm_max(); // max force norm + else fdotf = fnorm_sqr(); // Euclidean force 2-norm if (update->multireplica == 0) { if (fdotf < update->ftol*update->ftol) return FTOL; } else { diff --git a/src/min_sd.cpp b/src/min_sd.cpp index dd59c9d2d6..3ded85990d 100644 --- a/src/min_sd.cpp +++ b/src/min_sd.cpp @@ -34,7 +34,7 @@ MinSD::MinSD(LAMMPS *lmp) : MinLineSearch(lmp) {} int MinSD::iterate(int maxiter) { int i,m,n,fail,ntimestep; - double fdotf; + double fdotf,fdotfloc; double *fatom,*hatom; // initialize working vectors @@ -77,8 +77,8 @@ int MinSD::iterate(int maxiter) // force tolerance criterion - if (normstyle == 1) fdotf = fnorm_inf(); // max force norm - else fdotf = fnorm_sqr(); // Euclidean force norm + if (normstyle == MAX) fdotf = fnorm_max(); // max force norm + else fdotf = fnorm_sqr(); // Euclidean force 2-norm if (fdotf < update->ftol*update->ftol) return FTOL; // set new search direction h to f = -Grad(x) From bc0ff0db618be4d1f8b33aa938aebbd5de7e6abc Mon Sep 17 00:00:00 2001 From: julient31 Date: Mon, 23 Sep 2019 13:48:33 -0600 Subject: [PATCH 69/74] Commit2 JT 092319 - added enum to min.h (for norm choice) - completed doc min_modify - corrected torque tol issue in spin/min --- doc/src/min_modify.txt | 3 +++ examples/SPIN/spinmin/in.spinmin_lbfgs.bfo | 1 + src/SPIN/min_spin.cpp | 19 +++++-------------- src/SPIN/min_spin_cg.cpp | 20 +++++--------------- src/SPIN/min_spin_lbfgs.cpp | 20 +++++--------------- src/min.cpp | 2 -- src/min.h | 2 ++ 7 files changed, 21 insertions(+), 46 deletions(-) diff --git a/doc/src/min_modify.txt b/doc/src/min_modify.txt index b941a33559..b7c85a190b 100644 --- a/doc/src/min_modify.txt +++ b/doc/src/min_modify.txt @@ -86,6 +86,9 @@ all atoms :c,image(Eqs/norm_max.jpg) +For the min styles {spin}, {spin/cg} and {spin/lbfgs}, the force +norm is replaced by the spin-torque norm. + Keywords {alpha_damp} and {discrete_factor} only make sense when a "min_spin"_min_spin.html command is declared. Keyword {alpha_damp} defines an analog of a magnetic Gilbert diff --git a/examples/SPIN/spinmin/in.spinmin_lbfgs.bfo b/examples/SPIN/spinmin/in.spinmin_lbfgs.bfo index a73b863b11..56cd6b8fae 100644 --- a/examples/SPIN/spinmin/in.spinmin_lbfgs.bfo +++ b/examples/SPIN/spinmin/in.spinmin_lbfgs.bfo @@ -51,4 +51,5 @@ dump 1 all custom 50 dump.lammpstrj type x y z c_outsp[1] c_outsp[2] c_outsp[3 min_style spin/lbfgs # min_modify line spin_cubic discrete_factor 10.0 +min_modify norm max minimize 1.0e-15 1.0e-10 10000 1000 diff --git a/src/SPIN/min_spin.cpp b/src/SPIN/min_spin.cpp index 947e281b42..5c7e7eee30 100644 --- a/src/SPIN/min_spin.cpp +++ b/src/SPIN/min_spin.cpp @@ -116,7 +116,7 @@ void MinSpin::reset_vectors() int MinSpin::iterate(int maxiter) { bigint ntimestep; - double fmdotfm,fmsq,fmsqall; + double fmdotfm,fmsq; int flag,flagall; for (int iter = 0; iter < maxiter; iter++) { @@ -163,20 +163,11 @@ int MinSpin::iterate(int maxiter) // magnetic torque tolerance criterion // sync across replicas if running multi-replica minimization - fmdotfm = fmsq = fmsqall = 0.0; + fmdotfm = fmsq = 0.0; if (update->ftol > 0.0) { - if (normstyle == 1) { // max torque norm - fmsq = max_torque(); - fmsqall = fmsq; - if (update->multireplica == 0) - MPI_Allreduce(&fmsq,&fmsqall,1,MPI_INT,MPI_MAX,universe->uworld); - } else { // Euclidean torque norm - fmsq = total_torque(); - fmsqall = fmsq; - if (update->multireplica == 0) - MPI_Allreduce(&fmsq,&fmsqall,1,MPI_INT,MPI_SUM,universe->uworld); - } - fmdotfm = fmsqall*fmsqall; + if (normstyle == MAX) fmsq = max_torque(); // max norm + else fmsq = total_torque(); // Euclidean 2-norm + fmdotfm = fmsq*fmsq; if (update->multireplica == 0) { if (fmdotfm < update->ftol*update->ftol) return FTOL; } else { diff --git a/src/SPIN/min_spin_cg.cpp b/src/SPIN/min_spin_cg.cpp index 322915c0f3..a87d3aaa36 100644 --- a/src/SPIN/min_spin_cg.cpp +++ b/src/SPIN/min_spin_cg.cpp @@ -60,7 +60,6 @@ static const char cite_minstyle_spin_cg[] = #define DELAYSTEP 5 - /* ---------------------------------------------------------------------- */ MinSpinCG::MinSpinCG(LAMMPS *lmp) : @@ -183,7 +182,7 @@ int MinSpinCG::iterate(int maxiter) { int nlocal = atom->nlocal; bigint ntimestep; - double fmdotfm,fmsq,fmsqall; + double fmdotfm,fmsq; int flag, flagall; double **sp = atom->sp; double der_e_cur_tmp = 0.0; @@ -269,20 +268,11 @@ int MinSpinCG::iterate(int maxiter) // magnetic torque tolerance criterion // sync across replicas if running multi-replica minimization - fmdotfm = fmsq = fmsqall = 0.0; + fmdotfm = fmsq = 0.0; if (update->ftol > 0.0) { - if (normstyle == 1) { // max torque norm - fmsq = max_torque(); - fmsqall = fmsq; - if (update->multireplica == 0) - MPI_Allreduce(&fmsq,&fmsqall,1,MPI_INT,MPI_MAX,universe->uworld); - } else { // Euclidean torque norm - fmsq = total_torque(); - fmsqall = fmsq; - if (update->multireplica == 0) - MPI_Allreduce(&fmsq,&fmsqall,1,MPI_INT,MPI_SUM,universe->uworld); - } - fmdotfm = fmsqall*fmsqall; + if (normstyle == MAX) fmsq = max_torque(); // max norm + else fmsq = total_torque(); // Euclidean 2-norm + fmdotfm = fmsq*fmsq; if (update->multireplica == 0) { if (fmdotfm < update->ftol*update->ftol) return FTOL; } else { diff --git a/src/SPIN/min_spin_lbfgs.cpp b/src/SPIN/min_spin_lbfgs.cpp index 891dec5c93..e161aa2a30 100644 --- a/src/SPIN/min_spin_lbfgs.cpp +++ b/src/SPIN/min_spin_lbfgs.cpp @@ -59,7 +59,6 @@ static const char cite_minstyle_spin_lbfgs[] = #define DELAYSTEP 5 - /* ---------------------------------------------------------------------- */ MinSpinLBFGS::MinSpinLBFGS(LAMMPS *lmp) : @@ -192,7 +191,7 @@ int MinSpinLBFGS::iterate(int maxiter) { int nlocal = atom->nlocal; bigint ntimestep; - double fmdotfm,fmsq,fmsqall; + double fmdotfm,fmsq; int flag, flagall; double **sp = atom->sp; double der_e_cur_tmp = 0.0; @@ -284,20 +283,11 @@ int MinSpinLBFGS::iterate(int maxiter) // magnetic torque tolerance criterion // sync across replicas if running multi-replica minimization - fmdotfm = fmsq = fmsqall = 0.0; + fmdotfm = fmsq = 0.0; if (update->ftol > 0.0) { - if (normstyle == 1) { // max torque norm - fmsq = max_torque(); - fmsqall = fmsq; - if (update->multireplica == 0) - MPI_Allreduce(&fmsq,&fmsqall,1,MPI_INT,MPI_MAX,universe->uworld); - } else { // Euclidean torque norm - fmsq = total_torque(); - fmsqall = fmsq; - if (update->multireplica == 0) - MPI_Allreduce(&fmsq,&fmsqall,1,MPI_INT,MPI_SUM,universe->uworld); - } - fmdotfm = fmsqall*fmsqall; + if (normstyle == MAX) fmsq = max_torque(); // max norm + else fmsq = total_torque(); // Euclidean 2-norm + fmdotfm = fmsq*fmsq; if (update->multireplica == 0) { if (fmdotfm < update->ftol*update->ftol) return FTOL; } else { diff --git a/src/min.cpp b/src/min.cpp index 33643d4837..23c3021010 100644 --- a/src/min.cpp +++ b/src/min.cpp @@ -49,8 +49,6 @@ using namespace LAMMPS_NS; using namespace MathConst; -enum{TWO,MAX} - /* ---------------------------------------------------------------------- */ Min::Min(LAMMPS *lmp) : Pointers(lmp) diff --git a/src/min.h b/src/min.h index ac7a3c1e9b..303e2123d8 100644 --- a/src/min.h +++ b/src/min.h @@ -43,6 +43,8 @@ class Min : protected Pointers { double fnorm_inf(); double fnorm_max(); + enum{TWO,MAX}; + // methods for spin minimizers double max_torque(); double total_torque(); From 34f81041461913ab6e2515a026aa4c493f5ddb5f Mon Sep 17 00:00:00 2001 From: julient31 Date: Mon, 23 Sep 2019 13:52:48 -0600 Subject: [PATCH 70/74] Commit3 JT 092319 - corrected a typo in doc/src/min_modify.txt --- doc/src/min_modify.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/min_modify.txt b/doc/src/min_modify.txt index b7c85a190b..209e9e4a67 100644 --- a/doc/src/min_modify.txt +++ b/doc/src/min_modify.txt @@ -81,7 +81,7 @@ global force vector: :c,image(Eqs/norm_two.jpg) The {max} norm computes the length of the 3-vector force -for each atom (2-norm), and takes the maximum value of those accross +for each atom (2-norm), and takes the maximum value of those across all atoms :c,image(Eqs/norm_max.jpg) From a0f0c2357883dc437d790e3264fa8f593ea91300 Mon Sep 17 00:00:00 2001 From: julient31 Date: Mon, 23 Sep 2019 14:32:39 -0600 Subject: [PATCH 71/74] Commit3 JT 092319 - corrected src/min.h merging conflict --- src/min.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/min.h b/src/min.h index 8bc6284b4b..e03b034147 100644 --- a/src/min.h +++ b/src/min.h @@ -39,7 +39,6 @@ class Min : protected Pointers { virtual bigint memory_usage() {return 0;} void modify_params(int, char **); virtual int modify_param(int, char **) {return 0;} -<<<<<<< HEAD double fnorm_sqr(); double fnorm_inf(); double fnorm_max(); @@ -49,10 +48,6 @@ class Min : protected Pointers { // methods for spin minimizers double max_torque(); double total_torque(); -======= - virtual double fnorm_sqr(); - virtual double fnorm_inf(); ->>>>>>> aa2b885783e471ed622e1402adeed67e3224aa53 virtual void init_style() {} virtual void setup_style() = 0; From d9306a58656925e94f00fe27b7a2a387308f78c4 Mon Sep 17 00:00:00 2001 From: julient31 Date: Tue, 24 Sep 2019 13:58:56 -0600 Subject: [PATCH 72/74] Commit JT 092419 - added inf norm option --- doc/src/Eqs/norm_inf.jpg | Bin 0 -> 14859 bytes doc/src/Eqs/norm_inf.tex | 15 +++++++++++++++ doc/src/min_modify.txt | 8 +++++++- src/SPIN/min_spin.cpp | 6 ++++-- src/SPIN/min_spin_cg.cpp | 6 ++++-- src/SPIN/min_spin_lbfgs.cpp | 6 ++++-- src/min.cpp | 34 ++++++++++++++++++++++++++++++++++ src/min.h | 8 ++++---- src/min_cg.cpp | 10 +++++++--- src/min_fire.cpp | 7 +++++-- src/min_quickmin.cpp | 7 +++++-- src/min_sd.cpp | 7 +++++-- 12 files changed, 94 insertions(+), 20 deletions(-) create mode 100644 doc/src/Eqs/norm_inf.jpg create mode 100644 doc/src/Eqs/norm_inf.tex diff --git a/doc/src/Eqs/norm_inf.jpg b/doc/src/Eqs/norm_inf.jpg new file mode 100644 index 0000000000000000000000000000000000000000..42a2afb3d299b7ef031d9def8fe7eb1de0b7d931 GIT binary patch literal 14859 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 > 0.0) { - if (normstyle == MAX) fmsq = max_torque(); // max norm - else fmsq = total_torque(); // Euclidean 2-norm + if (normstyle == MAX) fmsq = max_torque(); // max torque norm + else if (normstyle == INF) fmsq = inf_torque(); // inf torque norm + else if (normstyle == TWO) fmsq = total_torque(); // Euclidean torque 2-norm + else error->all(FLERR,"Illegal min_modify command"); fmdotfm = fmsq*fmsq; if (update->multireplica == 0) { if (fmdotfm < update->ftol*update->ftol) return FTOL; diff --git a/src/SPIN/min_spin_cg.cpp b/src/SPIN/min_spin_cg.cpp index a87d3aaa36..95bbcf437b 100644 --- a/src/SPIN/min_spin_cg.cpp +++ b/src/SPIN/min_spin_cg.cpp @@ -270,8 +270,10 @@ int MinSpinCG::iterate(int maxiter) fmdotfm = fmsq = 0.0; if (update->ftol > 0.0) { - if (normstyle == MAX) fmsq = max_torque(); // max norm - else fmsq = total_torque(); // Euclidean 2-norm + if (normstyle == MAX) fmsq = max_torque(); // max torque norm + else if (normstyle == INF) fmsq = inf_torque(); // inf torque norm + else if (normstyle == TWO) fmsq = total_torque(); // Euclidean torque 2-norm + else error->all(FLERR,"Illegal min_modify command"); fmdotfm = fmsq*fmsq; if (update->multireplica == 0) { if (fmdotfm < update->ftol*update->ftol) return FTOL; diff --git a/src/SPIN/min_spin_lbfgs.cpp b/src/SPIN/min_spin_lbfgs.cpp index e161aa2a30..db0dbbaa76 100644 --- a/src/SPIN/min_spin_lbfgs.cpp +++ b/src/SPIN/min_spin_lbfgs.cpp @@ -285,8 +285,10 @@ int MinSpinLBFGS::iterate(int maxiter) fmdotfm = fmsq = 0.0; if (update->ftol > 0.0) { - if (normstyle == MAX) fmsq = max_torque(); // max norm - else fmsq = total_torque(); // Euclidean 2-norm + if (normstyle == MAX) fmsq = max_torque(); // max torque norm + else if (normstyle == INF) fmsq = inf_torque(); // inf torque norm + else if (normstyle == TWO) fmsq = total_torque(); // Euclidean torque 2-norm + else error->all(FLERR,"Illegal min_modify command"); fmdotfm = fmsq*fmsq; if (update->multireplica == 0) { if (fmdotfm < update->ftol*update->ftol) return FTOL; diff --git a/src/min.cpp b/src/min.cpp index 1e56d4c466..b57dd44d4f 100644 --- a/src/min.cpp +++ b/src/min.cpp @@ -670,6 +670,7 @@ void Min::modify_params(int narg, char **arg) if (iarg+2 > narg) error->all(FLERR,"Illegal min_modify command"); if (strcmp(arg[iarg+1],"two") == 0) normstyle = TWO; else if (strcmp(arg[iarg+1],"max") == 0) normstyle = MAX; + else if (strcmp(arg[iarg+1],"inf") == 0) normstyle = INF; else error->all(FLERR,"Illegal min_modify command"); iarg += 2; } else { @@ -899,6 +900,39 @@ double Min::total_torque() return sqrt(ftotsqall) * hbar; } +/* ---------------------------------------------------------------------- + compute and return max_i ||mag. torque components|| (in eV) +------------------------------------------------------------------------- */ + +double Min::inf_torque() +{ + double fmsq,fmaxsqone,fmaxsqall; + int nlocal = atom->nlocal; + double hbar = force->hplanck/MY_2PI; + double tx,ty,tz; + double **sp = atom->sp; + double **fm = atom->fm; + + fmsq = fmaxsqone = fmaxsqall = 0.0; + for (int i = 0; i < nlocal; i++) { + tx = fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1]; + ty = fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2]; + tz = fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0]; + fmaxsqone = MAX(fmaxsqone,tx*tx); + fmaxsqone = MAX(fmaxsqone,ty*ty); + fmaxsqone = MAX(fmaxsqone,tz*tz); + } + + // finding max fm on this replica + + fmaxsqall = fmaxsqone; + MPI_Allreduce(&fmaxsqone,&fmaxsqall,1,MPI_DOUBLE,MPI_MAX,world); + + // multiply it by hbar so that units are in eV + + return sqrt(fmaxsqall) * hbar; +} + /* ---------------------------------------------------------------------- compute and return max_i ||mag. torque_i|| (in eV) ------------------------------------------------------------------------- */ diff --git a/src/min.h b/src/min.h index e03b034147..61f9ce0bda 100644 --- a/src/min.h +++ b/src/min.h @@ -43,11 +43,12 @@ class Min : protected Pointers { double fnorm_inf(); double fnorm_max(); - enum{TWO,MAX}; + enum{TWO,MAX,INF}; // methods for spin minimizers - double max_torque(); double total_torque(); + double inf_torque(); + double max_torque(); virtual void init_style() {} virtual void setup_style() = 0; @@ -67,8 +68,7 @@ class Min : protected Pointers { int linestyle; // 0 = backtrack, 1 = quadratic, 2 = forcezero // 3 = spin_cubic, 4 = spin_none - int normstyle; // TWO or MAX flag for force norm evaluation - // int normstyle; // 0 = Euclidean norm, 1 = inf. norm + int normstyle; // TWO, MAX or INF flag for force norm evaluation int nelist_global,nelist_atom; // # of PE,virial computes to check int nvlist_global,nvlist_atom; diff --git a/src/min_cg.cpp b/src/min_cg.cpp index d98ec0ef97..80dde25f51 100644 --- a/src/min_cg.cpp +++ b/src/min_cg.cpp @@ -14,6 +14,7 @@ #include "min_cg.h" #include #include +#include "error.h" #include "update.h" #include "output.h" #include "timer.h" @@ -110,12 +111,15 @@ int MinCG::iterate(int maxiter) } fmax = 0.0; - if (normstyle == MAX) { // max force norm + if (normstyle == MAX) { // max force norm fmax = fnorm_max(); if (fmax < update->ftol*update->ftol) return FTOL; - } else { // Euclidean force 2-norm + } else if (normstyle == INF) { // infinite force norm + fmax = fnorm_inf(); + if (fmax < update->ftol*update->ftol) return FTOL; + } else if (normstyle == TWO) { // Euclidean force 2-norm if (dotall[0] < update->ftol*update->ftol) return FTOL; - } + } else error->all(FLERR,"Illegal min_modify command"); // update new search direction h from new f = -Grad(x) and old g // this is Polak-Ribieri formulation diff --git a/src/min_fire.cpp b/src/min_fire.cpp index dbb7f36148..e0cc2437d4 100644 --- a/src/min_fire.cpp +++ b/src/min_fire.cpp @@ -16,6 +16,7 @@ #include #include "universe.h" #include "atom.h" +#include "error.h" #include "force.h" #include "update.h" #include "output.h" @@ -250,8 +251,10 @@ int MinFire::iterate(int maxiter) // sync across replicas if running multi-replica minimization if (update->ftol > 0.0) { - if (normstyle == MAX) fdotf = fnorm_inf(); // max force norm - else fdotf = fnorm_sqr(); // Euclidean force 2-norm + if (normstyle == MAX) fdotf = fnorm_max(); // max force norm + else if (normstyle == INF) fdotf = fnorm_inf(); // inf force norm + else if (normstyle == TWO) fdotf = fnorm_sqr(); // Euclidean force 2-norm + else error->all(FLERR,"Illegal min_modify command"); if (update->multireplica == 0) { if (fdotf < update->ftol*update->ftol) return FTOL; } else { diff --git a/src/min_quickmin.cpp b/src/min_quickmin.cpp index 6846aaba0a..ef649b4dac 100644 --- a/src/min_quickmin.cpp +++ b/src/min_quickmin.cpp @@ -16,6 +16,7 @@ #include #include "universe.h" #include "atom.h" +#include "error.h" #include "force.h" #include "update.h" #include "output.h" @@ -215,8 +216,10 @@ int MinQuickMin::iterate(int maxiter) // sync across replicas if running multi-replica minimization if (update->ftol > 0.0) { - if (normstyle == MAX) fdotfloc = fnorm_max(); // max force norm - else fdotf = fnorm_sqr(); // Euclidean force 2-norm + if (normstyle == MAX) fdotfloc = fnorm_max(); // max force norm + else if (normstyle == INF) fdotfloc = fnorm_inf(); // inf force norm + else if (normstyle == TWO) fdotfloc = fnorm_sqr(); // Euclidean force 2-norm + else error->all(FLERR,"Illegal min_modify command"); if (update->multireplica == 0) { if (fdotf < update->ftol*update->ftol) return FTOL; } else { diff --git a/src/min_sd.cpp b/src/min_sd.cpp index 3ded85990d..8541b0ccdf 100644 --- a/src/min_sd.cpp +++ b/src/min_sd.cpp @@ -13,6 +13,7 @@ #include "min_sd.h" #include +#include "error.h" #include "update.h" #include "output.h" #include "timer.h" @@ -77,8 +78,10 @@ int MinSD::iterate(int maxiter) // force tolerance criterion - if (normstyle == MAX) fdotf = fnorm_max(); // max force norm - else fdotf = fnorm_sqr(); // Euclidean force 2-norm + if (normstyle == MAX) fdotf = fnorm_max(); // max force norm + else if (normstyle == INF) fdotf = fnorm_inf(); // infinite force norm + else if (normstyle == TWO) fdotf = fnorm_sqr(); // Euclidean force 2-norm + else error->all(FLERR,"Illegal min_modify command"); if (fdotf < update->ftol*update->ftol) return FTOL; // set new search direction h to f = -Grad(x) From 14933958f78d0e1fc174931349fba64b060e97fa Mon Sep 17 00:00:00 2001 From: alxvov Date: Mon, 30 Sep 2019 14:55:33 +0000 Subject: [PATCH 73/74] change units --- doc/src/min_modify.txt | 6 +++--- doc/src/neb_spin.txt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/src/min_modify.txt b/doc/src/min_modify.txt index 06c1f7514f..411f43f3b1 100644 --- a/doc/src/min_modify.txt +++ b/doc/src/min_modify.txt @@ -101,9 +101,9 @@ and {spin/cg}. Convergence of {spin/lbfgs} can be more robust if [Restrictions:] -The line search procedure of styles {spin/cg} and {spin/lbfgs} cannot be -used for magnetic GNEB calculations. See "neb/spin"_neb_spin.html for more -explanation. +For magnetic GNEB calculations, only {spin_none} value for {line} keyword can be used +when styles {spin/cg} and {spin/lbfgs} are employed. +See "neb/spin"_neb_spin.html for more explanation. [Related commands:] diff --git a/doc/src/neb_spin.txt b/doc/src/neb_spin.txt index b64df39219..0d093979a6 100644 --- a/doc/src/neb_spin.txt +++ b/doc/src/neb_spin.txt @@ -359,8 +359,8 @@ This command can only be used if LAMMPS was built with the SPIN package. See the "Build package"_Build_package.html doc page for more info. -The line search procedures of the {spin/cg} and {spin/lbfgs} -minimization styles cannot be used in a GNEB calculation. +For magnetic GNEB calculations, only {spin_none} value for {line} keyword can be used +when styles {spin/cg} and {spin/lbfgs} are employed. :line From d117ed2b147f2c73010328d567af4a2f7b9b7a23 Mon Sep 17 00:00:00 2001 From: alxvov Date: Thu, 3 Oct 2019 22:14:15 +0000 Subject: [PATCH 74/74] remove unnecessary operations. calloc only if rho is positive --- src/SPIN/min_spin_lbfgs.cpp | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/SPIN/min_spin_lbfgs.cpp b/src/SPIN/min_spin_lbfgs.cpp index db0dbbaa76..f86bdd5d48 100644 --- a/src/SPIN/min_spin_lbfgs.cpp +++ b/src/SPIN/min_spin_lbfgs.cpp @@ -372,9 +372,6 @@ void MinSpinLBFGS::calc_search_direction() factor = 1.0; } - q = (double *) calloc(3*nlocal, sizeof(double)); - alpha = (double *) calloc(num_mem, sizeof(double)); - if (local_iter == 0){ // steepest descent direction //if no line search then calculate maximum rotation @@ -387,10 +384,12 @@ void MinSpinLBFGS::calc_search_direction() for (int k = 0; k < num_mem; k++){ ds[k][i] = 0.0; dy[k][i] = 0.0; - rho[k] = 0.0; } } - } else { + for (int k = 0; k < num_mem; k++) + rho[k] = 0.0; + + } else { dyds = 0.0; for (int i = 0; i < 3 * nlocal; i++) { ds[m_index][i] = p_s[i]; @@ -410,15 +409,10 @@ void MinSpinLBFGS::calc_search_direction() if (rho[m_index] < 0.0){ local_iter = 0; - for (int k = 0; k < num_mem; k++){ - for (int i = 0; i < nlocal; i ++){ - ds[k][i] = 0.0; - dy[k][i] = 0.0; - } - } return calc_search_direction(); } - + q = (double *) calloc(3*nlocal, sizeof(double)); + alpha = (double *) calloc(num_mem, sizeof(double)); // set the q vector for (int i = 0; i < 3 * nlocal; i++) { @@ -511,12 +505,10 @@ void MinSpinLBFGS::calc_search_direction() p_s[i] = - factor * p_s[i] * scaling; g_old[i] = g_cur[i] * factor; } + free(q); + free(alpha); } - local_iter++; - free(q); - free(alpha); - } /* ----------------------------------------------------------------------