1 /* ----------------------------------------------------------------------
2     This is the
3 
4     ██╗     ██╗ ██████╗  ██████╗  ██████╗ ██╗  ██╗████████╗███████╗
5     ██║     ██║██╔════╝ ██╔════╝ ██╔════╝ ██║  ██║╚══██╔══╝██╔════╝
6     ██║     ██║██║  ███╗██║  ███╗██║  ███╗███████║   ██║   ███████╗
7     ██║     ██║██║   ██║██║   ██║██║   ██║██╔══██║   ██║   ╚════██║
8     ███████╗██║╚██████╔╝╚██████╔╝╚██████╔╝██║  ██║   ██║   ███████║
9     ╚══════╝╚═╝ ╚═════╝  ╚═════╝  ╚═════╝ ╚═╝  ╚═╝   ╚═╝   ╚══════╝®
10 
11     DEM simulation engine, released by
12     DCS Computing Gmbh, Linz, Austria
13     http://www.dcs-computing.com, office@dcs-computing.com
14 
15     LIGGGHTS® is part of CFDEM®project:
16     http://www.liggghts.com | http://www.cfdem.com
17 
18     Core developer and main author:
19     Christoph Kloss, christoph.kloss@dcs-computing.com
20 
21     LIGGGHTS® is open-source, distributed under the terms of the GNU Public
22     License, version 2 or later. It is distributed in the hope that it will
23     be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
24     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. You should have
25     received a copy of the GNU General Public License along with LIGGGHTS®.
26     If not, see http://www.gnu.org/licenses . See also top-level README
27     and LICENSE files.
28 
29     LIGGGHTS® and CFDEM® are registered trade marks of DCS Computing GmbH,
30     the producer of the LIGGGHTS® software and the CFDEM®coupling software
31     See http://www.cfdem.com/terms-trademark-policy for details.
32 
33 -------------------------------------------------------------------------
34     Contributing author and copyright for this file:
35     This file is from LAMMPS
36     LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
37     http://lammps.sandia.gov, Sandia National Laboratories
38     Steve Plimpton, sjplimp@sandia.gov
39 
40     Copyright (2003) Sandia Corporation.  Under the terms of Contract
41     DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
42     certain rights in this software.  This software is distributed under
43     the GNU General Public License.
44 ------------------------------------------------------------------------- */
45 
46 #include <string.h>
47 #include <stdlib.h>
48 #include "fix_addforce.h"
49 #include "atom.h"
50 #include "update.h"
51 #include "modify.h"
52 #include "domain.h"
53 #include "region.h"
54 #include "respa.h"
55 #include "input.h"
56 #include "variable.h"
57 #include "memory.h"
58 #include "error.h"
59 #include "force.h"
60 
61 using namespace LAMMPS_NS;
62 using namespace FixConst;
63 
64 enum{NONE,CONSTANT,EQUAL,ATOM};
65 
66 /* ---------------------------------------------------------------------- */
67 
FixAddForce(LAMMPS * lmp,int narg,char ** arg)68 FixAddForce::FixAddForce(LAMMPS *lmp, int narg, char **arg) :
69   Fix(lmp, narg, arg)
70 {
71   if (narg < 6) error->all(FLERR,"Illegal fix addforce command");
72 
73   scalar_flag = 1;
74   vector_flag = 1;
75   size_vector = 3;
76   global_freq = 1;
77   extscalar = 1;
78   extvector = 1;
79 
80   xstr = ystr = zstr = NULL;
81 
82   if (strstr(arg[3],"v_") == arg[3]) {
83     int n = strlen(&arg[3][2]) + 1;
84     xstr = new char[n];
85     strcpy(xstr,&arg[3][2]);
86   } else {
87     xvalue = force->numeric(FLERR,arg[3]);
88     xstyle = CONSTANT;
89   }
90   if (strstr(arg[4],"v_") == arg[4]) {
91     int n = strlen(&arg[4][2]) + 1;
92     ystr = new char[n];
93     strcpy(ystr,&arg[4][2]);
94   } else {
95     yvalue = force->numeric(FLERR,arg[4]);
96     ystyle = CONSTANT;
97   }
98   if (strstr(arg[5],"v_") == arg[5]) {
99     int n = strlen(&arg[5][2]) + 1;
100     zstr = new char[n];
101     strcpy(zstr,&arg[5][2]);
102   } else {
103     zvalue = force->numeric(FLERR,arg[5]);
104     zstyle = CONSTANT;
105   }
106 
107   // optional args
108 
109   iregion = -1;
110   idregion = NULL;
111   estr = NULL;
112 
113   int iarg = 6;
114   while (iarg < narg) {
115     if (strcmp(arg[iarg],"region") == 0) {
116       if (iarg+2 > narg) error->all(FLERR,"Illegal fix addforce command");
117       iregion = domain->find_region(arg[iarg+1]);
118       if (iregion == -1)
119         error->all(FLERR,"Region ID for fix addforce does not exist");
120       int n = strlen(arg[iarg+1]) + 1;
121       idregion = new char[n];
122       strcpy(idregion,arg[iarg+1]);
123       iarg += 2;
124     } else if (strcmp(arg[iarg],"energy") == 0) {
125       if (iarg+2 > narg) error->all(FLERR,"Illegal fix addforce command");
126       if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) {
127         int n = strlen(&arg[iarg+1][2]) + 1;
128         estr = new char[n];
129         strcpy(estr,&arg[iarg+1][2]);
130       } else error->all(FLERR,"Illegal fix addforce command");
131       iarg += 2;
132     } else error->all(FLERR,"Illegal fix addforce command");
133   }
134 
135   force_flag = 0;
136   foriginal[0] = foriginal[1] = foriginal[2] = foriginal[3] = 0.0;
137 
138   maxatom = 0;
139   sforce = NULL;
140 }
141 
142 /* ---------------------------------------------------------------------- */
143 
~FixAddForce()144 FixAddForce::~FixAddForce()
145 {
146   delete [] xstr;
147   delete [] ystr;
148   delete [] zstr;
149   delete [] estr;
150   delete [] idregion;
151   memory->destroy(sforce);
152 }
153 
154 /* ---------------------------------------------------------------------- */
155 
setmask()156 int FixAddForce::setmask()
157 {
158   int mask = 0;
159   mask |= POST_FORCE;
160   mask |= THERMO_ENERGY;
161   mask |= POST_FORCE_RESPA;
162   mask |= MIN_POST_FORCE;
163   return mask;
164 }
165 
166 /* ---------------------------------------------------------------------- */
167 
init()168 void FixAddForce::init()
169 {
170   // check variables
171 
172   if (xstr) {
173     xvar = input->variable->find(xstr);
174     if (xvar < 0)
175       error->all(FLERR,"Variable name for fix addforce does not exist");
176     if (input->variable->equalstyle(xvar)) xstyle = EQUAL;
177     else if (input->variable->atomstyle(xvar)) xstyle = ATOM;
178     else error->all(FLERR,"Variable for fix addforce is invalid style");
179   }
180   if (ystr) {
181     yvar = input->variable->find(ystr);
182     if (yvar < 0)
183       error->all(FLERR,"Variable name for fix addforce does not exist");
184     if (input->variable->equalstyle(yvar)) ystyle = EQUAL;
185     else if (input->variable->atomstyle(yvar)) ystyle = ATOM;
186     else error->all(FLERR,"Variable for fix addforce is invalid style");
187   }
188   if (zstr) {
189     zvar = input->variable->find(zstr);
190     if (zvar < 0)
191       error->all(FLERR,"Variable name for fix addforce does not exist");
192     if (input->variable->equalstyle(zvar)) zstyle = EQUAL;
193     else if (input->variable->atomstyle(zvar)) zstyle = ATOM;
194     else error->all(FLERR,"Variable for fix addforce is invalid style");
195   }
196   if (estr) {
197     evar = input->variable->find(estr);
198     if (evar < 0)
199       error->all(FLERR,"Variable name for fix addforce does not exist");
200     if (input->variable->atomstyle(evar)) estyle = ATOM;
201     else error->all(FLERR,"Variable for fix addforce is invalid style");
202   } else estyle = NONE;
203 
204   // set index and check validity of region
205 
206   if (iregion >= 0) {
207     iregion = domain->find_region(idregion);
208     if (iregion == -1)
209       error->all(FLERR,"Region ID for fix addforce does not exist");
210   }
211 
212   if (xstyle == ATOM || ystyle == ATOM || zstyle == ATOM)
213     varflag = ATOM;
214   else if (xstyle == EQUAL || ystyle == EQUAL || zstyle == EQUAL)
215     varflag = EQUAL;
216   else varflag = CONSTANT;
217 
218   if (varflag == CONSTANT && estyle != NONE)
219     error->all(FLERR,"Cannot use variable energy with "
220                "constant force in fix addforce");
221   if ((varflag == EQUAL || varflag == ATOM) &&
222       update->whichflag == 2 && estyle == NONE)
223     error->all(FLERR,"Must use variable energy with fix addforce");
224 
225   if (strstr(update->integrate_style,"respa"))
226     nlevels_respa = ((Respa *) update->integrate)->nlevels;
227 
228   // error checks on coarsegraining
229   if(force->cg_active())
230     error->cg(FLERR,this->style);
231 }
232 
233 /* ---------------------------------------------------------------------- */
234 
setup(int vflag)235 void FixAddForce::setup(int vflag)
236 {
237   if (strstr(update->integrate_style,"verlet"))
238     post_force(vflag);
239   else {
240     ((Respa *) update->integrate)->copy_flevel_f(nlevels_respa-1);
241     post_force_respa(vflag,nlevels_respa-1,0);
242     ((Respa *) update->integrate)->copy_f_flevel(nlevels_respa-1);
243   }
244 }
245 
246 /* ---------------------------------------------------------------------- */
247 
min_setup(int vflag)248 void FixAddForce::min_setup(int vflag)
249 {
250   post_force(vflag);
251 }
252 
253 /* ---------------------------------------------------------------------- */
254 
post_force(int vflag)255 void FixAddForce::post_force(int vflag)
256 {
257   double **x = atom->x;
258   double **f = atom->f;
259   int *mask = atom->mask;
260   tagint *image = atom->image;
261   int nlocal = atom->nlocal;
262 
263   // reallocate sforce array if necessary
264 
265   if ((varflag == ATOM || estyle == ATOM) && nlocal > maxatom) {
266     maxatom = atom->nmax;
267     memory->destroy(sforce);
268     memory->create(sforce,maxatom,4,"addforce:sforce");
269   }
270 
271   // foriginal[0] = "potential energy" for added force
272   // foriginal[123] = force on atoms before extra force added
273 
274   foriginal[0] = foriginal[1] = foriginal[2] = foriginal[3] = 0.0;
275   force_flag = 0;
276 
277   // constant force
278   // potential energy = - x dot f in unwrapped coords
279 
280   if (varflag == CONSTANT) {
281     double unwrap[3];
282     for (int i = 0; i < nlocal; i++)
283       if (mask[i] & groupbit) {
284         if (iregion >= 0 &&
285             !domain->regions[iregion]->match(x[i][0],x[i][1],x[i][2]))
286           continue;
287 
288         domain->unmap(x[i],image[i],unwrap);
289         foriginal[0] -= xvalue*unwrap[0] + yvalue*unwrap[1] + zvalue*unwrap[2];
290         foriginal[1] += f[i][0];
291         foriginal[2] += f[i][1];
292         foriginal[3] += f[i][2];
293         f[i][0] += xvalue;
294         f[i][1] += yvalue;
295         f[i][2] += zvalue;
296       }
297 
298   // variable force, wrap with clear/add
299   // potential energy = evar if defined, else 0.0
300   // wrap with clear/add
301 
302   } else {
303 
304     modify->clearstep_compute();
305 
306     if (xstyle == EQUAL) xvalue = input->variable->compute_equal(xvar);
307     else if (xstyle == ATOM && sforce)
308       input->variable->compute_atom(xvar,igroup,&sforce[0][0],4,0);
309     if (ystyle == EQUAL) yvalue = input->variable->compute_equal(yvar);
310     else if (ystyle == ATOM && sforce)
311       input->variable->compute_atom(yvar,igroup,&sforce[0][1],4,0);
312     if (zstyle == EQUAL) zvalue = input->variable->compute_equal(zvar);
313     else if (zstyle == ATOM && sforce)
314       input->variable->compute_atom(zvar,igroup,&sforce[0][2],4,0);
315     if (estyle == ATOM && sforce)
316       input->variable->compute_atom(evar,igroup,&sforce[0][3],4,0);
317 
318     modify->addstep_compute(update->ntimestep + 1);
319 
320     for (int i = 0; i < nlocal; i++)
321       if (mask[i] & groupbit) {
322         if (iregion >= 0 &&
323             !domain->regions[iregion]->match(x[i][0],x[i][1],x[i][2]))
324           continue;
325 
326         if (estyle == ATOM) foriginal[0] += sforce[i][3];
327         foriginal[1] += f[i][0];
328         foriginal[2] += f[i][1];
329         foriginal[3] += f[i][2];
330         if (xstyle == ATOM) f[i][0] += sforce[i][0];
331         else if (xstyle) f[i][0] += xvalue;
332         if (ystyle == ATOM) f[i][1] += sforce[i][1];
333         else if (ystyle) f[i][1] += yvalue;
334         if (zstyle == ATOM) f[i][2] += sforce[i][2];
335         else if (zstyle) f[i][2] += zvalue;
336       }
337   }
338 }
339 
340 /* ---------------------------------------------------------------------- */
341 
post_force_respa(int vflag,int ilevel,int iloop)342 void FixAddForce::post_force_respa(int vflag, int ilevel, int iloop)
343 {
344   if (ilevel == nlevels_respa-1) post_force(vflag);
345 }
346 
347 /* ---------------------------------------------------------------------- */
348 
min_post_force(int vflag)349 void FixAddForce::min_post_force(int vflag)
350 {
351   post_force(vflag);
352 }
353 
354 /* ----------------------------------------------------------------------
355    potential energy of added force
356 ------------------------------------------------------------------------- */
357 
compute_scalar()358 double FixAddForce::compute_scalar()
359 {
360   // only sum across procs one time
361 
362   if (force_flag == 0) {
363     MPI_Allreduce(foriginal,foriginal_all,4,MPI_DOUBLE,MPI_SUM,world);
364     force_flag = 1;
365   }
366   return foriginal_all[0];
367 }
368 
369 /* ----------------------------------------------------------------------
370    return components of total force on fix group before force was changed
371 ------------------------------------------------------------------------- */
372 
compute_vector(int n)373 double FixAddForce::compute_vector(int n)
374 {
375   // only sum across procs one time
376 
377   if (force_flag == 0) {
378     MPI_Allreduce(foriginal,foriginal_all,4,MPI_DOUBLE,MPI_SUM,world);
379     force_flag = 1;
380   }
381   return foriginal_all[n+1];
382 }
383 
384 /* ----------------------------------------------------------------------
385    memory usage of local atom-based array
386 ------------------------------------------------------------------------- */
387 
memory_usage()388 double FixAddForce::memory_usage()
389 {
390   double bytes = 0.0;
391   if (varflag == ATOM) bytes = atom->nmax*4 * sizeof(double);
392   return bytes;
393 }
394