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 /** Fix Drude Transform ******************************************************/
16 
17 #include "fix_drude_transform.h"
18 
19 #include "atom.h"
20 #include "comm.h"
21 #include "domain.h"
22 #include "error.h"
23 #include "fix_drude.h"
24 #include "modify.h"
25 
26 #include <cmath>
27 #include <cstring>
28 
29 using namespace LAMMPS_NS;
30 using namespace FixConst;
31 
32 /* ---------------------------------------------------------------------- */
33 template <bool inverse>
FixDrudeTransform(LAMMPS * lmp,int narg,char ** arg)34 FixDrudeTransform<inverse>::FixDrudeTransform(LAMMPS *lmp, int narg, char **arg) :
35   Fix(lmp, narg, arg), mcoeff(nullptr)
36 {
37   if (narg != 3) error->all(FLERR,"Illegal fix drude/transform command");
38   comm_forward = 9;
39   fix_drude = nullptr;
40 }
41 
42 /* ---------------------------------------------------------------------- */
43 template <bool inverse>
~FixDrudeTransform()44 FixDrudeTransform<inverse>::~FixDrudeTransform()
45 {
46   if (mcoeff) delete [] mcoeff;
47 }
48 
49 /* ---------------------------------------------------------------------- */
50 template <bool inverse>
init()51 void FixDrudeTransform<inverse>::init()
52 {
53   int ifix;
54   for (ifix = 0; ifix < modify->nfix; ifix++)
55     if (strcmp(modify->fix[ifix]->style,"drude") == 0) break;
56   if (ifix == modify->nfix) error->all(FLERR, "fix drude/transform requires fix drude");
57   fix_drude = (FixDrude *) modify->fix[ifix];
58 }
59 
60 /* ---------------------------------------------------------------------- */
61 template <bool inverse>
setmask()62 int FixDrudeTransform<inverse>::setmask()
63 {
64   int mask = 0;
65   mask |= INITIAL_INTEGRATE;
66   mask |= FINAL_INTEGRATE;
67   return mask;
68 }
69 
70 /* ---------------------------------------------------------------------- */
71 template <bool inverse>
setup(int)72 void FixDrudeTransform<inverse>::setup(int) {
73   int nlocal = atom->nlocal;
74   int ntypes = atom->ntypes;
75   int * type = atom->type;
76   double * rmass = atom->rmass, * mass = atom->mass;
77   tagint * drudeid = fix_drude->drudeid;
78   int * drudetype = fix_drude->drudetype;
79 
80   if (!rmass) {
81     if (!mcoeff) mcoeff = new double[ntypes+1];
82     double *mcoeff_loc = new double[ntypes+1];
83     for (int itype=0; itype<=ntypes; itype++) mcoeff_loc[itype] = 2.; // an impossible value: mcoeff is at most 1.
84     for (int i=0; i<nlocal; i++) {
85       if (drudetype[type[i]] == DRUDE_TYPE) {
86         int j = atom->map(drudeid[i]);
87         // i is drude, j is core
88         if (mcoeff_loc[type[i]] < 1.5) { // already done
89           if (mcoeff_loc[type[j]] > 1.5) { // not yet done ??
90             error->all(FLERR,"There must be one Drude type per core type");}
91           continue;
92         }
93         mcoeff_loc[type[i]] = mass[type[i]] / (mass[type[i]] + mass[type[j]]);
94         mcoeff_loc[type[j]] = -mass[type[i]] / mass[type[j]];
95       }
96     }
97 
98     MPI_Allreduce(mcoeff_loc, mcoeff, ntypes+1, MPI_DOUBLE, MPI_MIN, world);
99     // mcoeff is 2 for non polarizable
100     // 0 < mcoeff < 1 for drude
101     // mcoeff < 0 for core
102     delete[] mcoeff_loc;
103   }
104 }
105 
106 /* ---------------------------------------------------------------------- */
107 namespace LAMMPS_NS { // required for specialization
108 template <>
initial_integrate(int)109 void FixDrudeTransform<false>::initial_integrate(int) {
110   comm->forward_comm_fix(this);
111   real_to_reduced();
112   //comm->forward_comm_fix(this); // Normally not needed
113 }
114 
115 template <>
final_integrate()116 void FixDrudeTransform<false>::final_integrate() {
117   comm->forward_comm_fix(this);
118   real_to_reduced();
119   //comm->forward_comm_fix(this); // Normally not needed
120 }
121 
122 template <>
initial_integrate(int)123 void FixDrudeTransform<true>::initial_integrate(int) {
124   comm->forward_comm_fix(this);
125   reduced_to_real();
126   //comm->forward_comm_fix(this); // Normally not needed
127 }
128 
129 template <>
final_integrate()130 void FixDrudeTransform<true>::final_integrate() {
131   comm->forward_comm_fix(this);
132   reduced_to_real();
133   //comm->forward_comm_fix(this); // Normally not needed
134 }
135 
136 } // end of namespace
137 
138 /* ---------------------------------------------------------------------- */
139 template <bool inverse>
real_to_reduced()140 void FixDrudeTransform<inverse>::real_to_reduced()
141 {
142   int nlocal = atom->nlocal;
143   int ntypes = atom->ntypes;
144   int dim = domain->dimension;
145   int * mask = atom->mask, * type = atom->type;
146   double ** x = atom->x, ** v = atom->v, ** f = atom->f;
147   double * rmass = atom->rmass, * mass = atom->mass;
148   double mcore, mdrude, coeff;
149   int icore, idrude;
150   tagint * drudeid = fix_drude->drudeid;
151   int * drudetype = fix_drude->drudetype;
152 
153   if (!rmass) { // TODO: maybe drudetype can be used instead?
154     for (int itype=1; itype<=ntypes; itype++)
155       if (mcoeff[itype] < 1.5) mass[itype] *= 1. - mcoeff[itype];
156   }
157   for (int i=0; i<nlocal; i++) {
158     if (mask[i] & groupbit && drudetype[type[i]] != NOPOL_TYPE) {
159       drudeid[i] = (tagint) domain->closest_image(i, atom->map(drudeid[i]));
160     }
161   }
162   for (int i=0; i<nlocal; i++) {
163     if (mask[i] & groupbit && drudetype[type[i]] != NOPOL_TYPE) {
164       int j = (int) drudeid[i];
165       if (drudetype[type[i]] == DRUDE_TYPE && j < nlocal) continue;
166 
167       if (drudetype[type[i]] == DRUDE_TYPE) {
168         idrude = i;
169         icore = j;
170       } else {
171         icore = i;
172         idrude = j;
173       }
174       if (rmass) {
175         mcore = rmass[icore];
176         mdrude = rmass[idrude];
177         rmass[icore] += mdrude;
178         rmass[idrude] *= mcore / rmass[icore];
179         coeff = mdrude / (mcore + mdrude);
180       } else { // TODO check that all atoms of this types are in the group
181         coeff = mcoeff[type[idrude]];
182       }
183       for (int k=0; k<dim; k++) {
184         x[idrude][k] -= x[icore][k];
185         x[icore][k] += coeff * x[idrude][k];
186         v[idrude][k] -= v[icore][k];
187         v[icore][k] += coeff * v[idrude][k];
188         f[icore][k] += f[idrude][k];
189         f[idrude][k] -= coeff * f[icore][k];
190       }
191     }
192   }
193   fix_drude->is_reduced = true;
194 }
195 
196 /* ---------------------------------------------------------------------- */
197 template <bool inverse>
reduced_to_real()198 void FixDrudeTransform<inverse>::reduced_to_real()
199 {
200   int nlocal = atom->nlocal;
201   int ntypes = atom->ntypes;
202   int dim = domain->dimension;
203   int * mask = atom->mask, * type = atom->type;
204   double ** x = atom->x, ** v = atom->v, ** f = atom->f;
205   double * rmass = atom->rmass, * mass = atom->mass;
206   double mcore, mdrude, coeff;
207   int icore, idrude;
208   tagint * drudeid = fix_drude->drudeid;
209   int * drudetype = fix_drude->drudetype;
210 
211   for (int i=0; i<nlocal; i++) {
212     if (mask[i] & groupbit && drudetype[type[i]] != NOPOL_TYPE) {
213       int j = (int) drudeid[i]; // local index of drude partner because drudeid is in reduced form
214       if (drudetype[type[i]] == DRUDE_TYPE && j < nlocal) continue;
215 
216       if (drudetype[type[i]] == DRUDE_TYPE) {
217         idrude = i;
218         icore = j;
219       } else {
220         icore = i;
221         idrude = j;
222       }
223       if (rmass) {
224         double s = sqrt(1. - rmass[idrude]/rmass[icore]);
225         rmass[idrude] = 0.5 * rmass[icore] * (1. - s);
226         mdrude = rmass[idrude];
227         rmass[icore] -= mdrude;
228         mcore = rmass[icore];
229         coeff = mdrude / (mcore + mdrude);
230       } else {
231         if (!mcoeff[type[icore]]) { // TODO: should it be > 1.5 ?
232           double s = sqrt(1. - mass[type[idrude]] / mass[type[icore]]);
233           mass[type[idrude]] = 0.5 * mass[type[icore]] * (1. - s);
234           mdrude = mass[type[idrude]];
235           mass[type[icore]] -= mdrude;
236           mcore = mass[type[icore]];
237           mcoeff[type[icore]] = mdrude / (mcore + mdrude);
238         }
239         coeff = mcoeff[type[idrude]];
240       }
241       for (int k=0; k<dim; k++) {
242         x[icore][k] -= coeff * x[idrude][k];
243         x[idrude][k] += x[icore][k];
244         v[icore][k] -= coeff * v[idrude][k];
245         v[idrude][k] += v[icore][k];
246         f[idrude][k] += coeff * f[icore][k];
247         f[icore][k] -= f[idrude][k];
248       }
249     }
250   }
251   for (int i=0; i<nlocal; i++) {
252     if (mask[i] & groupbit && drudetype[type[i]] != NOPOL_TYPE) {
253       drudeid[i] = atom->tag[(int) drudeid[i]];
254     }
255   }
256   if (!rmass) {
257     for (int itype=1; itype<=ntypes; itype++)
258       if (mcoeff[itype] < 1.5) mass[itype] /= 1. - mcoeff[itype];
259   }
260   fix_drude->is_reduced = false;
261 }
262 
263 /* ---------------------------------------------------------------------- */
264 template <bool inverse>
pack_forward_comm(int n,int * list,double * buf,int pbc_flag,int * pbc)265 int FixDrudeTransform<inverse>::pack_forward_comm(int n, int *list, double *buf, int pbc_flag, int *pbc)
266 {
267   double ** x = atom->x, ** v = atom->v, ** f = atom->f;
268   int * type = atom->type, * drudetype = fix_drude->drudetype;
269   double dx,dy,dz;
270   int dim = domain->dimension;
271   int m = 0;
272   for (int i=0; i<n; i++) {
273     int j = list[i];
274     if (pbc_flag == 0 ||
275         (fix_drude->is_reduced && drudetype[type[j]] == DRUDE_TYPE)) {
276         for (int k=0; k<dim; k++) buf[m++] = x[j][k];
277     }
278     else {
279         if (domain->triclinic != 0) {
280             dx = pbc[0]*domain->xprd + pbc[5]*domain->xy;
281             dy = pbc[1]*domain->yprd;
282             if (dim == 3) {
283                 dx += + pbc[4]*domain->xz;
284                 dy += pbc[3]*domain->yz;
285                 dz = pbc[2]*domain->zprd;
286             }
287         }
288         else {
289             dx = pbc[0]*domain->xprd;
290             dy = pbc[1]*domain->yprd;
291             if (dim == 3)
292                 dz = pbc[2]*domain->zprd;
293         }
294         buf[m++] = x[j][0] + dx;
295         buf[m++] = x[j][1] + dy;
296         if (dim == 3)
297             buf[m++] = x[j][2] + dz;
298     }
299     for (int k=0; k<dim; k++) buf[m++] = v[j][k];
300     for (int k=0; k<dim; k++) buf[m++] = f[j][k];
301   }
302   return m;
303 }
304 
305 /* ---------------------------------------------------------------------- */
306 template <bool inverse>
unpack_forward_comm(int n,int first,double * buf)307 void FixDrudeTransform<inverse>::unpack_forward_comm(int n, int first, double *buf)
308 {
309   double ** x = atom->x, ** v = atom->v, ** f = atom->f;
310   int dim = domain->dimension;
311   int m = 0;
312   int last = first + n;
313   for (int i=first; i<last; i++) {
314     for (int k=0; k<dim; k++) x[i][k] = buf[m++];
315     for (int k=0; k<dim; k++) v[i][k] = buf[m++];
316     for (int k=0; k<dim; k++) f[i][k] = buf[m++];
317   }
318 }
319 
320 /* ---------------------------------------------------------------------- */
321 template class LAMMPS_NS::FixDrudeTransform<false>;
322 template class LAMMPS_NS::FixDrudeTransform<true>;
323 
324