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, but has been modified. Copyright for
36 modification:
37
38 Copyright 2012- DCS Computing GmbH, Linz
39 Copyright 2009-2012 JKU Linz
40
41 Copyright of original file:
42 LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
43 http://lammps.sandia.gov, Sandia National Laboratories
44 Steve Plimpton, sjplimp@sandia.gov
45
46 Copyright (2003) Sandia Corporation. Under the terms of Contract
47 DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
48 certain rights in this software. This software is distributed under
49 the GNU General Public License.
50 ------------------------------------------------------------------------- */
51
52 #include <stdlib.h>
53 #include <string.h>
54 #include "delete_atoms.h"
55 #include "atom.h"
56 #include "atom_vec.h"
57 #include "comm.h"
58 #include "domain.h"
59 #include "force.h"
60 #include "group.h"
61 #include "region.h"
62 #include "neighbor.h"
63 #include "neigh_list.h"
64 #include "neigh_request.h"
65 #include "random_mars.h"
66 #include "memory.h"
67 #include "error.h"
68
69 #include <map>
70
71 using namespace LAMMPS_NS;
72
73 // allocate space for static class variable
74
75 DeleteAtoms *DeleteAtoms::cptr;
76
77 /* ---------------------------------------------------------------------- */
78
DeleteAtoms(LAMMPS * lmp)79 DeleteAtoms::DeleteAtoms(LAMMPS *lmp) : Pointers(lmp) {}
80
81 /* ---------------------------------------------------------------------- */
82
command(int narg,char ** arg)83 void DeleteAtoms::command(int narg, char **arg)
84 {
85 if (domain->box_exist == 0)
86 error->all(FLERR,"Delete_atoms command before simulation box is defined");
87
88 if(modify->fix_restart_in_progress())
89 error->all(FLERR,"If restart file is read, delete_atoms command must come after first 'run' command");
90
91 if (narg < 1) error->all(FLERR,"Illegal delete_atoms command");
92 if (atom->tag_enable == 0)
93 error->all(FLERR,"Cannot use delete_atoms unless atoms have IDs");
94
95 // store state before delete
96
97 bigint natoms_previous = atom->natoms;
98
99 if(modify->n_fixes_style_strict("contacthistory") > 0)
100 modify->find_fix_style_strict("contacthistory",0)->pre_exchange();
101 if(modify->n_fixes_style_strict("bond/propagate/gran") > 0)
102 modify->find_fix_style_strict("bond/propagate/gran",0)->pre_exchange();
103
104 // delete the atoms
105
106 if (strcmp(arg[0],"group") == 0) delete_group(narg,arg);
107 else if (strcmp(arg[0],"region") == 0) delete_region(narg,arg);
108 else if (strcmp(arg[0],"overlap") == 0) delete_overlap(narg,arg);
109 else if (strcmp(arg[0],"porosity") == 0) delete_porosity(narg,arg);
110 else error->all(FLERR,"Illegal delete_atoms command");
111
112 // delete local atoms flagged in dlist
113 // reset nlocal
114
115 AtomVec *avec = atom->avec;
116 int nlocal = atom->nlocal;
117
118 int i = 0;
119 while (i < nlocal) {
120 if (dlist[i]) {
121 avec->copy(nlocal-1,i,1);
122 dlist[i] = dlist[nlocal-1];
123 nlocal--;
124 } else i++;
125 }
126
127 atom->nlocal = nlocal;
128 memory->destroy(dlist);
129
130 // if non-molecular system and compress flag set,
131 // reset atom tags to be contiguous
132 // set all atom IDs to 0, call tag_extend()
133
134 if (atom->molecular == 0 && compress_flag) {
135 int *tag = atom->tag;
136 for (i = 0; i < nlocal; i++) tag[i] = 0;
137 atom->tag_extend();
138 }
139
140 // reset atom->natoms
141 // reset atom->map if it exists
142 // set nghost to 0 so old ghosts of deleted atoms won't be mapped
143
144 bigint nblocal = atom->nlocal;
145 MPI_Allreduce(&nblocal,&atom->natoms,1,MPI_LMP_BIGINT,MPI_SUM,world);
146 if (atom->map_style) {
147 atom->nghost = 0;
148 atom->map_init();
149 atom->map_set();
150 }
151
152 // print before and after atom count
153
154 bigint ndelete = natoms_previous - atom->natoms;
155
156 if (comm->me == 0) {
157 if (screen) fprintf(screen,"Deleted " BIGINT_FORMAT
158 " atoms, new total = " BIGINT_FORMAT "\n",
159 ndelete,atom->natoms);
160 if (logfile) fprintf(logfile,"Deleted " BIGINT_FORMAT
161 " atoms, new total = " BIGINT_FORMAT "\n",
162 ndelete,atom->natoms);
163 }
164 }
165
166 /* ----------------------------------------------------------------------
167 delete all atoms in group
168 group will still exist
169 ------------------------------------------------------------------------- */
170
delete_group(int narg,char ** arg)171 void DeleteAtoms::delete_group(int narg, char **arg)
172 {
173 if (narg < 2) error->all(FLERR,"Illegal delete_atoms command");
174
175 int igroup = group->find(arg[1]);
176 if (igroup == -1) error->all(FLERR,"Could not find delete_atoms group ID");
177 options(narg-2,&arg[2]);
178
179 // allocate and initialize deletion list
180
181 int nlocal = atom->nlocal;
182 memory->create(dlist,nlocal,"delete_atoms:dlist");
183 for (int i = 0; i < nlocal; i++) dlist[i] = 0;
184
185 int *mask = atom->mask;
186 int groupbit = group->bitmask[igroup];
187
188 for (int i = 0; i < nlocal; i++)
189 if (mask[i] & groupbit) dlist[i] = 1;
190 }
191
192 /* ----------------------------------------------------------------------
193 delete all atoms in region
194 if mol_flag is set, also delete atoms in molecules with any deletions
195 ------------------------------------------------------------------------- */
196
delete_region(int narg,char ** arg)197 void DeleteAtoms::delete_region(int narg, char **arg)
198 {
199 if (narg < 2) error->all(FLERR,"Illegal delete_atoms command");
200
201 int iregion = domain->find_region(arg[1]);
202 if (iregion == -1) error->all(FLERR,"Could not find delete_atoms region ID");
203 options(narg-2,&arg[2]);
204
205 // allocate and initialize deletion list
206
207 int nlocal = atom->nlocal;
208 memory->create(dlist,nlocal,"delete_atoms:dlist");
209 for (int i = 0; i < nlocal; i++) dlist[i] = 0;
210
211 double **x = atom->x;
212
213 for (int i = 0; i < nlocal; i++)
214 if (domain->regions[iregion]->match(x[i][0],x[i][1],x[i][2])) dlist[i] = 1;
215 if (mol_flag == 0) return;
216
217 // delete entire molecules if any atom in molecule was deleted
218 // store list of molecule IDs I delete atoms from in list
219 // pass list from proc to proc via ring communication
220
221 hash = new std::map<int,int>();
222
223 int *molecule = atom->molecule;
224 for (int i = 0; i < nlocal; i++)
225 if (dlist[i] && hash->find(molecule[i]) == hash->end())
226 (*hash)[molecule[i]] = 1;
227
228 int n = hash->size();
229 int *list;
230 memory->create(list,n,"delete_atoms:list");
231
232 n = 0;
233 std::map<int,int>::iterator pos;
234 for (pos = hash->begin(); pos != hash->end(); ++pos) list[n++] = pos->first;
235
236 cptr = this;
237 comm->ring(n,sizeof(int),list,1,molring,NULL);
238
239 delete hash;
240 memory->destroy(list);
241 }
242
243 /* ----------------------------------------------------------------------
244 callback from comm->ring()
245 cbuf = list of N molecule IDs, put them in hash
246 loop over my atoms, if matches moleculed ID in hash, delete that atom
247 ------------------------------------------------------------------------- */
248
molring(int n,char * cbuf)249 void DeleteAtoms::molring(int n, char *cbuf)
250 {
251 int *list = (int *) cbuf;
252 int *dlist = cptr->dlist;
253 std::map<int,int> *hash = cptr->hash;
254 int nlocal = cptr->atom->nlocal;
255 int *molecule = cptr->atom->molecule;
256
257 hash->clear();
258 for (int i = 0; i < n; i++) (*hash)[list[i]] = 1;
259
260 for (int i = 0; i < nlocal; i++)
261 if (hash->find(molecule[i]) != hash->end()) dlist[i] = 1;
262 }
263
264 /* ----------------------------------------------------------------------
265 delete atoms so there are no pairs within cutoff
266 which atoms are deleted depends on ordering of atoms within proc
267 deletions can vary with processor count
268 no guarantee that minimium number of atoms will be deleted
269 ------------------------------------------------------------------------- */
270
delete_overlap(int narg,char ** arg)271 void DeleteAtoms::delete_overlap(int narg, char **arg)
272 {
273 if (narg < 4) error->all(FLERR,"Illegal delete_atoms command");
274
275 // read args
276
277 double cut = force->numeric(FLERR,arg[1]);
278 double cutsq = cut*cut;
279
280 int igroup1 = group->find(arg[2]);
281 int igroup2 = group->find(arg[3]);
282 if (igroup1 < 0 || igroup2 < 0)
283 error->all(FLERR,"Could not find delete_atoms group ID");
284 options(narg-4,&arg[4]);
285
286 int group1bit = group->bitmask[igroup1];
287 int group2bit = group->bitmask[igroup2];
288
289 if (comm->me == 0 && screen)
290 fprintf(screen,"System init for delete_atoms ...\n");
291
292 // request a full neighbor list for use by this command
293
294 int irequest = neighbor->request((void *) this);
295 neighbor->requests[irequest]->pair = 0;
296 neighbor->requests[irequest]->command = 1;
297 neighbor->requests[irequest]->half = 0;
298 neighbor->requests[irequest]->full = 1;
299 neighbor->requests[irequest]->occasional = 1;
300
301 // init entire system since comm->borders and neighbor->build is done
302 // comm::init needs neighbor::init needs pair::init needs kspace::init, etc
303
304 lmp->init();
305
306 // error check on cutoff
307 // if no pair style, neighbor list will be empty
308
309 if (force->pair == NULL)
310 error->all(FLERR,"Delete_atoms requires a pair style be defined");
311 if (cut > neighbor->cutneighmax)
312 error->all(FLERR,"Delete_atoms cutoff > neighbor cutoff");
313
314 // setup domain, communication and neighboring
315 // acquire ghosts
316 // build neighbor list based on earlier request
317
318 if (domain->triclinic) domain->x2lamda(atom->nlocal);
319 domain->pbc();
320 domain->reset_box();
321 comm->setup();
322 if (neighbor->style) neighbor->setup_bins();
323 comm->exchange();
324 comm->borders();
325 if (domain->triclinic) domain->lamda2x(atom->nlocal+atom->nghost);
326
327 NeighList *list = neighbor->lists[irequest];
328 neighbor->build_one(irequest);
329
330 // allocate and initialize deletion list
331 // must be after exchange potentially changes nlocal
332
333 int nlocal = atom->nlocal;
334 memory->create(dlist,nlocal,"delete_atoms:dlist");
335 for (int i = 0; i < nlocal; i++) dlist[i] = 0;
336
337 // double loop over owned atoms and their full neighbor list
338 // at end of loop, there are no more overlaps
339 // only ever delete owned atom I, never J even if owned
340
341 int *tag = atom->tag;
342 int *mask = atom->mask;
343 double **x = atom->x;
344 double *special_coul = force->special_coul;
345 double *special_lj = force->special_lj;
346
347 int i,j,ii,jj,inum,jnum;
348 double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
349 int *ilist,*jlist,*numneigh,**firstneigh;
350 double factor_lj,factor_coul;
351
352 inum = list->inum;
353 ilist = list->ilist;
354 numneigh = list->numneigh;
355 firstneigh = list->firstneigh;
356
357 for (ii = 0; ii < inum; ii++) {
358 i = ilist[ii];
359 xtmp = x[i][0];
360 ytmp = x[i][1];
361 ztmp = x[i][2];
362 jlist = firstneigh[i];
363 jnum = numneigh[i];
364
365 for (jj = 0; jj < jnum; jj++) {
366 j = jlist[jj];
367 factor_lj = special_lj[sbmask(j)];
368 factor_coul = special_coul[sbmask(j)];
369 j &= NEIGHMASK;
370
371 // if both weighting factors are 0, skip this pair
372 // could be 0 and still be in neigh list for long-range Coulombics
373 // want consistency with non-charged pairs which wouldn't be in list
374
375 if (factor_lj == 0.0 && factor_coul == 0.0) continue;
376
377 // only consider deletion if I,J distance < cutoff
378
379 delx = xtmp - x[j][0];
380 dely = ytmp - x[j][1];
381 delz = ztmp - x[j][2];
382 rsq = delx*delx + dely*dely + delz*delz;
383 if (rsq >= cutsq) continue;
384
385 // only consider deletion if I,J are in groups 1,2 respectively
386 // true whether J is owned or ghost atom
387
388 if (!(mask[i] & group1bit)) continue;
389 if (!(mask[j] & group2bit)) continue;
390
391 // J is owned atom:
392 // delete atom I if atom J has not already been deleted
393 // J is ghost atom:
394 // delete atom I if J,I is not a candidate deletion pair
395 // due to being in groups 1,2 respectively
396 // if they are candidate pair, then either:
397 // another proc owns J and could delete J
398 // J is a ghost of another of my owned atoms, and I could delete J
399 // test on tags of I,J insures that only I or J is deleted
400
401 if (j < nlocal) {
402 if (dlist[j]) continue;
403 } else if ((mask[i] & group2bit) && (mask[j] & group1bit)) {
404 if (tag[i] > tag[j]) continue;
405 }
406
407 dlist[i] = 1;
408 break;
409 }
410 }
411 }
412
413 /* ----------------------------------------------------------------------
414 create porosity by deleting atoms in a specified region
415 ------------------------------------------------------------------------- */
416
delete_porosity(int narg,char ** arg)417 void DeleteAtoms::delete_porosity(int narg, char **arg)
418 {
419 if (narg < 4) error->all(FLERR,"Illegal delete_atoms command");
420
421 int iregion = domain->find_region(arg[1]);
422 if (iregion == -1) error->all(FLERR,"Could not find delete_atoms region ID");
423
424 double porosity_fraction = force->numeric(FLERR,arg[2]);
425 RanMars *random = new RanMars(lmp, arg[3], true);
426 options(narg-4,&arg[4]);
427
428 // allocate and initialize deletion list
429
430 int nlocal = atom->nlocal;
431 memory->create(dlist,nlocal,"delete_atoms:dlist");
432 for (int i = 0; i < nlocal; i++) dlist[i] = 0;
433
434 double **x = atom->x;
435
436 for (int i = 0; i < nlocal; i++)
437 if (domain->regions[iregion]->match(x[i][0],x[i][1],x[i][2]))
438 if (random->uniform() <= porosity_fraction) dlist[i] = 1;
439 }
440
441 /* ----------------------------------------------------------------------
442 process command options
443 ------------------------------------------------------------------------- */
444
options(int narg,char ** arg)445 void DeleteAtoms::options(int narg, char **arg)
446 {
447 compress_flag = 1;
448 mol_flag = 0;
449
450 int iarg = 0;
451 while (iarg < narg) {
452 if (strcmp(arg[iarg],"compress") == 0) {
453 if (iarg+2 > narg) error->all(FLERR,"Illegal delete_atoms command");
454 if (strcmp(arg[iarg+1],"yes") == 0) compress_flag = 1;
455 else if (strcmp(arg[iarg+1],"no") == 0) compress_flag = 0;
456 else error->all(FLERR,"Illegal delete_atoms command");
457 iarg += 2;
458 } else if (strcmp(arg[iarg],"mol") == 0) {
459 if (iarg+2 > narg) error->all(FLERR,"Illegal delete_atoms command");
460 if (strcmp(arg[iarg+1],"yes") == 0) mol_flag = 1;
461 else if (strcmp(arg[iarg+1],"no") == 0) mol_flag = 0;
462 else error->all(FLERR,"Illegal delete_atoms command");
463 iarg += 2;
464 } else error->all(FLERR,"Illegal delete_atoms command");
465 }
466 }
467