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     (if not contributing author is listed, this file has been contributed
36     by the core developer)
37 
38     Copyright 2012-     DCS Computing GmbH, Linz
39     Copyright 2009-2012 JKU Linz
40 ------------------------------------------------------------------------- */
41 
42 #include <stdio.h>
43 #include <string.h>
44 #include <cmath>
45 #include <algorithm>
46 #include "modify.h"
47 #include "style_compute.h"
48 #include "style_fix.h"
49 #include "atom.h"
50 #include "comm.h"
51 #include "fix.h"
52 #include "compute.h"
53 #include "group.h"
54 #include "update.h"
55 #include "fix_property_atom.h"
56 #include "fix_property_global.h"
57 #include "domain.h"
58 #include "memory.h"
59 #include "error.h"
60 
61 using namespace LAMMPS_NS;
62 
63 /* ----------------------------------------------------------------------
64 
65    add a fix property
66 ------------------------------------------------------------------------- */
67 
add_fix_property_global(int narg,char ** arg,const char * caller)68 FixPropertyGlobal* Modify::add_fix_property_global(int narg,char **arg,const char *caller)
69 {
70     if(narg < 5) error->all(FLERR,"Not enough arguments to add a fix property");
71     add_fix(narg,arg);
72     return static_cast<FixPropertyGlobal*>(find_fix_property(arg[3],"property/global",arg[4],0,0,caller));
73 }
74 
add_fix_property_atom(int narg,char ** arg,const char * caller)75 FixPropertyAtom* Modify::add_fix_property_atom(int narg,char **arg,const char *caller)
76 {
77     if(narg < 5) error->all(FLERR,"Not enough arguments to add a fix property");
78     add_fix(narg,arg);
79     return static_cast<FixPropertyAtom*>(find_fix_property(arg[3],"property/atom",arg[4],0,0,caller));
80 }
81 
82 /* ----------------------------------------------------------------------
83    find a fix scalar transport equation
84 ------------------------------------------------------------------------- */
85 
find_fix_scalar_transport_equation_strict(const char * equation_id)86 FixScalarTransportEquation* Modify::find_fix_scalar_transport_equation_strict(const char *equation_id)
87 {
88 
89     for(int ifix = 0; ifix < nfix; ifix++)
90       if(strcmp(fix[ifix]->style,"transportequation/scalar") == 0)
91       {
92           FixScalarTransportEquation *fix_ste = static_cast<FixScalarTransportEquation*>(fix[ifix]);
93           if(fix_ste->match_equation_id(equation_id)) return fix_ste;
94       }
95     return NULL;
96 }
97 
find_fix_scalar_transport_equation(const char * equation_id)98 FixScalarTransportEquation* Modify::find_fix_scalar_transport_equation(const char *equation_id)
99 {
100 
101     for(int ifix = 0; ifix < nfix; ifix++)
102       if(dynamic_cast<FixScalarTransportEquation*>(fix[ifix]))
103       {
104           FixScalarTransportEquation *fix_ste = static_cast<FixScalarTransportEquation*>(fix[ifix]);
105           if(fix_ste->match_equation_id(equation_id)) return fix_ste;
106       }
107     return NULL;
108 }
109 
110 /* ----------------------------------------------------------------------
111    find a fix with the requested style
112 ------------------------------------------------------------------------- */
113 
find_fix_style_strict(const char * style,int rank)114 Fix* Modify::find_fix_style_strict(const char *style, int rank)
115 {
116     for(int ifix = 0; ifix < nfix; ifix++)
117       if(strcmp(fix[ifix]->style,style) == 0)
118       {
119           if(rank > 0) rank --;
120           else return fix[ifix];
121       }
122     return NULL;
123 }
124 
find_fix_style(const char * style,int rank)125 Fix* Modify::find_fix_style(const char *style, int rank)
126 {
127     int len = strlen(style);
128     for(int ifix = 0; ifix < nfix; ifix++)
129       if(strncmp(fix[ifix]->style,style,len) == 0)
130       {
131           if(rank > 0) rank --;
132           else return fix[ifix];
133       }
134     return NULL;
135 }
136 
137 /* ----------------------------------------------------------------------
138    find a compute with the requested style
139 ------------------------------------------------------------------------- */
140 
find_compute_style_strict(const char * style,int rank)141 Compute* Modify::find_compute_style_strict(const char *style, int rank)
142 {
143     for(int icompute = 0; icompute < ncompute; icompute++)
144       if(strcmp(compute[icompute]->style,style) == 0)
145       {
146           if(rank > 0) rank --;
147           else return compute[icompute];
148       }
149     return NULL;
150 }
151 
152 /* ----------------------------------------------------------------------
153    find a fix by ID, return NULL if not found
154 ------------------------------------------------------------------------- */
155 
find_fix_id(const char * id)156 Fix* Modify::find_fix_id(const char *id)
157 {
158   int ifix;
159   for (ifix = 0; ifix < nfix; ifix++)
160     if (strcmp(id,fix[ifix]->id) == 0) break;
161   if (ifix == nfix) return NULL;
162   return fix[ifix];
163 }
164 
165 /* ----------------------------------------------------------------------
166    find a compute by ID, return NULL if not found
167 ------------------------------------------------------------------------- */
168 
find_compute_id(const char * id)169 Compute* Modify::find_compute_id(const char *id)
170 {
171   int icompute;
172   for (icompute = 0; icompute < ncompute; icompute++)
173     if (strcmp(id,compute[icompute]->id) == 0) break;
174   if (icompute == ncompute) return NULL;
175   return compute[icompute];
176 }
177 
178 /* ----------------------------------------------------------------------
179    find a fix by ID and style, return NULL if not found
180 ------------------------------------------------------------------------- */
181 
find_fix_id_style(const char * id,const char * style)182 Fix* Modify::find_fix_id_style(const char *id,const char* style)
183 {
184   int ifix;
185   for (ifix = 0; ifix < nfix; ifix++)
186     if (strcmp(id,fix[ifix]->id) == 0 && strncmp(style,fix[ifix]->style,strlen(style)) == 0) break;
187   if (ifix == nfix) return NULL;
188   return fix[ifix];
189 }
190 
191 /* ----------------------------------------------------------------------
192    return number of fixes/computes with requested style
193 ------------------------------------------------------------------------- */
194 
n_fixes_style(const char * style)195 int Modify::n_fixes_style(const char *style)
196 {
197     int n_fixes,len;
198 
199     n_fixes = 0;
200     len = strlen(style);
201 
202     for(int ifix = 0; ifix < nfix; ifix++)
203       if(strncmp(fix[ifix]->style,style,len) == 0)
204           n_fixes++;
205 
206     return n_fixes;
207 }
208 
n_computes_style(const char * style)209 int Modify::n_computes_style(const char *style)
210 {
211     int n_computes,len;
212 
213     n_computes = 0;
214     len = strlen(style);
215 
216     for(int icompute = 0; icompute < ncompute; icompute++)
217       if(strncmp(compute[icompute]->style,style,len) == 0)
218           n_computes++;
219 
220     return n_computes;
221 }
222 
n_fixes_style_strict(const char * style)223 int Modify::n_fixes_style_strict(const char *style)
224 {
225     int n_fixes = 0;
226 
227     for(int ifix = 0; ifix < nfix; ifix++)
228       if(strcmp(fix[ifix]->style,style) == 0)
229           n_fixes++;
230 
231     return n_fixes;
232 }
233 
234 /* ----------------------------------------------------------------------
235    find a fix property/atom for output
236 ------------------------------------------------------------------------- */
237 
n_fixes_property_atom()238 int Modify::n_fixes_property_atom()
239 {
240     int n_fixes = 0;
241 
242     for(int ifix = 0; ifix < nfix; ifix++)
243       if(dynamic_cast<FixPropertyAtom*>(fix[ifix]))
244           n_fixes++;
245 
246     return n_fixes;
247 }
248 
find_fix_property_atom(int rank)249 FixPropertyAtom* Modify::find_fix_property_atom(int rank)
250 {
251     for(int ifix = 0; ifix < nfix; ifix++)
252       if(dynamic_cast<FixPropertyAtom*>(fix[ifix]))
253       {
254           if(rank > 0) rank --;
255           else return dynamic_cast<FixPropertyAtom*>(fix[ifix]);
256       }
257     return NULL;
258 }
259 
260 /* ----------------------------------------------------------------------
261    find a fix property/atom for output
262 ------------------------------------------------------------------------- */
263 
n_fixes_property_atom_not_internal()264 int Modify::n_fixes_property_atom_not_internal()
265 {
266     int n_fixes = 0;
267 
268     for(int ifix = 0; ifix < nfix; ifix++)
269       if(dynamic_cast<FixPropertyAtom*>(fix[ifix]) && !dynamic_cast<FixPropertyAtom*>(fix[ifix])->get_internal())
270           n_fixes++;
271 
272     return n_fixes;
273 }
274 
dump_size_fixes_property_atom_not_internal()275 int Modify::dump_size_fixes_property_atom_not_internal()
276 {
277     int n_dump = 0;
278 
279     for(int ifix = 0; ifix < nfix; ifix++)
280       if(dynamic_cast<FixPropertyAtom*>(fix[ifix]) && !dynamic_cast<FixPropertyAtom*>(fix[ifix])->get_internal())
281       {
282           n_dump += dynamic_cast<FixPropertyAtom*>(fix[ifix])->get_nvalues();
283       }
284 
285     return n_dump;
286 }
287 
find_fix_property_atom_not_internal(int rank)288 FixPropertyAtom* Modify::find_fix_property_atom_not_internal(int rank)
289 {
290     for(int ifix = 0; ifix < nfix; ifix++)
291       if(dynamic_cast<FixPropertyAtom*>(fix[ifix]) && !dynamic_cast<FixPropertyAtom*>(fix[ifix])->get_internal())
292       {
293           if(rank > 0) rank --;
294           else return dynamic_cast<FixPropertyAtom*>(fix[ifix]);
295       }
296     return NULL;
297 }
298 
299 /* ----------------------------------------------------------------------
300 
301    checks if I am the first fix of a specified style
302 ------------------------------------------------------------------------- */
303 
i_am_first_of_style(Fix * fix_to_check)304 bool Modify::i_am_first_of_style(Fix *fix_to_check)
305 {
306     for(int ifix = 0; ifix < nfix; ifix++)
307     {
308         if(strcmp(fix[ifix]->style,fix_to_check->style) == 0)
309         {
310             if(fix_to_check == fix[ifix]) return true;
311             return false;
312         }
313     }
314 
315     // no fix at all of this style found
316     return false;
317 }
318 
319 /* ----------------------------------------------------------------------
320 
321    returns the index of first/last fix of specified style
322 ------------------------------------------------------------------------- */
323 
index_first_fix_of_style(const char * style)324 int Modify::index_first_fix_of_style(const char *style)
325 {
326     for(int ifix = 0; ifix < nfix; ifix++)
327         if(strcmp(fix[ifix]->style,style) == 0)
328             return ifix;
329 
330     return -1;
331 }
332 
index_last_fix_of_style(const char * style)333 int Modify::index_last_fix_of_style(const char *style)
334 {
335     int idx = -1;
336 
337     for(int ifix = 0; ifix < nfix; ifix++)
338         if(strcmp(fix[ifix]->style,style) == 0)
339             idx = ifix;
340 
341     return idx;
342 }
343 
344 /* ----------------------------------------------------------------------
345 
346    returns the index of first fix that implements a specified function
347 ------------------------------------------------------------------------- */
348 
my_index(Fix * fixptr)349 int Modify::my_index(Fix *fixptr)
350 {
351 
352     for(int ifix = 0; ifix < nfix; ifix++)
353       if(fix[ifix] == fixptr)
354         return ifix;
355 
356     return -1;
357 }
358 
359 /* ----------------------------------------------------------------------
360 
361    returns the index of first fix that implements a specified function
362 ------------------------------------------------------------------------- */
363 
index_first_fix_with_function(const int FUNCTION,bool integrate)364 int Modify::index_first_fix_with_function(const int FUNCTION, bool integrate)
365 {
366 
367     for(int ifix = 0; ifix < nfix; ifix++)
368       if((!integrate || fix[ifix]->time_integrate) && (fmask[ifix] & FUNCTION))
369         return ifix;
370 
371     return -1;
372 }
373 
374 /* ----------------------------------------------------------------------
375 
376    find a property registered by a fix property/global or fix property/atom
377    check if it is of desired style
378    return the index in the fix array
379 ------------------------------------------------------------------------- */
380 
find_fix_property(const char * varname,const char * style,const char * svmstyle,int len1,int len2,const char * caller)381 Fix* Modify::find_fix_property(const char *varname,const char *style,const char *svmstyle,int len1,int len2,const char *caller)
382 {
383     return find_fix_property(varname,style,svmstyle,len1,len2,caller,true);
384 }
385 
find_fix_property(const char * varname,const char * style,const char * svmstyle,int len1,int len2,const char * caller,bool errflag)386 Fix* Modify::find_fix_property(const char *varname,const char *style,const char *svmstyle,int len1,int len2,const char *caller,bool errflag)
387 {
388   int ifix;
389   char errmsg[500];
390   Fix *fix_i = NULL;
391 
392   if((strcmp(style,"property/global")) && (strncmp(style,"property/atom",13)))
393     error->all(FLERR,"Valid styles for find_fix_property are 'property/global' and 'property/atom'");
394 
395   if((len1 < 0) || (len2 < 0))
396     error->all(FLERR,"Lengths for find_fix_property not valid");
397 
398   for(ifix = 0; ifix < nfix; ifix++)
399   {
400       if(strncmp(fix[ifix]->style,"property/atom",13) == 0 && dynamic_cast<FixPropertyAtom*>(fix[ifix]))
401          fix_i = static_cast<FixPropertyAtom*>(fix[ifix])->check_fix(varname,svmstyle,len1,len2,caller,errflag);
402       else if(strcmp(fix[ifix]->style,"property/global") == 0 && dynamic_cast<FixPropertyGlobal*>(fix[ifix]))
403          fix_i = static_cast<FixPropertyGlobal*>(fix[ifix])->check_fix(varname,svmstyle,len1,len2,caller,errflag);
404 
405       // check_fix returns either this or NULL
406       if(fix_i) return fix_i;
407   }
408 
409   // no fix found
410   if(errflag)
411   {
412       sprintf(errmsg,"Could not locate a fix/property storing value(s) for %s as requested by %s.",varname,caller);
413       error->all(FLERR,errmsg);
414   }
415   return NULL;
416 }
417 
418 /* ----------------------------------------------------------------------
419    return if fix restart in progress
420 ------------------------------------------------------------------------- */
421 
fix_restart_in_progress()422 int Modify::fix_restart_in_progress()
423 {
424     return  nfix_restart_global || nfix_restart_peratom;
425 }
426 
427 /* ----------------------------------------------------------------------
428    check if restart data available for this fix
429 ------------------------------------------------------------------------- */
430 
have_restart_data(Fix * f)431 bool Modify::have_restart_data(Fix *f)
432 {
433 
434   // check if Fix is in restart_global list
435 
436   for (int i = 0; i < nfix_restart_global; i++)
437     if (strcmp(id_restart_global[i],f->id) == 0 && strcmp(style_restart_global[i],f->style) == 0)
438       return true;
439 
440   // check if Fix is in restart_peratom list
441 
442   for (int i = 0; i < nfix_restart_peratom; i++)
443     if (strcmp(id_restart_peratom[i],f->id) == 0 &&        strcmp(style_restart_peratom[i],f->style) == 0)
444       return true;
445 
446   return false;
447 }
448 
have_restart_data_style(const char * _style)449 bool Modify::have_restart_data_style(const char* _style)
450 {
451 
452   // check if Fix is in restart_global list
453 
454   for (int i = 0; i < nfix_restart_global; i++)
455     if (strncmp(style_restart_global[i],_style,strlen(_style)) == 0)
456       return true;
457 
458   // check if Fix is in restart_peratom list
459 
460   for (int i = 0; i < nfix_restart_peratom; i++)
461     if (strncmp(style_restart_peratom[i],_style,strlen(_style)) == 0)
462       return true;
463 
464   return false;
465 }
466 
n_restart_data_global_style(const char * _style)467 int Modify::n_restart_data_global_style(const char* _style)
468 {
469 
470   int nhave = 0;
471 
472   // check if Fix is in restart_global list
473 
474   for (int i = 0; i < nfix_restart_global; i++)
475     if (strncmp(style_restart_global[i],_style,strlen(_style)) == 0)
476       nhave++;
477 
478   return nhave;
479 }
480 
id_restart_data_global_style(const char * _style,int _rank)481 char* Modify::id_restart_data_global_style(const char* _style,int _rank)
482 {
483 
484   // check if Fix is in restart_global list
485 
486   for (int i = 0; i < nfix_restart_global; i++)
487     if (strncmp(style_restart_global[i],_style,strlen(_style)) == 0)
488     {
489           if(_rank > 0) _rank --;
490           else return id_restart_global[i];
491     }
492 
493   return 0;
494 }
495 
496 /* ----------------------------------------------------------------------
497    let fixes extend bounding box
498 ------------------------------------------------------------------------- */
499 
box_extent(double & xlo,double & xhi,double & ylo,double & yhi,double & zlo,double & zhi)500 void Modify::box_extent(double &xlo,double &xhi,double &ylo,double &yhi,double &zlo,double &zhi)
501 {
502 
503   // check if Fix is in restart_global list
504 
505   for (int i = 0; i < nfix; i++)
506     fix[i]->box_extent(xlo,xhi,ylo,yhi,zlo,zhi);
507 }
508 
509 /* ----------------------------------------------------------------------
510    return min particle radius
511 ------------------------------------------------------------------------- */
512 
max_min_rad(double & maxrad,double & minrad)513 void Modify::max_min_rad(double &maxrad,double &minrad)
514 {
515     maxrad = 0.;
516     minrad = 1000.;
517     int nlocal = atom->nlocal;
518     double *radius = atom->radius;
519     int ntypes = atom->ntypes;
520 
521     for (int i = 0; i < nfix; i++) {
522       for (int j = 1; j <= ntypes; j++) {
523 
524         maxrad = std::max(maxrad,fix[i]->max_rad(j));
525         if(modify->fix[i]->min_rad(j) > 0.)
526             minrad = std::min(minrad,fix[i]->min_rad(j));
527       }
528     }
529 
530     if (radius) {
531       for (int i = 0; i < nlocal; i++) {
532         maxrad = std::max(maxrad,radius[i]);
533         minrad = std::min(minrad,radius[i]);
534       }
535     }
536 
537     MPI_Min_Scalar(minrad,world);
538     MPI_Max_Scalar(maxrad,world);
539 }
540 
541 /* ----------------------------------------------------------------------
542    calls the exchange routine for fix mesh/...
543    This is a kind of workaround.
544 ------------------------------------------------------------------------- */
545 
forceMeshExchange()546 void Modify::forceMeshExchange()
547 {
548     for (int i = 0; i < n_pre_force; ++i) {
549         Fix *cfix = fix[list_pre_force[i]];
550         if( strncmp(cfix->style,"mesh/surface",12) == 0 && dynamic_cast<FixMesh*>(cfix) )
551             static_cast<FixMesh*>(cfix)->setup_pre_force(0);
552     }
553 }
554