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