1 // clang-format off
2 /* ----------------------------------------------------------------------
3 LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
4 https://www.lammps.org/, Sandia National Laboratories
5 Steve Plimpton, sjplimp@sandia.gov
6
7 Copyright (2003) Sandia Corporation. Under the terms of Contract
8 DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
9 certain rights in this software. This software is distributed under
10 the GNU General Public License.
11
12 See the README file in the top-level LAMMPS directory.
13 ------------------------------------------------------------------------- */
14
15 /* ----------------------------------------------------------------------
16 Contributing author: Aidan Thompson (SNL)
17 improved CG and backtrack ls, added quadratic ls
18 Sources: Numerical Recipes frprmn routine
19 "Conjugate Gradient Method Without the Agonizing Pain" by
20 JR Shewchuk, https://www.cs.cmu.edu/~quake-papers/painless-conjugate-gradient.pdf
21 ------------------------------------------------------------------------- */
22
23 #include "min.h"
24
25 #include "angle.h"
26 #include "atom.h"
27 #include "atom_vec.h"
28 #include "bond.h"
29 #include "comm.h"
30 #include "compute.h"
31 #include "dihedral.h"
32 #include "domain.h"
33 #include "error.h"
34 #include "fix_minimize.h"
35 #include "force.h"
36 #include "improper.h"
37 #include "kspace.h"
38 #include "math_const.h"
39 #include "memory.h"
40 #include "modify.h"
41 #include "neighbor.h"
42 #include "output.h"
43 #include "pair.h"
44 #include "thermo.h"
45 #include "timer.h"
46 #include "update.h"
47
48 #include <cmath>
49 #include <cstring>
50
51 using namespace LAMMPS_NS;
52 using namespace MathConst;
53
54 /* ---------------------------------------------------------------------- */
55
Min(LAMMPS * lmp)56 Min::Min(LAMMPS *lmp) : Pointers(lmp)
57 {
58 dmax = 0.1;
59 searchflag = 0;
60 linestyle = 1;
61 normstyle = TWO;
62
63 delaystep = 20;
64 dtgrow = 1.1;
65 dtshrink = 0.5;
66 alpha0 = 0.25;
67 alphashrink = 0.99;
68 tmax = 10.0;
69 tmin = 0.02;
70 integrator = 0;
71 halfstepback_flag = 1;
72 delaystep_start_flag = 1;
73 max_vdotf_negatif = 2000;
74 alpha_final = 0.0;
75
76 elist_global = elist_atom = nullptr;
77 vlist_global = vlist_atom = cvlist_atom = nullptr;
78
79 nextra_global = 0;
80 fextra = nullptr;
81
82 nextra_atom = 0;
83 xextra_atom = fextra_atom = nullptr;
84 extra_peratom = extra_nlen = nullptr;
85 extra_max = nullptr;
86 requestor = nullptr;
87
88 external_force_clear = 0;
89
90 kokkosable = 0;
91 }
92
93 /* ---------------------------------------------------------------------- */
94
~Min()95 Min::~Min()
96 {
97 delete [] elist_global;
98 delete [] elist_atom;
99 delete [] vlist_global;
100 delete [] vlist_atom;
101 delete [] cvlist_atom;
102
103 delete [] fextra;
104
105 memory->sfree(xextra_atom);
106 memory->sfree(fextra_atom);
107 memory->destroy(extra_peratom);
108 memory->destroy(extra_nlen);
109 memory->destroy(extra_max);
110 memory->sfree(requestor);
111 }
112
113 /* ---------------------------------------------------------------------- */
114
init()115 void Min::init()
116 {
117 if (lmp->kokkos && !kokkosable)
118 error->all(FLERR,"Must use a Kokkos-enabled min style "
119 "(e.g. min_style cg/kk) with Kokkos minimize");
120
121 // create fix needed for storing atom-based quantities
122 // will delete it at end of run
123
124 fix_minimize = (FixMinimize *) modify->add_fix("MINIMIZE all MINIMIZE");
125
126 // clear out extra global and per-atom dof
127 // will receive requests for new per-atom dof during pair init()
128 // can then add vectors to fix_minimize in setup()
129
130 nextra_global = 0;
131 delete [] fextra;
132 fextra = nullptr;
133
134 nextra_atom = 0;
135 memory->sfree(xextra_atom);
136 memory->sfree(fextra_atom);
137 memory->destroy(extra_peratom);
138 memory->destroy(extra_nlen);
139 memory->destroy(extra_max);
140 memory->sfree(requestor);
141 xextra_atom = fextra_atom = nullptr;
142 extra_peratom = extra_nlen = nullptr;
143 extra_max = nullptr;
144 requestor = nullptr;
145
146 // virial_style:
147 // VIRIAL_PAIR if computed explicitly in pair via sum over pair interactions
148 // VIRIAL_FDOTR if computed implicitly in pair by
149 // virial_fdotr_compute() via sum over ghosts
150
151 if (force->newton_pair) virial_style = VIRIAL_FDOTR;
152 else virial_style = VIRIAL_PAIR;
153
154 // setup lists of computes for global and per-atom PE and pressure
155
156 ev_setup();
157
158 // detect if fix omp is present for clearing force arrays
159
160 int ifix = modify->find_fix("package_omp");
161 if (ifix >= 0) external_force_clear = 1;
162
163 // set flags for arrays to clear in force_clear()
164
165 torqueflag = extraflag = 0;
166 if (atom->torque_flag) torqueflag = 1;
167 if (atom->avec->forceclearflag) extraflag = 1;
168
169 // allow pair and Kspace compute() to be turned off via modify flags
170
171 if (force->pair && force->pair->compute_flag) pair_compute_flag = 1;
172 else pair_compute_flag = 0;
173 if (force->kspace && force->kspace->compute_flag) kspace_compute_flag = 1;
174 else kspace_compute_flag = 0;
175
176 // orthogonal vs triclinic simulation box
177
178 triclinic = domain->triclinic;
179
180 // reset reneighboring criteria if necessary
181
182 neigh_every = neighbor->every;
183 neigh_delay = neighbor->delay;
184 neigh_dist_check = neighbor->dist_check;
185
186 if (neigh_every != 1 || neigh_delay != 0 || neigh_dist_check != 1) {
187 if (comm->me == 0)
188 error->warning(FLERR, "Using 'neigh_modify every 1 delay 0 check"
189 " yes' setting during minimization");
190 }
191
192 neighbor->every = 1;
193 neighbor->delay = 0;
194 neighbor->dist_check = 1;
195
196 niter = neval = 0;
197
198 // store timestep size (important for variable timestep minimizer)
199
200 dtinit = update->dt;
201 }
202
203 /* ----------------------------------------------------------------------
204 setup before run
205 ------------------------------------------------------------------------- */
206
setup(int flag)207 void Min::setup(int flag)
208 {
209 if (comm->me == 0 && screen) {
210 fmt::print(screen,"Setting up {} style minimization ...\n",
211 update->minimize_style);
212 if (flag) {
213 fmt::print(screen," Unit style : {}\n", update->unit_style);
214 fmt::print(screen," Current step : {}\n", update->ntimestep);
215 timer->print_timeout(screen);
216 }
217 }
218 update->setupflag = 1;
219
220 // setup extra global dof due to fixes
221 // cannot be done in init() b/c update init() is before modify init()
222
223 nextra_global = modify->min_dof();
224 if (nextra_global) {
225 fextra = new double[nextra_global];
226 if (comm->me == 0 && screen)
227 fprintf(screen,"WARNING: Energy due to %d extra global DOFs will"
228 " be included in minimizer energies\n",nextra_global);
229 }
230
231 // compute for potential energy
232
233 int id = modify->find_compute("thermo_pe");
234 if (id < 0) error->all(FLERR,"Minimization could not find thermo_pe compute");
235 pe_compute = modify->compute[id];
236
237 // style-specific setup does two tasks
238 // setup extra global dof vectors
239 // setup extra per-atom dof vectors due to requests from Pair classes
240 // cannot be done in init() b/c update init() is before modify/pair init()
241
242 setup_style();
243
244 // ndoftotal = total dof for entire minimization problem
245 // dof for atoms, extra per-atom, extra global
246
247 bigint ndofme = 3 * static_cast<bigint>(atom->nlocal);
248 for (int m = 0; m < nextra_atom; m++)
249 ndofme += extra_peratom[m]*static_cast<bigint>(atom->nlocal);
250 MPI_Allreduce(&ndofme,&ndoftotal,1,MPI_LMP_BIGINT,MPI_SUM,world);
251 ndoftotal += nextra_global;
252
253 // setup domain, communication and neighboring
254 // acquire ghosts
255 // build neighbor lists
256
257 atom->setup();
258 modify->setup_pre_exchange();
259 if (triclinic) domain->x2lamda(atom->nlocal);
260 domain->pbc();
261 domain->reset_box();
262 comm->setup();
263 if (neighbor->style) neighbor->setup_bins();
264 comm->exchange();
265 if (atom->sortfreq > 0) atom->sort();
266 comm->borders();
267 if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost);
268 domain->image_check();
269 domain->box_too_small_check();
270 modify->setup_pre_neighbor();
271 neighbor->build(1);
272 modify->setup_post_neighbor();
273 neighbor->ncalls = 0;
274
275 // remove these restriction eventually
276
277 if (searchflag == 0) {
278 if (nextra_global)
279 error->all(FLERR,
280 "Cannot use a damped dynamics min style with fix box/relax");
281 if (nextra_atom)
282 error->all(FLERR,
283 "Cannot use a damped dynamics min style with per-atom DOF");
284 }
285
286 if (strcmp(update->minimize_style,"hftn") == 0) {
287 if (nextra_global)
288 error->all(FLERR, "Cannot use hftn min style with fix box/relax");
289 if (nextra_atom)
290 error->all(FLERR, "Cannot use hftn min style with per-atom DOF");
291 }
292
293 // atoms may have migrated in comm->exchange()
294
295 reset_vectors();
296
297 // compute all forces
298
299 force->setup();
300 ev_set(update->ntimestep);
301 force_clear();
302 modify->setup_pre_force(vflag);
303
304 if (pair_compute_flag) force->pair->compute(eflag,vflag);
305 else if (force->pair) force->pair->compute_dummy(eflag,vflag);
306
307 if (atom->molecular != Atom::ATOMIC) {
308 if (force->bond) force->bond->compute(eflag,vflag);
309 if (force->angle) force->angle->compute(eflag,vflag);
310 if (force->dihedral) force->dihedral->compute(eflag,vflag);
311 if (force->improper) force->improper->compute(eflag,vflag);
312 }
313
314 if (force->kspace) {
315 force->kspace->setup();
316 if (kspace_compute_flag) force->kspace->compute(eflag,vflag);
317 else force->kspace->compute_dummy(eflag,vflag);
318 }
319
320 modify->setup_pre_reverse(eflag,vflag);
321 if (force->newton) comm->reverse_comm();
322
323 // update per-atom minimization variables stored by pair styles
324
325 if (nextra_atom)
326 for (int m = 0; m < nextra_atom; m++)
327 requestor[m]->min_xf_get(m);
328
329 modify->setup(vflag);
330 output->setup(flag);
331 update->setupflag = 0;
332
333 // stats for initial thermo output
334
335 ecurrent = pe_compute->compute_scalar();
336 if (nextra_global) ecurrent += modify->min_energy(fextra);
337 if (output->thermo->normflag) ecurrent /= atom->natoms;
338
339 einitial = ecurrent;
340 fnorm2_init = sqrt(fnorm_sqr());
341 fnorminf_init = sqrt(fnorm_inf());
342 }
343
344 /* ----------------------------------------------------------------------
345 setup without output or one-time post-init setup
346 flag = 0 = just force calculation
347 flag = 1 = reneighbor and force calculation
348 ------------------------------------------------------------------------- */
349
setup_minimal(int flag)350 void Min::setup_minimal(int flag)
351 {
352 update->setupflag = 1;
353
354 // setup domain, communication and neighboring
355 // acquire ghosts
356 // build neighbor lists
357
358 if (flag) {
359 modify->setup_pre_exchange();
360 if (triclinic) domain->x2lamda(atom->nlocal);
361 domain->pbc();
362 domain->reset_box();
363 comm->setup();
364 if (neighbor->style) neighbor->setup_bins();
365 comm->exchange();
366 comm->borders();
367 if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost);
368 domain->image_check();
369 domain->box_too_small_check();
370 modify->setup_pre_neighbor();
371 neighbor->build(1);
372 modify->setup_post_neighbor();
373 neighbor->ncalls = 0;
374 }
375
376 // atoms may have migrated in comm->exchange()
377
378 reset_vectors();
379
380 // compute all forces
381
382 ev_set(update->ntimestep);
383 force_clear();
384 modify->setup_pre_force(vflag);
385
386 if (pair_compute_flag) force->pair->compute(eflag,vflag);
387 else if (force->pair) force->pair->compute_dummy(eflag,vflag);
388
389 if (atom->molecular != Atom::ATOMIC) {
390 if (force->bond) force->bond->compute(eflag,vflag);
391 if (force->angle) force->angle->compute(eflag,vflag);
392 if (force->dihedral) force->dihedral->compute(eflag,vflag);
393 if (force->improper) force->improper->compute(eflag,vflag);
394 }
395
396 if (force->kspace) {
397 force->kspace->setup();
398 if (kspace_compute_flag) force->kspace->compute(eflag,vflag);
399 else force->kspace->compute_dummy(eflag,vflag);
400 }
401
402 modify->setup_pre_reverse(eflag,vflag);
403 if (force->newton) comm->reverse_comm();
404
405 // update per-atom minimization variables stored by pair styles
406
407 if (nextra_atom)
408 for (int m = 0; m < nextra_atom; m++)
409 requestor[m]->min_xf_get(m);
410
411 modify->setup(vflag);
412 update->setupflag = 0;
413
414 // stats for Finish to print
415
416 ecurrent = pe_compute->compute_scalar();
417 if (nextra_global) ecurrent += modify->min_energy(fextra);
418 if (output->thermo->normflag) ecurrent /= atom->natoms;
419
420 einitial = ecurrent;
421 fnorm2_init = sqrt(fnorm_sqr());
422 fnorminf_init = sqrt(fnorm_inf());
423 }
424
425 /* ----------------------------------------------------------------------
426 perform minimization, calling iterate() for N steps
427 ------------------------------------------------------------------------- */
428
run(int n)429 void Min::run(int n)
430 {
431 // minimizer iterations
432
433 stop_condition = iterate(n);
434 stopstr = stopstrings(stop_condition);
435
436 // if early exit from iterate loop:
437 // set update->nsteps to niter for Finish stats to print
438 // set output->next values to this timestep
439 // call energy_force() to insure vflag is set when forces computed
440 // output->write does final output for thermo, dump, restart files
441 // add ntimestep to all computes that store invocation times
442 // since are hardwiring call to thermo/dumps and computes may not be ready
443
444 if (stop_condition != MAXITER) {
445 update->nsteps = niter;
446
447 if (update->restrict_output == 0) {
448 for (int idump = 0; idump < output->ndump; idump++)
449 output->next_dump[idump] = update->ntimestep;
450 output->next_dump_any = update->ntimestep;
451 if (output->restart_flag) {
452 output->next_restart = update->ntimestep;
453 if (output->restart_every_single)
454 output->next_restart_single = update->ntimestep;
455 if (output->restart_every_double)
456 output->next_restart_double = update->ntimestep;
457 }
458 }
459 output->next_thermo = update->ntimestep;
460
461 modify->addstep_compute_all(update->ntimestep);
462 ecurrent = energy_force(0);
463 output->write(update->ntimestep);
464 }
465 }
466
467 /* ---------------------------------------------------------------------- */
468
cleanup()469 void Min::cleanup()
470 {
471 modify->post_run();
472
473 // stats for Finish to print
474
475 efinal = ecurrent;
476 fnorm2_final = sqrt(fnorm_sqr());
477 fnorminf_final = sqrt(fnorm_inf());
478
479 // reset reneighboring criteria
480
481 neighbor->every = neigh_every;
482 neighbor->delay = neigh_delay;
483 neighbor->dist_check = neigh_dist_check;
484
485 // delete fix at end of run, so its atom arrays won't persist
486
487 modify->delete_fix("MINIMIZE");
488 domain->box_too_small_check();
489
490 // reset timestep size (important for variable timestep minimizer)
491
492 update->dt = dtinit;
493 }
494
495 /* ----------------------------------------------------------------------
496 evaluate potential energy and forces
497 may migrate atoms due to reneighboring
498 return new energy, which should include nextra_global dof
499 return negative gradient stored in atom->f
500 return negative gradient for nextra_global dof in fextra
501 ------------------------------------------------------------------------- */
502
energy_force(int resetflag)503 double Min::energy_force(int resetflag)
504 {
505 // check for reneighboring
506 // always communicate since minimizer moved atoms
507
508 int nflag = neighbor->decide();
509
510 if (nflag == 0) {
511 timer->stamp();
512 comm->forward_comm();
513 timer->stamp(Timer::COMM);
514 } else {
515 if (modify->n_min_pre_exchange) {
516 timer->stamp();
517 modify->min_pre_exchange();
518 timer->stamp(Timer::MODIFY);
519 }
520 if (triclinic) domain->x2lamda(atom->nlocal);
521 domain->pbc();
522 if (domain->box_change) {
523 domain->reset_box();
524 comm->setup();
525 if (neighbor->style) neighbor->setup_bins();
526 }
527 timer->stamp();
528 comm->exchange();
529 if (atom->sortfreq > 0 &&
530 update->ntimestep >= atom->nextsort) atom->sort();
531 comm->borders();
532 if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost);
533 timer->stamp(Timer::COMM);
534 if (modify->n_min_pre_neighbor) {
535 modify->min_pre_neighbor();
536 timer->stamp(Timer::MODIFY);
537 }
538 neighbor->build(1);
539 timer->stamp(Timer::NEIGH);
540 if (modify->n_min_post_neighbor) {
541 modify->min_post_neighbor();
542 timer->stamp(Timer::MODIFY);
543 }
544 }
545
546 ev_set(update->ntimestep);
547 force_clear();
548
549 timer->stamp();
550
551 if (modify->n_min_pre_force) {
552 modify->min_pre_force(vflag);
553 timer->stamp(Timer::MODIFY);
554 }
555
556 if (pair_compute_flag) {
557 force->pair->compute(eflag,vflag);
558 timer->stamp(Timer::PAIR);
559 }
560
561 if (atom->molecular != Atom::ATOMIC) {
562 if (force->bond) force->bond->compute(eflag,vflag);
563 if (force->angle) force->angle->compute(eflag,vflag);
564 if (force->dihedral) force->dihedral->compute(eflag,vflag);
565 if (force->improper) force->improper->compute(eflag,vflag);
566 timer->stamp(Timer::BOND);
567 }
568
569 if (kspace_compute_flag) {
570 force->kspace->compute(eflag,vflag);
571 timer->stamp(Timer::KSPACE);
572 }
573
574 if (modify->n_min_pre_reverse) {
575 modify->min_pre_reverse(eflag,vflag);
576 timer->stamp(Timer::MODIFY);
577 }
578
579 if (force->newton) {
580 comm->reverse_comm();
581 timer->stamp(Timer::COMM);
582 }
583
584 // update per-atom minimization variables stored by pair styles
585
586 if (nextra_atom)
587 for (int m = 0; m < nextra_atom; m++)
588 requestor[m]->min_xf_get(m);
589
590 // fixes that affect minimization
591
592 if (modify->n_min_post_force) {
593 timer->stamp();
594 modify->min_post_force(vflag);
595 timer->stamp(Timer::MODIFY);
596 }
597
598 // compute potential energy of system
599 // normalize if thermo PE does
600
601 double energy = pe_compute->compute_scalar();
602 if (nextra_global) energy += modify->min_energy(fextra);
603 if (output->thermo->normflag) energy /= atom->natoms;
604
605 // if reneighbored, atoms migrated
606 // if resetflag = 1, update x0 of atoms crossing PBC
607 // reset vectors used by lo-level minimizer
608
609 if (nflag) {
610 if (resetflag) fix_minimize->reset_coords();
611 reset_vectors();
612 }
613
614 return energy;
615 }
616
617 /* ----------------------------------------------------------------------
618 clear force on own & ghost atoms
619 clear other arrays as needed
620 ------------------------------------------------------------------------- */
621
force_clear()622 void Min::force_clear()
623 {
624 if (external_force_clear) return;
625
626 // clear global force array
627 // if either newton flag is set, also include ghosts
628
629 size_t nbytes = sizeof(double) * atom->nlocal;
630 if (force->newton) nbytes += sizeof(double) * atom->nghost;
631
632 if (nbytes) {
633 memset(&atom->f[0][0],0,3*nbytes);
634 if (torqueflag) memset(&atom->torque[0][0],0,3*nbytes);
635 if (extraflag) atom->avec->force_clear(0,nbytes);
636 }
637 }
638
639 /* ----------------------------------------------------------------------
640 pair style makes request to add a per-atom variables to minimization
641 requestor stores callback to pair class to invoke during min
642 to get current variable and forces on it and to update the variable
643 return flag that pair can use if it registers multiple variables
644 ------------------------------------------------------------------------- */
645
request(Pair * pair,int peratom,double maxvalue)646 int Min::request(Pair *pair, int peratom, double maxvalue)
647 {
648 int n = nextra_atom + 1;
649 xextra_atom = (double **) memory->srealloc(xextra_atom,n*sizeof(double *),
650 "min:xextra_atom");
651 fextra_atom = (double **) memory->srealloc(fextra_atom,n*sizeof(double *),
652 "min:fextra_atom");
653 memory->grow(extra_peratom,n,"min:extra_peratom");
654 memory->grow(extra_nlen,n,"min:extra_nlen");
655 memory->grow(extra_max,n,"min:extra_max");
656 requestor = (Pair **) memory->srealloc(requestor,n*sizeof(Pair *),
657 "min:requestor");
658
659 requestor[nextra_atom] = pair;
660 extra_peratom[nextra_atom] = peratom;
661 extra_max[nextra_atom] = maxvalue;
662 nextra_atom++;
663 return nextra_atom-1;
664 }
665
666 /* ---------------------------------------------------------------------- */
667
modify_params(int narg,char ** arg)668 void Min::modify_params(int narg, char **arg)
669 {
670 if (narg == 0) error->all(FLERR,"Illegal min_modify command");
671
672 int iarg = 0;
673 while (iarg < narg) {
674 if (strcmp(arg[iarg],"dmax") == 0) {
675 if (iarg+2 > narg) error->all(FLERR,"Illegal min_modify command");
676 dmax = utils::numeric(FLERR,arg[iarg+1],false,lmp);
677 iarg += 2;
678 } else if (strcmp(arg[iarg],"delaystep") == 0) {
679 if (iarg+2 > narg) error->all(FLERR,"Illegal min_modify command");
680 delaystep = utils::numeric(FLERR,arg[iarg+1],false,lmp);
681 iarg += 2;
682 } else if (strcmp(arg[iarg],"dtgrow") == 0) {
683 if (iarg+2 > narg) error->all(FLERR,"Illegal min_modify command");
684 dtgrow = utils::numeric(FLERR,arg[iarg+1],false,lmp);
685 iarg += 2;
686 } else if (strcmp(arg[iarg],"dtshrink") == 0) {
687 if (iarg+2 > narg) error->all(FLERR,"Illegal min_modify command");
688 dtshrink = utils::numeric(FLERR,arg[iarg+1],false,lmp);
689 iarg += 2;
690 } else if (strcmp(arg[iarg],"alpha0") == 0) {
691 if (iarg+2 > narg) error->all(FLERR,"Illegal min_modify command");
692 alpha0 = utils::numeric(FLERR,arg[iarg+1],false,lmp);
693 iarg += 2;
694 } else if (strcmp(arg[iarg],"alphashrink") == 0) {
695 if (iarg+2 > narg) error->all(FLERR,"Illegal min_modify command");
696 alphashrink = utils::numeric(FLERR,arg[iarg+1],false,lmp);
697 iarg += 2;
698 } else if (strcmp(arg[iarg],"tmax") == 0) {
699 if (iarg+2 > narg) error->all(FLERR,"Illegal min_modify command");
700 tmax = utils::numeric(FLERR,arg[iarg+1],false,lmp);
701 iarg += 2;
702 } else if (strcmp(arg[iarg],"tmin") == 0) {
703 if (iarg+2 > narg) error->all(FLERR,"Illegal min_modify command");
704 tmin = utils::numeric(FLERR,arg[iarg+1],false,lmp);
705 iarg += 2;
706 } else if (strcmp(arg[iarg],"halfstepback") == 0) {
707 if (iarg+2 > narg) error->all(FLERR,"Illegal min_modify command");
708 if (strcmp(arg[iarg+1],"yes") == 0) halfstepback_flag = 1;
709 else if (strcmp(arg[iarg+1],"no") == 0) halfstepback_flag = 0;
710 else error->all(FLERR,"Illegal min_modify command");
711 iarg += 2;
712 } else if (strcmp(arg[iarg],"initialdelay") == 0) {
713 if (iarg+2 > narg) error->all(FLERR,"Illegal min_modify command");
714 if (strcmp(arg[iarg+1],"yes") == 0) delaystep_start_flag = 1;
715 else if (strcmp(arg[iarg+1],"no") == 0) delaystep_start_flag = 0;
716 else error->all(FLERR,"Illegal min_modify command");
717 iarg += 2;
718 } else if (strcmp(arg[iarg],"vdfmax") == 0) {
719 if (iarg+2 > narg) error->all(FLERR,"Illegal min_modify command");
720 max_vdotf_negatif = utils::numeric(FLERR,arg[iarg+1],false,lmp);
721 iarg += 2;
722 } else if (strcmp(arg[iarg],"integrator") == 0) {
723 if (iarg+2 > narg) error->all(FLERR,"Illegal min_modify command");
724 if (strcmp(arg[iarg+1],"eulerimplicit") == 0) integrator = 0;
725 else if (strcmp(arg[iarg+1],"verlet") == 0) integrator = 1;
726 else if (strcmp(arg[iarg+1],"leapfrog") == 0) integrator = 2;
727 else if (strcmp(arg[iarg+1],"eulerexplicit") == 0) integrator = 3;
728 else error->all(FLERR,"Illegal min_modify command");
729 iarg += 2;
730 } else if (strcmp(arg[iarg],"line") == 0) {
731 if (iarg+2 > narg) error->all(FLERR,"Illegal min_modify command");
732 if (strcmp(arg[iarg+1],"backtrack") == 0) linestyle = 0;
733 else if (strcmp(arg[iarg+1],"quadratic") == 0) linestyle = 1;
734 else if (strcmp(arg[iarg+1],"forcezero") == 0) linestyle = 2;
735 else if (strcmp(arg[iarg+1],"spin_cubic") == 0) linestyle = 3;
736 else if (strcmp(arg[iarg+1],"spin_none") == 0) linestyle = 4;
737 else error->all(FLERR,"Illegal min_modify command");
738 iarg += 2;
739 } else if (strcmp(arg[iarg],"norm") == 0) {
740 if (iarg+2 > narg) error->all(FLERR,"Illegal min_modify command");
741 if (strcmp(arg[iarg+1],"two") == 0) normstyle = TWO;
742 else if (strcmp(arg[iarg+1],"max") == 0) normstyle = MAX;
743 else if (strcmp(arg[iarg+1],"inf") == 0) normstyle = INF;
744 else error->all(FLERR,"Illegal min_modify command");
745 iarg += 2;
746 } else {
747 int n = modify_param(narg-iarg,&arg[iarg]);
748 if (n == 0) error->all(FLERR,"Illegal fix_modify command");
749 iarg += n;
750 }
751 }
752 }
753
754 /* ----------------------------------------------------------------------
755 setup lists of computes for global and per-atom PE and pressure
756 ------------------------------------------------------------------------- */
757
ev_setup()758 void Min::ev_setup()
759 {
760 delete [] elist_global;
761 delete [] elist_atom;
762 delete [] vlist_global;
763 delete [] vlist_atom;
764 delete [] cvlist_atom;
765 elist_global = elist_atom = nullptr;
766 vlist_global = vlist_atom = cvlist_atom = nullptr;
767
768 nelist_global = nelist_atom = 0;
769 nvlist_global = nvlist_atom = ncvlist_atom = 0;
770 for (int i = 0; i < modify->ncompute; i++) {
771 if (modify->compute[i]->peflag) nelist_global++;
772 if (modify->compute[i]->peatomflag) nelist_atom++;
773 if (modify->compute[i]->pressflag) nvlist_global++;
774 if (modify->compute[i]->pressatomflag & 1) nvlist_atom++;
775 if (modify->compute[i]->pressatomflag & 2) ncvlist_atom++;
776 }
777
778 if (nelist_global) elist_global = new Compute*[nelist_global];
779 if (nelist_atom) elist_atom = new Compute*[nelist_atom];
780 if (nvlist_global) vlist_global = new Compute*[nvlist_global];
781 if (nvlist_atom) vlist_atom = new Compute*[nvlist_atom];
782 if (ncvlist_atom) cvlist_atom = new Compute*[ncvlist_atom];
783
784 nelist_global = nelist_atom = 0;
785 nvlist_global = nvlist_atom = ncvlist_atom = 0;
786 for (int i = 0; i < modify->ncompute; i++) {
787 if (modify->compute[i]->peflag)
788 elist_global[nelist_global++] = modify->compute[i];
789 if (modify->compute[i]->peatomflag)
790 elist_atom[nelist_atom++] = modify->compute[i];
791 if (modify->compute[i]->pressflag)
792 vlist_global[nvlist_global++] = modify->compute[i];
793 if (modify->compute[i]->pressatomflag & 1)
794 vlist_atom[nvlist_atom++] = modify->compute[i];
795 if (modify->compute[i]->pressatomflag & 2)
796 cvlist_atom[ncvlist_atom++] = modify->compute[i];
797 }
798 }
799
800 /* ----------------------------------------------------------------------
801 set eflag,vflag for current iteration
802 invoke matchstep() on all timestep-dependent computes to clear their arrays
803 eflag/vflag based on computes that need info on this ntimestep
804 always set eflag_global = 1, since need energy every iteration
805 eflag: set any or no bits
806 ENERGY_GLOBAL bit for global energy
807 ENERGY_ATOM bit for per-atom energy
808 vflag: set any or no bits, but GLOBAL/FDOTR bit cannot both be set
809 VIRIAL_PAIR bit for global virial as sum of pairwise terms
810 VIRIAL_FDOTR bit for global virial via F dot r
811 VIRIAL_ATOM bit for per-atom virial
812 VIRIAL_CENTROID bit for per-atom centroid virial
813 all force components (pair,bond,angle,...,kspace) use eflag/vflag
814 in their ev_setup() method to set local energy/virial flags
815 ------------------------------------------------------------------------- */
816
ev_set(bigint ntimestep)817 void Min::ev_set(bigint ntimestep)
818 {
819 int i,flag;
820
821 int eflag_global = 1;
822 for (i = 0; i < nelist_global; i++)
823 elist_global[i]->matchstep(ntimestep);
824
825 flag = 0;
826 int eflag_atom = 0;
827 for (i = 0; i < nelist_atom; i++)
828 if (elist_atom[i]->matchstep(ntimestep)) flag = 1;
829 if (flag) eflag_atom = ENERGY_ATOM;
830
831 if (eflag_global) update->eflag_global = update->ntimestep;
832 if (eflag_atom) update->eflag_atom = update->ntimestep;
833 eflag = eflag_global + eflag_atom;
834
835 flag = 0;
836 int vflag_global = 0;
837 for (i = 0; i < nvlist_global; i++)
838 if (vlist_global[i]->matchstep(ntimestep)) flag = 1;
839 if (flag) vflag_global = virial_style;
840
841 flag = 0;
842 int vflag_atom = 0;
843 for (i = 0; i < nvlist_atom; i++)
844 if (vlist_atom[i]->matchstep(ntimestep)) flag = 1;
845 if (flag) vflag_atom = VIRIAL_ATOM;
846
847 flag = 0;
848 int cvflag_atom = 0;
849 for (i = 0; i < ncvlist_atom; i++)
850 if (cvlist_atom[i]->matchstep(ntimestep)) flag = 1;
851 if (flag) cvflag_atom = VIRIAL_CENTROID;
852
853 if (vflag_global) update->vflag_global = update->ntimestep;
854 if (vflag_atom || cvflag_atom) update->vflag_atom = update->ntimestep;
855 vflag = vflag_global + vflag_atom + cvflag_atom;
856 }
857
858 /* ----------------------------------------------------------------------
859 compute and return ||force||_2^2
860 ------------------------------------------------------------------------- */
861
fnorm_sqr()862 double Min::fnorm_sqr()
863 {
864 int i,n;
865 double *fatom;
866
867 double local_norm2_sqr = 0.0;
868 for (i = 0; i < nvec; i++) local_norm2_sqr += fvec[i]*fvec[i];
869 if (nextra_atom) {
870 for (int m = 0; m < nextra_atom; m++) {
871 fatom = fextra_atom[m];
872 n = extra_nlen[m];
873 for (i = 0; i < n; i++)
874 local_norm2_sqr += fatom[i]*fatom[i];
875 }
876 }
877
878 double norm2_sqr = 0.0;
879 MPI_Allreduce(&local_norm2_sqr,&norm2_sqr,1,MPI_DOUBLE,MPI_SUM,world);
880
881 if (nextra_global)
882 for (i = 0; i < nextra_global; i++)
883 norm2_sqr += fextra[i]*fextra[i];
884
885 return norm2_sqr;
886 }
887
888 /* ----------------------------------------------------------------------
889 compute and return ||force||_inf
890 ------------------------------------------------------------------------- */
891
fnorm_inf()892 double Min::fnorm_inf()
893 {
894 int i,n;
895 double *fatom;
896
897 double local_norm_inf = 0.0;
898 for (i = 0; i < nvec; i++)
899 local_norm_inf = MAX(fvec[i]*fvec[i],local_norm_inf);
900 if (nextra_atom) {
901 for (int m = 0; m < nextra_atom; m++) {
902 fatom = fextra_atom[m];
903 n = extra_nlen[m];
904 for (i = 0; i < n; i++)
905 local_norm_inf = MAX(fatom[i]*fatom[i],local_norm_inf);
906 }
907 }
908
909 double norm_inf = 0.0;
910 MPI_Allreduce(&local_norm_inf,&norm_inf,1,MPI_DOUBLE,MPI_MAX,world);
911
912 if (nextra_global)
913 for (i = 0; i < nextra_global; i++)
914 norm_inf = MAX(fextra[i]*fextra[i],norm_inf);
915
916 return norm_inf;
917 }
918
919 /* ----------------------------------------------------------------------
920 compute and return ||force||_max (inf norm per-vector)
921 ------------------------------------------------------------------------- */
922
fnorm_max()923 double Min::fnorm_max()
924 {
925 int i,n;
926 double fdotf,*fatom;
927
928 double local_norm_max = 0.0;
929 for (i = 0; i < nvec; i+=3) {
930 fdotf = fvec[i]*fvec[i]+fvec[i+1]*fvec[i+1]+fvec[i+2]*fvec[i+2];
931 local_norm_max = MAX(fdotf,local_norm_max);
932 }
933 if (nextra_atom) {
934 for (int m = 0; m < nextra_atom; m++) {
935 fatom = fextra_atom[m];
936 n = extra_nlen[m];
937 for (i = 0; i < n; i+=3) {
938 fdotf = fatom[i]*fatom[i]+fatom[i+1]*fatom[i+1]+fatom[i+2]*fatom[i+2];
939 local_norm_max = MAX(fdotf,local_norm_max);
940 }
941 }
942 }
943
944 double norm_max = 0.0;
945 MPI_Allreduce(&local_norm_max,&norm_max,1,MPI_DOUBLE,MPI_MAX,world);
946
947 if (nextra_global) {
948 for (i = 0; i < nextra_global; i+=3) {
949 fdotf = fextra[i]*fextra[i];
950 norm_max = MAX(fdotf,norm_max);
951 }
952 }
953 return norm_max;
954 }
955
956 /* ----------------------------------------------------------------------
957 compute and return sum_i||mag. torque_i||_2 (in eV)
958 ------------------------------------------------------------------------- */
959
total_torque()960 double Min::total_torque()
961 {
962 double ftotsqone,ftotsqall;
963 int nlocal = atom->nlocal;
964 double hbar = force->hplanck/MY_2PI;
965 double tx,ty,tz;
966 double **sp = atom->sp;
967 double **fm = atom->fm;
968
969 ftotsqone = ftotsqall = 0.0;
970 for (int i = 0; i < nlocal; i++) {
971 tx = fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1];
972 ty = fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2];
973 tz = fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0];
974 ftotsqone += tx*tx + ty*ty + tz*tz;
975 }
976
977 // summing all fmsqtot on this replica
978
979 MPI_Allreduce(&ftotsqone,&ftotsqall,1,MPI_DOUBLE,MPI_SUM,world);
980
981 // multiply it by hbar so that units are in eV
982
983 return sqrt(ftotsqall) * hbar;
984 }
985
986 /* ----------------------------------------------------------------------
987 compute and return max_i ||mag. torque components|| (in eV)
988 ------------------------------------------------------------------------- */
989
inf_torque()990 double Min::inf_torque()
991 {
992 double fmaxsqone,fmaxsqall;
993 int nlocal = atom->nlocal;
994 double hbar = force->hplanck/MY_2PI;
995 double tx,ty,tz;
996 double **sp = atom->sp;
997 double **fm = atom->fm;
998
999 fmaxsqone = fmaxsqall = 0.0;
1000 for (int i = 0; i < nlocal; i++) {
1001 tx = fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1];
1002 ty = fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2];
1003 tz = fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0];
1004 fmaxsqone = MAX(fmaxsqone,tx*tx);
1005 fmaxsqone = MAX(fmaxsqone,ty*ty);
1006 fmaxsqone = MAX(fmaxsqone,tz*tz);
1007 }
1008
1009 // finding max fm on this replica
1010
1011 fmaxsqall = fmaxsqone;
1012 MPI_Allreduce(&fmaxsqone,&fmaxsqall,1,MPI_DOUBLE,MPI_MAX,world);
1013
1014 // multiply it by hbar so that units are in eV
1015
1016 return sqrt(fmaxsqall) * hbar;
1017 }
1018
1019 /* ----------------------------------------------------------------------
1020 compute and return max_i ||mag. torque_i|| (in eV)
1021 ------------------------------------------------------------------------- */
1022
max_torque()1023 double Min::max_torque()
1024 {
1025 double fmsq,fmaxsqone,fmaxsqall;
1026 int nlocal = atom->nlocal;
1027 double hbar = force->hplanck/MY_2PI;
1028 double tx,ty,tz;
1029 double **sp = atom->sp;
1030 double **fm = atom->fm;
1031
1032 fmaxsqone = fmaxsqall = 0.0;
1033 for (int i = 0; i < nlocal; i++) {
1034 tx = fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1];
1035 ty = fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2];
1036 tz = fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0];
1037 fmsq = tx*tx + ty*ty + tz*tz;
1038 fmaxsqone = MAX(fmaxsqone,fmsq);
1039 }
1040
1041 // finding max fm on this replica
1042
1043 fmaxsqall = fmaxsqone;
1044 MPI_Allreduce(&fmaxsqone,&fmaxsqall,1,MPI_DOUBLE,MPI_MAX,world);
1045
1046 // multiply it by hbar so that units are in eV
1047
1048 return sqrt(fmaxsqall) * hbar;
1049 }
1050
1051 /* ----------------------------------------------------------------------
1052 possible stop conditions
1053 ------------------------------------------------------------------------- */
1054
stopstrings(int n)1055 char *Min::stopstrings(int n)
1056 {
1057 const char *strings[] = {"max iterations",
1058 "max force evaluations",
1059 "energy tolerance",
1060 "force tolerance",
1061 "search direction is not downhill",
1062 "linesearch alpha is zero",
1063 "forces are zero",
1064 "quadratic factors are zero",
1065 "trust region too small",
1066 "HFTN minimizer error",
1067 "walltime limit reached",
1068 "max iterations with v.f negative"};
1069 return (char *) strings[n];
1070 }
1071