1
/* ----------------------------------------------------------------------
2
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
3
http://lammps.sandia.gov, Sandia National Laboratories
4
Steve Plimpton, sjplimp@sandia.gov
6
Copyright (2003) Sandia Corporation. Under the terms of Contract
7
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
8
certain rights in this software. This software is distributed under
9
the GNU General Public License.
11
See the README file in the top-level LAMMPS directory.
12
------------------------------------------------------------------------- */
14
/* ----------------------------------------------------------------------
15
Contributing author: Paul Crozier (SNL)
16
------------------------------------------------------------------------- */
20
#include "fix_tune_kspace.h"
37
#define SWAP(a,b) {temp=(a);(a)=(b);(b)=temp;}
38
#define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
42
using namespace LAMMPS_NS;
43
using namespace FixConst;
45
/* ---------------------------------------------------------------------- */
47
FixTuneKspace::FixTuneKspace(LAMMPS *lmp, int narg, char **arg) :
50
if (narg < 3) error->all(FLERR,"Illegal fix tune/kspace command");
55
niter_adjust_rcut = 0;
56
keep_bracketing = true;
57
first_brent_pass = true;
59
need_fd2_brent = false;
61
ewald_time = pppm_time = msm_time = 0.0;
65
nevery = force->inumeric(FLERR,arg[3]);
67
// set up reneighboring
70
next_reneighbor = update->ntimestep + 1;
73
/* ---------------------------------------------------------------------- */
75
int FixTuneKspace::setmask()
83
/* ---------------------------------------------------------------------- */
85
void FixTuneKspace::init()
88
error->all(FLERR,"Cannot use fix tune/kspace without a kspace style");
90
error->all(FLERR,"Cannot use fix tune/kspace without a pair style");
92
double old_acc = force->kspace->accuracy/force->kspace->two_charge_force;
94
sprintf(old_acc_str,"%g",old_acc);
95
strcpy(new_acc_str,old_acc_str);
98
double *p_cutoff = (double *) force->pair->extract("cut_coul",itmp);
99
pair_cut_coul = *p_cutoff;
102
/* ----------------------------------------------------------------------
103
perform dynamic kspace parameter optimization
104
------------------------------------------------------------------------- */
106
void FixTuneKspace::pre_exchange()
109
if (!force->kspace) return;
110
if (!force->pair) return;
111
if (next_reneighbor != update->ntimestep) return;
112
next_reneighbor = update->ntimestep + nevery;
114
double time = get_timing_info();
116
if (strcmp(force->kspace_style,"ewald") == 0) ewald_time = time;
117
if (strcmp(force->kspace_style,"pppm") == 0) pppm_time = time;
118
if (strcmp(force->kspace_style,"msm") == 0) msm_time = time;
123
store_old_kspace_settings();
124
strcpy(new_kspace_style,"ewald");
125
sprintf(new_pair_style,"%s/long",base_pair_style);
126
update_pair_style(new_pair_style,pair_cut_coul);
127
update_kspace_style(new_kspace_style,new_acc_str);
128
} else if (niter == 2) {
130
store_old_kspace_settings();
131
strcpy(new_kspace_style,"pppm");
132
sprintf(new_pair_style,"%s/long",base_pair_style);
133
update_pair_style(new_pair_style,pair_cut_coul);
134
update_kspace_style(new_kspace_style,new_acc_str);
135
} else if (niter == 3) {
137
store_old_kspace_settings();
138
strcpy(new_kspace_style,"msm");
139
sprintf(new_pair_style,"%s/msm",base_pair_style);
140
update_pair_style(new_pair_style,pair_cut_coul);
141
update_kspace_style(new_kspace_style,new_acc_str);
142
} else if (niter == 4) {
143
store_old_kspace_settings();
144
cout << "ewald_time = " << ewald_time << endl;
145
cout << "pppm_time = " << pppm_time << endl;
146
cout << "msm_time = " << msm_time << endl;
147
// switch to fastest one
148
strcpy(new_kspace_style,"ewald");
149
sprintf(new_pair_style,"%s/long",base_pair_style);
150
if (pppm_time < ewald_time && pppm_time < msm_time)
151
strcpy(new_kspace_style,"pppm");
152
else if (msm_time < pppm_time && msm_time < ewald_time) {
153
strcpy(new_kspace_style,"msm");
154
sprintf(new_pair_style,"%s/msm",base_pair_style);
156
update_pair_style(new_pair_style,pair_cut_coul);
157
update_kspace_style(new_kspace_style,new_acc_str);
162
last_spcpu = timer->elapsed(TIME_LOOP);
165
/* ----------------------------------------------------------------------
166
figure out CPU time per timestep since last time checked
167
------------------------------------------------------------------------- */
169
double FixTuneKspace::get_timing_info()
173
int new_step = update->ntimestep;
175
if (firststep == 0) {
180
new_cpu = timer->elapsed(TIME_LOOP);
181
double cpu_diff = new_cpu - last_spcpu;
182
int step_diff = new_step - last_step;
183
if (step_diff > 0.0) dvalue = cpu_diff/step_diff;
187
last_step = new_step;
188
last_spcpu = new_cpu;
193
/* ----------------------------------------------------------------------
194
store old kspace settings: style, accuracy, order, etc
195
------------------------------------------------------------------------- */
197
void FixTuneKspace::store_old_kspace_settings()
199
int n = strlen(force->kspace_style) + 1;
200
char *old_kspace_style = new char[n];
201
strcpy(old_kspace_style,force->kspace_style);
202
strcpy(new_kspace_style,old_kspace_style);
203
double old_acc = force->kspace->accuracy_relative;
204
char old_acc_str[12];
205
sprintf(old_acc_str,"%g",old_acc);
206
strcpy(new_pair_style,force->pair_style);
207
strcpy(base_pair_style,force->pair_style);
209
if ((trunc = strstr(base_pair_style, "/long")) != NULL) *trunc = '\0';
210
if ((trunc = strstr(base_pair_style, "/msm" )) != NULL) *trunc = '\0';
212
old_differentiation_flag = force->kspace->differentiation_flag;
213
old_slabflag = force->kspace->slabflag;
214
old_slab_volfactor = force->kspace->slab_volfactor;
217
/* ----------------------------------------------------------------------
218
update the pair style if necessary, preserving the settings
219
------------------------------------------------------------------------- */
221
void FixTuneKspace::update_pair_style(char *new_pair_style, double pair_cut_coul)
224
double *p_cutoff = (double *) force->pair->extract("cut_coul",itmp);
225
*p_cutoff = pair_cut_coul;
227
// check to see if we need to change pair styles
228
if (strcmp(new_pair_style,force->pair_style) == 0) return;
230
// create a temporary file to store current pair settings
231
FILE *p_pair_settings_file;
232
p_pair_settings_file = tmpfile();
233
force->pair->write_restart(p_pair_settings_file);
234
rewind(p_pair_settings_file);
236
cout << "Creating new pair style: " << new_pair_style << endl;
237
// delete old pair style and create new one
238
force->create_pair(new_pair_style,lmp->suffix);
240
// restore current pair settings from temporary file
241
force->pair->read_restart(p_pair_settings_file);
243
double *pcutoff = (double *) force->pair->extract("cut_coul",itmp);
244
double current_cutoff = *pcutoff;
245
cout << "Coulomb cutoff for real space: " << current_cutoff << endl;
247
// close temporary file
248
fclose(p_pair_settings_file);
251
/* ----------------------------------------------------------------------
252
update the kspace style if necessary
253
------------------------------------------------------------------------- */
255
void FixTuneKspace::update_kspace_style(char *new_kspace_style, char *new_acc_str)
257
// create kspace style char string
263
arg = (char **) memory->srealloc(arg,maxarg*sizeof(char *),"tune/kspace:arg");
265
arg[0] = new char[n];
266
strcpy(arg[0],new_kspace_style);
267
arg[1] = new char[n];
268
strcpy(arg[1],new_acc_str);
270
// delete old kspace style and create new one
272
force->create_kspace(narg,arg,lmp->suffix);
274
force->kspace->differentiation_flag = old_differentiation_flag;
275
force->kspace->slabflag = old_slabflag;
276
force->kspace->slab_volfactor = old_slab_volfactor;
278
// initialize new kspace style, pair style, molecular styles
283
force->kspace->setup_grid();
285
// Re-init neighbor list. Probably only needed when redefining the pair style. Should happen after pair->init() to get pair style neighbor list request registered
289
// Re-init computes to update pointers to virials, etc.
291
for (int i = 0; i < modify->ncompute; i++) modify->compute[i]->init();
296
/* ----------------------------------------------------------------------
297
find the optimal real space coulomb cutoff
298
------------------------------------------------------------------------- */
300
void FixTuneKspace::adjust_rcut(double time)
302
if (strcmp(force->kspace_style,"msm") == 0) return;
303
if (converged) return;
306
const double TINY = 1.0e-20;
308
// get the current cutoff
310
double *p_cutoff = (double *) force->pair->extract("cut_coul",itmp);
311
double current_cutoff = *p_cutoff;
312
cout << "Old Coulomb cutoff for real space: " << current_cutoff << endl;
314
// use Brent's method from Numerical Recipes to find optimal real space cutoff
316
// first time through, get ax_brent and fa_brent, and adjust cutoff
317
if (keep_bracketing) {
318
if (niter_adjust_rcut == 0) {
320
} else if (niter_adjust_rcut == 1) {
321
ax_brent = current_cutoff;
325
// second time through, get bx_brent and fb_brent, and adjust cutoff
326
} else if (niter_adjust_rcut == 2) {
327
bx_brent = current_cutoff;
329
if (fb_brent > fa_brent) {
330
SWAP(ax_brent,bx_brent);
331
SWAP(fb_brent,fa_brent);
337
// third time through, get cx_brent and fc_brent, and adjust cutoff if needed
338
} else if (niter_adjust_rcut == 3) {
339
cx_brent = current_cutoff;
341
if (fc_brent > fb_brent) keep_bracketing = false;
343
double r = (bx_brent - ax_brent)*(fb_brent - fc_brent);
344
double q = (bx_brent - cx_brent)*(fb_brent - fa_brent);
345
dx_brent = bx_brent - ((bx_brent - cx_brent)*q - (bx_brent - ax_brent)*r)/
346
(2.0*SIGN(MAX(fabs(q - r),TINY),q - r));
347
pair_cut_coul = dx_brent;
350
// after third time through, bracket the minimum, and adjust cutoff
351
} else if (niter_adjust_rcut > 3) {
352
dx_brent = current_cutoff;
353
if (need_fd2_brent) fd2_brent = time;
354
else fd_brent = time;
356
pair_cut_coul = dx_brent;
360
if (!keep_bracketing) {
361
dx_brent = current_cutoff;
363
if (first_brent_pass) brent0();
366
pair_cut_coul = dx_brent;
371
if (pair_cut_coul <= 0.0) pair_cut_coul = fabs(MIN(ax_brent,MIN(bx_brent,(MIN(cx_brent,dx_brent))))/2.0) + TINY;
373
if (pair_cut_coul != pair_cut_coul)
374
error->all(FLERR,"Bad real space Coulomb cutoff in fix tune/kspace");
376
// change the cutoff to pair_cut_coul
377
*p_cutoff = pair_cut_coul;
379
// report the new cutoff
380
double *new_cutoff = (double *) force->pair->extract("cut_coul",itmp);
381
current_cutoff = *new_cutoff;
382
cout << "Adjusted Coulomb cutoff for real space: " << current_cutoff << endl;
384
store_old_kspace_settings();
385
update_pair_style(new_pair_style,pair_cut_coul);
386
update_kspace_style(new_kspace_style,new_acc_str);
389
/* ----------------------------------------------------------------------
390
bracket a minimum using parabolic extrapolation
391
------------------------------------------------------------------------- */
393
void FixTuneKspace::mnbrak()
395
const double GLIMIT = 100.0, TINY = 1.0e-20;
397
r = (bx_brent - ax_brent)*(fb_brent - fc_brent);
398
q = (bx_brent - cx_brent)*(fb_brent - fa_brent);
399
dx_brent = bx_brent - ((bx_brent - cx_brent)*q - (bx_brent - ax_brent)*r)/
400
(2.0*SIGN(MAX(fabs(q - r),TINY),q - r));
401
dxlim = bx_brent + GLIMIT*(cx_brent - bx_brent);
403
if ((bx_brent - dx_brent)*(dx_brent - cx_brent) > 0.0) {
404
if (fd_brent < fc_brent) {
409
keep_bracketing = false;
411
} else if (fd_brent > fb_brent) {
414
keep_bracketing = false;
417
dx_brent = cx_brent + GOLD*(cx_brent - bx_brent);
418
if (need_fd2_brent) {
419
fd_brent = fd2_brent;
420
need_fd2_brent = false;
422
need_fd2_brent = true;
425
} else if ((cx_brent - dx_brent)*(dx_brent - dxlim) > 0.0) {
426
if (fd_brent < fc_brent) {
427
if (need_fd2_brent) {
428
need_fd2_brent = false;
430
need_fd2_brent = true;
431
dx_brent += GOLD*(dx_brent - cx_brent);
434
shft3(bx_brent,cx_brent,dx_brent,dx_brent + GOLD*(dx_brent - cx_brent));
435
shft3(fb_brent,fc_brent,fd_brent,fd2_brent);
437
} else if ((dx_brent - dxlim)*(dxlim - cx_brent) >= 0.0) {
439
if (need_fd2_brent) {
440
fd_brent = fd2_brent;
441
need_fd2_brent = false;
443
need_fd2_brent = true;
447
dx_brent = cx_brent + GOLD*(cx_brent - bx_brent);
448
if (need_fd2_brent) {
449
fd_brent = fd2_brent;
450
need_fd2_brent = false;
452
need_fd2_brent = true;
456
shft3(ax_brent,bx_brent,cx_brent,dx_brent);
457
shft3(fa_brent,fb_brent,fc_brent,fd_brent);
460
/* ----------------------------------------------------------------------
461
Brent's method from Numerical Recipes
462
------------------------------------------------------------------------- */
464
void FixTuneKspace::brent0()
466
a_brent=(ax_brent < cx_brent ? ax_brent : cx_brent);
467
b_brent=(ax_brent > cx_brent ? ax_brent : cx_brent);
468
x_brent=w_brent=v_brent=bx_brent;
469
fw_brent=fv_brent=fx_brent=fb_brent;
472
/* ----------------------------------------------------------------------
473
Brent's method from Numerical Recipes
474
------------------------------------------------------------------------- */
476
void FixTuneKspace::brent1()
479
const double CGOLD=0.3819660;
480
const double ZEPS=numeric_limits<double>::epsilon()*1.0e-3;
482
double p,q,r,tol1,tol2,xm;
486
xm=0.5*(a_brent+b_brent);
487
tol2=2.0*(tol1=tol*fabs(x_brent)+ZEPS);
488
if (fabs(x_brent-xm) <= (tol2-0.5*(b_brent-a_brent))) {
493
if (fabs(e) > tol1) {
494
r=(x_brent-w_brent)*(fx_brent-fv_brent);
495
q=(x_brent-v_brent)*(fx_brent-fw_brent);
496
p=(x_brent-v_brent)*q-(x_brent-w_brent)*r;
502
if (fabs(p) >= fabs(0.5*q*etemp) || p <= q*(a_brent-x_brent) || p >= q*(b_brent-x_brent))
503
d=CGOLD*(e=(x_brent >= xm ? a_brent-x_brent : b_brent-x_brent));
507
if (dx_brent-a_brent < tol2 || b_brent-dx_brent < tol2)
508
d=SIGN(tol1,xm-x_brent);
511
d=CGOLD*(e=(x_brent >= xm ? a_brent-x_brent : b_brent-x_brent));
513
dx_brent=(fabs(d) >= tol1 ? x_brent+d : x_brent+SIGN(tol1,d));
515
first_brent_pass = false;
520
/* ----------------------------------------------------------------------
521
Brent's method from Numerical Recipes
522
------------------------------------------------------------------------- */
524
void FixTuneKspace::brent2()
526
if (fd_brent <= fx_brent) {
527
if (dx_brent >= x_brent) a_brent=x_brent; else b_brent=x_brent;
528
shft3(v_brent,w_brent,x_brent,dx_brent);
529
shft3(fv_brent,fw_brent,fx_brent,fd_brent);
531
if (dx_brent < x_brent) a_brent=dx_brent; else b_brent=dx_brent;
532
if (fd_brent <= fw_brent || w_brent == x_brent) {
537
} else if (fd_brent <= fv_brent || v_brent == x_brent || v_brent == w_brent) {