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 <stdio.h>
47 #include <string.h>
48 #include <stdlib.h>
49 #include "fix_external.h"
50 #include "atom.h"
51 #include "update.h"
52 #include "memory.h"
53 #include "error.h"
54 #include "force.h"
55 
56 using namespace LAMMPS_NS;
57 using namespace FixConst;
58 
59 enum{PF_CALLBACK,PF_ARRAY};
60 
61 /* ---------------------------------------------------------------------- */
62 
FixExternal(LAMMPS * lmp,int narg,char ** arg)63 FixExternal::FixExternal(LAMMPS *lmp, int narg, char **arg) :
64   Fix(lmp, narg, arg)
65 {
66   if (narg < 4) error->all(FLERR,"Illegal fix external command");
67 
68   scalar_flag = 1;
69   global_freq = 1;
70   extscalar = 1;
71 
72   if (strcmp(arg[3],"pf/callback") == 0) {
73     if (narg != 6) error->all(FLERR,"Illegal fix external command");
74     mode = PF_CALLBACK;
75     ncall = force->inumeric(FLERR,arg[4]);
76     napply = force->inumeric(FLERR,arg[5]);
77     if (ncall <= 0 || napply <= 0)
78       error->all(FLERR,"Illegal fix external command");
79   } else if (strcmp(arg[3],"pf/array") == 0) {
80     if (narg != 5) error->all(FLERR,"Illegal fix external command");
81     mode = PF_ARRAY;
82     napply = force->inumeric(FLERR,arg[4]);
83     if (napply <= 0) error->all(FLERR,"Illegal fix external command");
84   } else error->all(FLERR,"Illegal fix external command");
85 
86   callback = NULL;
87 
88   // perform initial allocation of atom-based array
89   // register with Atom class
90 
91   fexternal = NULL;
92   grow_arrays(atom->nmax);
93   atom->add_callback(0);
94 
95   user_energy = 0.0;
96 }
97 
98 /* ---------------------------------------------------------------------- */
99 
~FixExternal()100 FixExternal::~FixExternal()
101 {
102   // unregister callbacks to this fix from Atom class
103 
104   atom->delete_callback(id,0);
105 
106   memory->destroy(fexternal);
107 }
108 
109 /* ---------------------------------------------------------------------- */
110 
setmask()111 int FixExternal::setmask()
112 {
113   int mask = 0;
114   if (mode == PF_CALLBACK || mode == PF_ARRAY) {
115     mask |= POST_FORCE;
116     mask |= THERMO_ENERGY;
117     mask |= MIN_POST_FORCE;
118   }
119   return mask;
120 }
121 
122 /* ---------------------------------------------------------------------- */
123 
init()124 void FixExternal::init()
125 {
126   if (mode == PF_CALLBACK && callback == NULL)
127     error->all(FLERR,"Fix external callback function not set");
128 }
129 
130 /* ---------------------------------------------------------------------- */
131 
setup(int vflag)132 void FixExternal::setup(int vflag)
133 {
134   post_force(vflag);
135 }
136 
137 /* ---------------------------------------------------------------------- */
138 
min_setup(int vflag)139 void FixExternal::min_setup(int vflag)
140 {
141   post_force(vflag);
142 }
143 
144 /* ---------------------------------------------------------------------- */
145 
post_force(int vflag)146 void FixExternal::post_force(int vflag)
147 {
148   bigint ntimestep = update->ntimestep;
149 
150   // invoke the callback in driver program
151   // it will fill fexternal with forces
152 
153   if (mode == PF_CALLBACK && ntimestep % ncall == 0)
154     (this->callback)(ptr_caller,update->ntimestep,
155                      atom->nlocal,atom->tag,atom->x,fexternal);
156 
157   // add forces from fexternal to atoms in group
158 
159   if (ntimestep % napply == 0) {
160     double **f = atom->f;
161     int *mask = atom->mask;
162     int nlocal = atom->nlocal;
163 
164     for (int i = 0; i < nlocal; i++)
165       if (mask[i] & groupbit) {
166         f[i][0] += fexternal[i][0];
167         f[i][1] += fexternal[i][1];
168         f[i][2] += fexternal[i][2];
169       }
170   }
171 }
172 
173 /* ---------------------------------------------------------------------- */
174 
min_post_force(int vflag)175 void FixExternal::min_post_force(int vflag)
176 {
177   post_force(vflag);
178 }
179 
180 /* ---------------------------------------------------------------------- */
181 
set_energy(double eng)182 void FixExternal::set_energy(double eng)
183 {
184   user_energy = eng;
185 }
186 
187 /* ----------------------------------------------------------------------
188    potential energy of added force
189    up to user to set it via set_energy()
190 ------------------------------------------------------------------------- */
191 
compute_scalar()192 double FixExternal::compute_scalar()
193 {
194   return user_energy;
195 }
196 
197 /* ----------------------------------------------------------------------
198    memory usage of local atom-based array
199 ------------------------------------------------------------------------- */
200 
memory_usage()201 double FixExternal::memory_usage()
202 {
203   double bytes = 3*atom->nmax * sizeof(double);
204   return bytes;
205 }
206 
207 /* ----------------------------------------------------------------------
208    allocate atom-based array
209 ------------------------------------------------------------------------- */
210 
grow_arrays(int nmax)211 void FixExternal::grow_arrays(int nmax)
212 {
213   memory->grow(fexternal,nmax,3,"external:fexternal");
214 }
215 
216 /* ----------------------------------------------------------------------
217    copy values within local atom-based array
218 ------------------------------------------------------------------------- */
219 
copy_arrays(int i,int j,int delflag)220 void FixExternal::copy_arrays(int i, int j, int delflag)
221 {
222   fexternal[j][0] = fexternal[i][0];
223   fexternal[j][1] = fexternal[i][1];
224   fexternal[j][2] = fexternal[i][2];
225 }
226 
227 /* ----------------------------------------------------------------------
228    pack values in local atom-based array for exchange with another proc
229 ------------------------------------------------------------------------- */
230 
pack_exchange(int i,double * buf)231 int FixExternal::pack_exchange(int i, double *buf)
232 {
233   buf[0] = fexternal[i][0];
234   buf[1] = fexternal[i][1];
235   buf[2] = fexternal[i][2];
236   return 3;
237 }
238 
239 /* ----------------------------------------------------------------------
240    unpack values in local atom-based array from exchange with another proc
241 ------------------------------------------------------------------------- */
242 
unpack_exchange(int nlocal,double * buf)243 int FixExternal::unpack_exchange(int nlocal, double *buf)
244 {
245   fexternal[nlocal][0] = buf[0];
246   fexternal[nlocal][1] = buf[1];
247   fexternal[nlocal][2] = buf[2];
248   return 3;
249 }
250 
251 /* ----------------------------------------------------------------------
252    external caller sets a callback function to invoke in post_force()
253 ------------------------------------------------------------------------- */
254 
set_callback(FnPtr caller_callback,void * caller_ptr)255 void FixExternal::set_callback(FnPtr caller_callback, void *caller_ptr)
256 {
257   callback = caller_callback;
258   ptr_caller = caller_ptr;
259 }
260