1 /* ----------------------------------------------------------------------
2    SPARTA - Stochastic PArallel Rarefied-gas Time-accurate Analyzer
3    http://sparta.sandia.gov
4    Steve Plimpton, sjplimp@sandia.gov, Michael Gallis, magalli@sandia.gov
5    Sandia National Laboratories
6 
7    Copyright (2014) 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 SPARTA directory.
13 ------------------------------------------------------------------------- */
14 
15 #include "ctype.h"
16 #include "surf.h"
17 #include "style_surf_collide.h"
18 #include "style_surf_react.h"
19 #include "surf_collide.h"
20 #include "surf_react.h"
21 #include "domain.h"
22 #include "region.h"
23 #include "grid.h"
24 #include "comm.h"
25 #include "geometry.h"
26 #include "input.h"
27 #include "math_extra.h"
28 #include "math_const.h"
29 #include "hash3.h"
30 #include "memory.h"
31 #include "error.h"
32 
33 using namespace SPARTA_NS;
34 using namespace MathConst;
35 
36 enum{TALLYAUTO,TALLYREDUCE,TALLYRVOUS};         // same as Update
37 enum{REGION_ALL,REGION_ONE,REGION_CENTER};      // same as Grid
38 enum{TYPE,MOLECULE,ID};
39 enum{LT,LE,GT,GE,EQ,NEQ,BETWEEN};
40 enum{INT,DOUBLE};                      // several files
41 
42 #define DELTA 1024
43 #define DELTAMODEL 4
44 #define EPSSQ 1.0e-12
45 #define EPSILON_GRID 1.0e-3
46 #define BIG 1.0e20
47 #define MAXGROUP 32
48 
49 /* ---------------------------------------------------------------------- */
50 
Surf(SPARTA * sparta)51 Surf::Surf(SPARTA *sparta) : Pointers(sparta)
52 {
53   me = comm->me;
54   nprocs = comm->nprocs;
55 
56   exist = 0;
57   implicit = 0;
58   distributed = 0;
59   surf_collision_check = 1;
60 
61   gnames = (char **) memory->smalloc(MAXGROUP*sizeof(char *),"surf:gnames");
62   bitmask = (int *) memory->smalloc(MAXGROUP*sizeof(int),"surf:bitmask");
63   inversemask = (int *) memory->smalloc(MAXGROUP*sizeof(int),
64                                         "surf:inversemask");
65 
66   for (int i = 0; i < MAXGROUP; i++) bitmask[i] = 1 << i;
67   for (int i = 0; i < MAXGROUP; i++) inversemask[i] = bitmask[i] ^ ~0;
68 
69   ngroup = 1;
70   int n = strlen("all") + 1;
71   gnames[0] = new char[n];
72   strcpy(gnames[0],"all");
73 
74   nsurf = 0;
75 
76   nlocal = nghost = nmax = 0;
77   lines = NULL;
78   tris = NULL;
79 
80   nown = maxown = 0;
81   mylines = NULL;
82   mytris = NULL;
83 
84   nsc = maxsc = 0;
85   sc = NULL;
86   nsr = maxsr = 0;
87   sr = NULL;
88 
89   tally_comm = TALLYAUTO;
90 
91   // custom per-surf vectors/arrays
92 
93   ncustom = 0;
94   ename = NULL;
95   etype = esize = ewhich = NULL;
96 
97   ncustom_ivec = ncustom_iarray = 0;
98   icustom_ivec = icustom_iarray = NULL;
99   eivec = NULL;
100   eiarray = NULL;
101   eicol = NULL;
102 
103   ncustom_dvec = ncustom_darray = 0;
104   icustom_dvec = icustom_darray = NULL;
105   edvec = NULL;
106   edarray = NULL;
107   edcol = NULL;
108 
109   custom_restart_flag = NULL;
110 
111   // allocate hash for surf IDs
112 
113   hash = new MySurfHash();
114   hashfilled = 0;
115 }
116 
117 /* ---------------------------------------------------------------------- */
118 
~Surf()119 Surf::~Surf()
120 {
121   for (int i = 0; i < ngroup; i++) delete [] gnames[i];
122   memory->sfree(gnames);
123   memory->sfree(bitmask);
124   memory->sfree(inversemask);
125 
126   memory->sfree(lines);
127   memory->sfree(tris);
128   memory->sfree(mylines);
129   memory->sfree(mytris);
130 
131   for (int i = 0; i < nsc; i++) delete sc[i];
132   memory->sfree(sc);
133   for (int i = 0; i < nsr; i++) delete sr[i];
134   memory->sfree(sr);
135 
136   hash->clear();
137   delete hash;
138 
139   for (int i = 0; i < ncustom; i++) delete [] ename[i];
140   memory->sfree(ename);
141   memory->destroy(etype);
142   memory->destroy(esize);
143   memory->destroy(ewhich);
144 
145   for (int i = 0; i < ncustom_ivec; i++) memory->destroy(eivec[i]);
146   for (int i = 0; i < ncustom_iarray; i++) memory->destroy(eiarray[i]);
147   for (int i = 0; i < ncustom_dvec; i++) memory->destroy(edvec[i]);
148   for (int i = 0; i < ncustom_darray; i++) memory->destroy(edarray[i]);
149 
150   memory->destroy(icustom_ivec);
151   memory->destroy(icustom_iarray);
152   memory->sfree(eivec);
153   memory->sfree(eiarray);
154   memory->destroy(eicol);
155   memory->destroy(icustom_dvec);
156   memory->destroy(icustom_darray);
157   memory->sfree(edvec);
158   memory->sfree(edarray);
159   memory->destroy(edcol);
160 }
161 
162 /* ---------------------------------------------------------------------- */
163 
global(char * arg)164 void Surf::global(char *arg)
165 {
166   if (exist)
167     error->all(FLERR,"Cannot set global surfs when surfaces already exist");
168 
169   if (strcmp(arg,"explicit") == 0) {
170     implicit = 0;
171     distributed = 0;
172   } else if (strcmp(arg,"explicit/distributed") == 0) {
173     implicit = 0;
174     distributed = 1;
175   } else if (strcmp(arg,"implicit") == 0) {
176     implicit = 1;
177     distributed = 1;
178   } else error->all(FLERR,"Illegal global command");
179 }
180 
181 /* ---------------------------------------------------------------------- */
182 
modify_params(int narg,char ** arg)183 void Surf::modify_params(int narg, char **arg)
184 {
185   if (narg < 2) error->all(FLERR,"Illegal surf_modify command");
186   int igroup = find_group(arg[0]);
187   if (igroup < 0) error->all(FLERR,"Surf_modify surface group is not defined");
188   int groupbit = bitmask[igroup];
189 
190   int dim = domain->dimension;
191 
192   int iarg = 1;
193   while (iarg < narg) {
194     if (strcmp(arg[iarg],"collide") == 0) {
195       if (iarg+2 > narg) error->all(FLERR,"Illegal surf_modify command");
196       if (!exist) error->all(FLERR,"Surf_modify when surfs do not yet exist");
197 
198       int isc = find_collide(arg[iarg+1]);
199       if (isc < 0) error->all(FLERR,"Could not find surf_modify sc-ID");
200 
201       // NOTE: is this also needed for mylines and mytris?
202       // set surf collision model for each surf in surface group
203 
204       if (dim == 2) {
205         for (int i = 0; i < nlocal+nghost; i++)
206           if (lines[i].mask & groupbit) lines[i].isc = isc;
207       }
208       if (dim == 3) {
209         for (int i = 0; i < nlocal+nghost; i++)
210           if (tris[i].mask & groupbit) tris[i].isc = isc;
211       }
212 
213       iarg += 2;
214 
215     } else if (strcmp(arg[iarg],"react") == 0) {
216       if (iarg+2 > narg) error->all(FLERR,"Illegal surf_modify command");
217       if (!exist) error->all(FLERR,"Surf_modify when surfs do not yet exist");
218 
219       int isr;
220       if (strcmp(arg[iarg+1],"none") == 0) isr = -1;
221       else {
222         isr = find_react(arg[iarg+1]);
223         if (isr < 0) error->all(FLERR,"Could not find surf_modify sr-ID");
224       }
225 
226       // set surf reaction model for each surf in surface group
227 
228       if (dim == 2) {
229         for (int i = 0; i < nlocal+nghost; i++)
230           if (lines[i].mask & groupbit) lines[i].isr = isr;
231       }
232       if (dim == 3) {
233         for (int i = 0; i < nlocal+nghost; i++)
234           if (tris[i].mask & groupbit) tris[i].isr = isr;
235       }
236 
237       iarg += 2;
238 
239     } else error->all(FLERR,"Illegal surf_modify command");
240   }
241 }
242 
243 /* ---------------------------------------------------------------------- */
244 
init()245 void Surf::init()
246 {
247   int dim = domain->dimension;
248   bigint flag,allflag;
249 
250   // warn if surfs are distributed (explicit or implicit)
251   //   and grid->cutoff < 0.0, since each proc will have copy of all cells
252 
253   if (exist && distributed && grid->cutoff < 0.0)
254     if (comm->me == 0)
255       error->warning(FLERR,"Surfs are distributed with infinite grid cutoff");
256 
257   // check that surf element types are all values >= 1
258 
259   flag = 0;
260   if (dim == 2) {
261     for (int i = 0; i < nlocal; i++)
262       if (lines[i].type <= 0) flag++;
263   }
264   if (dim == 3) {
265     for (int i = 0; i < nlocal; i++)
266       if (tris[i].type <= 0) flag++;
267   }
268 
269   if (distributed)
270     MPI_Allreduce(&flag,&allflag,1,MPI_SPARTA_BIGINT,MPI_SUM,world);
271   else allflag = flag;
272 
273   if (allflag) {
274     char str[64];
275     sprintf(str,BIGINT_FORMAT
276             " surface elements with invalid type <= 0",allflag);
277     error->all(FLERR,str);
278   }
279 
280   // check that every element is assigned to a surf collision model
281   // skip if caller turned off the check, e.g. BalanceGrid, b/c too early
282 
283   if (surf_collision_check) {
284     flag = 0;
285     if (dim == 2) {
286       for (int i = 0; i < nlocal+nghost; i++)
287         if (lines[i].isc < 0) flag++;
288     }
289     if (dim == 3) {
290       for (int i = 0; i < nlocal+nghost; i++)
291         if (tris[i].isc < 0) flag++;
292     }
293 
294     if (distributed)
295       MPI_Allreduce(&flag,&allflag,1,MPI_SPARTA_BIGINT,MPI_SUM,world);
296     else allflag = flag;
297 
298     if (allflag) {
299       char str[64];
300       sprintf(str,BIGINT_FORMAT
301               " surface elements not assigned to a collision model",allflag);
302       error->all(FLERR,str);
303     }
304   }
305 
306   // if a surf element is assigned a reaction model
307   // must have a collision model that allows reactions
308 
309   if (surf_collision_check) {
310     flag = 0;
311     if (dim == 2) {
312       for (int i = 0; i < nlocal+nghost; i++)
313         if (lines[i].isr >= 0 && sc[lines[i].isc]->allowreact == 0) flag++;
314     }
315     if (dim == 3) {
316       for (int i = 0; i < nlocal+nghost; i++)
317         if (tris[i].isr >= 0 && sc[tris[i].isc]->allowreact == 0) flag++;
318     }
319 
320     if (distributed)
321       MPI_Allreduce(&flag,&allflag,1,MPI_SPARTA_BIGINT,MPI_SUM,world);
322     else allflag = flag;
323 
324     if (allflag) {
325       char str[128];
326       sprintf(str,BIGINT_FORMAT " surface elements with reaction model, "
327               "but invalid collision model",allflag);
328       error->all(FLERR,str);
329     }
330   }
331 
332   // checks on transparent surfaces
333   // must be assigned to transparent surf collision model
334 
335   if (surf_collision_check) {
336     flag = 0;
337     if (dim == 2) {
338       for (int i = 0; i < nlocal+nghost; i++) {
339         if (!lines[i].transparent) continue;
340         if (!sc[lines[i].isc]->transparent) flag++;
341       }
342     }
343     if (dim == 3) {
344       for (int i = 0; i < nlocal+nghost; i++) {
345         if (!tris[i].transparent) continue;
346         if (!sc[tris[i].isc]->transparent) flag++;
347       }
348     }
349 
350     if (distributed)
351       MPI_Allreduce(&flag,&allflag,1,MPI_SPARTA_BIGINT,MPI_SUM,world);
352     else allflag = flag;
353 
354     if (allflag) {
355       char str[128];
356       sprintf(str,BIGINT_FORMAT " transparent surface elements "
357               "with invalid collision model or reaction model",allflag);
358       error->all(FLERR,str);
359     }
360   }
361 
362   // initialize surf collision and reaction models
363 
364   for (int i = 0; i < nsc; i++) sc[i]->init();
365   for (int i = 0; i < nsr; i++) sr[i]->init();
366 }
367 
368 /* ----------------------------------------------------------------------
369    remove all surfs
370    called by FixAblate
371 ------------------------------------------------------------------------- */
372 
clear()373 void Surf::clear()
374 {
375   nsurf = 0;
376   nlocal = nghost = 0;
377   nown = 0;
378   hash->clear();
379   hashfilled = 0;
380 }
381 
382 /* ----------------------------------------------------------------------
383    remove ghost surfs
384 ------------------------------------------------------------------------- */
385 
remove_ghosts()386 void Surf::remove_ghosts()
387 {
388   nghost = 0;
389 }
390 
391 /* ----------------------------------------------------------------------
392    add a line to lines list
393    called by ReadSurf (for non-distributed surfs) and ReadISurf
394 ------------------------------------------------------------------------- */
395 
add_line(surfint id,int itype,double * p1,double * p2)396 void Surf::add_line(surfint id, int itype, double *p1, double *p2)
397 {
398   if (nlocal == nmax) {
399     if ((bigint) nmax + DELTA > MAXSMALLINT)
400       error->one(FLERR,"Surf add_line overflowed");
401     nmax += DELTA;
402     grow(nmax-DELTA);
403   }
404 
405   lines[nlocal].id = id;
406   lines[nlocal].type = itype;
407   lines[nlocal].mask = 1;
408   lines[nlocal].isc = lines[nlocal].isr = -1;
409   lines[nlocal].p1[0] = p1[0];
410   lines[nlocal].p1[1] = p1[1];
411   lines[nlocal].p1[2] = 0.0;
412   lines[nlocal].p2[0] = p2[0];
413   lines[nlocal].p2[1] = p2[1];
414   lines[nlocal].p2[2] = 0.0;
415   lines[nlocal].transparent = 0;
416   nlocal++;
417 }
418 
419 /* ----------------------------------------------------------------------
420    add a line to owned or ghost lines list, depending on ownflag
421    called by Grid::unpack_one() or Grid::coarsen_cell()
422 ------------------------------------------------------------------------- */
423 
add_line_copy(int ownflag,Line * line)424 void Surf::add_line_copy(int ownflag, Line *line)
425 {
426   int index;
427 
428   if (ownflag) {
429     if (nlocal == nmax) {
430       if ((bigint) nmax + DELTA > MAXSMALLINT)
431         error->one(FLERR,"Surf add_line_copy overflowed");
432       nmax += DELTA;
433       grow(nmax-DELTA);
434     }
435     index = nlocal;
436     nlocal++;
437 
438   } else {
439     if (nlocal+nghost == nmax) {
440       if ((bigint) nmax + DELTA > MAXSMALLINT)
441         error->one(FLERR,"Surf add_line_copy overflowed");
442       nmax += DELTA;
443       grow(nmax-DELTA);
444     }
445     index = nlocal+nghost;
446     nghost++;
447   }
448 
449   memcpy(&lines[index],line,sizeof(Line));
450 }
451 
452 /* ----------------------------------------------------------------------
453    add a line to mylines list
454    called by ReadSurf for distributed surfs
455    NOT adding one line at a time, rather inserting at location M based on ID
456    assume mylines has been pre-allocated to correct length
457    caller sets surf->nown
458 ------------------------------------------------------------------------- */
459 
add_line_own(surfint id,int itype,double * p1,double * p2)460 void Surf::add_line_own(surfint id, int itype, double *p1, double *p2)
461 {
462   int m = (id-1) / nprocs;
463 
464   mylines[m].id = id;
465   mylines[m].type = itype;
466   mylines[m].mask = 1;
467   mylines[m].isc = mylines[m].isr = -1;
468   mylines[m].p1[0] = p1[0];
469   mylines[m].p1[1] = p1[1];
470   mylines[m].p1[2] = 0.0;
471   mylines[m].p2[0] = p2[0];
472   mylines[m].p2[1] = p2[1];
473   mylines[m].p2[2] = 0.0;
474   mylines[m].transparent = 0;
475 }
476 
477 /* ----------------------------------------------------------------------
478    add a line to tmplines list
479    called by ReadSurf for multiple file input
480 ------------------------------------------------------------------------- */
481 
add_line_temporary(surfint id,int itype,double * p1,double * p2)482 void Surf::add_line_temporary(surfint id, int itype, double *p1, double *p2)
483 {
484   if (ntmp == nmaxtmp) {
485     if ((bigint) nmaxtmp + DELTA > MAXSMALLINT)
486       error->one(FLERR,"Surf add_line_tmeporary overflowed");
487     nmaxtmp += DELTA;
488     grow_temporary(nmaxtmp-DELTA);
489   }
490 
491   tmplines[ntmp].id = id;
492   tmplines[ntmp].type = itype;
493   tmplines[ntmp].mask = 1;
494   tmplines[ntmp].isc = tmplines[ntmp].isr = -1;
495   tmplines[ntmp].p1[0] = p1[0];
496   tmplines[ntmp].p1[1] = p1[1];
497   tmplines[ntmp].p1[2] = 0.0;
498   tmplines[ntmp].p2[0] = p2[0];
499   tmplines[ntmp].p2[1] = p2[1];
500   tmplines[ntmp].p2[2] = 0.0;
501   tmplines[ntmp].transparent = 0;
502   ntmp++;
503 }
504 
505 /* ----------------------------------------------------------------------
506    add a triangle to tris list
507    called by ReadSurf (for non-distributed surfs) and
508      by ReadISurf via FixAblate and Marching Cubes/Squares
509 ------------------------------------------------------------------------- */
510 
add_tri(surfint id,int itype,double * p1,double * p2,double * p3)511 void Surf::add_tri(surfint id, int itype, double *p1, double *p2, double *p3)
512 {
513   if (nlocal == nmax) {
514     if ((bigint) nmax + DELTA > MAXSMALLINT)
515       error->one(FLERR,"Surf add_tri overflowed");
516     nmax += DELTA;
517     grow(nmax-DELTA);
518   }
519 
520   tris[nlocal].id = id;
521   tris[nlocal].type = itype;
522   tris[nlocal].mask = 1;
523   tris[nlocal].isc = tris[nlocal].isr = -1;
524   tris[nlocal].p1[0] = p1[0];
525   tris[nlocal].p1[1] = p1[1];
526   tris[nlocal].p1[2] = p1[2];
527   tris[nlocal].p2[0] = p2[0];
528   tris[nlocal].p2[1] = p2[1];
529   tris[nlocal].p2[2] = p2[2];
530   tris[nlocal].p3[0] = p3[0];
531   tris[nlocal].p3[1] = p3[1];
532   tris[nlocal].p3[2] = p3[2];
533   tris[nlocal].transparent = 0;
534   nlocal++;
535 }
536 
537 /* ----------------------------------------------------------------------
538    add a triangle to owned or ghost list, depending on ownflag
539    called by Grid::unpack_one
540 ------------------------------------------------------------------------- */
541 
add_tri_copy(int ownflag,Tri * tri)542 void Surf::add_tri_copy(int ownflag, Tri *tri)
543 {
544   int index;
545 
546   if (ownflag) {
547     if (nlocal == nmax) {
548       if ((bigint) nmax + DELTA > MAXSMALLINT)
549         error->one(FLERR,"Surf add_tri_copy overflowed");
550       nmax += DELTA;
551       grow(nmax-DELTA);
552     }
553     index = nlocal;
554     nlocal++;
555 
556   } else {
557     if (nlocal+nghost == nmax) {
558       if ((bigint) nmax + DELTA > MAXSMALLINT)
559         error->one(FLERR,"Surf add_tri_copy overflowed");
560       nmax += DELTA;
561       grow(nmax-DELTA);
562     }
563     index = nlocal+nghost;
564     nghost++;
565   }
566 
567   memcpy(&tris[index],tri,sizeof(Tri));
568 }
569 
570 /* ----------------------------------------------------------------------
571    add a triangls's info to mytris list
572    called by ReadSurf for distributed surfs
573    NOT adding one tri at a time, rather inserting at location M based on ID
574    assume mytris has been pre-allocated to correct length
575    caller sets surf->nown
576 ------------------------------------------------------------------------- */
577 
add_tri_own(surfint id,int itype,double * p1,double * p2,double * p3)578 void Surf::add_tri_own(surfint id, int itype, double *p1, double *p2, double *p3)
579 {
580   int m = (id-1) / nprocs;
581 
582   mytris[m].id = id;
583   mytris[m].type = itype;
584   mytris[m].mask = 1;
585   mytris[m].isc = mytris[m].isr = -1;
586   mytris[m].p1[0] = p1[0];
587   mytris[m].p1[1] = p1[1];
588   mytris[m].p1[2] = p1[2];
589   mytris[m].p2[0] = p2[0];
590   mytris[m].p2[1] = p2[1];
591   mytris[m].p2[2] = p2[2];
592   mytris[m].p3[0] = p3[0];
593   mytris[m].p3[1] = p3[1];
594   mytris[m].p3[2] = p3[2];
595   mytris[m].transparent = 0;
596 }
597 
598 /* ----------------------------------------------------------------------
599    add a triangls's info to mytris list
600    called by ReadSurf for distributed surfs when clip3d adds one
601    ARE adding one tri at a time, IDs will be renumbered after
602      and tris re-distributed to procs
603    check if mytris needs to be reallocated
604    increment nown
605 ------------------------------------------------------------------------- */
606 
add_tri_own_clip(surfint id,int itype,double * p1,double * p2,double * p3)607 void Surf::add_tri_own_clip(surfint id, int itype,
608                             double *p1, double *p2, double *p3)
609 {
610   if (nown == maxown) {
611     if ((bigint) maxown + DELTA > MAXSMALLINT)
612       error->one(FLERR,"Surf add_tri overflowed");
613     maxown += DELTA;
614     grow_own(maxown-DELTA);
615   }
616 
617   mytris[nown].id = id;
618   mytris[nown].type = itype;
619   mytris[nown].mask = 1;
620   mytris[nown].isc = mytris[nown].isr = -1;
621   mytris[nown].p1[0] = p1[0];
622   mytris[nown].p1[1] = p1[1];
623   mytris[nown].p1[2] = p1[2];
624   mytris[nown].p2[0] = p2[0];
625   mytris[nown].p2[1] = p2[1];
626   mytris[nown].p2[2] = p2[2];
627   mytris[nown].p3[0] = p3[0];
628   mytris[nown].p3[1] = p3[1];
629   mytris[nown].p3[2] = p3[2];
630   mytris[nown].transparent = 0;
631   nown++;
632 }
633 
634 /* ----------------------------------------------------------------------
635    add a triangle to tmptris list
636    called by ReadSurf for mutliple file input
637 ------------------------------------------------------------------------- */
638 
add_tri_temporary(surfint id,int itype,double * p1,double * p2,double * p3)639 void Surf::add_tri_temporary(surfint id, int itype,
640                              double *p1, double *p2, double *p3)
641 {
642   if (ntmp == nmaxtmp) {
643     if ((bigint) nmaxtmp + DELTA > MAXSMALLINT)
644       error->one(FLERR,"Surf add_tri_temporary overflowed");
645     nmaxtmp += DELTA;
646     grow_temporary(nmaxtmp-DELTA);
647   }
648 
649   tmptris[ntmp].id = id;
650   tmptris[ntmp].type = itype;
651   tmptris[ntmp].mask = 1;
652   tmptris[ntmp].isc = tmptris[ntmp].isr = -1;
653   tmptris[ntmp].p1[0] = p1[0];
654   tmptris[ntmp].p1[1] = p1[1];
655   tmptris[ntmp].p1[2] = p1[2];
656   tmptris[ntmp].p2[0] = p2[0];
657   tmptris[ntmp].p2[1] = p2[1];
658   tmptris[ntmp].p2[2] = p2[2];
659   tmptris[ntmp].p3[0] = p3[0];
660   tmptris[ntmp].p3[1] = p3[1];
661   tmptris[ntmp].p3[2] = p3[2];
662   tmptris[ntmp].transparent = 0;
663   ntmp++;
664 }
665 
666 /* ----------------------------------------------------------------------
667    hash all my nlocal surfs with key = ID, value = index
668    called only for distributed explicit surfs
669 ------------------------------------------------------------------------- */
670 
rehash()671 void Surf::rehash()
672 {
673   if (implicit) return;
674 
675   // hash all nlocal surfs
676   // key = ID, value = index into lines or tris
677 
678   hash->clear();
679   hashfilled = 1;
680 
681   if (domain->dimension == 2) {
682     for (int isurf = 0; isurf < nlocal; isurf++)
683       (*hash)[lines[isurf].id] = isurf;
684   } else {
685     for (int isurf = 0; isurf < nlocal; isurf++)
686       (*hash)[tris[isurf].id] = isurf;
687   }
688 }
689 
690 /* ----------------------------------------------------------------------
691    return 1 if all surfs are transparent, else return 0
692    called by set_inout()
693 ------------------------------------------------------------------------- */
694 
all_transparent()695 int Surf::all_transparent()
696 {
697   // implicit surfs cannot be transparent
698 
699   if (implicit) return 0;
700 
701   // explicit surfs may be transparent
702 
703   int flag = 0;
704   if (domain->dimension == 2) {
705     for (int i = 0; i < nlocal; i++)
706       if (!lines[i].transparent) flag = 1;
707   }
708   if (domain->dimension == 3) {
709     for (int i = 0; i < nlocal; i++)
710       if (!tris[i].transparent) flag = 1;
711   }
712 
713   int allflag;
714   if (distributed)
715     MPI_Allreduce(&flag,&allflag,1,MPI_INT,MPI_SUM,world);
716   else allflag = flag;
717 
718   if (allflag) return 0;
719   return 1;
720 }
721 
722 /* ----------------------------------------------------------------------
723    count owned surf elements = every Pth surf from global Nsurf list
724    only called when surfs = explict (all or distributed)
725    nothing to do when distributed b/c mylines/mytris already setup
726 ------------------------------------------------------------------------ */
727 
setup_owned()728 void Surf::setup_owned()
729 {
730   if (distributed) return;
731 
732   nown = nsurf/nprocs;
733   if (comm->me < nsurf % nprocs) nown++;
734 }
735 
736 /* ----------------------------------------------------------------------
737    set bounding box around all surfs based on their pts
738    sets surf->bblo and surf->bbhi
739    for 2d, set zlo,zhi to box bounds
740    only called when surfs = explict (all or distributed)
741 ------------------------------------------------------------------------- */
742 
bbox_all()743 void Surf::bbox_all()
744 {
745   int i,j;
746   double bblo_one[3],bbhi_one[3];
747   double *x;
748 
749   int dim = domain->dimension;
750 
751   int istart,istop,idelta;
752   Line *linelist;
753   Tri *trilist;
754 
755   if (!distributed) {
756     istart = me;
757     istop = nlocal;
758     idelta = nprocs;
759     linelist = lines;
760     trilist = tris;
761   } else {
762     istart = 0;
763     istop = nown;
764     idelta = 1;
765     linelist = mylines;
766     trilist = mytris;
767   }
768 
769   for (j = 0; j < 3; j++) {
770     bblo_one[j] = BIG;
771     bbhi_one[j] = -BIG;
772   }
773 
774   if (dim == 2) {
775     for (i = istart; i < istop; i += idelta) {
776       x = linelist[i].p1;
777       for (j = 0; j < 2; j++) {
778 	bblo_one[j] = MIN(bblo_one[j],x[j]);
779 	bbhi_one[j] = MAX(bbhi_one[j],x[j]);
780       }
781       x = linelist[i].p2;
782       for (j = 0; j < 2; j++) {
783 	bblo_one[j] = MIN(bblo_one[j],x[j]);
784 	bbhi_one[j] = MAX(bbhi_one[j],x[j]);
785       }
786     }
787     bblo_one[2] = domain->boxlo[2];
788     bbhi_one[2] = domain->boxhi[2];
789 
790   } else if (dim == 3) {
791     for (i = istart; i < istop; i += idelta) {
792       x = trilist[i].p1;
793       for (j = 0; j < 3; j++) {
794 	bblo_one[j] = MIN(bblo_one[j],x[j]);
795 	bbhi_one[j] = MAX(bbhi_one[j],x[j]);
796       }
797       x = trilist[i].p2;
798       for (j = 0; j < 3; j++) {
799 	bblo_one[j] = MIN(bblo_one[j],x[j]);
800 	bbhi_one[j] = MAX(bbhi_one[j],x[j]);
801       }
802       x = trilist[i].p3;
803       for (j = 0; j < 3; j++) {
804 	bblo_one[j] = MIN(bblo_one[j],x[j]);
805 	bbhi_one[j] = MAX(bbhi_one[j],x[j]);
806       }
807     }
808   }
809 
810   MPI_Allreduce(bblo_one,bblo,3,MPI_DOUBLE,MPI_MIN,world);
811   MPI_Allreduce(bbhi_one,bbhi,3,MPI_DOUBLE,MPI_MAX,world);
812 }
813 
814 /* ----------------------------------------------------------------------
815    set bounding box around one surf based on their pts
816    caller passes in the Line or Tri, can be from lines/tris or mylines/mytris
817    returns lo,hi which are allocated by caller
818    for 2d, set zlo,zhi to box bounds
819    only called when surfs = explict (all or distributed)
820 ------------------------------------------------------------------------- */
821 
bbox_one(void * ptr,double * lo,double * hi)822 void Surf::bbox_one(void *ptr, double *lo, double *hi)
823 {
824   double *p1,*p2,*p3;
825 
826   if (domain->dimension == 2) {
827     Line *line = (Line *) ptr;
828     p1 = line->p1; p2 = line->p2;
829     lo[0] = MIN(p1[0],p2[0]);
830     lo[1] = MIN(p1[1],p2[1]);
831     lo[2] = 0.0;
832     hi[0] = MAX(p1[0],p2[0]);
833     hi[1] = MAX(p1[1],p2[1]);
834     hi[2] = 0.0;
835 
836   } else {
837     Tri *tri = (Tri *) ptr;
838     p1 = tri->p1; p2 = tri->p2; p3 = tri->p3;
839     lo[0] = MIN(p1[0],p2[0]);
840     lo[0] = MIN(lo[0],p3[0]);
841     lo[1] = MIN(p1[1],p2[1]);
842     lo[1] = MIN(lo[1],p3[1]);
843     lo[2] = MIN(p1[2],p2[2]);
844     lo[2] = MIN(lo[2],p3[2]);
845     hi[0] = MAX(p1[0],p2[0]);
846     hi[0] = MAX(hi[0],p3[0]);
847     hi[1] = MAX(p1[1],p2[1]);
848     hi[1] = MAX(hi[1],p3[1]);
849     hi[2] = MAX(p1[2],p2[2]);
850     hi[2] = MAX(hi[2],p3[2]);
851   }
852 }
853 
854 /* ----------------------------------------------------------------------
855    compute unit outward normal vectors of all lines starting at Nold
856    outward normal = +z axis x (p2-p1)
857 ------------------------------------------------------------------------- */
858 
compute_line_normal(int old)859 void Surf::compute_line_normal(int old)
860 {
861   double z[3],delta[3];
862 
863   z[0] = 0.0; z[1] = 0.0; z[2] = 1.0;
864 
865   int n;
866   Line *newlines;
867 
868   if (!implicit && distributed) {
869     newlines = mylines;
870     n = nown;
871   } else {
872     newlines = lines;
873     n = nlocal;
874   }
875 
876   for (int i = old; i < n; i++) {
877     MathExtra::sub3(newlines[i].p2,newlines[i].p1,delta);
878     MathExtra::cross3(z,delta,newlines[i].norm);
879     MathExtra::norm3(newlines[i].norm);
880     newlines[i].norm[2] = 0.0;
881   }
882 }
883 
884 /* ----------------------------------------------------------------------
885    compute unit outward normal vectors of all lines starting at Nold
886    outward normal = (p2-p1) x (p3-p1)
887 ------------------------------------------------------------------------- */
888 
compute_tri_normal(int old)889 void Surf::compute_tri_normal(int old)
890 {
891   int p1,p2,p3;
892   double delta12[3],delta13[3];
893 
894   int n;
895   Tri *newtris;
896 
897   if (!implicit && distributed) {
898     newtris = mytris;
899     n = nown;
900   } else {
901     newtris = tris;
902     n = nlocal;
903   }
904 
905   for (int i = old; i < n; i++) {
906     MathExtra::sub3(newtris[i].p2,newtris[i].p1,delta12);
907     MathExtra::sub3(newtris[i].p3,newtris[i].p1,delta13);
908     MathExtra::cross3(delta12,delta13,newtris[i].norm);
909     MathExtra::norm3(newtris[i].norm);
910   }
911 }
912 
913 /* ----------------------------------------------------------------------
914    return coords of a corner point in a 2d quad
915    icorner pts 1 to 4 are ordered by x, then by y
916 ------------------------------------------------------------------------- */
917 
quad_corner_point(int icorner,double * lo,double * hi,double * pt)918 void Surf::quad_corner_point(int icorner, double *lo, double *hi, double *pt)
919 {
920   if (icorner % 2) pt[0] = hi[0];
921   else pt[0] = lo[0];
922   if (icorner / 2) pt[1] = hi[1];
923   else pt[1] = lo[1];
924   pt[2] = 0.0;
925 }
926 
927 /* ----------------------------------------------------------------------
928    return coords of a corner point in a 3d hex
929    icorner pts 1 to 8 are ordered by x, then by y, then by z
930 ------------------------------------------------------------------------- */
931 
hex_corner_point(int icorner,double * lo,double * hi,double * pt)932 void Surf::hex_corner_point(int icorner, double *lo, double *hi, double *pt)
933 {
934   if (icorner % 2) pt[0] = hi[0];
935   else pt[0] = lo[0];
936   if ((icorner/2) % 2) pt[1] = hi[1];
937   else pt[1] = lo[1];
938   if (icorner / 4) pt[2] = hi[2];
939   else pt[2] = lo[2];
940 }
941 
942 /* ----------------------------------------------------------------------
943    return length of line M from lines list (not myline)
944 ------------------------------------------------------------------------- */
945 
line_size(int m)946 double Surf::line_size(int m)
947 {
948   return line_size(lines[m].p1,lines[m].p2);
949 }
950 
951 /* ----------------------------------------------------------------------
952    return length of line
953 ------------------------------------------------------------------------- */
954 
line_size(Line * line)955 double Surf::line_size(Line *line)
956 {
957   return line_size(line->p1,line->p2);
958 }
959 
960 /* ----------------------------------------------------------------------
961    return length of line bewteen 2 points
962 ------------------------------------------------------------------------- */
963 
line_size(double * p1,double * p2)964 double Surf::line_size(double *p1, double *p2)
965 {
966   double delta[3];
967   MathExtra::sub3(p2,p1,delta);
968   return MathExtra::len3(delta);
969 }
970 
971 /* ----------------------------------------------------------------------
972    return area associated with rotating axisymmetric line around y=0 axis
973 ------------------------------------------------------------------------- */
974 
axi_line_size(int m)975 double Surf::axi_line_size(int m)
976 {
977   double *x1 = lines[m].p1;
978   double *x2 = lines[m].p2;
979   double h = x2[0]-x1[0];
980   double r = x2[1]-x1[1];
981   double area = MY_PI*(x1[1]+x2[1])*sqrt(r*r+h*h);
982   return area;
983 }
984 
985 /* ----------------------------------------------------------------------
986    return area associated with rotating axisymmetric line around y=0 axis
987 ------------------------------------------------------------------------- */
988 
axi_line_size(Line * line)989 double Surf::axi_line_size(Line *line)
990 {
991   double *x1 = line->p1;
992   double *x2 = line->p2;
993   double h = x2[0]-x1[0];
994   double r = x2[1]-x1[1];
995   double area = MY_PI*(x1[1]+x2[1])*sqrt(r*r+h*h);
996   return area;
997 }
998 
999 /* ----------------------------------------------------------------------
1000    compute side length and area of triangle M from tri list (not mytri)
1001    return len = length of shortest edge of triangle M
1002    return area = area of triangle M
1003 ------------------------------------------------------------------------- */
1004 
tri_size(int m,double & len)1005 double Surf::tri_size(int m, double &len)
1006 {
1007   return tri_size(tris[m].p1,tris[m].p2,tris[m].p3,len);
1008 }
1009 
1010 /* ----------------------------------------------------------------------
1011    compute side length and area of triangle tri
1012    return len = length of shortest edge of triangle M
1013    return area = area of triangle M
1014 ------------------------------------------------------------------------- */
1015 
tri_size(Tri * tri,double & len)1016 double Surf::tri_size(Tri *tri, double &len)
1017 {
1018   return tri_size(tri->p1,tri->p2,tri->p3,len);
1019 }
1020 
1021 /* ----------------------------------------------------------------------
1022    compute side length and area of a triangle
1023    return len = length of shortest edge of triangle M
1024    return area = area of triangle M
1025 ------------------------------------------------------------------------- */
1026 
tri_size(double * p1,double * p2,double * p3,double & len)1027 double Surf::tri_size(double *p1, double *p2, double *p3, double &len)
1028 {
1029   double delta12[3],delta13[3],delta23[3],cross[3];
1030 
1031   MathExtra::sub3(p2,p1,delta12);
1032   MathExtra::sub3(p3,p1,delta13);
1033   MathExtra::sub3(p3,p2,delta23);
1034   len = MIN(MathExtra::len3(delta12),MathExtra::len3(delta13));
1035   len = MIN(len,MathExtra::len3(delta23));
1036 
1037   MathExtra::cross3(delta12,delta13,cross);
1038   double area = 0.5 * MathExtra::len3(cross);
1039   return area;
1040 }
1041 
1042 /* ----------------------------------------------------------------------
1043    check if 2d surf elements are watertight
1044    each end point should appear exactly once as different ends of 2 lines
1045    exception: not required of end points on simulation box surface
1046 ------------------------------------------------------------------------- */
1047 
check_watertight_2d()1048 void Surf::check_watertight_2d()
1049 {
1050   if (distributed) check_watertight_2d_distributed();
1051   else check_watertight_2d_all();
1052 }
1053 
1054 /* ----------------------------------------------------------------------
1055    check if 2d surf elements are watertight
1056    this is for explicit non-distributed surfs where each proc has copy of all
1057    each proc tests the entire surface, no communication needed
1058 ------------------------------------------------------------------------- */
1059 
check_watertight_2d_all()1060 void Surf::check_watertight_2d_all()
1061 {
1062   // hash end points of all lines
1063   // key = end point
1064   // value = 1 if first point, 2 if second point, 3 if both points
1065 
1066   MyHashPoint phash;
1067   MyPointIt it;
1068 
1069   // insert each end point into hash
1070   // should appear once at each end
1071   // error if any duplicate points
1072 
1073   double *p1,*p2;
1074   OnePoint2d key;
1075   int value;
1076 
1077   int ndup = 0;
1078   for (int i = 0; i < nsurf; i++) {
1079     if (lines[i].transparent) continue;
1080     p1 = lines[i].p1;
1081     key.pt[0] = p1[0]; key.pt[1] = p1[1];
1082     if (phash.find(key) == phash.end()) phash[key] = 1;
1083     else {
1084       value = phash[key];
1085       if (value == 2) phash[key] = 3;
1086       else ndup++;
1087     }
1088 
1089     p2 = lines[i].p2;
1090     key.pt[0] = p2[0]; key.pt[1] = p2[1];
1091     if (phash.find(key) == phash.end()) phash[key] = 2;
1092     else {
1093       value = phash[key];
1094       if (value == 1) phash[key] = 3;
1095       else ndup++;
1096     }
1097   }
1098 
1099   if (ndup) {
1100     char str[128];
1101     sprintf(str,"Watertight check failed with %d duplicate points",ndup);
1102     error->all(FLERR,str);
1103   }
1104 
1105   // check that each end point has a match (value = 3)
1106   // allow for exception if end point on box surface
1107 
1108   double *boxlo = domain->boxlo;
1109   double *boxhi = domain->boxhi;
1110   double *kpt;
1111   double pt[3];
1112 
1113   int nbad = 0;
1114   for (it = phash.begin(); it != phash.end(); ++it) {
1115     if (it->second != 3) {
1116       kpt = (double *) it->first.pt;
1117       pt[0] = kpt[0]; pt[1] = kpt[1]; pt[2] = 0.0;
1118       if (!Geometry::point_on_hex(pt,boxlo,boxhi)) nbad++;
1119     }
1120   }
1121 
1122   if (nbad) {
1123     char str[128];
1124     sprintf(str,"Watertight check failed with %d unmatched points",nbad);
1125     error->all(FLERR,str);
1126   }
1127 }
1128 
1129 /* ----------------------------------------------------------------------
1130    check if 2d surf elements are watertight
1131    this is for explicit distributed surfs
1132    rendezvous communication used to check that each point appears twice
1133 ------------------------------------------------------------------------- */
1134 
check_watertight_2d_distributed()1135 void Surf::check_watertight_2d_distributed()
1136 {
1137   int n;
1138   Line *lines_rvous;
1139 
1140   if (implicit) {
1141     n = nlocal;
1142     lines_rvous = lines;
1143   } else {
1144     n = nown;
1145     lines_rvous = mylines;
1146   }
1147 
1148   // allocate memory for rvous input
1149 
1150   int *proclist;
1151   memory->create(proclist,n*2,"surf:proclist");
1152   InRvousPoint *inpoint =
1153     (InRvousPoint *) memory->smalloc((bigint) n*2*sizeof(InRvousPoint),
1154                                      "surf:inpoint");
1155 
1156   // create rvous inputs
1157   // proclist = owner of each point
1158   // each line end point is sent with flag indicating first/second
1159   // hash of point coord (xy) determines which proc to send to
1160 
1161   int nrvous = 0;
1162   for (int i = 0; i < n; i++) {
1163     proclist[nrvous] = hashlittle(lines_rvous[i].p1,2*sizeof(double),0) % nprocs;
1164     inpoint[nrvous].x[0] = lines_rvous[i].p1[0];
1165     inpoint[nrvous].x[1] = lines_rvous[i].p1[1];
1166     inpoint[nrvous].which = 1;
1167     nrvous++;
1168     proclist[nrvous] = hashlittle(lines_rvous[i].p2,2*sizeof(double),0) % nprocs;
1169     inpoint[nrvous].x[0] = lines_rvous[i].p2[0];
1170     inpoint[nrvous].x[1] = lines_rvous[i].p2[1];
1171     inpoint[nrvous].which = 2;
1172     nrvous++;
1173   }
1174 
1175   // perform rendezvous operation
1176   // each proc assigned subset of points
1177   // receives all copies of points, checks if count of each point is valid
1178 
1179   char *buf;
1180   int nout = comm->rendezvous(1,nrvous,(char *) inpoint,sizeof(InRvousPoint),
1181 			      0,proclist,rendezvous_watertight_2d,
1182 			      0,buf,0,(void *) this);
1183 
1184   memory->destroy(proclist);
1185   memory->destroy(inpoint);
1186 }
1187 
1188 /* ----------------------------------------------------------------------
1189    callback from rendezvous operation
1190    process points assigned to me
1191    inbuf = list of N Inbuf datums
1192    no outbuf
1193 ------------------------------------------------------------------------- */
1194 
rendezvous_watertight_2d(int n,char * inbuf,int & flag,int * & proclist,char * & outbuf,void * ptr)1195 int Surf::rendezvous_watertight_2d(int n, char *inbuf, int &flag, int *&proclist,
1196                                    char *&outbuf, void *ptr)
1197 {
1198   Surf *sptr = (Surf *) ptr;
1199   Domain *domain = sptr->domain;
1200   Error *error = sptr->error;
1201   MPI_Comm world = sptr->world;
1202 
1203   Surf::InRvousPoint *inpoint = (Surf::InRvousPoint *) inbuf;
1204 
1205   // hash all received end points
1206   // key = end point
1207   // value = 1 if first point, 2 if second point, 3 if both points
1208 
1209   Surf::MyHashPoint phash;
1210   Surf::MyPointIt it;
1211 
1212   // insert each point into hash
1213   // should appear once at each end of a line
1214   // error if any duplicate points
1215 
1216   Surf::OnePoint2d key;
1217   int which,value;
1218 
1219   int ndup = 0;
1220   for (int i = 0; i < n; i++) {
1221     key.pt[0] = inpoint[i].x[0]; key.pt[1] = inpoint[i].x[1];
1222     which = inpoint[i].which;
1223     if (phash.find(key) == phash.end()) phash[key] = which;
1224     else {
1225       value = phash[key];
1226       if (value == 3) ndup++;    // point already seen twice
1227       else if (value != which) phash[key] = 3;   // this is other point
1228       else ndup++;               // value = which, this is duplicate point
1229     }
1230   }
1231 
1232   int alldup;
1233   MPI_Allreduce(&ndup,&alldup,1,MPI_INT,MPI_SUM,world);
1234   if (alldup) {
1235     char str[128];
1236     sprintf(str,"Watertight check failed with %d duplicate points",alldup);
1237     error->all(FLERR,str);
1238   }
1239 
1240   // check that each end point has a match (value = 3)
1241   // allow for exception if end point on box surface
1242 
1243   double *boxlo = domain->boxlo;
1244   double *boxhi = domain->boxhi;
1245   double *kpt;
1246   double pt[3];
1247 
1248   int nbad = 0;
1249   for (it = phash.begin(); it != phash.end(); ++it) {
1250     if (it->second != 3) {
1251       kpt = (double *) it->first.pt;
1252       pt[0] = kpt[0]; pt[1] = kpt[1]; pt[2] = 0.0;
1253       if (!Geometry::point_on_hex(pt,boxlo,boxhi)) nbad++;
1254     }
1255   }
1256 
1257   int allbad;
1258   MPI_Allreduce(&nbad,&allbad,1,MPI_INT,MPI_SUM,world);
1259   if (nbad) {
1260     char str[128];
1261     sprintf(str,"Watertight check failed with %d unmatched points",allbad);
1262     error->all(FLERR,str);
1263   }
1264 
1265   // flag = 0: no second comm needed in rendezvous
1266 
1267   flag = 0;
1268   return 0;
1269 }
1270 
1271 /* ----------------------------------------------------------------------
1272    check if 3d surf elements are watertight
1273    each edge should appear exactly once in each direction
1274    exception: not required of triangle edge on simulation box surface
1275 ------------------------------------------------------------------------- */
1276 
check_watertight_3d()1277 void Surf::check_watertight_3d()
1278 {
1279   if (distributed) check_watertight_3d_distributed();
1280   else check_watertight_3d_all();
1281 }
1282 
1283 /* ----------------------------------------------------------------------
1284    check if 3d surf elements are watertight
1285    this is for explicit non-distributed surfs where each proc has copy of all
1286    each proc tests the entire surface, no communication needed
1287 ------------------------------------------------------------------------- */
1288 
check_watertight_3d_all()1289 void Surf::check_watertight_3d_all()
1290 {
1291   // hash directed edges of all triangles
1292   // key = directed edge
1293   // value = 1 if appears once, 2 if reverse also appears once
1294 
1295   MyHash2Point phash;
1296   My2PointIt it;
1297 
1298   // insert each edge into hash
1299   // should appear once in each direction
1300   // error if any duplicate edges
1301 
1302   double *p1,*p2,*p3;
1303   TwoPoint3d key,keyinv;
1304   int value;
1305 
1306   int ndup = 0;
1307   for (int i = 0; i < nsurf; i++) {
1308     if (tris[i].transparent) continue;
1309     p1 = tris[i].p1;
1310     p2 = tris[i].p2;
1311     p3 = tris[i].p3;
1312 
1313     key.pts[0] = p1[0]; key.pts[1] = p1[1]; key.pts[2] = p1[2];
1314     key.pts[3] = p2[0]; key.pts[4] = p2[1]; key.pts[5] = p2[2];
1315     if (phash.find(key) == phash.end()) {
1316       keyinv.pts[0] = p2[0]; keyinv.pts[1] = p2[1]; keyinv.pts[2] = p2[2];
1317       keyinv.pts[3] = p1[0]; keyinv.pts[4] = p1[1]; keyinv.pts[5] = p1[2];
1318       if (phash.find(keyinv) == phash.end()) phash[key] = 1;
1319       else {
1320 	value = phash[keyinv];
1321 	if (value == 1) phash[keyinv] = 2;
1322 	else ndup++;
1323       }
1324     } else ndup++;
1325 
1326     key.pts[0] = p2[0]; key.pts[1] = p2[1]; key.pts[2] = p2[2];
1327     key.pts[3] = p3[0]; key.pts[4] = p3[1]; key.pts[5] = p3[2];
1328     if (phash.find(key) == phash.end()) {
1329       keyinv.pts[0] = p3[0]; keyinv.pts[1] = p3[1]; keyinv.pts[2] = p3[2];
1330       keyinv.pts[3] = p2[0]; keyinv.pts[4] = p2[1]; keyinv.pts[5] = p2[2];
1331       if (phash.find(keyinv) == phash.end()) phash[key] = 1;
1332       else {
1333 	value = phash[keyinv];
1334 	if (value == 1) phash[keyinv] = 2;
1335 	else ndup++;
1336       }
1337     } else ndup++;
1338 
1339     key.pts[0] = p3[0]; key.pts[1] = p3[1]; key.pts[2] = p3[2];
1340     key.pts[3] = p1[0]; key.pts[4] = p1[1]; key.pts[5] = p1[2];
1341     if (phash.find(key) == phash.end()) {
1342       keyinv.pts[0] = p1[0]; keyinv.pts[1] = p1[1]; keyinv.pts[2] = p1[2];
1343       keyinv.pts[3] = p3[0]; keyinv.pts[4] = p3[1]; keyinv.pts[5] = p3[2];
1344       if (phash.find(keyinv) == phash.end()) phash[key] = 1;
1345       else {
1346 	value = phash[keyinv];
1347 	if (value == 1) phash[keyinv] = 2;
1348 	else ndup++;
1349       }
1350     } else ndup++;
1351   }
1352 
1353   if (ndup) {
1354     char str[128];
1355     sprintf(str,"Watertight check failed with %d duplicate edges",ndup);
1356     error->all(FLERR,str);
1357   }
1358 
1359   // check that each edge has an inverted match
1360   // allow for exception if edge is on box face
1361 
1362   double *boxlo = domain->boxlo;
1363   double *boxhi = domain->boxhi;
1364   double *pts;
1365 
1366   int nbad = 0;
1367   for (it = phash.begin(); it != phash.end(); ++it) {
1368     if (it->second != 2) {
1369       pts = (double *) it->first.pts;
1370       if (Geometry::edge_on_hex_face(&pts[0],&pts[3],boxlo,boxhi) < 0) nbad++;
1371     }
1372   }
1373 
1374   if (nbad) {
1375     char str[128];
1376     sprintf(str,"Watertight check failed with %d unmatched edges",nbad);
1377     error->all(FLERR,str);
1378   }
1379 }
1380 
1381 /* ----------------------------------------------------------------------
1382    check if 3d surf elements are watertight
1383    this is for explicit distributed surfs
1384    rendezvous communication used to check that each edge appears twice
1385 ------------------------------------------------------------------------- */
1386 
check_watertight_3d_distributed()1387 void Surf::check_watertight_3d_distributed()
1388 {
1389   int n;
1390   Tri *tris_rvous;
1391 
1392   if (implicit) {
1393     n = nlocal;
1394     tris_rvous = tris;
1395   } else {
1396     n = nown;
1397     tris_rvous = mytris;
1398   }
1399 
1400   // allocate memory for rvous input
1401 
1402   int *proclist;
1403   memory->create(proclist,n*6,"surf:proclist");
1404   InRvousEdge *inedge =
1405     (InRvousEdge *) memory->smalloc((bigint) n*6*sizeof(InRvousEdge),
1406                                      "surf:inedge");
1407 
1408   // create rvous inputs
1409   // proclist = owner of each point
1410   // each triangle edge is sent twice with flag indicating
1411   //   forward or reverse order
1412   // hash of edge coords (xyz for 2 pts) determines which proc to send to
1413 
1414   double edge[6];
1415   double *p1,*p2,*p3;
1416 
1417   int nbytes = 3*sizeof(double);
1418 
1419   int nrvous = 0;
1420   for (int i = 0; i < n; i++) {
1421     p1 = tris_rvous[i].p1;
1422     p2 = tris_rvous[i].p2;
1423     p3 = tris_rvous[i].p3;
1424 
1425     memcpy(&edge[0],p1,nbytes);
1426     memcpy(&edge[3],p2,nbytes);
1427     proclist[nrvous] = hashlittle(edge,2*nbytes,0) % nprocs;
1428     memcpy(inedge[nrvous].x1,p1,nbytes);
1429     memcpy(inedge[nrvous].x2,p2,nbytes);
1430     inedge[nrvous].which = 1;
1431     nrvous++;
1432 
1433     memcpy(&edge[0],p2,nbytes);
1434     memcpy(&edge[3],p1,nbytes);
1435     proclist[nrvous] = hashlittle(edge,2*nbytes,0) % nprocs;
1436     memcpy(inedge[nrvous].x1,p2,nbytes);
1437     memcpy(inedge[nrvous].x2,p1,nbytes);
1438     inedge[nrvous].which = 2;
1439     nrvous++;
1440 
1441     memcpy(&edge[0],p2,nbytes);
1442     memcpy(&edge[3],p3,nbytes);
1443     proclist[nrvous] = hashlittle(edge,2*nbytes,0) % nprocs;
1444     memcpy(inedge[nrvous].x1,p2,nbytes);
1445     memcpy(inedge[nrvous].x2,p3,nbytes);
1446     inedge[nrvous].which = 1;
1447     nrvous++;
1448 
1449     memcpy(&edge[0],p3,nbytes);
1450     memcpy(&edge[3],p2,nbytes);
1451     proclist[nrvous] = hashlittle(edge,2*nbytes,0) % nprocs;
1452     memcpy(inedge[nrvous].x1,p3,nbytes);
1453     memcpy(inedge[nrvous].x2,p2,nbytes);
1454     inedge[nrvous].which = 2;
1455     nrvous++;
1456 
1457     memcpy(&edge[0],p3,nbytes);
1458     memcpy(&edge[3],p1,nbytes);
1459     proclist[nrvous] = hashlittle(edge,2*nbytes,0) % nprocs;
1460     memcpy(inedge[nrvous].x1,p3,nbytes);
1461     memcpy(inedge[nrvous].x2,p1,nbytes);
1462     inedge[nrvous].which = 1;
1463     nrvous++;
1464 
1465     memcpy(&edge[0],p1,nbytes);
1466     memcpy(&edge[3],p3,nbytes);
1467     proclist[nrvous] = hashlittle(edge,2*nbytes,0) % nprocs;
1468     memcpy(inedge[nrvous].x1,p1,nbytes);
1469     memcpy(inedge[nrvous].x2,p3,nbytes);
1470     inedge[nrvous].which = 2;
1471     nrvous++;
1472   }
1473 
1474   // perform rendezvous operation
1475   // each proc assigned subset of edges
1476   // receives all copies of edges, checks if count of each edge is valid
1477 
1478   char *buf;
1479   int nout = comm->rendezvous(1,nrvous,(char *) inedge,sizeof(InRvousEdge),
1480 			      0,proclist,rendezvous_watertight_3d,
1481 			      0,buf,0,(void *) this);
1482 
1483   memory->destroy(proclist);
1484   memory->destroy(inedge);
1485 }
1486 
1487 /* ----------------------------------------------------------------------
1488    callback from rendezvous operation
1489    process points assigned to me
1490    inbuf = list of N Inbuf datums
1491    no outbuf
1492 ------------------------------------------------------------------------- */
1493 
rendezvous_watertight_3d(int n,char * inbuf,int & flag,int * & proclist,char * & outbuf,void * ptr)1494 int Surf::rendezvous_watertight_3d(int n, char *inbuf, int &flag, int *&proclist,
1495                                    char *&outbuf, void *ptr)
1496 {
1497   Surf *sptr = (Surf *) ptr;
1498   Domain *domain = sptr->domain;
1499   Error *error = sptr->error;
1500   MPI_Comm world = sptr->world;
1501 
1502   Surf::InRvousEdge *inedge = (Surf::InRvousEdge *) inbuf;
1503 
1504   // hash all received end points
1505   // key = end point
1506   // value = 1 if first point, 2 if second point, 3 if both points
1507 
1508   Surf::MyHash2Point phash;
1509   Surf::My2PointIt it;
1510 
1511   // insert each edge into hash
1512   // should appear once in each direction
1513   // error if any duplicate edges
1514 
1515   Surf::TwoPoint3d key;
1516   double *x1,*x2;
1517   int which,value;
1518 
1519   int ndup = 0;
1520   for (int i = 0; i < n; i++) {
1521     x1 = inedge[i].x1; x2 = inedge[i].x2;
1522     key.pts[0] = x1[0]; key.pts[1] = x1[1]; key.pts[2] = x1[2];
1523     key.pts[3] = x2[0]; key.pts[4] = x2[1]; key.pts[5] = x2[2];
1524     which = inedge[i].which;
1525     if (phash.find(key) == phash.end()) phash[key] = which;
1526     else {
1527       value = phash[key];
1528       if (value == 3) ndup++;    // edge already seen twice
1529       else if (value != which) phash[key] = 3;   // this is flipped edge
1530       else ndup++;               // value = which, this is duplicate edge
1531     }
1532   }
1533 
1534   int alldup;
1535   MPI_Allreduce(&ndup,&alldup,1,MPI_INT,MPI_SUM,world);
1536   alldup /= 2;              // avoid double counting
1537   if (alldup) {
1538     char str[128];
1539     sprintf(str,"Watertight check failed with %d duplicate edges",alldup);
1540     error->all(FLERR,str);
1541   }
1542 
1543   // check that each edge has an inverted match(value = 3)
1544   // allow for exception if edge is on box face
1545 
1546   double *boxlo = domain->boxlo;
1547   double *boxhi = domain->boxhi;
1548   double *pts;
1549 
1550   int nbad = 0;
1551   for (it = phash.begin(); it != phash.end(); ++it) {
1552     if (it->second != 3) {
1553       pts = (double *) it->first.pts;
1554       if (Geometry::edge_on_hex_face(&pts[0],&pts[3],boxlo,boxhi) < 0) nbad++;
1555     }
1556   }
1557 
1558   int allbad;
1559   MPI_Allreduce(&nbad,&allbad,1,MPI_INT,MPI_SUM,world);
1560   allbad /= 2;              // avoid double counting
1561   if (nbad) {
1562     char str[128];
1563     sprintf(str,"Watertight check failed with %d unmatched edges",allbad);
1564     error->all(FLERR,str);
1565   }
1566 
1567   // flag = 0: no second comm needed in rendezvous
1568 
1569   flag = 0;
1570   return 0;
1571 }
1572 
1573 /* ----------------------------------------------------------------------
1574    check if all points are inside or on surface of global simulation box
1575    called by ReadSurf for lines or triangles
1576    old = previous # of elements
1577 ------------------------------------------------------------------------- */
1578 
check_point_inside(int old)1579 void Surf::check_point_inside(int old)
1580 {
1581   int nbad;
1582   double *x;
1583 
1584   int dim = domain->dimension;
1585   double *boxlo = domain->boxlo;
1586   double *boxhi = domain->boxhi;
1587 
1588   if (dim == 2) {
1589     Line *newlines;
1590     int n;
1591     if (distributed) {
1592       newlines = mylines;
1593       n = nown;
1594     } else {
1595       newlines = lines;
1596       n = nlocal;
1597     }
1598 
1599     nbad = 0;
1600     for (int i = old; i < n; i++) {
1601       x = newlines[i].p1;
1602       if (x[0] < boxlo[0] || x[0] > boxhi[0] ||
1603 	  x[1] < boxlo[1] || x[1] > boxhi[1] ||
1604 	  x[2] < boxlo[2] || x[2] > boxhi[2]) nbad++;
1605       x = newlines[i].p2;
1606       if (x[0] < boxlo[0] || x[0] > boxhi[0] ||
1607 	  x[1] < boxlo[1] || x[1] > boxhi[1] ||
1608 	  x[2] < boxlo[2] || x[2] > boxhi[2]) nbad++;
1609     }
1610 
1611   } else if (dim == 3) {
1612     Tri *newtris;
1613     int n;
1614     if (distributed) {
1615       newtris = mytris;
1616       n = nown;
1617     } else {
1618       newtris = tris;
1619       n = nlocal;
1620     }
1621 
1622     nbad = 0;
1623     for (int i = old; i < n; i++) {
1624       x = newtris[i].p1;
1625       if (x[0] < boxlo[0] || x[0] > boxhi[0] ||
1626 	  x[1] < boxlo[1] || x[1] > boxhi[1] ||
1627 	  x[2] < boxlo[2] || x[2] > boxhi[2]) nbad++;
1628       x = newtris[i].p2;
1629       if (x[0] < boxlo[0] || x[0] > boxhi[0] ||
1630 	  x[1] < boxlo[1] || x[1] > boxhi[1] ||
1631 	  x[2] < boxlo[2] || x[2] > boxhi[2]) nbad++;
1632       x = newtris[i].p3;
1633       if (x[0] < boxlo[0] || x[0] > boxhi[0] ||
1634 	  x[1] < boxlo[1] || x[1] > boxhi[1] ||
1635 	  x[2] < boxlo[2] || x[2] > boxhi[2]) nbad++;
1636     }
1637   }
1638 
1639   int nbadall;
1640   if (distributed) MPI_Allreduce(&nbad,&nbadall,1,MPI_INT,MPI_SUM,world);
1641   else nbadall = nbad;
1642 
1643   if (nbadall) {
1644     char str[128];
1645     sprintf(str,"%d surface points are not inside simulation box",
1646 	    nbadall);
1647     error->all(FLERR,str);
1648   }
1649 }
1650 
1651 /* ----------------------------------------------------------------------
1652    check nearness of all points to other lines in same cell
1653    error if point is on line, including duplicate point
1654    warn if closer than EPSILON_GRID = fraction of grid cell size
1655    NOTE: this can miss a close point/line pair in 2 different grid cells
1656 ------------------------------------------------------------------------- */
1657 
check_point_near_surf_2d()1658 void Surf::check_point_near_surf_2d()
1659 {
1660   int i,j,n;
1661   surfint *csurfs;
1662   double side,epssq;
1663   double *p1,*p2,*lo,*hi;
1664   Surf::Line *line;
1665 
1666   Surf::Line *lines = surf->lines;
1667   Grid::ChildCell *cells = grid->cells;
1668   int nglocal = grid->nlocal;
1669 
1670   int nerror = 0;
1671   int nwarn = 0;
1672 
1673   for (int icell = 0; icell < nglocal; icell++) {
1674     if (cells[icell].nsplit <= 0) continue;
1675     n = cells[icell].nsurf;
1676     if (n == 0) continue;
1677 
1678     lo = cells[icell].lo;
1679     hi = cells[icell].hi;
1680     side = MIN(hi[0]-lo[0],hi[1]-lo[1]);
1681     epssq = (EPSILON_GRID*side) * (EPSILON_GRID*side);
1682 
1683     csurfs = cells[icell].csurfs;
1684     for (i = 0; i < n; i++) {
1685       line = &lines[csurfs[i]];
1686       // skip transparent surf elements
1687       if (line->transparent) continue;
1688       for (j = 0; j < n; j++) {
1689         if (i == j) continue;
1690         p1 = lines[csurfs[j]].p1;
1691         p2 = lines[csurfs[j]].p2;
1692         point_line_compare(p1,line->p1,line->p2,epssq,nerror,nwarn);
1693         point_line_compare(p2,line->p1,line->p2,epssq,nerror,nwarn);
1694       }
1695     }
1696   }
1697 
1698   int all;
1699   MPI_Allreduce(&nerror,&all,1,MPI_INT,MPI_SUM,world);
1700   if (all) {
1701     char str[128];
1702     sprintf(str,"Surface check failed with %d points on lines",all);
1703     error->all(FLERR,str);
1704   }
1705 
1706   MPI_Allreduce(&nwarn,&all,1,MPI_INT,MPI_SUM,world);
1707   if (all) {
1708     char str[128];
1709     sprintf(str,"Surface check found %d points nearly on lines",all);
1710     if (comm->me == 0) error->warning(FLERR,str);
1711   }
1712 }
1713 
1714 /* ----------------------------------------------------------------------
1715    check nearness of all points to other triangles in same cell
1716    error if point is on triangle, including duplicate point
1717    warn if closer than EPSILON_GRID = fraction of grid cell size
1718    NOTE: this can miss a close point/triangle pair in 2 different grid cells
1719 ------------------------------------------------------------------------- */
1720 
check_point_near_surf_3d()1721 void Surf::check_point_near_surf_3d()
1722 {
1723   int i,j,n;
1724   surfint *csurfs;
1725   double side,epssq;
1726   double *p1,*p2,*p3,*lo,*hi;
1727   Surf::Tri *tri;
1728 
1729   Surf::Tri *tris = surf->tris;
1730   Grid::ChildCell *cells = grid->cells;
1731   int nglocal = grid->nlocal;
1732 
1733   int nerror = 0;
1734   int nwarn = 0;
1735 
1736   for (int icell = 0; icell < nglocal; icell++) {
1737     if (cells[icell].nsplit <= 0) continue;
1738     n = cells[icell].nsurf;
1739     if (n == 0) continue;
1740 
1741     lo = cells[icell].lo;
1742     hi = cells[icell].hi;
1743     side = MIN(hi[0]-lo[0],hi[1]-lo[1]);
1744     side = MIN(side,hi[2]-lo[2]);
1745     epssq = (EPSILON_GRID*side) * (EPSILON_GRID*side);
1746 
1747     csurfs = cells[icell].csurfs;
1748     for (i = 0; i < n; i++) {
1749       tri = &tris[csurfs[i]];
1750       // skip transparent surf elements
1751       if (tri->transparent) continue;
1752       for (j = 0; j < n; j++) {
1753         if (i == j) continue;
1754         p1 = tris[csurfs[j]].p1;
1755         p2 = tris[csurfs[j]].p2;
1756         p3 = tris[csurfs[j]].p3;
1757         point_tri_compare(p1,tri->p1,tri->p2,tri->p3,tri->norm,
1758                           epssq,nerror,nwarn,icell,csurfs[i],csurfs[j]);
1759         point_tri_compare(p2,tri->p1,tri->p2,tri->p3,tri->norm,
1760                           epssq,nerror,nwarn,icell,csurfs[i],csurfs[j]);
1761         point_tri_compare(p3,tri->p1,tri->p2,tri->p3,tri->norm,
1762                           epssq,nerror,nwarn,icell,csurfs[i],csurfs[j]);
1763       }
1764     }
1765   }
1766 
1767   int all;
1768   MPI_Allreduce(&nerror,&all,1,MPI_INT,MPI_SUM,world);
1769   if (all) {
1770     char str[128];
1771     sprintf(str,"Surface check failed with %d points on triangles",all);
1772     error->all(FLERR,str);
1773   }
1774 
1775   MPI_Allreduce(&nwarn,&all,1,MPI_INT,MPI_SUM,world);
1776   if (all) {
1777     char str[128];
1778     sprintf(str,"Surface check found %d points nearly on triangles",all);
1779     if (comm->me == 0) error->warning(FLERR,str);
1780   }
1781 }
1782 
1783 /* ----------------------------------------------------------------------
1784    compute extent of read-in surfs, including geometric transformations
1785 ------------------------------------------------------------------------- */
1786 
output_extent(int old)1787 void Surf::output_extent(int old)
1788 {
1789   // extent of surfs after geometric transformations
1790   // compute sizes of smallest surface elements
1791 
1792   double extent[3][2],extentall[3][2];
1793   extent[0][0] = extent[1][0] = extent[2][0] = BIG;
1794   extent[0][1] = extent[1][1] = extent[2][1] = -BIG;
1795 
1796   int dim = domain->dimension;
1797 
1798   if (dim == 2) {
1799     Line *newlines;
1800     int n;
1801     if (!implicit && distributed) {
1802       newlines = mylines;
1803       n = nown;
1804     } else {
1805       newlines = lines;
1806       n = nlocal;
1807     }
1808 
1809     for (int i = old; i < n; i++) {
1810       for (int j = 0; j < 3; j++) {
1811         extent[j][0] = MIN(extent[j][0],newlines[i].p1[j]);
1812         extent[j][0] = MIN(extent[j][0],newlines[i].p2[j]);
1813         extent[j][1] = MAX(extent[j][1],newlines[i].p1[j]);
1814         extent[j][1] = MAX(extent[j][1],newlines[i].p2[j]);
1815       }
1816     }
1817 
1818   } else {
1819     Tri *newtris;
1820     int n;
1821     if (!implicit && distributed) {
1822       newtris = mytris;
1823       n = nown;
1824     } else {
1825       newtris = tris;
1826       n = nlocal;
1827     }
1828 
1829     for (int i = old; i < n; i++) {
1830       for (int j = 0; j < 3; j++) {
1831         extent[j][0] = MIN(extent[j][0],newtris[i].p1[j]);
1832         extent[j][0] = MIN(extent[j][0],newtris[i].p2[j]);
1833         extent[j][0] = MIN(extent[j][0],newtris[i].p3[j]);
1834         extent[j][1] = MAX(extent[j][1],newtris[i].p1[j]);
1835         extent[j][1] = MAX(extent[j][1],newtris[i].p2[j]);
1836         extent[j][1] = MAX(extent[j][1],newtris[i].p3[j]);
1837       }
1838     }
1839   }
1840 
1841   extent[0][0] = -extent[0][0];
1842   extent[1][0] = -extent[1][0];
1843   extent[2][0] = -extent[2][0];
1844   MPI_Allreduce(extent,extentall,6,MPI_DOUBLE,MPI_MAX,world);
1845   extentall[0][0] = -extentall[0][0];
1846   extentall[1][0] = -extentall[1][0];
1847   extentall[2][0] = -extentall[2][0];
1848 
1849   double minlen,minarea;
1850   if (dim == 2) minlen = shortest_line(old);
1851   if (dim == 3) smallest_tri(old,minlen,minarea);
1852 
1853   if (comm->me == 0) {
1854     if (screen) {
1855       fprintf(screen,"  %g %g xlo xhi\n",extentall[0][0],extentall[0][1]);
1856       fprintf(screen,"  %g %g ylo yhi\n",extentall[1][0],extentall[1][1]);
1857       fprintf(screen,"  %g %g zlo zhi\n",extentall[2][0],extentall[2][1]);
1858       if (dim == 2)
1859 	fprintf(screen,"  %g min line length\n",minlen);
1860       if (dim == 3) {
1861 	fprintf(screen,"  %g min triangle edge length\n",minlen);
1862 	fprintf(screen,"  %g min triangle area\n",minarea);
1863       }
1864     }
1865     if (logfile) {
1866       fprintf(logfile,"  %g %g xlo xhi\n",extentall[0][0],extentall[0][1]);
1867       fprintf(logfile,"  %g %g ylo yhi\n",extentall[1][0],extentall[1][1]);
1868       fprintf(logfile,"  %g %g zlo zhi\n",extentall[2][0],extentall[2][1]);
1869       if (dim == 2)
1870 	fprintf(logfile,"  %g min line length\n",minlen);
1871       if (dim == 3) {
1872 	fprintf(logfile,"  %g min triangle edge length\n",minlen);
1873 	fprintf(logfile,"  %g min triangle area\n",minarea);
1874       }
1875     }
1876   }
1877 }
1878 
1879 /* ----------------------------------------------------------------------
1880    return shortest line length
1881 ------------------------------------------------------------------------- */
1882 
shortest_line(int old)1883 double Surf::shortest_line(int old)
1884 {
1885   double len = BIG;
1886 
1887   if (!implicit && distributed) {
1888     for (int i = old; i < nown; i++)
1889       len = MIN(len,line_size(&mylines[i]));
1890   } else {
1891     for (int i = old; i < nlocal; i++)
1892       len = MIN(len,line_size(&lines[i]));
1893   }
1894 
1895   double lenall;
1896   MPI_Allreduce(&len,&lenall,1,MPI_DOUBLE,MPI_MIN,world);
1897 
1898   return lenall;
1899 }
1900 
1901 /* ----------------------------------------------------------------------
1902    return shortest tri edge and smallest tri area
1903 ------------------------------------------------------------------------- */
1904 
smallest_tri(int old,double & lenall,double & areaall)1905 void Surf::smallest_tri(int old, double &lenall, double &areaall)
1906 {
1907   double lenone,areaone;
1908   double len = BIG;
1909   double area = BIG;
1910 
1911   if (!implicit && distributed) {
1912     for (int i = old; i < nown; i++) {
1913       areaone = tri_size(&mytris[i],lenone);
1914       len = MIN(len,lenone);
1915       area = MIN(area,areaone);
1916     }
1917   } else {
1918     for (int i = old; i < nlocal; i++) {
1919       areaone = tri_size(&tris[i],lenone);
1920       len = MIN(len,lenone);
1921       area = MIN(area,areaone);
1922     }
1923   }
1924 
1925   MPI_Allreduce(&len,&lenall,1,MPI_DOUBLE,MPI_MIN,world);
1926   MPI_Allreduce(&area,&areaall,1,MPI_DOUBLE,MPI_MIN,world);
1927 }
1928 
1929 /* ----------------------------------------------------------------------
1930    compute distance bewteen a point and line
1931    just return if point is an endpoint of line
1932    increment nerror if point on line
1933    increment nwarn if point is within epssq distance of line
1934 ------------------------------------------------------------------------- */
1935 
point_line_compare(double * pt,double * p1,double * p2,double epssq,int & nerror,int & nwarn)1936 void Surf::point_line_compare(double *pt, double *p1, double *p2,
1937                               double epssq, int &nerror, int &nwarn)
1938 {
1939   if (pt[0] == p1[0] && pt[1] == p1[1]) return;
1940   if (pt[0] == p2[0] && pt[1] == p2[1]) return;
1941   double rsq = Geometry::distsq_point_line(pt,p1,p2);
1942   if (rsq == 0.0) nerror++;
1943   else if (rsq < epssq) nwarn++;
1944 }
1945 
1946 /* ----------------------------------------------------------------------
1947    compute distance bewteen a point and triangle
1948    just return if point is an endpoint of triangle
1949    increment nerror if point on triangle
1950    increment nwarn if point is within epssq distance of triangle
1951 ------------------------------------------------------------------------- */
1952 
point_tri_compare(double * pt,double * p1,double * p2,double * p3,double * norm,double epssq,int & nerror,int & nwarn,int,int,int)1953 void Surf::point_tri_compare(double *pt, double *p1, double *p2, double *p3,
1954                              double *norm, double epssq, int &nerror, int &nwarn,
1955                              int, int, int)
1956 {
1957   if (pt[0] == p1[0] && pt[1] == p1[1] && pt[2] == p1[2]) return;
1958   if (pt[0] == p2[0] && pt[1] == p2[1] && pt[2] == p2[2]) return;
1959   if (pt[0] == p3[0] && pt[1] == p3[1] && pt[2] == p3[2]) return;
1960   double rsq = Geometry::distsq_point_tri(pt,p1,p2,p3,norm);
1961   if (rsq == 0.0) nerror++;
1962   else if (rsq < epssq) nwarn++;
1963 }
1964 
1965 
1966 /* ----------------------------------------------------------------------
1967    add a surface collision model
1968 ------------------------------------------------------------------------- */
1969 
add_collide(int narg,char ** arg)1970 void Surf::add_collide(int narg, char **arg)
1971 {
1972   if (narg < 2) error->all(FLERR,"Illegal surf_collide command");
1973 
1974   // error check
1975 
1976   for (int i = 0; i < nsc; i++)
1977     if (strcmp(arg[0],sc[i]->id) == 0)
1978       error->all(FLERR,"Reuse of surf_collide ID");
1979 
1980   // extend SurfCollide list if necessary
1981 
1982   if (nsc == maxsc) {
1983     maxsc += DELTAMODEL;
1984     sc = (SurfCollide **)
1985       memory->srealloc(sc,maxsc*sizeof(SurfCollide *),"surf:sc");
1986   }
1987 
1988   // create new SurfCollide class
1989 
1990   if (sparta->suffix_enable) {
1991     if (sparta->suffix) {
1992       char estyle[256];
1993       sprintf(estyle,"%s/%s",arg[1],sparta->suffix);
1994 
1995       if (0) return;
1996 
1997 #define SURF_COLLIDE_CLASS
1998 #define SurfCollideStyle(key,Class) \
1999       else if (strcmp(estyle,#key) == 0) { \
2000         sc[nsc] = new Class(sparta,narg,arg); \
2001         nsc++; \
2002         return; \
2003       }
2004 #include "style_surf_collide.h"
2005 #undef SurfCollideStyle
2006 #undef SURF_COLLIDE_CLASS
2007     }
2008   }
2009 
2010   if (0) return;
2011 
2012 #define SURF_COLLIDE_CLASS
2013 #define SurfCollideStyle(key,Class) \
2014   else if (strcmp(arg[1],#key) == 0) \
2015     sc[nsc] = new Class(sparta,narg,arg);
2016 #include "style_surf_collide.h"
2017 #undef SurfCollideStyle
2018 #undef SURF_COLLIDE_CLASS
2019 
2020   else error->all(FLERR,"Unrecognized surf_collide style");
2021 
2022   nsc++;
2023 }
2024 
2025 /* ----------------------------------------------------------------------
2026    find a surface collide model by ID
2027    return index of surf collide model or -1 if not found
2028 ------------------------------------------------------------------------- */
2029 
find_collide(const char * id)2030 int Surf::find_collide(const char *id)
2031 {
2032   int isc;
2033   for (isc = 0; isc < nsc; isc++)
2034     if (strcmp(id,sc[isc]->id) == 0) break;
2035   if (isc == nsc) return -1;
2036   return isc;
2037 }
2038 
2039 /* ----------------------------------------------------------------------
2040    add a surface reaction model
2041 ------------------------------------------------------------------------- */
2042 
add_react(int narg,char ** arg)2043 void Surf::add_react(int narg, char **arg)
2044 {
2045   if (narg < 2) error->all(FLERR,"Illegal surf_react command");
2046 
2047   // error check
2048 
2049   for (int i = 0; i < nsr; i++)
2050     if (strcmp(arg[0],sr[i]->id) == 0)
2051       error->all(FLERR,"Reuse of surf_react ID");
2052 
2053   // extend SurfReact list if necessary
2054 
2055   if (nsr == maxsr) {
2056     maxsr += DELTAMODEL;
2057     sr = (SurfReact **)
2058       memory->srealloc(sr,maxsr*sizeof(SurfReact *),"surf:sr");
2059   }
2060 
2061   // create new SurfReact class
2062 
2063   if (0) return;
2064 
2065 #define SURF_REACT_CLASS
2066 #define SurfReactStyle(key,Class) \
2067   else if (strcmp(arg[1],#key) == 0) \
2068     sr[nsr] = new Class(sparta,narg,arg);
2069 #include "style_surf_react.h"
2070 #undef SurfReactStyle
2071 #undef SURF_REACT_CLASS
2072 
2073   else error->all(FLERR,"Unrecognized surf_react style");
2074 
2075   nsr++;
2076 }
2077 
2078 /* ----------------------------------------------------------------------
2079    find a surface reaction model by ID
2080    return index of surf reaction model or -1 if not found
2081 ------------------------------------------------------------------------- */
2082 
find_react(const char * id)2083 int Surf::find_react(const char *id)
2084 {
2085   int isr;
2086   for (isr = 0; isr < nsr; isr++)
2087     if (strcmp(id,sr[isr]->id) == 0) break;
2088   if (isr == nsr) return -1;
2089   return isr;
2090 }
2091 
2092 /* ----------------------------------------------------------------------
2093    group surf command called via input script
2094    NOTE: need to apply this also to mylines and mytris ??
2095 ------------------------------------------------------------------------- */
2096 
group(int narg,char ** arg)2097 void Surf::group(int narg, char **arg)
2098 {
2099   int i,flag;
2100   double x[3];
2101 
2102   if (narg < 3) error->all(FLERR,"Illegal group command");
2103 
2104   int dim = domain->dimension;
2105 
2106   int igroup = find_group(arg[0]);
2107   if (igroup < 0) igroup = add_group(arg[0]);
2108   int bit = bitmask[igroup];
2109 
2110   // style = type or id
2111   // add surf to group if matches types/ids or condition
2112 
2113   if (strcmp(arg[2],"type") == 0 || strcmp(arg[2],"id") == 0) {
2114     if (narg < 4) error->all(FLERR,"Illegal group command");
2115 
2116     int category;
2117     if (strcmp(arg[2],"type") == 0) category = TYPE;
2118     else if (strcmp(arg[2],"id") == 0) category = ID;
2119 
2120     // args = logical condition
2121 
2122     if (narg > 4 &&
2123         (strcmp(arg[3],"<") == 0 || strcmp(arg[3],">") == 0 ||
2124          strcmp(arg[3],"<=") == 0 || strcmp(arg[3],">=") == 0 ||
2125          strcmp(arg[3],"==") == 0 || strcmp(arg[3],"!=") == 0 ||
2126          strcmp(arg[3],"<>") == 0)) {
2127 
2128       int condition = -1;
2129       if (strcmp(arg[3],"<") == 0) condition = LT;
2130       else if (strcmp(arg[3],"<=") == 0) condition = LE;
2131       else if (strcmp(arg[3],">") == 0) condition = GT;
2132       else if (strcmp(arg[3],">=") == 0) condition = GE;
2133       else if (strcmp(arg[3],"==") == 0) condition = EQ;
2134       else if (strcmp(arg[3],"!=") == 0) condition = NEQ;
2135       else if (strcmp(arg[3],"<>") == 0) condition = BETWEEN;
2136       else error->all(FLERR,"Illegal group command");
2137 
2138       int bound1,bound2;
2139       bound1 = input->inumeric(FLERR,arg[4]);
2140       bound2 = -1;
2141 
2142       if (condition == BETWEEN) {
2143         if (narg != 6) error->all(FLERR,"Illegal group command");
2144         bound2 = input->inumeric(FLERR,arg[5]);
2145       } else if (narg != 5) error->all(FLERR,"Illegal group command");
2146 
2147       // add surf to group if meets condition
2148 
2149       if (category == ID) {
2150         if (condition == LT) {
2151           if (dim == 2) {
2152             for (i = 0; i < nlocal+nghost; i++)
2153               if (lines[i].id < bound1) lines[i].mask |= bit;
2154           } else {
2155             for (i = 0; i < nlocal+nghost; i++)
2156               if (tris[i].id < bound1) tris[i].mask |= bit;
2157           }
2158         } else if (condition == LE) {
2159           if (dim == 2) {
2160             for (i = 0; i < nlocal+nghost; i++)
2161               if (lines[i].id <= bound1) lines[i].mask |= bit;
2162           } else {
2163             for (i = 0; i < nlocal+nghost; i++)
2164               if (tris[i].id <= bound1) tris[i].mask |= bit;
2165           }
2166         } else if (condition == GT) {
2167           if (dim == 2) {
2168             for (i = 0; i < nlocal+nghost; i++)
2169               if (lines[i].id > bound1) lines[i].mask |= bit;
2170           } else {
2171             for (i = 0; i < nlocal+nghost; i++)
2172               if (tris[i].id > bound1) tris[i].mask |= bit;
2173           }
2174         } else if (condition == GE) {
2175           if (dim == 2) {
2176             for (i = 0; i < nlocal+nghost; i++)
2177               if (lines[i].id >= bound1) lines[i].mask |= bit;
2178           } else {
2179             for (i = 0; i < nlocal+nghost; i++)
2180               if (tris[i].id >= bound1) tris[i].mask |= bit;
2181           }
2182         } else if (condition == EQ) {
2183           if (dim == 2) {
2184             for (i = 0; i < nlocal+nghost; i++)
2185               if (lines[i].id == bound1) lines[i].mask |= bit;
2186           } else {
2187             for (i = 0; i < nlocal+nghost; i++)
2188               if (tris[i].id == bound1) tris[i].mask |= bit;
2189           }
2190         } else if (condition == NEQ) {
2191           if (dim == 2) {
2192             for (i = 0; i < nlocal+nghost; i++)
2193               if (lines[i].id != bound1) lines[i].mask |= bit;
2194           } else {
2195             for (i = 0; i < nlocal+nghost; i++)
2196               if (tris[i].id != bound1) tris[i].mask |= bit;
2197           }
2198         } else if (condition == BETWEEN) {
2199           if (dim == 2) {
2200             for (i = 0; i < nlocal+nghost; i++)
2201               if (lines[i].id >= bound1 && lines[i].id <= bound2)
2202                 lines[i].mask |= bit;
2203           } else {
2204             for (i = 0; i < nlocal+nghost; i++)
2205               if (tris[i].id >= bound1 && tris[i].id <= bound2)
2206                 tris[i].mask |= bit;
2207           }
2208         }
2209       } else if (category == TYPE) {
2210         if (condition == LT) {
2211           if (dim == 2) {
2212             for (i = 0; i < nlocal+nghost; i++)
2213               if (lines[i].type < bound1) lines[i].mask |= bit;
2214           } else {
2215             for (i = 0; i < nlocal+nghost; i++)
2216               if (tris[i].type < bound1) lines[i].mask |= bit;
2217           }
2218         } else if (condition == LE) {
2219           if (dim == 2) {
2220             for (i = 0; i < nlocal+nghost; i++)
2221               if (lines[i].type <= bound1) lines[i].mask |= bit;
2222           } else {
2223             for (i = 0; i < nlocal+nghost; i++)
2224               if (tris[i].type <= bound1) lines[i].mask |= bit;
2225           }
2226         } else if (condition == GT) {
2227           if (dim == 2) {
2228             for (i = 0; i < nlocal+nghost; i++)
2229               if (lines[i].type > bound1) lines[i].mask |= bit;
2230           } else {
2231             for (i = 0; i < nlocal+nghost; i++)
2232               if (tris[i].type > bound1) lines[i].mask |= bit;
2233           }
2234         } else if (condition == GE) {
2235           if (dim == 2) {
2236             for (i = 0; i < nlocal+nghost; i++)
2237               if (lines[i].type >= bound1) lines[i].mask |= bit;
2238           } else {
2239             for (i = 0; i < nlocal+nghost; i++)
2240               if (tris[i].type >= bound1) lines[i].mask |= bit;
2241           }
2242         } else if (condition == EQ) {
2243           if (dim == 2) {
2244             for (i = 0; i < nlocal+nghost; i++)
2245               if (lines[i].type == bound1) lines[i].mask |= bit;
2246           } else {
2247             for (i = 0; i < nlocal+nghost; i++)
2248               if (tris[i].type == bound1) lines[i].mask |= bit;
2249           }
2250         } else if (condition == NEQ) {
2251           if (dim == 2) {
2252             for (i = 0; i < nlocal+nghost; i++)
2253               if (lines[i].type != bound1) lines[i].mask |= bit;
2254           } else {
2255             for (i = 0; i < nlocal+nghost; i++)
2256               if (tris[i].type != bound1) lines[i].mask |= bit;
2257           }
2258         } else if (condition == BETWEEN) {
2259           if (dim == 2) {
2260             for (i = 0; i < nlocal+nghost; i++)
2261               if (lines[i].type >= bound1 && lines[i].type <= bound2)
2262                 lines[i].mask |= bit;
2263           } else {
2264             for (i = 0; i < nlocal+nghost; i++)
2265               if (tris[i].type >= bound1 && tris[i].type <= bound2)
2266                 tris[i].mask |= bit;
2267           }
2268         }
2269       }
2270 
2271     // args = list of values
2272 
2273     } else {
2274       char *ptr;
2275       int start,stop;
2276 
2277       for (int iarg = 3; iarg < narg; iarg++) {
2278         if (strchr(arg[iarg],':')) {
2279           ptr = strchr(arg[iarg],':');
2280           *ptr = '\0';
2281           start = input->inumeric(FLERR,arg[iarg]);
2282           *ptr = ':';
2283           stop = input->inumeric(FLERR,ptr+1);
2284         } else {
2285           start = stop = input->inumeric(FLERR,arg[iarg]);
2286         }
2287 
2288         // add surf to group if type/id matches value or sequence
2289 
2290         if (category == ID) {
2291           if (dim == 2) {
2292             for (i = 0; i < nlocal+nghost; i++)
2293               if (lines[i].id >= start && lines[i].id <= stop)
2294                 lines[i].mask |= bit;
2295           } else {
2296             for (i = 0; i < nlocal+nghost; i++)
2297               if (tris[i].id >= start && tris[i].id <= stop)
2298                 tris[i].mask |= bit;
2299           }
2300         } else if (category == TYPE) {
2301           if (dim == 2) {
2302             for (i = 0; i < nlocal+nghost; i++)
2303               if (lines[i].type >= start && lines[i].type <= stop)
2304                 lines[i].mask |= bit;
2305           } else {
2306             for (i = 0; i < nlocal+nghost; i++)
2307               if (tris[i].type >= start && tris[i].type <= stop)
2308                 tris[i].mask |= bit;
2309           }
2310         }
2311       }
2312     }
2313 
2314   // style = region
2315   // add surf to group if in region
2316 
2317   } else if (strcmp(arg[2],"region") == 0) {
2318     if (narg != 5) error->all(FLERR,"Illegal group command");
2319     int iregion = domain->find_region(arg[3]);
2320     if (iregion == -1) error->all(FLERR,"Group region ID does not exist");
2321     Region *region = domain->regions[iregion];
2322 
2323     int rstyle;
2324     if (strcmp(arg[4],"all") == 0) rstyle = REGION_ALL;
2325     else if (strcmp(arg[4],"one") == 0) rstyle = REGION_ONE;
2326     else if (strcmp(arg[4],"center") == 0) rstyle = REGION_CENTER;
2327     else error->all(FLERR,"Illegal group command");
2328 
2329     if (dim == 2) {
2330       if (rstyle == REGION_ALL) {
2331         for (i = 0; i < nlocal+nghost; i++) {
2332           flag = 1;
2333           if (!region->match(lines[i].p1)) flag = 0;
2334           if (!region->match(lines[i].p2)) flag = 0;
2335           if (flag) lines[i].mask |= bit;
2336         }
2337       } else if (rstyle == REGION_ONE) {
2338         for (i = 0; i < nlocal+nghost; i++) {
2339           flag = 0;
2340           if (region->match(lines[i].p1)) flag = 1;
2341           if (region->match(lines[i].p2)) flag = 1;
2342           if (flag) lines[i].mask |= bit;
2343         }
2344       } else if (rstyle == REGION_CENTER) {
2345         for (i = 0; i < nlocal+nghost; i++) {
2346           x[0] = 0.5 * (lines[i].p1[0] + lines[i].p2[0]);
2347           x[1] = 0.5 * (lines[i].p1[1] + lines[i].p2[1]);
2348           x[2] = 0.0;
2349           if (region->match(x)) lines[i].mask |= bit;
2350         }
2351       }
2352 
2353     } else if (dim == 3) {
2354       if (rstyle == REGION_ALL) {
2355         for (i = 0; i < nlocal+nghost; i++) {
2356           flag = 1;
2357           if (!region->match(tris[i].p1)) flag = 0;
2358           if (!region->match(tris[i].p2)) flag = 0;
2359           if (!region->match(tris[i].p3)) flag = 0;
2360           if (flag) tris[i].mask |= bit;
2361         }
2362       } else if (rstyle == REGION_ONE) {
2363         for (i = 0; i < nlocal+nghost; i++) {
2364           flag = 0;
2365           if (region->match(tris[i].p1)) flag = 1;
2366           if (region->match(tris[i].p2)) flag = 1;
2367           if (region->match(tris[i].p3)) flag = 1;
2368           if (flag) tris[i].mask |= bit;
2369         }
2370       } else if (rstyle == REGION_CENTER) {
2371         for (i = 0; i < nlocal+nghost; i++) {
2372           x[0] = (tris[i].p1[0] + tris[i].p2[0] + tris[i].p3[0]) / 3.0;
2373           x[1] = (tris[i].p1[1] + tris[i].p2[1] + tris[i].p3[1]) / 3.0;
2374           x[2] = (tris[i].p1[2] + tris[i].p2[2] + tris[i].p3[2]) / 3.0;
2375           if (region->match(x)) tris[i].mask |= bit;
2376         }
2377       }
2378     }
2379 
2380   // style = subtract
2381 
2382   } else if (strcmp(arg[2],"subtract") == 0) {
2383     if (narg < 5) error->all(FLERR,"Illegal group command");
2384 
2385     int length = narg-3;
2386     int *list = new int[length];
2387 
2388     int jgroup;
2389     for (int iarg = 3; iarg < narg; iarg++) {
2390       jgroup = find_group(arg[iarg]);
2391       if (jgroup == -1) error->all(FLERR,"Group ID does not exist");
2392       list[iarg-3] = jgroup;
2393     }
2394 
2395     // add to group if in 1st group in list
2396 
2397     int otherbit = bitmask[list[0]];
2398 
2399     if (dim == 2) {
2400       for (i = 0; i < nlocal+nghost; i++)
2401         if (lines[i].mask & otherbit) lines[i].mask |= bit;
2402     } else {
2403       for (i = 0; i < nlocal+nghost; i++)
2404         if (tris[i].mask & otherbit) tris[i].mask |= bit;
2405     }
2406 
2407     // remove surfs if they are in any of the other groups
2408     // AND with inverse mask removes the surf from group
2409 
2410     int inverse = inversemask[igroup];
2411 
2412     for (int ilist = 1; ilist < length; ilist++) {
2413       otherbit = bitmask[list[ilist]];
2414       if (dim == 2) {
2415         for (i = 0; i < nlocal+nghost; i++)
2416           if (lines[i].mask & otherbit) lines[i].mask &= inverse;
2417       } else {
2418         for (i = 0; i < nlocal+nghost; i++)
2419           if (tris[i].mask & otherbit) tris[i].mask &= inverse;
2420       }
2421     }
2422 
2423     delete [] list;
2424 
2425   // style = union
2426 
2427   } else if (strcmp(arg[2],"union") == 0) {
2428     if (narg < 4) error->all(FLERR,"Illegal group command");
2429 
2430     int length = narg-3;
2431     int *list = new int[length];
2432 
2433     int jgroup;
2434     for (int iarg = 3; iarg < narg; iarg++) {
2435       jgroup = find_group(arg[iarg]);
2436       if (jgroup == -1) error->all(FLERR,"Group ID does not exist");
2437       list[iarg-3] = jgroup;
2438     }
2439 
2440     // add to group if in any other group in list
2441 
2442     int otherbit;
2443 
2444     for (int ilist = 0; ilist < length; ilist++) {
2445       otherbit = bitmask[list[ilist]];
2446       if (dim == 2) {
2447         for (i = 0; i < nlocal+nghost; i++)
2448           if (lines[i].mask & otherbit) lines[i].mask |= bit;
2449       } else {
2450         for (i = 0; i < nlocal+nghost; i++)
2451           if (tris[i].mask & otherbit) tris[i].mask |= bit;
2452       }
2453     }
2454 
2455     delete [] list;
2456 
2457   // style = intersect
2458 
2459   } else if (strcmp(arg[2],"intersect") == 0) {
2460     if (narg < 5) error->all(FLERR,"Illegal group command");
2461 
2462     int length = narg-3;
2463     int *list = new int[length];
2464 
2465     int jgroup;
2466     for (int iarg = 3; iarg < narg; iarg++) {
2467       jgroup = find_group(arg[iarg]);
2468       if (jgroup == -1) error->all(FLERR,"Group ID does not exist");
2469       list[iarg-3] = jgroup;
2470     }
2471 
2472     // add to group if in all groups in list
2473 
2474     int otherbit,ok,ilist;
2475 
2476     if (dim == 2) {
2477       for (i = 0; i < nlocal+nghost; i++) {
2478         ok = 1;
2479         for (ilist = 0; ilist < length; ilist++) {
2480           otherbit = bitmask[list[ilist]];
2481           if ((lines[i].mask & otherbit) == 0) ok = 0;
2482         }
2483         if (ok) lines[i].mask |= bit;
2484       }
2485     } else {
2486       for (i = 0; i < nlocal+nghost; i++) {
2487         ok = 1;
2488         for (ilist = 0; ilist < length; ilist++) {
2489           otherbit = bitmask[list[ilist]];
2490           if ((tris[i].mask & otherbit) == 0) ok = 0;
2491         }
2492         if (ok) tris[i].mask |= bit;
2493       }
2494     }
2495 
2496     delete [] list;
2497 
2498   // style = clear
2499   // remove all surfs from group
2500 
2501   } else if (strcmp(arg[2],"clear") == 0) {
2502     if (igroup == 0) error->all(FLERR,"Cannot clear group all");
2503     int inversebits = inversemask[igroup];
2504 
2505     if (dim == 2) {
2506       for (i = 0; i < nlocal+nghost; i++) lines[i].mask &= inversebits;
2507     } else {
2508       for (i = 0; i < nlocal+nghost; i++) tris[i].mask &= inversebits;
2509     }
2510   }
2511 
2512   // print stats for changed group
2513 
2514   bigint n = 0;
2515   if (dim == 2) {
2516     for (i = 0; i < nlocal; i++)
2517       if (lines[i].mask & bit) n++;
2518   } else {
2519     for (i = 0; i < nlocal; i++)
2520       if (tris[i].mask & bit) n++;
2521   }
2522 
2523   bigint nall;
2524   if (distributed) MPI_Allreduce(&n,&nall,1,MPI_SPARTA_BIGINT,MPI_SUM,world);
2525   else nall = n;
2526 
2527   if (comm->me == 0) {
2528     if (screen)
2529       fprintf(screen,BIGINT_FORMAT " surfaces in group %s\n",
2530               nall,gnames[igroup]);
2531     if (logfile)
2532       fprintf(logfile,BIGINT_FORMAT " surfaces in group %s\n",
2533               nall,gnames[igroup]);
2534   }
2535 }
2536 
2537 /* ----------------------------------------------------------------------
2538    add a new surface group ID, assumed to be unique
2539 ------------------------------------------------------------------------- */
2540 
add_group(const char * id)2541 int Surf::add_group(const char *id)
2542 {
2543   if (ngroup == MAXGROUP)
2544     error->all(FLERR,"Cannot have more than 32 surface groups");
2545 
2546   int n = strlen(id) + 1;
2547   gnames[ngroup] = new char[n];
2548   strcpy(gnames[ngroup],id);
2549 
2550   for (int i = 0; i < n-1; i++)
2551     if (!isalnum(id[i]) && id[i] != '_')
2552       error->all(FLERR,"Group ID must be alphanumeric or "
2553                  "underscore characters");
2554 
2555   ngroup++;
2556   return ngroup-1;
2557 }
2558 
2559 /* ----------------------------------------------------------------------
2560    find a surface group ID
2561    return index of group or -1 if not found
2562 ------------------------------------------------------------------------- */
2563 
find_group(const char * id)2564 int Surf::find_group(const char *id)
2565 {
2566   int igroup;
2567   for (igroup = 0; igroup < ngroup; igroup++)
2568     if (strcmp(id,gnames[igroup]) == 0) break;
2569   if (igroup == ngroup) return -1;
2570   return igroup;
2571 }
2572 
2573 /* ----------------------------------------------------------------------
2574    compress owned explicit distributed surfs to account for deleted grid cells
2575      either due to load-balancing migration or grid adapt coarsening
2576    called from Comm::migrate_cells() and AdaptGrid::coarsen()
2577      AFTER grid cells are compressed
2578    discard nlocal surfs that are no longer referenced by owned grid cells
2579    use hash to store referenced surfs
2580    only called for explicit distributed surfs
2581 ------------------------------------------------------------------------- */
2582 
compress_explicit()2583 void Surf::compress_explicit()
2584 {
2585   int i,m,ns;
2586   surfint *csurfs;
2587 
2588   int dim = domain->dimension;
2589 
2590   // keep = 1 if a local surf is referenced by a compressed local grid cell
2591 
2592   int *keep;
2593   memory->create(keep,nlocal,"surf:keep");
2594   for (i = 0; i < nlocal; i++) keep[i] = 0;
2595 
2596   // convert grid cell csurfs to surf IDs so can reset after surf compression
2597   // skip cells with no surfs or sub-cells
2598 
2599   Grid::ChildCell *cells = grid->cells;
2600   int nglocal = grid->nlocal;
2601 
2602   for (i = 0; i < nglocal; i++) {
2603     if (!cells[i].nsurf) continue;
2604     if (cells[i].nsplit <= 0) continue;
2605     csurfs = cells[i].csurfs;
2606     ns = cells[i].nsurf;
2607     if (dim == 2) {
2608       for (m = 0; m < ns; m++) {
2609         keep[csurfs[m]] = 1;
2610         csurfs[m] = lines[csurfs[m]].id;
2611       }
2612     } else {
2613       for (m = 0; m < ns; m++) {
2614         keep[csurfs[m]] = 1;
2615         csurfs[m] = tris[csurfs[m]].id;
2616       }
2617     }
2618   }
2619 
2620   // compress nlocal surfs based on keep flags
2621 
2622   m = 0;
2623   while (i < nlocal) {
2624     if (!keep[i]) {
2625       if (dim == 2) memcpy(&lines[i],&lines[nlocal-1],sizeof(Line));
2626       else memcpy(&tris[i],&tris[nlocal-1],sizeof(Tri));
2627       keep[i] = keep[nlocal-1];
2628       nlocal--;
2629     } else i++;
2630   }
2631 
2632   memory->destroy(keep);
2633 
2634   // reset grid cell csurfs IDs back to local surf indices
2635   // hash compressed surf list, then clear hash
2636   // skip cells with no surfs or sub-cells
2637 
2638   rehash();
2639 
2640   for (i = 0; i < nglocal; i++) {
2641     if (!cells[i].nsurf) continue;
2642     if (cells[i].nsplit <= 0) continue;
2643     csurfs = cells[i].csurfs;
2644     ns = cells[i].nsurf;
2645     for (m = 0; m < ns; m++) csurfs[m] = (*hash)[csurfs[m]];
2646   }
2647 
2648   hash->clear();
2649   hashfilled = 0;
2650 }
2651 
2652 /* ----------------------------------------------------------------------
2653    compress owned implicit surfs to account for migrating grid cells
2654    called from Comm::migrate_cells() BEFORE grid cells are compressed
2655    migrating grid cells are ones with proc != me
2656    reset csurfs indices for kept cells
2657    only called for implicit surfs
2658 ------------------------------------------------------------------------- */
2659 
compress_implicit()2660 void Surf::compress_implicit()
2661 {
2662   int j,ns,icell;
2663   cellint cellID;
2664   surfint *csurfs;
2665 
2666   if (!grid->hashfilled) grid->rehash();
2667 
2668   Grid::ChildCell *cells = grid->cells;
2669   Grid::MyHash *ghash = grid->hash;
2670   int me = comm->me;
2671   int n = 0;
2672 
2673   if (domain->dimension == 2) {
2674     for (int i = 0; i < nlocal; i++) {
2675       icell = (*ghash)[lines[i].id];
2676       if (cells[icell].proc != me) continue;
2677       if (i != n) {
2678         // compress my surf list
2679         memcpy(&lines[n],&lines[i],sizeof(Line));
2680         // reset matching csurfs index in grid cell from i to n
2681         csurfs = cells[icell].csurfs;
2682         ns = cells[icell].nsurf;
2683         for (j = 0; j < ns; j++)
2684           if (csurfs[j] == i) {
2685             csurfs[j] = n;
2686             break;
2687           }
2688       }
2689       n++;
2690     }
2691 
2692   } else {
2693     for (int i = 0; i < nlocal; i++) {
2694       icell = (*ghash)[tris[i].id];
2695       if (cells[icell].proc != me) continue;
2696       if (i != n) {
2697         // compress my surf list
2698         memcpy(&tris[n],&tris[i],sizeof(Tri));
2699         // reset matching csurfs index in grid cell from i to n
2700         csurfs = cells[icell].csurfs;
2701         ns = cells[icell].nsurf;
2702         for (j = 0; j < ns; j++)
2703           if (csurfs[j] == i) {
2704             csurfs[j] = n;
2705             break;
2706           }
2707       }
2708       n++;
2709     }
2710   }
2711 
2712   nlocal = n;
2713 }
2714 
2715 /* ----------------------------------------------------------------------
2716    comm of tallies across all procs
2717    nrow = # of tally entries in input vector
2718    tally2surf = surf index of each entry in input vector
2719    in = input vector of tallies
2720    instride = stride between entries in input vector
2721    return out = summed tallies for explicit surfs I own
2722 ------------------------------------------------------------------------- */
2723 
collate_vector(int nrow,surfint * tally2surf,double * in,int instride,double * out)2724 void Surf::collate_vector(int nrow, surfint *tally2surf,
2725                           double *in, int instride, double *out)
2726 {
2727   // collate version depends on tally_comm setting
2728 
2729   if (tally_comm == TALLYAUTO) {
2730     if (nprocs > nsurf)
2731       collate_vector_reduce(nrow,tally2surf,in,instride,out);
2732     else collate_vector_rendezvous(nrow,tally2surf,in,instride,out);
2733   } else if (tally_comm == TALLYREDUCE) {
2734     collate_vector_reduce(nrow,tally2surf,in,instride,out);
2735   } else if (tally_comm == TALLYRVOUS) {
2736     collate_vector_rendezvous(nrow,tally2surf,in,instride,out);
2737   }
2738 }
2739 
2740 /* ----------------------------------------------------------------------
2741    allreduce version of collate
2742 ------------------------------------------------------------------------- */
2743 
collate_vector_reduce(int nrow,surfint * tally2surf,double * in,int instride,double * out)2744 void Surf::collate_vector_reduce(int nrow, surfint *tally2surf,
2745                                  double *in, int instride, double *out)
2746 {
2747   int i,j,m;
2748 
2749   if (nsurf > MAXSMALLINT)
2750     error->all(FLERR,"Two many surfs to tally reduce - "
2751                "use global surf/comm auto or rvous");
2752 
2753   int nglobal = nsurf;
2754 
2755   double *one,*all;
2756   memory->create(one,nglobal,"surf:one");
2757   memory->create(all,nglobal,"surf:all");
2758 
2759   // zero all values and add in values I accumulated
2760 
2761   for (i = 0; i < nglobal; i++) one[i] = 0.0;
2762 
2763   Surf::Line *lines = surf->lines;
2764   Surf::Tri *tris = surf->tris;
2765   int dim = domain->dimension;
2766   surfint id;
2767 
2768   j = 0;
2769   for (i = 0; i < nrow; i++) {
2770     m = (int) tally2surf[i] - 1;
2771     one[m] = in[j];
2772     j += instride;
2773   }
2774 
2775   // global allreduce
2776 
2777   MPI_Allreduce(one,all,nglobal,MPI_DOUBLE,MPI_SUM,world);
2778 
2779   // out = only surfs I own
2780 
2781   m = 0;
2782   for (i = me; i < nglobal; i += nprocs)
2783     out[m++] = all[i];
2784 
2785   // NOTE: could persist these for multiple invocations
2786 
2787   memory->destroy(one);
2788   memory->destroy(all);
2789 }
2790 
2791 /* ----------------------------------------------------------------------
2792    rendezvous version of collate
2793 ------------------------------------------------------------------------- */
2794 
collate_vector_rendezvous(int nrow,surfint * tally2surf,double * in,int instride,double * out)2795 void Surf::collate_vector_rendezvous(int nrow, surfint *tally2surf,
2796                                      double *in, int instride, double *out)
2797 {
2798   // allocate memory for rvous input
2799 
2800   int *proclist;
2801   memory->create(proclist,nrow,"surf:proclist");
2802   InRvousVec *in_rvous =
2803     (InRvousVec *) memory->smalloc((bigint) nrow*sizeof(InRvousVec),
2804                                    "surf:in_rvous");
2805 
2806   // create rvous inputs
2807   // proclist = owner of each surf
2808   // logic of (id-1) % nprocs sends
2809   //   surf IDs 1,11,21,etc on 10 procs to proc 0
2810 
2811   Surf::Line *lines = surf->lines;
2812   Surf::Tri *tris = surf->tris;
2813   int dim = domain->dimension;
2814 
2815   surfint id;
2816 
2817   int m = 0;
2818   for (int i = 0; i < nrow; i++) {
2819     id = tally2surf[i];
2820     proclist[i] = (id-1) % nprocs;
2821     in_rvous[i].id = id;
2822     in_rvous[i].value = in[m];
2823     m += instride;
2824   }
2825 
2826   // perform rendezvous operation
2827   // each proc owns subset of surfs
2828   // receives all tally contributions to surfs it owns
2829 
2830   out_rvous = out;
2831 
2832   char *buf;
2833   int nout = comm->rendezvous(1,nrow,(char *) in_rvous,sizeof(InRvousVec),
2834 			      0,proclist,rendezvous_vector,
2835 			      0,buf,0,(void *) this);
2836 
2837   memory->destroy(proclist);
2838   memory->destroy(in_rvous);
2839 }
2840 
2841 /* ----------------------------------------------------------------------
2842    callback from rendezvous operation
2843    process tallies for surfs assigned to me
2844    inbuf = list of N Inbuf datums
2845    no outbuf
2846 ------------------------------------------------------------------------- */
2847 
rendezvous_vector(int n,char * inbuf,int & flag,int * & proclist,char * & outbuf,void * ptr)2848 int Surf::rendezvous_vector(int n, char *inbuf, int &flag, int *&proclist,
2849                             char *&outbuf, void *ptr)
2850 {
2851   Surf *sptr = (Surf *) ptr;
2852   Memory *memory = sptr->memory;
2853   int nown = sptr->nown;
2854   double *out = sptr->out_rvous;
2855   int nprocs = sptr->comm->nprocs;
2856   int me = sptr->comm->me;
2857 
2858   // zero my owned surf values
2859 
2860   for (int i = 0; i < nown; i++) out[i] = 0.0;
2861 
2862   // accumulate per-surf values from different procs to my owned surfs
2863   // logic of (id-1-me) / nprocs maps
2864   //   surf IDs [1,11,21,...] on 10 procs to [0,1,2,...] on proc 0
2865 
2866   Surf::InRvousVec *in_rvous = (Surf::InRvousVec *) inbuf;
2867 
2868   int m;
2869   for (int i = 0; i < n; i++) {
2870     m = (in_rvous[i].id-1-me) / nprocs;
2871     out[m] += in_rvous[i].value;
2872   }
2873 
2874   // flag = 0: no second comm needed in rendezvous
2875 
2876   flag = 0;
2877   return 0;
2878 }
2879 
2880 /* ----------------------------------------------------------------------
2881    comm of tallies across all procs
2882    nrow,ncol = # of entries and columns in input array
2883    tally2surf = global surf index of each entry in input array
2884    in = input array of tallies
2885    return out = summed tallies for explicit surfs I own
2886 ------------------------------------------------------------------------- */
2887 
collate_array(int nrow,int ncol,surfint * tally2surf,double ** in,double ** out)2888 void Surf::collate_array(int nrow, int ncol, surfint *tally2surf,
2889                          double **in, double **out)
2890 {
2891   // collate version depends on tally_comm setting
2892 
2893   if (tally_comm == TALLYAUTO) {
2894     if (nprocs > nsurf)
2895       collate_array_reduce(nrow,ncol,tally2surf,in,out);
2896     else collate_array_rendezvous(nrow,ncol,tally2surf,in,out);
2897   } else if (tally_comm == TALLYREDUCE) {
2898     collate_array_reduce(nrow,ncol,tally2surf,in,out);
2899   } else if (tally_comm == TALLYRVOUS) {
2900     collate_array_rendezvous(nrow,ncol,tally2surf,in,out);
2901   }
2902 }
2903 
2904 /* ----------------------------------------------------------------------
2905    allreduce version of collate
2906 ------------------------------------------------------------------------- */
2907 
collate_array_reduce(int nrow,int ncol,surfint * tally2surf,double ** in,double ** out)2908 void Surf::collate_array_reduce(int nrow, int ncol, surfint *tally2surf,
2909                                 double **in, double **out)
2910 {
2911   int i,j,m;
2912 
2913   bigint ntotal = (bigint) nsurf * ncol;
2914 
2915   if (ntotal > MAXSMALLINT)
2916     error->all(FLERR,"Two many surfs to tally reduce - "
2917                "use global surf/comm auto or rvous");
2918 
2919   int nglobal = nsurf;
2920 
2921   double **one,**all;
2922   memory->create(one,nglobal,ncol,"surf:one");
2923   memory->create(all,nglobal,ncol,"surf:all");
2924 
2925   // zero all values and set values I accumulated
2926 
2927   for (i = 0; i < nglobal; i++)
2928     for (j = 0; j < ncol; j++)
2929       one[i][j] = 0.0;
2930 
2931   Surf::Line *lines = surf->lines;
2932   Surf::Tri *tris = surf->tris;
2933   int dim = domain->dimension;
2934 
2935   for (i = 0; i < nrow; i++) {
2936     m = (int) tally2surf[i] - 1;
2937     for (j = 0; j < ncol; j++)
2938       one[m][j] = in[i][j];
2939   }
2940 
2941   // global allreduce
2942 
2943   MPI_Allreduce(&one[0][0],&all[0][0],ntotal,MPI_DOUBLE,MPI_SUM,world);
2944 
2945   // out = only surfs I own
2946 
2947   m = 0;
2948   for (i = me; i < nglobal; i += nprocs) {
2949     for (j = 0; j < ncol; j++) out[m][j] = all[i][j];
2950     m++;
2951   }
2952 
2953   // NOTE: could persist these for multiple invocations
2954 
2955   memory->destroy(one);
2956   memory->destroy(all);
2957 }
2958 
2959 /* ----------------------------------------------------------------------
2960    rendezvous version of collate
2961 ------------------------------------------------------------------------- */
2962 
collate_array_rendezvous(int nrow,int ncol,surfint * tally2surf,double ** in,double ** out)2963 void Surf::collate_array_rendezvous(int nrow, int ncol, surfint *tally2surf,
2964                                     double **in, double **out)
2965 {
2966   int i,j,m;
2967 
2968   // allocate memory for rvous input
2969 
2970   int *proclist;
2971   memory->create(proclist,nrow,"surf:proclist");
2972   double *in_rvous = (double *)     // worry about overflow
2973     memory->smalloc(nrow*(ncol+1)*sizeof(double*),"surf:in_rvous");
2974 
2975   // create rvous inputs
2976   // proclist = owner of each surf
2977   // logic of (id-1) % nprocs sends
2978   //   surf IDs 1,11,21,etc on 10 procs to proc 0
2979 
2980   Surf::Line *lines = surf->lines;
2981   Surf::Tri *tris = surf->tris;
2982   int dim = domain->dimension;
2983   surfint id;
2984 
2985   m = 0;
2986   for (int i = 0; i < nrow; i++) {
2987     id = tally2surf[i];
2988     proclist[i] = (id-1) % nprocs;
2989     in_rvous[m++] = ubuf(id).d;
2990     for (j = 0; j < ncol; j++)
2991       in_rvous[m++] = in[i][j];
2992   }
2993 
2994   // perform rendezvous operation
2995   // each proc owns subset of surfs
2996   // receives all tally contributions to surfs it owns
2997 
2998   ncol_rvous = ncol;
2999   if (out == NULL) out_rvous = NULL;
3000   else out_rvous = &out[0][0];
3001   int size = (ncol+1) * sizeof(double);
3002 
3003   char *buf;
3004   int nout = comm->rendezvous(1,nrow,(char *) in_rvous,size,
3005 			      0,proclist,rendezvous_array,
3006 			      0,buf,0,(void *) this);
3007 
3008   memory->destroy(proclist);
3009   memory->sfree(in_rvous);
3010 }
3011 
3012 /* ----------------------------------------------------------------------
3013    callback from rendezvous operation
3014    process tallies for surfs assigned to me
3015    inbuf = list of N Inbuf datums
3016    no outbuf
3017 ------------------------------------------------------------------------- */
3018 
rendezvous_array(int n,char * inbuf,int & flag,int * & proclist,char * & outbuf,void * ptr)3019 int Surf::rendezvous_array(int n, char *inbuf,
3020                            int &flag, int *&proclist, char *&outbuf,
3021                            void *ptr)
3022 {
3023   int i,j,k,m;
3024 
3025   Surf *sptr = (Surf *) ptr;
3026   Memory *memory = sptr->memory;
3027   int nown = sptr->nown;
3028   int ncol = sptr->ncol_rvous;
3029   double *out = sptr->out_rvous;
3030   int nprocs = sptr->comm->nprocs;
3031   int me = sptr->comm->me;
3032 
3033   // zero my owned surf values
3034   // NOTE: is this needed if caller zeroes ?
3035 
3036   int ntotal = nown*ncol;
3037   for (m = 0; m < ntotal; m++) out[m] = 0.0;
3038 
3039   // accumulate per-surf values from different procs to my owned surfs
3040   // logic of (id-1-me) / nprocs maps
3041   //   surf IDs [1,11,21,...] on 10 procs to [0,1,2,...] on proc 0
3042 
3043   double *in_rvous = (double *) inbuf;
3044   surfint id;
3045 
3046   m = 0;
3047   for (int i = 0; i < n; i++) {
3048     id = (surfint) ubuf(in_rvous[m++]).i;
3049     k = (id-1-me) / nprocs * ncol;
3050     for (j = 0; j < ncol; j++)
3051       out[k++] += in_rvous[m++];
3052   }
3053 
3054   // flag = 0: no second comm needed in rendezvous
3055 
3056   flag = 0;
3057   return 0;
3058 }
3059 
3060 /* ----------------------------------------------------------------------
3061    comm of tallies across all procs
3062    called from compute isurf/grid and fix ave/grid
3063      for implicit surf tallies by grid cell
3064    nrow = # of tallies
3065    tally2surf = surf ID for each tally (same as cell ID)
3066    in = vectir of tally values
3067    return out = summed tallies for grid cells I own
3068    done via rendezvous algorithm
3069 ------------------------------------------------------------------------- */
3070 
collate_vector_implicit(int nrow,surfint * tally2surf,double * in,double * out)3071 void Surf::collate_vector_implicit(int nrow, surfint *tally2surf,
3072                                    double *in, double *out)
3073 {
3074   int i,j,m,icell;
3075   cellint cellID;
3076 
3077   int me = comm->me;
3078   int nprocs = comm->nprocs;
3079 
3080   // create a grid cell hash for only my owned cells
3081 
3082   Grid::ChildCell *cells = grid->cells;
3083   int nglocal = grid->nlocal;
3084 
3085   MyCellHash hash;
3086 
3087   for (int icell = 0; icell < nglocal; icell++) {
3088     if (cells[icell].nsplit <= 0) continue;
3089     hash[cells[icell].id] = icell;
3090   }
3091 
3092   // for implicit surfs, tally2surf stores cellIDs
3093 
3094   cellint *tally2cell = (cellint *) tally2surf;
3095 
3096   // if I own tally grid cell, sum tallies to out directly
3097   // else nsend = # of tallies to contribute to rendezvous
3098 
3099   int nsend = 0;
3100   for (i = 0; i < nrow; i++) {
3101     if (hash.find(tally2cell[i]) == hash.end()) nsend++;
3102     else {
3103       icell = hash[tally2cell[i]];
3104       out[icell] += in[i];
3105     }
3106   }
3107 
3108   // done if just one proc
3109 
3110   if (nprocs == 1) return;
3111 
3112   // ncell = # of owned grid cells with implicit surfs, excluding sub cells
3113   // NOTE: could limit to cell group of caller
3114 
3115   int ncell = 0;
3116   for (int icell = 0; icell < nglocal; icell++) {
3117     if (cells[icell].nsurf <= 0) continue;
3118     if (cells[icell].nsplit <= 0) continue;
3119     ncell++;
3120   }
3121 
3122   // allocate memory for rvous input
3123   // ncount = ncell + nsend
3124   // 3 doubles for each input = proc, cellID, tally
3125 
3126   int ncount = ncell + nsend;
3127 
3128   int *proclist;
3129   double *in_rvous;
3130   memory->create(proclist,ncount,"surf:proclist");
3131   memory->create(in_rvous,3*ncount,"surf:in_rvous");
3132 
3133   // create rvous inputs
3134   // owning proc for each datum = random hash of cellID
3135   // flavor 1: one per ncell with proc and cellID, no tally
3136   // flavor 2: one per nsend with proc = -1, cellID, one tally
3137 
3138   ncount = m = 0;
3139 
3140   for (int icell = 0; icell < nglocal; icell++) {
3141     if (cells[icell].nsurf <= 0) continue;
3142     if (cells[icell].nsplit <= 0) continue;
3143     proclist[ncount] = hashlittle(&cells[icell].id,sizeof(cellint),0) % nprocs;
3144     in_rvous[m++] = me;
3145     in_rvous[m++] = cells[icell].id;    // NOTE: should use ubuf
3146     in_rvous[m++] = 0.0;
3147     ncount++;
3148   }
3149 
3150   for (i = 0; i < nrow; i++) {
3151     if (hash.find(tally2cell[i]) == hash.end()) {
3152       proclist[ncount] = hashlittle(&tally2cell[i],sizeof(cellint),0) % nprocs;
3153       in_rvous[m++] = -1;
3154       in_rvous[m++] = tally2cell[i];    // NOTE: should use ubuf
3155       in_rvous[m++] = in[i];
3156       ncount++;
3157     }
3158   }
3159 
3160   // perform rendezvous operation
3161 
3162   ncol_rvous = 1;
3163   char *buf;
3164   int nout = comm->rendezvous(1,ncount,(char *) in_rvous,3*sizeof(double),
3165 			      0,proclist,rendezvous_implicit,
3166 			      0,buf,2*sizeof(double),(void *) this);
3167   double *out_rvous = (double *) buf;
3168 
3169   memory->destroy(proclist);
3170   memory->destroy(in_rvous);
3171 
3172   // sum tallies returned for grid cells I own into out
3173 
3174   m = 0;
3175   for (i = 0; i < nout; i++) {
3176     cellID = out_rvous[m++];      // NOTE: should use ubuf
3177     icell = hash[cellID];
3178     out[icell] += out_rvous[m++];
3179   }
3180 
3181   // clean-up
3182 
3183   memory->destroy(out_rvous);
3184 }
3185 
3186 /* ----------------------------------------------------------------------
3187    comm of tallies across all procs
3188    called from compute isurf/grid and fix ave/grid
3189      for implicit surf tallies by grid cell
3190    nrow = # of tallies
3191    ncol = # of values per tally
3192    tally2surf = surf ID for each tally (same as cell ID)
3193    in = array of tally values, nrow by ncol
3194    return out = summed tallies for grid cells I own, nlocal by ncol
3195    done via rendezvous algorithm
3196 ------------------------------------------------------------------------- */
3197 
collate_array_implicit(int nrow,int ncol,surfint * tally2surf,double ** in,double ** out)3198 void Surf::collate_array_implicit(int nrow, int ncol, surfint *tally2surf,
3199                                   double **in, double **out)
3200 {
3201   int i,j,m,icell;
3202   cellint cellID;
3203 
3204   int me = comm->me;
3205   int nprocs = comm->nprocs;
3206 
3207   // create a grid cell hash for only my owned cells
3208 
3209   Grid::ChildCell *cells = grid->cells;
3210   int nglocal = grid->nlocal;
3211 
3212   MyCellHash hash;
3213 
3214   for (int icell = 0; icell < nglocal; icell++) {
3215     if (cells[icell].nsplit <= 0) continue;
3216     hash[cells[icell].id] = icell;
3217   }
3218 
3219   // for implicit surfs, tally2surf stores cellIDs
3220 
3221   cellint *tally2cell = (cellint *) tally2surf;
3222 
3223   // if I own tally grid cell, sum tallies to out directly
3224   // else nsend = # of tallies to contribute to rendezvous
3225 
3226   int nsend = 0;
3227   for (i = 0; i < nrow; i++) {
3228     if (hash.find(tally2cell[i]) == hash.end()) nsend++;
3229     else {
3230       icell = hash[tally2cell[i]];
3231       for (j = 0; j < ncol; j++)
3232         out[icell][j] += in[i][j];
3233     }
3234   }
3235 
3236   // done if just one proc
3237 
3238   if (nprocs == 1) return;
3239 
3240   // ncell = # of owned grid cells with implicit surfs, excluding sub cells
3241   // NOTE: could limit to cell group of caller
3242 
3243   int ncell = 0;
3244   for (int icell = 0; icell < nglocal; icell++) {
3245     if (cells[icell].nsurf <= 0) continue;
3246     if (cells[icell].nsplit <= 0) continue;
3247     ncell++;
3248   }
3249 
3250   // allocate memory for rvous input
3251   // ncount = ncell + nsend
3252   // ncol+2 doubles for each input = proc, cellID, ncol values
3253 
3254   int ncount = ncell + nsend;
3255 
3256   int *proclist;
3257   double *in_rvous;
3258   memory->create(proclist,ncount,"surf:proclist");
3259   memory->create(in_rvous,ncount*(ncol+2),"surf:in_rvous");
3260 
3261   // create rvous inputs
3262   // owning proc for each datum = random hash of cellID
3263   // flavor 1: one per ncell with proc and cellID, no tallies
3264   // flavor 2: one per nsend with proc = -1, cellID, tallies
3265 
3266   ncount = m = 0;
3267 
3268   for (int icell = 0; icell < nglocal; icell++) {
3269     if (cells[icell].nsurf <= 0) continue;
3270     if (cells[icell].nsplit <= 0) continue;
3271     proclist[ncount] = hashlittle(&cells[icell].id,sizeof(cellint),0) % nprocs;
3272     in_rvous[m++] = me;
3273     in_rvous[m++] = cells[icell].id;    // NOTE: should use ubuf
3274     for (j = 0; j < ncol; j++)
3275       in_rvous[m++] = 0.0;
3276     ncount++;
3277   }
3278 
3279   for (i = 0; i < nrow; i++) {
3280     if (hash.find(tally2cell[i]) == hash.end()) {
3281       proclist[ncount] = hashlittle(&tally2cell[i],sizeof(cellint),0) % nprocs;
3282       in_rvous[m++] = -1;
3283       in_rvous[m++] = tally2cell[i];    // NOTE: should use ubuf
3284       for (j = 0; j < ncol; j++)
3285         in_rvous[m++] = in[i][j];
3286       ncount++;
3287     }
3288   }
3289 
3290   // perform rendezvous operation
3291 
3292   ncol_rvous = ncol;
3293   char *buf;
3294   int nout = comm->rendezvous(1,ncount,(char *) in_rvous,
3295                               (ncol+2)*sizeof(double),
3296 			      0,proclist,rendezvous_implicit,
3297 			      0,buf,(ncol+1)*sizeof(double),(void *) this);
3298   double *out_rvous = (double *) buf;
3299 
3300   memory->destroy(proclist);
3301   memory->destroy(in_rvous);
3302 
3303   // sum tallies returned for grid cells I own into out
3304 
3305   m = 0;
3306   for (i = 0; i < nout; i++) {
3307     cellID = out_rvous[m++];      // NOTE: should use ubuf
3308     icell = hash[cellID] - 1;     // subtract one for child cell index
3309     for (j = 0; j < ncol; j++)
3310       out[icell][j] += out_rvous[m++];
3311   }
3312 
3313   // clean-up
3314 
3315   memory->destroy(out_rvous);
3316 }
3317 
3318 /* ----------------------------------------------------------------------
3319    callback from rendezvous operation
3320    create summed tallies for each grid cell assigned to me
3321    inbuf = list of N input datums
3322    send cellID + Ncol values back to owning proc of each grid cell
3323 ------------------------------------------------------------------------- */
3324 
rendezvous_implicit(int n,char * inbuf,int & flag,int * & proclist,char * & outbuf,void * ptr)3325 int Surf::rendezvous_implicit(int n, char *inbuf,
3326                               int &flag, int *&proclist, char *&outbuf, void *ptr)
3327 {
3328   int i,j,k,m,proc,iout;
3329   cellint cellID;
3330 
3331   Surf *sptr = (Surf *) ptr;
3332   Memory *memory = sptr->memory;
3333   int ncol = sptr->ncol_rvous;
3334 
3335   // scan inbuf for (proc,cellID) entries
3336   // create phash so can lookup the proc for each cellID
3337 
3338   double *in_rvous = (double *) inbuf;
3339   MyCellHash phash;
3340 
3341   m = 0;
3342   for (i = 0; i < n; i++) {
3343     proc = static_cast<int> (in_rvous[m++]);
3344     cellID = static_cast<cellint> (in_rvous[m++]);
3345     if (proc >= 0 && phash.find(cellID) == phash.end()) phash[cellID] = proc;
3346     m += ncol;
3347   }
3348 
3349   // allocate proclist & outbuf, based on size of max-size of phash
3350 
3351   int nmax = phash.size();
3352   memory->create(proclist,nmax,"surf:proclist");
3353   double *out;
3354   memory->create(out,nmax*(ncol+1),"surf:out");
3355 
3356   // scan inbuf for (cellID,tallies) entries
3357   // create a 2nd hash so can lookup the outbuf entry for each cellID
3358   // create proclist and outbuf with summed tallies for every cellID
3359 
3360   MyCellHash ohash;
3361 
3362   int nout = 0;
3363   k = m = 0;
3364 
3365   for (i = 0; i < n; i++) {
3366     proc = static_cast<int> (in_rvous[m++]);
3367     cellID = static_cast<cellint> (in_rvous[m++]);
3368     if (proc >= 0) {
3369       m += ncol;                         // skip entries with novalues
3370       continue;
3371     }
3372     if (ohash.find(cellID) == phash.end()) {
3373       ohash[cellID] = nout;              // add a new set of out values
3374       proclist[nout] = phash[cellID];
3375       out[k++] = cellID;
3376       for (j = 0; j < ncol; j++)
3377         out[k++] = in_rvous[m++];
3378       nout++;
3379     } else {
3380       iout = ohash[cellID] * (ncol+1);   // offset into existing out values
3381       iout++;                            // skip cellID;
3382       for (j = 0; j < ncol; j++)
3383         out[iout++] += in_rvous[m++];    // sum to existing values
3384     }
3385   }
3386 
3387   // flag = 2: new outbuf
3388 
3389   flag = 2;
3390   outbuf = (char *) out;
3391   return nout;
3392 }
3393 
3394 /* ----------------------------------------------------------------------
3395    redistribute newly created distributed lines to owing procs
3396    nold = original nown value before new surfs were read in
3397    nown = current nown value that includes my new surfs to redistribute
3398    nnew = nown value after new surfs from all procs are assigned to me
3399    called by ReadSurf:clip() after proc creates new surfs via clipping
3400    only called for distributed surfs
3401 ------------------------------------------------------------------------- */
3402 
redistribute_lines_clip(int nold,int nnew)3403 void Surf::redistribute_lines_clip(int nold, int nnew)
3404 {
3405   // allocate memory for rvous input
3406 
3407   int nsend = nown - nold;
3408 
3409   int *proclist;
3410   memory->create(proclist,nsend,"surf:proclist");
3411   Line *in_rvous = (Line *) memory->smalloc(nsend*sizeof(Line),"surf:in_rvous");
3412 
3413   // create rvous inputs
3414   // proclist = owner of each surf = (id-1) % nprocs
3415 
3416   surfint id;
3417 
3418   int i = nold;
3419   for (int m = 0; m < nsend; m++) {
3420     id = mylines[i].id;
3421     proclist[m] = (id-1) % nprocs;
3422     memcpy(&in_rvous[m],&mylines[i],sizeof(Line));
3423     i++;
3424   }
3425 
3426   // insure mylines is allocated sufficient for new lines
3427   // reset nown to new value after rendezvous
3428 
3429   if (nnew > maxown) {
3430     int old = maxown;
3431     maxown = nnew;
3432     grow_own(old);
3433   }
3434   nown = nnew;
3435 
3436   // perform rendezvous operation
3437   // each proc owns subset of new surfs
3438   // receives them from other procs
3439 
3440   char *buf;
3441   int nout = comm->rendezvous(1,nsend,(char *) in_rvous,sizeof(Line),
3442 			      0,proclist,rendezvous_lines,
3443 			      0,buf,0,(void *) this);
3444 
3445   memory->destroy(proclist);
3446   memory->sfree(in_rvous);
3447 }
3448 
3449 /* ----------------------------------------------------------------------
3450    redistribute newly created distributed lines to owing procs
3451    nnew = nown value after new surfs from all procs are assigned to me
3452    called by ReadSurf:read_multiple()
3453    only called for distributed surfs
3454 ------------------------------------------------------------------------- */
3455 
redistribute_lines_temporary(int nnew)3456 void Surf::redistribute_lines_temporary(int nnew)
3457 {
3458   // allocate memory for rvous input
3459 
3460   int nsend = ntmp;
3461 
3462   int *proclist;
3463   memory->create(proclist,nsend,"surf:proclist");
3464   Line *in_rvous = (Line *) memory->smalloc(nsend*sizeof(Line),"surf:in_rvous");
3465 
3466   // create rvous inputs
3467   // proclist = owner of each surf = (id-1) % nprocs
3468 
3469   surfint id;
3470 
3471   for (int i = 0; i < nsend; i++) {
3472     id = tmplines[i].id;
3473     proclist[i] = (id-1) % nprocs;
3474     memcpy(&in_rvous[i],&tmplines[i],sizeof(Line));
3475   }
3476 
3477   // insure mylines is allocated sufficient for new lines
3478   // reset nown to new value after rendezvous
3479 
3480   if (nnew > maxown) {
3481     int old = maxown;
3482     maxown = nnew;
3483     grow_own(old);
3484   }
3485   nown = nnew;
3486 
3487   // perform rendezvous operation
3488   // each proc owns subset of new surfs
3489   // receives them from other procs
3490 
3491   char *buf;
3492   int nout = comm->rendezvous(1,nsend,(char *) in_rvous,sizeof(Line),
3493 			      0,proclist,rendezvous_lines,
3494 			      0,buf,0,(void *) this);
3495 
3496   memory->destroy(proclist);
3497   memory->sfree(in_rvous);
3498 }
3499 
3500 /* ----------------------------------------------------------------------
3501    callback from rendezvous operation
3502    store received surfs assigned to me in correct location in mylines
3503    inbuf = list of N Inbuf datums
3504    no outbuf
3505 ------------------------------------------------------------------------- */
3506 
rendezvous_lines(int n,char * inbuf,int & flag,int * & proclist,char * & outbuf,void * ptr)3507 int Surf::rendezvous_lines(int n, char *inbuf,
3508                            int &flag, int *&proclist, char *&outbuf,
3509                            void *ptr)
3510 {
3511   int i,j,k,m;
3512 
3513   Surf *sptr = (Surf *) ptr;
3514   Line *lines = sptr->mylines;
3515   int nprocs = sptr->comm->nprocs;
3516   int me = sptr->comm->me;
3517 
3518   // zero my owned surf values
3519 
3520   Line *in_rvous = (Line *) inbuf;
3521   surfint id;
3522 
3523   for (int i = 0; i < n; i++) {
3524     id = in_rvous[i].id;
3525     m = (id-1-me) / nprocs;
3526     memcpy(&lines[m],&in_rvous[i],sizeof(Line));
3527   }
3528 
3529   // flag = 0: no second comm needed in rendezvous
3530 
3531   flag = 0;
3532   return 0;
3533 }
3534 
3535 /* ----------------------------------------------------------------------
3536    redistribute newly created distributed tris to owing procs
3537    nold = original nown value before new surfs were read in
3538    nown = current nown value that includes my new surfs to redistribute
3539    nnew = nown value after new surfs from all procs are assigned to me
3540    old = starting index that skips previously distributed surfs
3541    called by ReadSurf:clip() after proc create new surfs via clipping
3542    only called for distributed surfs
3543 ------------------------------------------------------------------------- */
3544 
redistribute_tris_clip(int nold,int nnew)3545 void Surf::redistribute_tris_clip(int nold, int nnew)
3546 {
3547   // allocate memory for rvous input
3548 
3549   int nsend = nown - nold;
3550 
3551   int *proclist;
3552   memory->create(proclist,nsend,"surf:proclist");
3553   Tri *in_rvous = (Tri *) memory->smalloc(nsend*sizeof(Tri),"surf:in_rvous");
3554 
3555   // create rvous inputs
3556   // proclist = owner of each surf = (id-1) % nprocs
3557 
3558   surfint id;
3559 
3560   int i = nold;
3561   for (int m = 0; m < nsend; m++) {
3562     id = mytris[i].id;
3563     proclist[m] = (id-1) % nprocs;
3564     memcpy(&in_rvous[m],&mytris[i],sizeof(Tri));
3565     i++;
3566   }
3567 
3568   // insure mytris is allocated sufficient for new tris
3569   // reset nown to new value after rendezvous
3570 
3571   if (nnew > maxown) {
3572     int old = maxown;
3573     maxown = nnew;
3574     grow_own(old);
3575   }
3576   nown = nnew;
3577 
3578   // perform rendezvous operation
3579   // each proc owns subset of new surfs
3580   // receives them from other procs
3581 
3582   char *buf;
3583   int nout = comm->rendezvous(1,nsend,(char *) in_rvous,sizeof(Tri),
3584 			      0,proclist,rendezvous_tris,
3585 			      0,buf,0,(void *) this);
3586 
3587   memory->destroy(proclist);
3588   memory->sfree(in_rvous);
3589 }
3590 
3591 /* ----------------------------------------------------------------------
3592    redistribute newly created distributed tris to owing procs
3593    nnew = nown value after new surfs from all procs are assigned to me
3594    called by ReadSurf:read_multiple()
3595    only called for distributed surfs
3596 ------------------------------------------------------------------------- */
3597 
redistribute_tris_temporary(int nnew)3598 void Surf::redistribute_tris_temporary(int nnew)
3599 {
3600   // allocate memory for rvous input
3601 
3602   int nsend = ntmp;
3603 
3604   int *proclist;
3605   memory->create(proclist,nsend,"surf:proclist");
3606   Tri *in_rvous = (Tri *) memory->smalloc(nsend*sizeof(Tri),"surf:in_rvous");
3607 
3608   // create rvous inputs
3609   // proclist = owner of each surf = (id-1) % nprocs
3610 
3611   surfint id;
3612 
3613   for (int i = 0; i < nsend; i++) {
3614     id = tmptris[i].id;
3615     proclist[i] = (id-1) % nprocs;
3616     memcpy(&in_rvous[i],&tmptris[i],sizeof(Tri));
3617   }
3618 
3619   // insure mytris is allocated sufficient for new tris
3620   // reset nown to new value after rendezvous
3621 
3622   if (nnew > maxown) {
3623     int old = maxown;
3624     maxown = nnew;
3625     grow_own(old);
3626   }
3627   nown = nnew;
3628 
3629   // perform rendezvous operation
3630   // each proc owns subset of new surfs
3631   // receives them from other procs
3632 
3633   char *buf;
3634   int nout = comm->rendezvous(1,nsend,(char *) in_rvous,sizeof(Tri),
3635 			      0,proclist,rendezvous_tris,
3636 			      0,buf,0,(void *) this);
3637 
3638   memory->destroy(proclist);
3639   memory->sfree(in_rvous);
3640 }
3641 
3642 /* ----------------------------------------------------------------------
3643    callback from rendezvous operation
3644    store received surfs assigned to me in correct location in mytris
3645    inbuf = list of N Inbuf datums
3646    no outbuf
3647 ------------------------------------------------------------------------- */
3648 
rendezvous_tris(int n,char * inbuf,int & flag,int * & proclist,char * & outbuf,void * ptr)3649 int Surf::rendezvous_tris(int n, char *inbuf,
3650                           int &flag, int *&proclist, char *&outbuf,
3651                           void *ptr)
3652 {
3653   int i,j,k,m;
3654 
3655   Surf *sptr = (Surf *) ptr;
3656   Tri *tris = sptr->mytris;
3657   int nprocs = sptr->comm->nprocs;
3658   int me = sptr->comm->me;
3659 
3660   // zero my owned surf values
3661 
3662   Tri *in_rvous = (Tri *) inbuf;
3663   surfint id;
3664 
3665   for (int i = 0; i < n; i++) {
3666     id = in_rvous[i].id;
3667     m = (id-1-me) / nprocs;
3668     memcpy(&tris[m],&in_rvous[i],sizeof(Tri));
3669   }
3670 
3671   // flag = 0: no second comm needed in rendezvous
3672 
3673   flag = 0;
3674   return 0;
3675 }
3676 
3677 // ----------------------------------------------------------------------
3678 // methods for per-surf custom attributes
3679 // ----------------------------------------------------------------------
3680 
3681 /* ----------------------------------------------------------------------
3682    find custom per-atom vector/array with name
3683    return index if found
3684    return -1 if not found
3685 ------------------------------------------------------------------------- */
3686 
find_custom(char * name)3687 int Surf::find_custom(char *name)
3688 {
3689   for (int i = 0; i < ncustom; i++)
3690     if (ename[i] && strcmp(ename[i],name) == 0) return i;
3691   return -1;
3692 }
3693 
3694 /* ----------------------------------------------------------------------
3695    add a custom attribute with name
3696    assumes name does not already exist, except in case of restart
3697    type = 0/1 for int/double
3698    size = 0 for vector, size > 0 for array with size columns
3699    return index of its location;
3700 ------------------------------------------------------------------------- */
3701 
add_custom(char * name,int type,int size)3702 int Surf::add_custom(char *name, int type, int size)
3703 {
3704   int index;
3705 
3706   // if name already exists
3707   // just return index if a restart script and re-defining the name
3708   // else error
3709 
3710   index = find_custom(name);
3711   if (index >= 0) {
3712     if (custom_restart_flag == NULL || custom_restart_flag[index] == 1)
3713       error->all(FLERR,"Custom surf attribute name already exists");
3714     custom_restart_flag[index] = 1;
3715     return index;
3716   }
3717 
3718   // use first available NULL entry or allocate a new one
3719 
3720   for (index = 0; index < ncustom; index++)
3721     if (ename[index] == NULL) break;
3722 
3723   if (index == ncustom) {
3724     ncustom++;
3725     ename = (char **) memory->srealloc(ename,ncustom*sizeof(char *),
3726                                        "surf:ename");
3727     memory->grow(etype,ncustom,"surf:etype");
3728     memory->grow(esize,ncustom,"surf:etype");
3729     memory->grow(ewhich,ncustom,"surf:etype");
3730   }
3731 
3732   int n = strlen(name) + 1;
3733   ename[index] = new char[n];
3734   strcpy(ename[index],name);
3735   etype[index] = type;
3736   esize[index] = size;
3737 
3738   if (type == INT) {
3739     if (size == 0) {
3740       ewhich[index] = ncustom_ivec++;
3741       eivec = (int **)
3742         memory->srealloc(eivec,ncustom_ivec*sizeof(int *),"surf:eivec");
3743       memory->grow(icustom_ivec,ncustom_ivec,"surf:icustom_ivec");
3744       icustom_ivec[ncustom_ivec-1] = index;
3745     } else {
3746       ewhich[index] = ncustom_iarray++;
3747       eiarray = (int ***)
3748         memory->srealloc(eiarray,ncustom_iarray*sizeof(int **),
3749                          "surf:eiarray");
3750       memory->grow(icustom_iarray,ncustom_iarray,"surf:icustom_iarray");
3751       icustom_iarray[ncustom_iarray-1] = index;
3752       memory->grow(eicol,ncustom_iarray,"surf:eicol");
3753       eicol[ncustom_iarray-1] = size;
3754     }
3755   } else if (type == DOUBLE) {
3756     if (size == 0) {
3757       ewhich[index] = ncustom_dvec++;
3758       edvec = (double **)
3759         memory->srealloc(edvec,ncustom_dvec*sizeof(double *),"surf:edvec");
3760       memory->grow(icustom_dvec,ncustom_dvec,"surf:icustom_dvec");
3761       icustom_dvec[ncustom_dvec-1] = index;
3762     } else {
3763       ewhich[index] = ncustom_darray++;
3764       edarray = (double ***)
3765         memory->srealloc(edarray,ncustom_darray*sizeof(double **),
3766                          "surf:edarray");
3767       memory->grow(icustom_darray,ncustom_darray,"surf:icustom_darray");
3768       icustom_darray[ncustom_darray-1] = index;
3769       memory->grow(edcol,ncustom_darray,"surf:edcol");
3770       edcol[ncustom_darray-1] = size;
3771     }
3772   }
3773 
3774   allocate_custom(index,nlocal);
3775 
3776   return index;
3777 }
3778 
3779 /* ----------------------------------------------------------------------
3780    allocate vector/array associated with custom attribute with index
3781    set new values to 0 via memset()
3782 ------------------------------------------------------------------------- */
3783 
allocate_custom(int index,int n)3784 void Surf::allocate_custom(int index, int n)
3785 {
3786   if (etype[index] == INT) {
3787     if (esize[index] == 0) {
3788       int *ivector = memory->create(eivec[ewhich[index]],n,"surf:eivec");
3789       if (ivector) memset(ivector,0,n*sizeof(int));
3790     } else {
3791       int **iarray = memory->create(eiarray[ewhich[index]],
3792                                     n,eicol[ewhich[index]],"surf:eiarray");
3793       if (iarray) memset(&iarray[0][0],0,n*eicol[ewhich[index]]*sizeof(int));
3794     }
3795 
3796   } else {
3797     if (esize[index] == 0) {
3798       double *dvector = memory->create(edvec[ewhich[index]],n,"surf:edvec");
3799       if (dvector) memset(dvector,0,n*sizeof(double));
3800     } else {
3801       double **darray = memory->create(edarray[ewhich[index]],
3802                                        n,edcol[ewhich[index]],"surf:eearray");
3803       if (darray) memset(&darray[0][0],0,n*edcol[ewhich[index]]*sizeof(double));
3804     }
3805   }
3806 }
3807 
3808 /* ----------------------------------------------------------------------
3809    remove a custom attribute at location index
3810    free memory for name and vector/array and set ptrs to NULL
3811    ncustom lists never shrink, but indices stored between
3812      the ncustom list and the dense vector/array lists must be reset
3813 ------------------------------------------------------------------------- */
3814 
remove_custom(int index)3815 void Surf::remove_custom(int index)
3816 {
3817   delete [] ename[index];
3818   ename[index] = NULL;
3819 
3820   if (etype[index] == INT) {
3821     if (esize[index] == 0) {
3822       memory->destroy(eivec[ewhich[index]]);
3823       ncustom_ivec--;
3824       for (int i = ewhich[index]; i < ncustom_ivec; i++) {
3825         icustom_ivec[i] = icustom_ivec[i+1];
3826         ewhich[icustom_ivec[i]] = i;
3827         eivec[i] = eivec[i+1];
3828       }
3829     } else{
3830       memory->destroy(eiarray[ewhich[index]]);
3831       ncustom_iarray--;
3832       for (int i = ewhich[index]; i < ncustom_iarray; i++) {
3833         icustom_iarray[i] = icustom_iarray[i+1];
3834         ewhich[icustom_iarray[i]] = i;
3835         eiarray[i] = eiarray[i+1];
3836         eicol[i] = eicol[i+1];
3837       }
3838     }
3839   } else if (etype[index] == DOUBLE) {
3840     if (esize[index] == 0) {
3841       memory->destroy(edvec[ewhich[index]]);
3842       ncustom_dvec--;
3843       for (int i = ewhich[index]; i < ncustom_dvec; i++) {
3844         icustom_dvec[i] = icustom_dvec[i+1];
3845         ewhich[icustom_dvec[i]] = i;
3846         edvec[i] = edvec[i+1];
3847       }
3848     } else{
3849       memory->destroy(edarray[ewhich[index]]);
3850       ncustom_darray--;
3851       for (int i = ewhich[index]; i < ncustom_darray; i++) {
3852         icustom_darray[i] = icustom_darray[i+1];
3853         ewhich[icustom_darray[i]] = i;
3854         edarray[i] = edarray[i+1];
3855         edcol[i] = edcol[i+1];
3856       }
3857     }
3858   }
3859 
3860   // set ncustom = 0 if custom list is now entirely empty
3861 
3862   int empty = 1;
3863   for (int i = 0; i < ncustom; i++)
3864     if (ename[i]) empty = 0;
3865   if (empty) ncustom = 0;
3866 }
3867 
3868 // ----------------------------------------------------------------------
3869 // methods for write/read restart info
3870 // ----------------------------------------------------------------------
3871 
3872 /* ----------------------------------------------------------------------
3873    proc 0 writes surf geometry to restart file
3874    NOTE: needs to be generalized for different surf styles
3875 ------------------------------------------------------------------------- */
3876 
write_restart(FILE * fp)3877 void Surf::write_restart(FILE *fp)
3878 {
3879   if (distributed || implicit)
3880     error->all(FLERR,
3881                "Restart files with distributed surfaces are not yet supported");
3882 
3883   fwrite(&ngroup,sizeof(int),1,fp);
3884 
3885   int n;
3886   for (int i = 0; i < ngroup; i++) {
3887     n = strlen(gnames[i]) + 1;
3888     fwrite(&n,sizeof(int),1,fp);
3889     fwrite(gnames[i],sizeof(char),n,fp);
3890   }
3891 
3892   if (domain->dimension == 2) {
3893     fwrite(&nsurf,sizeof(bigint),1,fp);
3894     for (int i = 0; i < nsurf; i++) {
3895       fwrite(&lines[i].id,sizeof(surfint),1,fp);
3896       fwrite(&lines[i].type,sizeof(int),1,fp);
3897       fwrite(&lines[i].mask,sizeof(int),1,fp);
3898       fwrite(&lines[i].transparent,sizeof(int),1,fp);
3899       fwrite(lines[i].p1,sizeof(double),3,fp);
3900       fwrite(lines[i].p2,sizeof(double),3,fp);
3901     }
3902   }
3903 
3904   if (domain->dimension == 3) {
3905     fwrite(&nsurf,sizeof(bigint),1,fp);
3906     for (int i = 0; i < nsurf; i++) {
3907       fwrite(&tris[i].id,sizeof(surfint),1,fp);
3908       fwrite(&tris[i].type,sizeof(int),1,fp);
3909       fwrite(&tris[i].mask,sizeof(int),1,fp);
3910       fwrite(&tris[i].transparent,sizeof(int),1,fp);
3911       fwrite(tris[i].p1,sizeof(double),3,fp);
3912       fwrite(tris[i].p2,sizeof(double),3,fp);
3913       fwrite(tris[i].p3,sizeof(double),3,fp);
3914     }
3915   }
3916 }
3917 
3918 /* ----------------------------------------------------------------------
3919    proc 0 reads surf geometry from restart file
3920    bcast to other procs
3921    NOTE: needs to be generalized for different surf styles
3922 ------------------------------------------------------------------------- */
3923 
read_restart(FILE * fp)3924 void Surf::read_restart(FILE *fp)
3925 {
3926   if (distributed || implicit)
3927     error->all(FLERR,
3928                "Restart files with distributed surfaces are not yet supported");
3929 
3930   int me = comm->me;
3931 
3932   // if any exist, clear existing group names, before reading new ones
3933 
3934   for (int i = 0; i < ngroup; i++) delete [] gnames[i];
3935 
3936   if (me == 0) fread(&ngroup,sizeof(int),1,fp);
3937   MPI_Bcast(&ngroup,1,MPI_INT,0,world);
3938 
3939   int n;
3940   for (int i = 0; i < ngroup; i++) {
3941     if (me == 0) fread(&n,sizeof(int),1,fp);
3942     MPI_Bcast(&n,1,MPI_INT,0,world);
3943     gnames[i] = new char[n];
3944     if (me == 0) fread(gnames[i],sizeof(char),n,fp);
3945     MPI_Bcast(gnames[i],n,MPI_CHAR,0,world);
3946   }
3947 
3948   if (domain->dimension == 2) {
3949     if (me == 0) fread(&nsurf,sizeof(bigint),1,fp);
3950     MPI_Bcast(&nsurf,1,MPI_SPARTA_BIGINT,0,world);
3951     lines = (Line *) memory->smalloc(nsurf*sizeof(Line),"surf:lines");
3952     // NOTE: need different logic for different surf styles
3953     nlocal = nsurf;
3954 
3955     if (me == 0) {
3956       for (int i = 0; i < nsurf; i++) {
3957         fread(&lines[i].id,sizeof(surfint),1,fp);
3958         fread(&lines[i].type,sizeof(int),1,fp);
3959         fread(&lines[i].mask,sizeof(int),1,fp);
3960         fread(&lines[i].transparent,sizeof(int),1,fp);
3961         lines[i].isc = lines[i].isr = -1;
3962         fread(lines[i].p1,sizeof(double),3,fp);
3963         fread(lines[i].p2,sizeof(double),3,fp);
3964         lines[i].norm[0] = lines[i].norm[1] = lines[i].norm[2] = 0.0;
3965       }
3966     }
3967     if (nsurf*sizeof(Line) > MAXSMALLINT)
3968       error->all(FLERR,"Surf restart memory exceeded");
3969     MPI_Bcast(lines,nsurf*sizeof(Line),MPI_CHAR,0,world);
3970   }
3971 
3972   if (domain->dimension == 3) {
3973     if (me == 0) fread(&nsurf,sizeof(bigint),1,fp);
3974     MPI_Bcast(&nsurf,1,MPI_SPARTA_BIGINT,0,world);
3975     tris = (Tri *) memory->smalloc(nsurf*sizeof(Tri),"surf:tris");
3976     // NOTE: need different logic for different surf styles
3977     nlocal = nsurf;
3978 
3979     if (me == 0) {
3980       for (int i = 0; i < nsurf; i++) {
3981         fread(&tris[i].id,sizeof(surfint),1,fp);
3982         fread(&tris[i].type,sizeof(int),1,fp);
3983         fread(&tris[i].mask,sizeof(int),1,fp);
3984         fread(&tris[i].transparent,sizeof(int),1,fp);
3985         tris[i].isc = tris[i].isr = -1;
3986         fread(tris[i].p1,sizeof(double),3,fp);
3987         fread(tris[i].p2,sizeof(double),3,fp);
3988         fread(tris[i].p3,sizeof(double),3,fp);
3989         tris[i].norm[0] = tris[i].norm[1] = tris[i].norm[2] = 0.0;
3990       }
3991     }
3992     if (nsurf*sizeof(Tri) > MAXSMALLINT)
3993       error->all(FLERR,"Surf restart memory exceeded");
3994     MPI_Bcast(tris,nsurf*sizeof(Tri),MPI_CHAR,0,world);
3995   }
3996 }
3997 
3998 /* ---------------------------------------------------------------------- */
3999 
grow(int old)4000 void Surf::grow(int old)
4001 {
4002   if (nmax <= old) return;
4003 
4004   if (domain->dimension == 2) {
4005     lines = (Surf::Line *)
4006       memory->srealloc(lines,nmax*sizeof(Line),"surf:lines");
4007     memset(&lines[old],0,(nmax-old)*sizeof(Line));
4008   } else {
4009     tris = (Surf::Tri *)
4010       memory->srealloc(tris,nmax*sizeof(Tri),"surf:tris");
4011     memset(&tris[old],0,(nmax-old)*sizeof(Tri));
4012   }
4013 }
4014 
4015 /* ---------------------------------------------------------------------- */
4016 
grow_own(int old)4017 void Surf::grow_own(int old)
4018 {
4019   if (domain->dimension == 2) {
4020     mylines = (Surf::Line *)
4021       memory->srealloc(mylines,maxown*sizeof(Line),"surf:mylines");
4022     memset(&mylines[old],0,(maxown-old)*sizeof(Line));
4023   } else {
4024     mytris = (Surf::Tri *)
4025       memory->srealloc(mytris,maxown*sizeof(Tri),"surf:mytris");
4026     memset(&mytris[old],0,(maxown-old)*sizeof(Tri));
4027   }
4028 }
4029 
4030 /* ---------------------------------------------------------------------- */
4031 
grow_temporary(int old)4032 void Surf::grow_temporary(int old)
4033 {
4034   if (domain->dimension == 2) {
4035     tmplines = (Surf::Line *)
4036       memory->srealloc(tmplines,nmaxtmp*sizeof(Line),"surf:lines");
4037     memset(&tmplines[old],0,(nmaxtmp-old)*sizeof(Line));
4038   } else {
4039     tmptris = (Surf::Tri *)
4040       memory->srealloc(tmptris,nmaxtmp*sizeof(Tri),"surf:tris");
4041     memset(&tmptris[old],0,(nmaxtmp-old)*sizeof(Tri));
4042   }
4043 }
4044 
4045 /* ---------------------------------------------------------------------- */
4046 
memory_usage()4047 bigint Surf::memory_usage()
4048 {
4049   bigint bytes = 0;
4050 
4051   if (implicit) {
4052     if (domain->dimension == 2) bytes += nlocal * sizeof(Line);
4053     else bytes += nlocal * sizeof(Tri);
4054   } else if (distributed) {
4055     if (domain->dimension == 2) bytes += (nlocal+nghost) * sizeof(Line);
4056     else bytes += (nlocal+nghost) * sizeof(Tri);
4057     if (domain->dimension == 2) bytes += nown * sizeof(Line);
4058     else bytes += nown * sizeof(Tri);
4059   } else {
4060     if (domain->dimension == 2) bytes += nsurf * sizeof(Line);
4061     else bytes += nsurf * sizeof(Tri);
4062     bytes += nlocal * sizeof(int);
4063   }
4064 
4065   return bytes;
4066 }
4067 
4068