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