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 "mpi.h"
16 #include "string.h"
17 #include "stdlib.h"
18 #include "ctype.h"
19 #include "dirent.h"
20 #include "read_surf.h"
21 #include "math_extra.h"
22 #include "surf.h"
23 #include "domain.h"
24 #include "grid.h"
25 #include "comm.h"
26 #include "geometry.h"
27 #include "input.h"
28 #include "write_surf.h"
29 #include "math_const.h"
30 #include "memory.h"
31 #include "error.h"
32
33 using namespace SPARTA_NS;
34 using namespace MathConst;
35
36 enum{NEITHER,BAD,GOOD};
37 enum{NONE,CHECK,KEEP};
38 enum{UNKNOWN,OUTSIDE,INSIDE,OVERLAP}; // several files
39 enum{LOCAL,MINE,TEMPALL,TEMPSTRIDE};
40
41 #define MAXLINE 256
42 #define CHUNK 16384
43 #define EPSILON_NORM 1.0e-12
44 #define BIG 1.0e20
45 #define DELTA 128 // must be 2 or greater
46 #define DELTA_DISCARD 128
47
48 /* ---------------------------------------------------------------------- */
49
ReadSurf(SPARTA * sparta)50 ReadSurf::ReadSurf(SPARTA *sparta) : Pointers(sparta)
51 {
52 MPI_Comm_rank(world,&me);
53 MPI_Comm_size(world,&nprocs);
54
55 line = new char[MAXLINE];
56 keyword = new char[MAXLINE];
57 buffer = new char[CHUNK*MAXLINE];
58 }
59
60 /* ---------------------------------------------------------------------- */
61
~ReadSurf()62 ReadSurf::~ReadSurf()
63 {
64 delete [] line;
65 delete [] keyword;
66 delete [] buffer;
67 }
68
69 /* ---------------------------------------------------------------------- */
70
command(int narg,char ** arg)71 void ReadSurf::command(int narg, char **arg)
72 {
73 if (!grid->exist)
74 error->all(FLERR,"Cannot read_surf before grid is defined");
75 if (surf->implicit)
76 error->all(FLERR,"Cannot read_surf unless global surfs explicit is set");
77
78 surf->exist = 1;
79 dim = domain->dimension;
80 distributed = surf->distributed;
81
82 if (narg < 1) error->all(FLERR,"Illegal read_surf command");
83
84 // if filename contains "*", search dir for latest surface file
85
86 char *file = new char[strlen(arg[0]) + 16];
87 if (strchr(arg[0],'*')) {
88 int n;
89 if (me == 0) {
90 file_search(arg[0],file);
91 n = strlen(file) + 1;
92 }
93 MPI_Bcast(&n,1,MPI_INT,0,world);
94 MPI_Bcast(file,n,MPI_CHAR,0,world);
95 } else strcpy(file,arg[0]);
96
97 // check for multiproc files
98
99 if (strchr(arg[0],'%')) multiproc = 1;
100 else multiproc = 0;
101
102 if (me == 0)
103 if (screen) fprintf(screen,"Reading surface file ...\n");
104
105 MPI_Barrier(world);
106 double time1 = MPI_Wtime();
107
108 // -----------------------
109 // read surface data from file(s)
110 // -----------------------
111
112 // multiproc = 0/1 = single or multiple files
113 // files may list Points or not
114 // store surfs as distributed or all
115
116 if (!multiproc) read_single(file);
117 else read_multiple(file);
118
119 delete [] file;
120
121 MPI_Barrier(world);
122 double time2 = MPI_Wtime();
123
124 // -----------------------
125 // transform and check surface elements
126 // -----------------------
127
128 // check for consecutive IDs
129
130 check_consecutive();
131
132 // process command-line args
133 // geometry transformations, group, type, etc
134
135 process_args(1,narg,arg);
136
137 // write out new surf file if requested
138 // do this before grid cell assignment or checks, in case an error occurs
139
140 if (filearg) {
141 WriteSurf *wf = new WriteSurf(sparta);
142 wf->statflag = 0;
143 wf->command(narg-filearg,&arg[filearg]);
144 delete wf;
145 }
146
147 // output extent of new surfs, tiny ones may have been created by clip
148
149 if (dim == 2) surf->output_extent(nsurf_old);
150 else surf->output_extent(nsurf_old);
151
152 // compute normals of new surfs
153
154 if (dim == 2) surf->compute_line_normal(nsurf_old);
155 else surf->compute_tri_normal(nsurf_old);
156
157 // error check on new surfs
158 // all points must be inside or on surface of simulation box
159
160 if (dim == 2) surf->check_point_inside(nsurf_old);
161 else surf->check_point_inside(nsurf_old);
162
163 // error checks that can be done before surfs are mapped to grid cells
164
165 if (dim == 2) {
166 surf->check_watertight_2d();
167 check_neighbor_norm_2d();
168 } else {
169 surf->check_watertight_3d();
170 check_neighbor_norm_3d();
171 }
172
173 MPI_Barrier(world);
174 double time3 = MPI_Wtime();
175
176 // -----------------------
177 // map surfs to grid cells
178 // -----------------------
179
180 // sort particles
181
182 if (particle->exist) particle->sort();
183
184 // make list of surf elements I own
185 // clear grid of surf info including split cells
186
187 surf->setup_owned();
188 grid->unset_neighbors();
189 grid->remove_ghosts();
190
191 if (particle->exist && grid->nsplitlocal) {
192 Grid::ChildCell *cells = grid->cells;
193 int nglocal = grid->nlocal;
194 for (int icell = 0; icell < nglocal; icell++)
195 if (cells[icell].nsplit > 1)
196 grid->combine_split_cell_particles(icell,1);
197 }
198
199 grid->clear_surf();
200
201 MPI_Barrier(world);
202 double time4 = MPI_Wtime();
203
204 // assign surfs to grid cells
205
206 grid->surf2grid(1);
207
208 MPI_Barrier(world);
209 double time5 = MPI_Wtime();
210
211 // error check on any points too near other surfs
212 // done on per-grid-cell basis, expensive to do globally
213
214 if (dim == 2) surf->check_point_near_surf_2d();
215 else surf->check_point_near_surf_3d();
216
217 // re-setup grid ghosts and neighbors
218
219 grid->setup_owned();
220 grid->acquire_ghosts();
221 grid->reset_neighbors();
222 comm->reset_neighbors();
223
224 MPI_Barrier(world);
225 double time6 = MPI_Wtime();
226
227 // flag cells and corners as OUTSIDE or INSIDE
228
229 grid->set_inout();
230 grid->type_check();
231
232 // DEBUG
233 //grid->debug();
234
235 MPI_Barrier(world);
236 double time7 = MPI_Wtime();
237
238 // remove particles in any cell that is now INSIDE or has new surfs
239 // reassign particles in split cells to sub cell owner
240 // compress particles if any flagged for deletion
241
242 bigint ndeleted;
243 if (particle->exist) {
244 Grid::ChildCell *cells = grid->cells;
245 Grid::ChildInfo *cinfo = grid->cinfo;
246 int nglocal = grid->nlocal;
247 int delflag = 0;
248
249 for (int icell = 0; icell < nglocal; icell++) {
250 if (cinfo[icell].type == INSIDE) {
251 if (partflag == KEEP)
252 error->one(FLERR,"Particles are inside new surfaces");
253 if (cinfo[icell].count) delflag = 1;
254 particle->remove_all_from_cell(cinfo[icell].first);
255 cinfo[icell].count = 0;
256 cinfo[icell].first = -1;
257 continue;
258 }
259 if (cells[icell].nsurf && cells[icell].nsplit >= 1) {
260 int nsurf = cells[icell].nsurf;
261 surfint *csurfs = cells[icell].csurfs;
262 int m;
263 if (dim == 2) {
264 Surf::Line *lines = surf->lines;
265 for (m = 0; m < nsurf; m++) {
266 if (lines[csurfs[m]].id > nsurf_total_old) break;
267 }
268 } else {
269 Surf::Tri *tris = surf->tris;
270 for (m = 0; m < nsurf; m++) {
271 if (tris[csurfs[m]].id >= nsurf_total_old) break;
272 }
273 }
274 if (m < nsurf && partflag == CHECK) {
275 if (cinfo[icell].count) delflag = 1;
276 particle->remove_all_from_cell(cinfo[icell].first);
277 cinfo[icell].count = 0;
278 cinfo[icell].first = -1;
279 }
280 }
281 if (cells[icell].nsplit > 1)
282 grid->assign_split_cell_particles(icell);
283 }
284 int nlocal_old = particle->nlocal;
285 if (delflag) particle->compress_rebalance();
286 bigint delta = nlocal_old - particle->nlocal;
287 MPI_Allreduce(&delta,&ndeleted,1,MPI_SPARTA_BIGINT,MPI_SUM,world);
288 }
289
290 MPI_Barrier(world);
291 double time8 = MPI_Wtime();
292
293 // stats
294
295 double time_total = time6-time1;
296 double time_s2g = time5-time4;
297
298 if (comm->me == 0) {
299 if (screen) {
300 if (particle->exist)
301 fprintf(screen," " BIGINT_FORMAT " deleted particles\n",ndeleted);
302 fprintf(screen," CPU time = %g secs\n",time_total);
303 fprintf(screen," read/check/sort/surf2grid/ghost/"
304 "inout/particle percent = "
305 "%g %g %g %g %g %g %g\n",
306 100.0*(time2-time1)/time_total,100.0*(time3-time2)/time_total,
307 100.0*(time4-time3)/time_total,100.0*(time5-time4)/time_total,
308 100.0*(time6-time5)/time_total,100.0*(time7-time6)/time_total,
309 100.0*(time8-time7)/time_total);
310 fprintf(screen," surf2grid time = %g secs\n",time_s2g);
311 fprintf(screen," map/comm1/comm2/comm3/comm4/split percent = "
312 "%g %g %g %g %g %g\n",
313 100.0*grid->tmap/time_s2g,100.0*grid->tcomm1/time_s2g,
314 100.0*grid->tcomm2/time_s2g,100.0*grid->tcomm3/time_s2g,
315 100.0*grid->tcomm4/time_s2g,100.0*grid->tsplit/time_s2g);
316 }
317
318 if (logfile) {
319 if (particle->exist)
320 fprintf(logfile," " BIGINT_FORMAT " deleted particles\n",ndeleted);
321 fprintf(logfile," CPU time = %g secs\n",time_total);
322 fprintf(logfile," read/check/sort/surf2grid/ghost/"
323 "inout/particle percent = "
324 "%g %g %g %g %g %g %g\n",
325 100.0*(time2-time1)/time_total,100.0*(time3-time2)/time_total,
326 100.0*(time4-time3)/time_total,100.0*(time5-time4)/time_total,
327 100.0*(time6-time5)/time_total,100.0*(time7-time6)/time_total,
328 100.0*(time8-time7)/time_total);
329 fprintf(logfile," surf2grid time = %g secs\n",time_s2g);
330 fprintf(logfile," map/comm1/comm2/comm3/comm4/split percent = "
331 "%g %g %g %g %g %g\n",
332 100.0*grid->tmap/time_s2g,100.0*grid->tcomm1/time_s2g,
333 100.0*grid->tcomm2/time_s2g,100.0*grid->tcomm3/time_s2g,
334 100.0*grid->tcomm4/time_s2g,100.0*grid->tsplit/time_s2g);
335 }
336 }
337 }
338
339 // ----------------------------------------------------------------------
340 // methods to read surface files
341 // ----------------------------------------------------------------------
342
343 /* ----------------------------------------------------------------------
344 read a single input file
345 store surfs directly in lines/tris (all) or mylines/mytris (distributed)
346 ------------------------------------------------------------------------- */
347
read_single(char * file)348 void ReadSurf::read_single(char *file)
349 {
350 // surf counts before new read
351
352 nsurf_total_old = surf->nsurf;
353 if (distributed) nsurf_old = surf->nown;
354 else nsurf_old = surf->nlocal;
355
356 // read file
357
358 if (me == 0) filereader = 1;
359 else filereader = 0;
360 filecomm = world;
361 me_file = me;
362 nprocs_file = nprocs;
363
364 if (distributed) read_file(file,MINE);
365 else read_file(file,LOCAL);
366
367 // surf counts, stats, error check
368
369 surf_counts();
370 }
371
372 /* ----------------------------------------------------------------------
373 read multiple files, cluster of procs for each file
374 store surfs initially in distributed tmplines/tmptris
375 communicate to populate lines/tris (all) or mylines/mytris (distributed)
376 ------------------------------------------------------------------------- */
377
read_multiple(char * file)378 void ReadSurf::read_multiple(char *file)
379 {
380 base(file);
381
382 // surf counts before new read
383
384 nsurf_total_old = surf->nsurf;
385 if (distributed) nsurf_old = surf->nown;
386 else nsurf_old = surf->nlocal;
387
388 // setup for read into temporary tmplines/tmptris
389
390 surf->ntmp = surf->nmaxtmp = 0;
391 surf->tmplines = NULL;
392 surf->tmptris = NULL;
393
394 char *procfile = new char[strlen(file) + 16];
395 char *ptr = strchr(file,'%');
396
397 // if nprocs > files, break procs into clusters, each cluster reads one file
398
399 if (nprocs > nfiles) {
400
401 // icluster = which cluster of procs this proc is in
402 // fileproc = ID of proc in my cluster who reads from file
403 // filereader = 1 if this proc reads file, else 0
404
405 int icluster = static_cast<int> ((bigint) me * nfiles/nprocs);
406 int fileproc = static_cast<int> ((bigint) icluster * nprocs/nfiles);
407 int fcluster = static_cast<int> ((bigint) fileproc * nfiles/nprocs);
408 if (fcluster < icluster) fileproc++;
409 if (me == fileproc) filereader = 1;
410 else filereader = 0;
411 MPI_Comm_split(world,icluster,0,&filecomm);
412 MPI_Comm_rank(filecomm,&me_file);
413 MPI_Comm_size(filecomm,&nprocs_file);
414
415 // each cluster reads a file, stores surfs in tmplines/tmptris
416
417 *ptr = '\0';
418 sprintf(procfile,"%s%d%s",file,icluster,ptr+1);
419 *ptr = '%';
420
421 read_file(procfile,TEMPSTRIDE);
422
423 // if nprocs <= files, each proc reads one or more files
424
425 } else {
426
427 filereader = 1;
428 MPI_Comm_split(world,me,0,&filecomm);
429 me_file = 0;
430 nprocs_file = 1;
431
432 // each proc reads every Pth file, stores surfs in tmplines/tmptris
433
434 surf->ntmp = surf->nmaxtmp = 0;
435 surf->tmplines = NULL;
436 surf->tmptris = NULL;
437
438 for (int iproc = me; iproc < nfiles; iproc += nprocs) {
439 *ptr = '\0';
440 sprintf(procfile,"%s%d%s",file,iproc,ptr+1);
441 *ptr = '%';
442
443 read_file(procfile,TEMPALL);
444 }
445 }
446
447 delete [] procfile;
448
449 // communicate surf data from tmplines/tmptris to lines/tris or mylines/mytris
450 // for all: perform MPI_Allgatherv
451 // for distributed: rendezvous comm, each proc fills its mylines/mytris
452
453 if (!distributed) {
454
455 bigint nbytes;
456 if (dim == 2) nbytes = (bigint) nsurf_basefile * sizeof(Surf::Line);
457 else nbytes = (bigint) nsurf_basefile * sizeof(Surf::Tri);
458 if (nbytes > MAXSMALLINT)
459 error->all(FLERR,"Aggregate surf byte count is too large");
460
461 int *recvcounts,*displs;
462 memory->create(recvcounts,nprocs,"read_surf:recvcounts");
463 memory->create(displs,nprocs,"read_surf:displs");
464
465 int n;
466 if (dim == 2) n = surf->ntmp * sizeof(Surf::Line);
467 else n = surf->ntmp * sizeof(Surf::Tri);
468
469 MPI_Allgather(&n,1,MPI_INT,recvcounts,1,MPI_INT,world);
470 displs[0] = 0;
471 for (int i = 1; i < nprocs; i++) displs[i] = displs[i-1] + recvcounts[i-1];
472
473 // allocate space in lines/tris for newly read surfs
474 // Allgatherv() puts new surfs at end of old surfs in lines/tris
475
476 if (nsurf_total_old + nsurf_basefile > surf->nmax) {
477 int old = surf->nmax;
478 surf->nmax = nsurf_total_old + nsurf_basefile;
479 surf->grow(old);
480 }
481
482 if (dim == 2)
483 MPI_Allgatherv(surf->tmplines,surf->ntmp*sizeof(Surf::Line),MPI_CHAR,
484 &surf->lines[nsurf_old],recvcounts,displs,MPI_CHAR,world);
485 else
486 MPI_Allgatherv(surf->tmptris,surf->ntmp*sizeof(Surf::Tri),MPI_CHAR,
487 &surf->tris[nsurf_old],recvcounts,displs,MPI_CHAR,world);
488
489 // set surf->nlocal to aggregate size of Allgatherv()
490
491 surf->nlocal = nsurf_total_old + nsurf_basefile;
492
493 memory->destroy(recvcounts);
494 memory->destroy(displs);
495
496 } else {
497 // NOTE: this is a big fat kludge
498 // but need to worry about more surfs in P files than in basefile
499 // could check for that earlier
500 bigint ntmp = surf->ntmp;
501 bigint nall;
502 MPI_Allreduce(&ntmp,&nall,1,MPI_SPARTA_BIGINT,MPI_SUM,world);
503 bigint nnew = nall / nprocs;
504 if (me < nall % nprocs) nnew++;
505 if (nnew > MAXSMALLINT)
506 error->one(FLERR,"Too many distributed surfs per processor");
507 int nown_new = nnew;
508
509 if (dim == 2) surf->redistribute_lines_temporary(nown_new);
510 else surf->redistribute_tris_temporary(nown_new);
511 }
512
513 // clean-up
514
515 MPI_Comm_free(&filecomm);
516 memory->sfree(surf->tmplines);
517 memory->sfree(surf->tmptris);
518
519 // surf counts, stats, error check
520
521 surf_counts();
522 }
523
524 /* ----------------------------------------------------------------------
525 check that surf count after file read is correct on all procs
526 ------------------------------------------------------------------------- */
527
surf_counts()528 void ReadSurf::surf_counts()
529 {
530 // set surf->nsurf based on single file header or base file
531 // set surf_new based on surf->nsurf
532
533 if (!multiproc) surf->nsurf = nsurf_total_old + nsurf_file;
534 else surf->nsurf = nsurf_total_old + nsurf_basefile;
535
536 if (distributed) {
537 bigint nnew = surf->nsurf / nprocs;
538 if (me < surf->nsurf % nprocs) nnew++;
539 nsurf_new = nnew;
540 } else nsurf_new = surf->nsurf;
541
542 // print stats
543
544 if (me == 0) {
545 if (!multiproc && npoint_file) {
546 if (screen) fprintf(screen," %d points\n",npoint_file);
547 if (logfile) fprintf(logfile," %d points\n",npoint_file);
548 }
549 if (dim == 2) {
550 if (screen) fprintf(screen," " BIGINT_FORMAT " lines\n",surf->nsurf);
551 if (logfile) fprintf(logfile," " BIGINT_FORMAT " lines\n",surf->nsurf);
552 }
553 if (dim == 3) {
554 if (screen) fprintf(screen," " BIGINT_FORMAT " triangles\n",surf->nsurf);
555 if (logfile) fprintf(logfile," " BIGINT_FORMAT " triangles\n",surf->nsurf);
556 }
557 }
558
559 if (distributed) {
560 bigint n = surf->nown;
561 bigint nall;
562 MPI_Allreduce(&n,&nall,1,MPI_SPARTA_BIGINT,MPI_SUM,world);
563 if (nall != surf->nsurf)
564 error->all(FLERR,"Surface element count does not match file");
565 } else {
566 if (surf->nlocal != surf->nsurf)
567 error->all(FLERR,"Surface element count does not match file");
568 }
569 }
570
571 /* ----------------------------------------------------------------------
572 read free-format header of data file
573 1st line and blank lines are skipped
574 non-blank lines are checked for header keywords and leading value is read
575 header ends with non-blank line containing no header keyword (or EOF)
576 return line with non-blank line (or empty line if EOF)
577 file does not have to contain points keyword
578 ------------------------------------------------------------------------- */
579
header()580 void ReadSurf::header()
581 {
582 int n;
583 char *ptr;
584
585 // skip 1st line of file
586
587 if (filereader) {
588 char *eof = fgets(line,MAXLINE,fp);
589 if (eof == NULL) error->one(FLERR,"Unexpected end of surf file");
590 }
591
592 npoint_file = 0;
593 int nline_file = 0;
594 int ntri_file = 0;
595
596 while (1) {
597
598 // read a line and bcast length
599
600 if (filereader) {
601 if (fgets(line,MAXLINE,fp) == NULL) n = 0;
602 else n = strlen(line) + 1;
603 }
604 MPI_Bcast(&n,1,MPI_INT,0,filecomm);
605
606 // if n = 0 then end-of-file so return with blank line
607
608 if (n == 0) {
609 line[0] = '\0';
610 return;
611 }
612
613 // bcast line
614
615 MPI_Bcast(line,n,MPI_CHAR,0,filecomm);
616
617 // trim anything from '#' onward
618 // if line is blank, continue
619
620 if ((ptr = strchr(line,'#'))) *ptr = '\0';
621 if (strspn(line," \t\n\r") == strlen(line)) continue;
622
623 // search line for header keyword and set corresponding variable
624 // else exit and line will store Section keyword
625
626 if (strstr(line,"points")) {
627 bigint bnpoint;
628 sscanf(line,BIGINT_FORMAT,&bnpoint);
629 if (bnpoint > MAXSMALLINT)
630 error->one(FLERR,"Read surf npoint is too large");
631 npoint_file = bnpoint;
632 } else if (strstr(line,"lines")) {
633 if (dim == 3)
634 error->one(FLERR,"Surf file cannot contain lines for 3d simulation");
635 bigint bnline;
636 sscanf(line,BIGINT_FORMAT,&bnline);
637 if (bnline > MAXSMALLINT) error->all(FLERR,"Read surf nline is too large");
638 nsurf_file = nline_file = bnline;
639 } else if (strstr(line,"triangles")) {
640 if (dim == 2)
641 error->one(FLERR,
642 "Surf file cannot contain triangles for 2d simulation");
643 bigint bntri;
644 sscanf(line,BIGINT_FORMAT,&bntri);
645 if (bntri > MAXSMALLINT) error->one(FLERR,"Read surf ntri is too large");
646 nsurf_file = ntri_file = bntri;
647
648 } else break;
649 }
650
651 if (dim == 2 && nline_file == 0)
652 error->one(FLERR,"Surf file does not contain lines");
653 if (dim == 3 && ntri_file == 0)
654 error->one(FLERR,"Surf file does not contain triangles");
655 }
656
657 /* ----------------------------------------------------------------------
658 read free-format base file for multiproc files
659 1st line and blank lines are skipped
660 non-blank lines are checked for header keywords and leading value is read
661 ------------------------------------------------------------------------- */
662
base(char * file)663 void ReadSurf::base(char *file)
664 {
665 int n;
666 char *ptr;
667
668 // open base file
669
670 if (me == 0) {
671 char *hfile;
672 hfile = new char[strlen(file) + 16];
673 char *ptr = strchr(file,'%');
674 *ptr = '\0';
675 sprintf(hfile,"%s%s%s",file,"base",ptr+1);
676 *ptr = '%';
677 fp = fopen(hfile,"r");
678 if (fp == NULL) {
679 char str[128];
680 sprintf(str,"Cannot open surface base file %s",hfile);
681 error->one(FLERR,str);
682 }
683 delete [] hfile;
684 }
685
686 // skip 1st line of file
687
688 if (me == 0) {
689 char *eof = fgets(line,MAXLINE,fp);
690 if (eof == NULL) error->one(FLERR,"Unexpected end of surf base file");
691 }
692
693 // read keywords from file
694
695 nfiles = 0;
696 bigint nline_basefile = 0;
697 bigint ntri_basefile = 0;
698
699 while (1) {
700
701 // read a line and bcast length
702
703 if (me == 0) {
704 if (fgets(line,MAXLINE,fp) == NULL) n = 0;
705 else n = strlen(line) + 1;
706 }
707 MPI_Bcast(&n,1,MPI_INT,0,world);
708
709 // if n = 0 then end-of-file so break
710
711 if (n == 0) break;
712
713 // bcast line
714
715 MPI_Bcast(line,n,MPI_CHAR,0,world);
716
717 // trim anything from '#' onward
718 // if line is blank, continue
719
720 if ((ptr = strchr(line,'#'))) *ptr = '\0';
721 if (strspn(line," \t\n\r") == strlen(line)) continue;
722
723 // search line for header keyword and set corresponding variable
724
725 if (strstr(line,"files")) {
726 sscanf(line,"%d",&nfiles);
727 } else if (strstr(line,"lines")) {
728 if (dim == 3)
729 error->all(FLERR,"Surf file cannot contain lines for 3d simulation");
730 sscanf(line,BIGINT_FORMAT,&nline_basefile);
731 nsurf_basefile = nline_basefile;
732 } else if (strstr(line,"triangles")) {
733 if (dim == 2)
734 error->all(FLERR,
735 "Surf file cannot contain triangles for 2d simulation");
736 sscanf(line,BIGINT_FORMAT,&ntri_basefile);
737 nsurf_basefile = ntri_basefile;
738
739 } else error->all(FLERR,"Invalid keyword in surf base file");
740 }
741
742 if (nfiles == 0)
743 error->all(FLERR,"Surf base file does not contain files");
744 if (dim == 2 && nline_basefile == 0)
745 error->all(FLERR,"Surf base file does not contain lines");
746 if (dim == 3 && ntri_basefile == 0)
747 error->all(FLERR,"Surf base file does not contain triangles");
748
749 if (me == 0) fclose(fp);
750 }
751
752 /* ----------------------------------------------------------------------
753 read a single input file, header and post-header sections
754 proc with filereader = 1 reads the file
755 filecomm = MPI communicator for all procs who share this file
756 storeflag = 0/1/2/3 = LOCAL/MINE/TEMPALL/TEMPSTRIDE
757 is passed to read points/lines/tris
758 LOCAL = store surfs in lines/tris
759 MINE = store surfs in mylines/mytris
760 TEMPALL/TEMPSTRIDE = store surfs in tmplines/tmptris
761 ------------------------------------------------------------------------- */
762
read_file(char * file,int storeflag)763 void ReadSurf::read_file(char *file, int storeflag)
764 {
765 // open file
766
767 if (filereader) open(file);
768
769 // read header
770
771 pts = NULL;
772 header();
773
774 // for single file & distributed surfs, allocate Surf mylines/mytris now
775 // since read lines/tri will store directly into it
776 // assumes added surf IDs are from 1 to N, checked when added
777
778 if (storeflag == MINE) {
779 bigint nnew = (surf->nsurf+nsurf_file) / nprocs;
780 if (me < (surf->nsurf+nsurf_file) % nprocs) nnew++;
781 if (nnew > MAXSMALLINT)
782 error->one(FLERR,"Too many distributed surfs per processor");
783 nsurf_new = nnew; // NOTE: this line is a kludge but needed for now
784 int maxown_old = surf->maxown;
785 surf->nown = surf->maxown = nnew;
786 surf->grow_own(maxown_old);
787 }
788
789 // read and store data from Points section
790
791 parse_keyword(1);
792
793 if (strcmp(keyword,"Points") == 0) {
794 if (npoint_file == 0)
795 error->all(FLERR,"Read_surf file has no points keyword");
796 read_points();
797 parse_keyword(0);
798 } else if (npoint_file)
799 error->one(FLERR,"Read_surf file has no Points section");
800
801 // read and store data from Lines or Triangles section
802
803 if (dim == 2) {
804 if (strcmp(keyword,"Lines") != 0)
805 error->one(FLERR,"Read_surf did not find Lines section of surf file");
806 read_lines(storeflag);
807 } else {
808 if (strcmp(keyword,"Triangles") != 0)
809 error->one(FLERR,"Read_surf did not find Triangles section of surf file");
810 read_tris(storeflag);
811 }
812
813 // can now free Points
814
815 if (npoint_file) memory->sfree(pts);
816
817 // close file
818
819 if (filereader) {
820 if (compressed) pclose(fp);
821 else fclose(fp);
822 }
823 }
824
825 /* ----------------------------------------------------------------------
826 read all points from a single file
827 store in local pts data struct
828 ------------------------------------------------------------------------- */
829
read_points()830 void ReadSurf::read_points()
831 {
832 int i,m,n,nchunk;
833 char *next,*buf;
834
835 bigint nbytes = (bigint) npoint_file * sizeof(Point);
836 pts = (Point *) memory->smalloc(nbytes,"readsurf:pts");
837
838 // read and broadcast one CHUNK of points at a time
839
840 int nread = 0;
841
842 while (nread < npoint_file) {
843 if (npoint_file-nread > CHUNK) nchunk = CHUNK;
844 else nchunk = npoint_file - nread;
845 if (filereader) {
846 char *eof;
847 m = 0;
848 for (i = 0; i < nchunk; i++) {
849 eof = fgets(&buffer[m],MAXLINE,fp);
850 if (eof == NULL) error->one(FLERR,"Unexpected end of surf file");
851 m += strlen(&buffer[m]);
852 }
853 m++;
854 }
855 MPI_Bcast(&m,1,MPI_INT,0,filecomm);
856 MPI_Bcast(buffer,m,MPI_CHAR,0,filecomm);
857
858 buf = buffer;
859 next = strchr(buf,'\n');
860 *next = '\0';
861 int nwords = input->count_words(buf);
862 *next = '\n';
863
864 if (dim == 2 && nwords != 3)
865 error->one(FLERR,"Incorrect point format in surf file");
866 if (dim == 3 && nwords != 4)
867 error->one(FLERR,"Incorrect point format in surf file");
868
869 n = nread;
870
871 for (int i = 0; i < nchunk; i++) {
872 next = strchr(buf,'\n');
873 strtok(buf," \t\n\r\f");
874 pts[n].x[0] = input->numeric(FLERR,strtok(NULL," \t\n\r\f"));
875 pts[n].x[1] = input->numeric(FLERR,strtok(NULL," \t\n\r\f"));
876 if (dim == 3)
877 pts[n].x[2] = input->numeric(FLERR,strtok(NULL," \t\n\r\f"));
878 else pts[n].x[2] = 0.0;
879 n++;
880 buf = next + 1;
881 }
882
883 nread += nchunk;
884 }
885 }
886
887 /* ----------------------------------------------------------------------
888 read Lines section of file
889 storeflag determines how each line is stored
890 ------------------------------------------------------------------------- */
891
read_lines(int storeflag)892 void ReadSurf::read_lines(int storeflag)
893 {
894 int i,m,nchunk,type,p1,p2;
895 surfint id;
896 double x1[2],x2[2];
897 char *next,*buf;
898
899 // read and broadcast one CHUNK of lines at a time
900
901 int nread = 0;
902
903 while (nread < nsurf_file) {
904 if (nsurf_file - nread > CHUNK) nchunk = CHUNK;
905 else nchunk = nsurf_file - nread;
906 if (filereader) {
907 char *eof;
908 m = 0;
909 for (i = 0; i < nchunk; i++) {
910 eof = fgets(&buffer[m],MAXLINE,fp);
911 if (eof == NULL) error->one(FLERR,"Unexpected end of surf file");
912 m += strlen(&buffer[m]);
913 }
914 m++;
915 }
916 MPI_Bcast(&m,1,MPI_INT,0,filecomm);
917 MPI_Bcast(buffer,m,MPI_CHAR,0,filecomm);
918
919 buf = buffer;
920 next = strchr(buf,'\n');
921 *next = '\0';
922 int nwords = input->count_words(buf);
923 *next = '\n';
924
925 // allow for optional type in each line element
926 // different logic depending on whether points included with each line
927
928 int typeflag = 0;
929
930 if (npoint_file) {
931 if (nwords != 3 && nwords != 4)
932 error->all(FLERR,"Incorrect line format in surf file");
933 if (nwords == 4) typeflag = 1;
934 } else {
935 if (nwords != 5 && nwords != 6)
936 error->all(FLERR,"Incorrect line format in surf file");
937 if (nwords == 6) typeflag = 1;
938 }
939
940 // if Points section in file, each read line has indices into it
941 // augment line IDs by previously read surfaces
942 // for storeflag = MINE, only store if I own surf ID
943
944 if (npoint_file) {
945 for (int i = 0; i < nchunk; i++) {
946 next = strchr(buf,'\n');
947 id = ATOSURFINT(strtok(buf," \t\n\r\f"));
948 id += nsurf_total_old;
949 if (typeflag) type = input->inumeric(FLERR,strtok(NULL," \t\n\r\f"));
950 else type = 1;
951
952 p1 = input->inumeric(FLERR,strtok(NULL," \t\n\r\f"));
953 p2 = input->inumeric(FLERR,strtok(NULL," \t\n\r\f"));
954 if (p1 < 1 || p1 > npoint_file || p2 < 1 || p2 > npoint_file || p1 == p2)
955 error->all(FLERR,"Invalid point index in Lines section");
956
957 if (storeflag == LOCAL) {
958 surf->add_line(id,type,pts[p1-1].x,pts[p2-1].x);
959 } else if (storeflag == MINE) {
960 if ((id-1) % nprocs == me) {
961 if ((id-1) / nprocs >= nsurf_new)
962 error->one(FLERR,"Invalid surf ID in read_surf file");
963 surf->add_line_own(id,type,pts[p1-1].x,pts[p2-1].x);
964 }
965 } else if (storeflag == TEMPALL) {
966 surf->add_line_temporary(id,type,pts[p1-1].x,pts[p2-1].x);
967 } else if (storeflag == TEMPSTRIDE) {
968 if (nread+i % nprocs_file == me_file)
969 surf->add_line_temporary(id,type,pts[p1-1].x,pts[p2-1].x);
970 }
971
972 buf = next + 1;
973 }
974
975 // if no Points section, each read line has point coords
976 // augment line IDs by previously read surfaces
977 // for storeflag = MINE, only store if I own surf ID
978
979 } else {
980 for (int i = 0; i < nchunk; i++) {
981 next = strchr(buf,'\n');
982 id = ATOSURFINT(strtok(buf," \t\n\r\f"));
983 id += nsurf_total_old;
984 if (typeflag) type = input->inumeric(FLERR,strtok(NULL," \t\n\r\f"));
985 else type = 1;
986
987 x1[0] = input->numeric(FLERR,strtok(NULL," \t\n\r\f"));
988 x1[1] = input->numeric(FLERR,strtok(NULL," \t\n\r\f"));
989 x2[0] = input->numeric(FLERR,strtok(NULL," \t\n\r\f"));
990 x2[1] = input->numeric(FLERR,strtok(NULL," \t\n\r\f"));
991
992 if (storeflag == LOCAL) {
993 surf->add_line(id,type,x1,x2);
994 } else if (storeflag == MINE) {
995 if ((id-1) % nprocs == me) {
996 if ((id-1) / nprocs >= nsurf_new)
997 error->one(FLERR,"Invalid surf ID in read_surf file");
998 surf->add_line_own(id,type,x1,x2);
999 }
1000 } else if (storeflag == TEMPALL) {
1001 surf->add_line_temporary(id,type,x1,x2);
1002 } else if (storeflag == TEMPSTRIDE) {
1003 if ((nread+i) % nprocs_file == me_file)
1004 surf->add_line_temporary(id,type,x1,x2);
1005 }
1006
1007 buf = next + 1;
1008 }
1009 }
1010
1011 nread += nchunk;
1012 }
1013 }
1014
1015 /* ----------------------------------------------------------------------
1016 read Triangles section of file
1017 storeflag determines how each tri is stored
1018 ------------------------------------------------------------------------- */
1019
read_tris(int storeflag)1020 void ReadSurf::read_tris(int storeflag)
1021 {
1022 int i,m,nchunk,type,p1,p2,p3,ipt;
1023 surfint id;
1024 double x1[3],x2[3],x3[3];
1025 char *next,*buf;
1026
1027 // read and broadcast one CHUNK of triangles at a time
1028
1029 int nread = 0;
1030
1031 // DEBUG
1032 int count = 0;
1033
1034 while (nread < nsurf_file) {
1035 if (nsurf_file - nread > CHUNK) nchunk = CHUNK;
1036 else nchunk = nsurf_file - nread;
1037 if (filereader) {
1038 char *eof;
1039 m = 0;
1040 for (i = 0; i < nchunk; i++) {
1041 eof = fgets(&buffer[m],MAXLINE,fp);
1042 if (eof == NULL) error->one(FLERR,"Unexpected end of surf file");
1043 m += strlen(&buffer[m]);
1044 }
1045 m++;
1046 }
1047 MPI_Bcast(&m,1,MPI_INT,0,filecomm);
1048 MPI_Bcast(buffer,m,MPI_CHAR,0,filecomm);
1049
1050 buf = buffer;
1051 next = strchr(buf,'\n');
1052 *next = '\0';
1053 int nwords = input->count_words(buf);
1054 *next = '\n';
1055
1056 // allow for optional type in each line element
1057 // different logic depending on whether points included with each line
1058
1059 int typeflag = 0;
1060
1061 if (npoint_file) {
1062 if (nwords != 4 && nwords != 5)
1063 error->all(FLERR,"Incorrect triangle format in surf file");
1064 if (nwords == 5) typeflag = 1;
1065 } else {
1066 if (nwords != 10 && nwords != 11)
1067 error->all(FLERR,"Incorrect triangle format in surf file");
1068 if (nwords == 11) typeflag = 1;
1069 }
1070
1071 // if Points section in file, each read line has indices into it
1072 // augment tri IDs by previously read surfaces
1073 // for storeflag = MINE, only store if I own surf ID
1074
1075 if (npoint_file) {
1076 for (int i = 0; i < nchunk; i++) {
1077 next = strchr(buf,'\n');
1078 id = ATOSURFINT(strtok(buf," \t\n\r\f"));
1079 id += nsurf_total_old;
1080 if (typeflag) type = input->inumeric(FLERR,strtok(NULL," \t\n\r\f"));
1081 else type = 1;
1082
1083 p1 = input->inumeric(FLERR,strtok(NULL," \t\n\r\f"));
1084 p2 = input->inumeric(FLERR,strtok(NULL," \t\n\r\f"));
1085 p3 = input->inumeric(FLERR,strtok(NULL," \t\n\r\f"));
1086 if (p1 < 1 || p1 > npoint_file || p2 < 1 || p2 > npoint_file ||
1087 p3 < 1 || p3 > npoint_file || p1 == p2 || p2 == p3)
1088 error->all(FLERR,"Invalid point index in Triangles section");
1089
1090 if (storeflag == LOCAL) {
1091 surf->add_tri(id,type,pts[p1-1].x,pts[p2-1].x,pts[p3-1].x);
1092 } else if (storeflag == MINE) {
1093 if ((id-1) % nprocs == me) {
1094 if ((id-1) / nprocs >= nsurf_new)
1095 error->one(FLERR,"Invalid surf ID in read_surf file");
1096 surf->add_tri_own(id,type,pts[p1-1].x,pts[p2-1].x,pts[p3-1].x);
1097 }
1098 } else if (storeflag == TEMPALL) {
1099 surf->add_tri_temporary(id,type,pts[p1-1].x,pts[p2-1].x,pts[p3-1].x);
1100 } else if (storeflag == TEMPSTRIDE) {
1101 if (nread+i % nprocs_file == me_file)
1102 surf->add_tri_temporary(id,type,pts[p1-1].x,pts[p2-1].x,pts[p3-1].x);
1103 }
1104
1105 buf = next + 1;
1106 }
1107
1108 // if no Points section, each read line has point coords
1109 // augment tri IDs by previously read surfaces
1110 // for storeflag = MINE, only store if I own surf ID
1111
1112 } else {
1113 for (int i = 0; i < nchunk; i++) {
1114 next = strchr(buf,'\n');
1115 id = ATOSURFINT(strtok(buf," \t\n\r\f"));
1116 id += nsurf_total_old;
1117 if (typeflag) type = input->inumeric(FLERR,strtok(NULL," \t\n\r\f"));
1118 else type = 1;
1119
1120 x1[0] = input->numeric(FLERR,strtok(NULL," \t\n\r\f"));
1121 x1[1] = input->numeric(FLERR,strtok(NULL," \t\n\r\f"));
1122 x1[2] = input->numeric(FLERR,strtok(NULL," \t\n\r\f"));
1123 x2[0] = input->numeric(FLERR,strtok(NULL," \t\n\r\f"));
1124 x2[1] = input->numeric(FLERR,strtok(NULL," \t\n\r\f"));
1125 x2[2] = input->numeric(FLERR,strtok(NULL," \t\n\r\f"));
1126 x3[0] = input->numeric(FLERR,strtok(NULL," \t\n\r\f"));
1127 x3[1] = input->numeric(FLERR,strtok(NULL," \t\n\r\f"));
1128 x3[2] = input->numeric(FLERR,strtok(NULL," \t\n\r\f"));
1129
1130 if (storeflag == LOCAL) {
1131 surf->add_tri(id,type,x1,x2,x3);
1132 } else if (storeflag == MINE) {
1133 if ((id-1) % nprocs == me) {
1134 if ((id-1) / nprocs >= nsurf_new)
1135 error->one(FLERR,"Invalid surf ID in read_surf file");
1136 surf->add_tri_own(id,type,x1,x2,x3);
1137 }
1138 } else if (storeflag == TEMPALL) {
1139 surf->add_tri_temporary(id,type,x1,x2,x3);
1140 } else if (storeflag == TEMPSTRIDE) {
1141 if ((nread+i) % nprocs_file == me_file) {
1142 surf->add_tri_temporary(id,type,x1,x2,x3);
1143 count++;
1144 }
1145 }
1146
1147 buf = next + 1;
1148 }
1149 }
1150
1151 nread += nchunk;
1152 }
1153 }
1154
1155 // -----------------------
1156 // transform surface elements
1157 // -----------------------
1158
1159 /* ----------------------------------------------------------------------
1160 apply optional keywords for geometric transformations
1161 store optional keywords for group and type information
1162 store optional keyword for file output
1163 ------------------------------------------------------------------------- */
1164
process_args(int start,int narg,char ** arg)1165 void ReadSurf::process_args(int start, int narg, char **arg)
1166 {
1167 origin[0] = origin[1] = origin[2] = 0.0;
1168 int grouparg = 0;
1169 int typeadd = 0;
1170 partflag = NONE;
1171 filearg = 0;
1172
1173 int iarg = start;
1174 while (iarg < narg) {
1175 if (strcmp(arg[iarg],"origin") == 0) {
1176 if (iarg+4 > narg) error->all(FLERR,"Invalid read_surf command");
1177 double ox = atof(arg[iarg+1]);
1178 double oy = atof(arg[iarg+2]);
1179 double oz = atof(arg[iarg+3]);
1180 if (dim == 2 && oz != 0.0)
1181 error->all(FLERR,"Invalid read_surf geometry transformation "
1182 "for 2d simulation");
1183 origin[0] = ox;
1184 origin[1] = oy;
1185 origin[2] = oz;
1186 iarg += 4;
1187 } else if (strcmp(arg[iarg],"trans") == 0) {
1188 if (iarg+4 > narg) error->all(FLERR,"Invalid read_surf command");
1189 double dx = input->numeric(FLERR,arg[iarg+1]);
1190 double dy = input->numeric(FLERR,arg[iarg+2]);
1191 double dz = input->numeric(FLERR,arg[iarg+3]);
1192 if (dim == 2 && dz != 0.0)
1193 error->all(FLERR,"Invalid read_surf geometry transformation "
1194 "for 2d simulation");
1195 origin[0] += dx;
1196 origin[1] += dy;
1197 origin[2] += dz;
1198 translate(dx,dy,dz);
1199 iarg += 4;
1200 } else if (strcmp(arg[iarg],"atrans") == 0) {
1201 if (iarg+4 > narg) error->all(FLERR,"Invalid read_surf command");
1202 double ax = input->numeric(FLERR,arg[iarg+1]);
1203 double ay = input->numeric(FLERR,arg[iarg+2]);
1204 double az = input->numeric(FLERR,arg[iarg+3]);
1205 if (dim == 2 && az != 0.0)
1206 error->all(FLERR,"Invalid read_surf geometry transformation "
1207 "for 2d simulation");
1208 double dx = ax - origin[0];
1209 double dy = ay - origin[1];
1210 double dz = az - origin[2];
1211 origin[0] = ax;
1212 origin[1] = ay;
1213 origin[2] = az;
1214 translate(dx,dy,dz);
1215 iarg += 4;
1216 } else if (strcmp(arg[iarg],"ftrans") == 0) {
1217 if (iarg+4 > narg) error->all(FLERR,"Invalid read_surf command");
1218 double fx = input->numeric(FLERR,arg[iarg+1]);
1219 double fy = input->numeric(FLERR,arg[iarg+2]);
1220 double fz = input->numeric(FLERR,arg[iarg+3]);
1221 if (dim == 2 && fz != 0.5)
1222 error->all(FLERR,"Invalid read_surf geometry transformation "
1223 "for 2d simulation");
1224 double ax = domain->boxlo[0] + fx*domain->xprd;
1225 double ay = domain->boxlo[1] + fy*domain->yprd;
1226 double az;
1227 if (dim == 3) az = domain->boxlo[2] + fz*domain->zprd;
1228 else az = 0.0;
1229 double dx = ax - origin[0];
1230 double dy = ay - origin[1];
1231 double dz = az - origin[2];
1232 origin[0] = ax;
1233 origin[1] = ay;
1234 origin[2] = az;
1235 translate(dx,dy,dz);
1236 iarg += 4;
1237 } else if (strcmp(arg[iarg],"scale") == 0) {
1238 if (iarg+4 > narg) error->all(FLERR,"Invalid read_surf command");
1239 double sx = input->numeric(FLERR,arg[iarg+1]);
1240 double sy = input->numeric(FLERR,arg[iarg+2]);
1241 double sz = input->numeric(FLERR,arg[iarg+3]);
1242 if (dim == 2 && sz != 1.0)
1243 error->all(FLERR,"Invalid read_surf geometry transformation "
1244 "for 2d simulation");
1245 scale(sx,sy,sz);
1246 iarg += 4;
1247 } else if (strcmp(arg[iarg],"rotate") == 0) {
1248 if (iarg+5 > narg) error->all(FLERR,"Invalid read_surf command");
1249 double theta = input->numeric(FLERR,arg[iarg+1]);
1250 double rx = input->numeric(FLERR,arg[iarg+2]);
1251 double ry = input->numeric(FLERR,arg[iarg+3]);
1252 double rz = input->numeric(FLERR,arg[iarg+4]);
1253 if (dim == 2 && (rx != 0.0 || ry != 0.0 || rz != 1.0))
1254 error->all(FLERR,"Invalid read_surf geometry transformation "
1255 "for 2d simulation");
1256 if (rx == 0.0 && ry == 0.0 && rz == 0.0)
1257 error->all(FLERR,"Invalid read_surf geometry transformation "
1258 "for 2d simulation");
1259 rotate(theta,rx,ry,rz);
1260 iarg += 5;
1261 } else if (strcmp(arg[iarg],"invert") == 0) {
1262 invert();
1263 iarg += 1;
1264 } else if (strcmp(arg[iarg],"clip") == 0) {
1265 double frac = 0.0;
1266 if (iarg+1 < narg) {
1267 char c = arg[iarg+1][0];
1268 if (isdigit(c) || c == '-' || c == '+' || c == '.') {
1269 frac = input->numeric(FLERR,arg[iarg+1]);
1270 if (frac < 0.0 || frac >= 0.5)
1271 error->all(FLERR,"Invalid read_surf command");
1272 iarg++;
1273 }
1274 }
1275 if (frac > 0.0) push_points_to_boundary(frac);
1276 if (dim == 2) clip2d();
1277 else clip3d();
1278 iarg++;
1279
1280 } else if (strcmp(arg[iarg],"group") == 0) {
1281 if (iarg+2 > narg) error->all(FLERR,"Invalid read_surf command");
1282 grouparg = iarg+1;
1283 iarg += 2;
1284
1285 } else if (strcmp(arg[iarg],"typeadd") == 0) {
1286 if (iarg+2 > narg) error->all(FLERR,"Invalid read_surf command");
1287 typeadd = input->inumeric(FLERR,arg[iarg+1]);
1288 if (typeadd < 0) error->all(FLERR,"Invalid read_surf command");
1289 iarg += 2;
1290
1291 } else if (strcmp(arg[iarg],"particle") == 0) {
1292 if (iarg+2 > narg) error->all(FLERR,"Invalid read_surf command");
1293 if (strcmp(arg[iarg+1],"none") == 0) partflag = NONE;
1294 else if (strcmp(arg[iarg+1],"check") == 0) partflag = CHECK;
1295 else if (strcmp(arg[iarg+1],"keep") == 0) partflag = KEEP;
1296 else error->all(FLERR,"Invalid read_surf command");
1297 iarg += 2;
1298
1299 } else if (strcmp(arg[iarg],"transparent") == 0) {
1300 transparent();
1301 iarg++;
1302
1303 // file must be last keyword, else WriteSurf will flag error
1304
1305 } else if (strcmp(arg[iarg],"file") == 0) {
1306 if (iarg+2 > narg) error->all(FLERR,"Invalid read_surf command");
1307 filearg = iarg+1;
1308 iarg = narg;
1309
1310 } else error->all(FLERR,"Invalid read_surf command");
1311 }
1312
1313 // error test on particles
1314
1315 if (particle->exist && partflag == NONE)
1316 error->all(FLERR,"Using read_surf particle none when particles exist");
1317
1318 // if specified, apply group and typeadd keywords
1319 // these reset per-element mask/type info
1320
1321 if (grouparg) {
1322 int igroup = surf->find_group(arg[grouparg]);
1323 if (igroup < 0) igroup = surf->add_group(arg[grouparg]);
1324 int groupbit = surf->bitmask[igroup];
1325 if (dim == 2) {
1326 Surf::Line *lines;
1327 if (distributed) lines = surf->mylines;
1328 else lines = surf->lines;
1329 for (int i = nsurf_old; i < nsurf_new; i++) lines[i].mask |= groupbit;
1330 } else {
1331 Surf::Tri *tris;
1332 if (distributed) tris = surf->mytris;
1333 else tris = surf->tris;
1334 for (int i = nsurf_old; i < nsurf_new; i++) tris[i].mask |= groupbit;
1335 }
1336 }
1337
1338 if (typeadd) {
1339 if (dim == 2) {
1340 Surf::Line *lines;
1341 if (distributed) lines = surf->mylines;
1342 else lines = surf->lines;
1343 for (int i = nsurf_old; i < nsurf_new; i++) lines[i].type += typeadd;
1344 } else {
1345 Surf::Tri *tris;
1346 if (distributed) tris = surf->mytris;
1347 else tris = surf->tris;
1348 for (int i = nsurf_old; i < nsurf_new; i++) tris[i].type += typeadd;
1349 }
1350 }
1351 }
1352
1353 /* ----------------------------------------------------------------------
1354 translate vertices by (dx,dy,dz)
1355 for 2d, dz will be 0.0
1356 ------------------------------------------------------------------------- */
1357
translate(double dx,double dy,double dz)1358 void ReadSurf::translate(double dx, double dy, double dz)
1359 {
1360 if (dim == 2) {
1361 Surf::Line *lines;
1362 if (distributed) lines = surf->mylines;
1363 else lines = surf->lines;
1364
1365 for (int i = nsurf_old; i < nsurf_new; i++) {
1366 lines[i].p1[0] += dx;
1367 lines[i].p1[1] += dy;
1368 lines[i].p1[2] += dz;
1369 lines[i].p2[0] += dx;
1370 lines[i].p2[1] += dy;
1371 lines[i].p2[2] += dz;
1372 }
1373
1374 } else if (dim == 3) {
1375 Surf::Tri *tris;
1376 if (distributed) tris = surf->mytris;
1377 else tris = surf->tris;
1378
1379 for (int i = nsurf_old; i < nsurf_new; i++) {
1380 tris[i].p1[0] += dx;
1381 tris[i].p1[1] += dy;
1382 tris[i].p1[2] += dz;
1383 tris[i].p2[0] += dx;
1384 tris[i].p2[1] += dy;
1385 tris[i].p2[2] += dz;
1386 tris[i].p3[0] += dx;
1387 tris[i].p3[1] += dy;
1388 tris[i].p3[2] += dz;
1389 }
1390 }
1391 }
1392
1393 /* ----------------------------------------------------------------------
1394 scale vertices by (sx,sy,sz) around origin
1395 for 2d, do not reset x[2] to avoid epsilon change
1396 ------------------------------------------------------------------------- */
1397
scale(double sx,double sy,double sz)1398 void ReadSurf::scale(double sx, double sy, double sz)
1399 {
1400 if (dim == 2) {
1401 Surf::Line *lines;
1402 if (distributed) lines = surf->mylines;
1403 else lines = surf->lines;
1404
1405 for (int i = nsurf_old; i < nsurf_new; i++) {
1406 lines[i].p1[0] = sx*(lines[i].p1[0]-origin[0]) + origin[0];
1407 lines[i].p1[1] = sy*(lines[i].p1[1]-origin[1]) + origin[1];
1408 lines[i].p2[0] = sx*(lines[i].p2[0]-origin[0]) + origin[0];
1409 lines[i].p2[1] = sy*(lines[i].p2[1]-origin[1]) + origin[1];
1410 }
1411
1412 } else if (dim == 3) {
1413 Surf::Tri *tris;
1414 if (distributed) tris = surf->mytris;
1415 else tris = surf->tris;
1416
1417 for (int i = nsurf_old; i < nsurf_new; i++) {
1418 tris[i].p1[0] = sx*(tris[i].p1[0]-origin[0]) + origin[0];
1419 tris[i].p1[1] = sy*(tris[i].p1[1]-origin[1]) + origin[1];
1420 tris[i].p1[2] = sz*(tris[i].p1[2]-origin[2]) + origin[2];
1421 tris[i].p2[0] = sx*(tris[i].p2[0]-origin[0]) + origin[0];
1422 tris[i].p2[1] = sy*(tris[i].p2[1]-origin[1]) + origin[1];
1423 tris[i].p2[2] = sz*(tris[i].p2[2]-origin[2]) + origin[2];
1424 tris[i].p3[0] = sx*(tris[i].p3[0]-origin[0]) + origin[0];
1425 tris[i].p3[1] = sy*(tris[i].p3[1]-origin[1]) + origin[1];
1426 tris[i].p3[2] = sz*(tris[i].p3[2]-origin[2]) + origin[2];
1427 }
1428 }
1429 }
1430
1431 /* ----------------------------------------------------------------------
1432 rotate vertices around origin
1433 for 2d, do not reset x[2] to avoid epsilon change
1434 ------------------------------------------------------------------------- */
1435
rotate(double theta,double rx,double ry,double rz)1436 void ReadSurf::rotate(double theta, double rx, double ry, double rz)
1437 {
1438 double r[3],q[4],d[3],dnew[3];
1439 double rotmat[3][3];
1440
1441 theta *= MY_PI/180.0;
1442
1443 r[0] = rx; r[1] = ry; r[2] = rz;
1444 MathExtra::norm3(r);
1445 MathExtra::axisangle_to_quat(r,theta,q);
1446 MathExtra::quat_to_mat(q,rotmat);
1447
1448 if (dim == 2) {
1449 Surf::Line *lines;
1450 if (distributed) lines = surf->mylines;
1451 else lines = surf->lines;
1452
1453 for (int i = nsurf_old; i < nsurf_new; i++) {
1454 d[0] = lines[i].p1[0] - origin[0];
1455 d[1] = lines[i].p1[1] - origin[1];
1456 d[2] = lines[i].p1[2] - origin[2];
1457 MathExtra::matvec(rotmat,d,dnew);
1458 lines[i].p1[0] = dnew[0] + origin[0];
1459 lines[i].p1[1] = dnew[1] + origin[1];
1460
1461 d[0] = lines[i].p2[0] - origin[0];
1462 d[1] = lines[i].p2[1] - origin[1];
1463 d[2] = lines[i].p2[2] - origin[2];
1464 MathExtra::matvec(rotmat,d,dnew);
1465 lines[i].p2[0] = dnew[0] + origin[0];
1466 lines[i].p2[1] = dnew[1] + origin[1];
1467 }
1468 } else if (dim == 3) {
1469 Surf::Tri *tris;
1470 if (distributed) tris = surf->mytris;
1471 else tris = surf->tris;
1472
1473 for (int i = nsurf_old; i < nsurf_new; i++) {
1474 d[0] = tris[i].p1[0] - origin[0];
1475 d[1] = tris[i].p1[1] - origin[1];
1476 d[2] = tris[i].p1[2] - origin[2];
1477 MathExtra::matvec(rotmat,d,dnew);
1478 tris[i].p1[0] = dnew[0] + origin[0];
1479 tris[i].p1[1] = dnew[1] + origin[1];
1480 tris[i].p1[2] = dnew[2] + origin[2];
1481
1482 d[0] = tris[i].p2[0] - origin[0];
1483 d[1] = tris[i].p2[1] - origin[1];
1484 d[2] = tris[i].p2[2] - origin[2];
1485 MathExtra::matvec(rotmat,d,dnew);
1486 tris[i].p2[0] = dnew[0] + origin[0];
1487 tris[i].p2[1] = dnew[1] + origin[1];
1488 tris[i].p2[2] = dnew[2] + origin[2];
1489
1490 d[0] = tris[i].p3[0] - origin[0];
1491 d[1] = tris[i].p3[1] - origin[1];
1492 d[2] = tris[i].p3[2] - origin[2];
1493 MathExtra::matvec(rotmat,d,dnew);
1494 tris[i].p3[0] = dnew[0] + origin[0];
1495 tris[i].p3[1] = dnew[1] + origin[1];
1496 tris[i].p3[2] = dnew[2] + origin[2];
1497 }
1498 }
1499 }
1500
1501 /* ----------------------------------------------------------------------
1502 invert vertex ordering within each line or tri
1503 this flips direction of surface normal
1504 ------------------------------------------------------------------------- */
1505
invert()1506 void ReadSurf::invert()
1507 {
1508 int tmp;
1509 double x[3];
1510
1511 if (dim == 2) {
1512 Surf::Line *lines;
1513 if (distributed) lines = surf->mylines;
1514 else lines = surf->lines;
1515
1516 for (int i = nsurf_old; i < nsurf_new; i++) {
1517 memcpy(x,lines[i].p1,3*sizeof(double));
1518 memcpy(lines[i].p1,lines[i].p2,3*sizeof(double));
1519 memcpy(lines[i].p2,x,3*sizeof(double));
1520 }
1521
1522 } else if (dim == 3) {
1523 Surf::Tri *tris;
1524 if (distributed) tris = surf->mytris;
1525 else tris = surf->tris;
1526
1527 for (int i = nsurf_old; i < nsurf_new; i++) {
1528 memcpy(x,tris[i].p2,3*sizeof(double));
1529 memcpy(tris[i].p2,tris[i].p3,3*sizeof(double));
1530 memcpy(tris[i].p3,x,3*sizeof(double));
1531 }
1532 }
1533 }
1534
1535 /* ----------------------------------------------------------------------
1536 clip all lines so fit inside simulation box
1537 may discard some lines completely
1538 ------------------------------------------------------------------------- */
1539
clip2d()1540 void ReadSurf::clip2d()
1541 {
1542 int i,dim,side,flag1,flag2;
1543 double value,param;
1544 double x[3];
1545 double *p1,*p2,*inpt,*outpt;
1546
1547 Surf::Line *lines;
1548 if (distributed) lines = surf->mylines;
1549 else lines = surf->lines;
1550
1551 int *discard;
1552 memory->create(discard,nsurf_new-nsurf_old,"readsurf:discard");
1553 for (i = nsurf_old; i < nsurf_new; i++) discard[i-nsurf_old] = 0;
1554 int discardflag = 0;
1555
1556 double *boxlo = domain->boxlo;
1557 double *boxhi = domain->boxhi;
1558
1559 for (int iface = 0; iface < 4; iface++) {
1560 dim = iface / 2;
1561 side = iface % 2;
1562 if (side == 0) value = boxlo[dim];
1563 else value = boxhi[dim];
1564
1565 // flag each point as (1,0,-1) = outside,on,inside clipping edge
1566 // keep line unchanged:
1567 // if both pts are inside or on clipping edge
1568 // at least one pt is inside clipping edge
1569 // discard line:
1570 // if both pts are either outside or on clipping edge
1571 // straddle line:
1572 // one pt is inside, one pt is outside
1573 // replace outside pt with pt on the clipping edge
1574
1575 for (i = nsurf_old; i < nsurf_new; i++) {
1576 if (discard[i-nsurf_old]) continue;
1577
1578 p1 = lines[i].p1;
1579 p2 = lines[i].p2;
1580
1581 if (side == 0) {
1582 if (p1[dim] < value) flag1 = 1;
1583 else if (p1[dim] > value) flag1 = -1;
1584 else flag1 = 0;
1585 if (p2[dim] < value) flag2 = 1;
1586 else if (p2[dim] > value) flag2 = -1;
1587 else flag2 = 0;
1588 } else {
1589 if (p1[dim] > value) flag1 = 1;
1590 else if (p1[dim] < value) flag1 = -1;
1591 else flag1 = 0;
1592 if (p2[dim] > value) flag2 = 1;
1593 else if (p2[dim] < value) flag2 = -1;
1594 else flag2 = 0;
1595 }
1596
1597 if (flag1 < 0 && flag2 <= 0) continue;
1598 if (flag1 <= 0 && flag2 < 0) continue;
1599
1600 if (flag1 >= 0 && flag2 >= 0) {
1601 discard[i-nsurf_old] = 1;
1602 discardflag = 1;
1603 continue;
1604 }
1605
1606 if (flag1 < 0) {
1607 inpt = p1;
1608 outpt = p2;
1609 } else {
1610 inpt = p2;
1611 outpt = p1;
1612 }
1613
1614 // reset outpt to intersection of line with clipping edge
1615 // last line insures outpt is exactly on clipping edge
1616
1617 param = (value-inpt[dim]) / (outpt[dim]-inpt[dim]);
1618 outpt[0] = inpt[0] + param*(outpt[0]-inpt[0]);
1619 outpt[1] = inpt[1] + param*(outpt[1]-inpt[1]);
1620 outpt[dim] = value;
1621 }
1622 }
1623
1624 // remove deleted lines
1625
1626 int n = nsurf_old;
1627 for (i = nsurf_old; i < nsurf_new; i++) {
1628 if (!discard[i-nsurf_old]) {
1629 if (n != i) memcpy(&lines[n],&lines[i],sizeof(Surf::Line));
1630 n++;
1631 }
1632 }
1633 nsurf_new = n;
1634
1635 // clean up
1636
1637 memory->destroy(discard);
1638
1639 // reset nsurf,nlocal,nown counts in Surf
1640
1641 if (!distributed) surf->nsurf = surf->nlocal = nsurf_new;
1642 else {
1643 surf->nown = nsurf_new;
1644 bigint bnown = surf->nown;
1645 MPI_Allreduce(&bnown,&surf->nsurf,1,MPI_SPARTA_BIGINT,MPI_SUM,world);
1646 }
1647
1648 // if discarded any surfs:
1649 // if non-distributed:
1650 // renumber all IDs for new surfs from nsurf_old to nsurf_new
1651 // if distributed:
1652 // MPI_Scan to find unique IDs for me,
1653 // reset IDs for new surfs in mylines,
1654 // perform rendezvous to send just new surfs to new owners
1655 // reset nsurf_new, surf->nsurf
1656
1657 int discardany;
1658 MPI_Allreduce(&discardflag,&discardany,1,MPI_INT,MPI_MAX,world);
1659
1660 if (discardany) {
1661 if (!distributed) {
1662 for (i = nsurf_old; i < nsurf_new; i++) lines[i].id = i+1;
1663
1664 } else {
1665 bigint delta = nsurf_new - nsurf_old;
1666 bigint offset;
1667 MPI_Scan(&delta,&offset,1,MPI_SPARTA_BIGINT,MPI_SUM,world);
1668 offset -= delta;
1669 for (i = nsurf_old; i < nsurf_new; i++)
1670 lines[i].id = static_cast<surfint>
1671 (nsurf_total_old+offset + i-nsurf_old + 1);
1672
1673 delta = nsurf_new;
1674 MPI_Allreduce(&delta,&offset,1,MPI_SPARTA_BIGINT,MPI_SUM,world);
1675 nsurf_new = offset/nprocs;
1676 if (me < offset % nprocs) nsurf_new++;
1677
1678 surf->redistribute_lines_clip(nsurf_old,nsurf_new); // sets surf->nown
1679
1680 nsurf_new = surf->nown;
1681 bigint bnown = surf->nown;
1682 MPI_Allreduce(&bnown,&surf->nsurf,1,MPI_SPARTA_BIGINT,MPI_SUM,world);
1683 }
1684 }
1685
1686 // check that surf IDs are still 1 to N
1687
1688 check_consecutive();
1689
1690 // stats
1691
1692 bigint delta = surf->nsurf - nsurf_total_old;
1693
1694 if (me == 0) {
1695 if (screen) fprintf(screen," clipped to " BIGINT_FORMAT " lines\n",delta);
1696 if (logfile) fprintf(logfile," clipped to " BIGINT_FORMAT " lines\n",delta);
1697 }
1698 }
1699
1700 /* ----------------------------------------------------------------------
1701 clip all tris so fit inside simulation box
1702 may discard some tris and their points completely
1703 new points and tris may be added which touch box surface
1704 condense data structures by removing deleted points & tris
1705 ------------------------------------------------------------------------- */
1706
clip3d()1707 void ReadSurf::clip3d()
1708 {
1709 int i,dim,side,flag1,flag2,flag3,nin,ntri_add;
1710 double value,param;
1711 double x1[3],x2[3];
1712 double *p1,*p2,*p3,*in1,*in2,*out1,*out2;
1713
1714 Surf::Tri *tris;
1715 if (distributed) tris = surf->mytris;
1716 else tris = surf->tris;
1717
1718 // discard flag for each surf
1719 // will be augmented in loop if tris are added
1720
1721 int *discard;
1722 int maxdiscard = nsurf_new - nsurf_old;
1723 memory->create(discard,maxdiscard,"readsurf:discard");
1724 for (i = 0; i < maxdiscard; i++) discard[i] = 0;
1725 int discardflag = 0;
1726 int addflag = 0;
1727
1728 double *boxlo = domain->boxlo;
1729 double *boxhi = domain->boxhi;
1730
1731 for (int iface = 0; iface < 6; iface++) {
1732 dim = iface / 2;
1733 side = iface % 2;
1734 if (side == 0) value = boxlo[dim];
1735 else value = boxhi[dim];
1736
1737 // flag each point as (1,0,-1) = outside,on,inside clipping edge
1738 // keep tri unchanged:
1739 // if all pts are inside or on clipping plane
1740 // at least one pt is inside clipping plane
1741 // discard tri:
1742 // if all pts are either outside or on clipping plane
1743 // straddle tri:
1744 // at least one pt is inside, at least one pt is outside
1745 // replace outside pts with pts on the clipping plane
1746 // if 1 pt is inside, triangle remains
1747 // if 2 pts are inside, trapezoid remains, convert to 2 tris
1748 // latter requires adding a triangle to Surf data struct
1749
1750 ntri_add = 0;
1751 for (i = nsurf_old; i < nsurf_new; i++) {
1752 if (discard[i-nsurf_old]) continue;
1753
1754 p1 = tris[i].p1;
1755 p2 = tris[i].p2;
1756 p3 = tris[i].p3;
1757
1758 if (side == 0) {
1759 if (p1[dim] < value) flag1 = 1;
1760 else if (p1[dim] > value) flag1 = -1;
1761 else flag1 = 0;
1762 if (p2[dim] < value) flag2 = 1;
1763 else if (p2[dim] > value) flag2 = -1;
1764 else flag2 = 0;
1765 if (p3[dim] < value) flag3 = 1;
1766 else if (p3[dim] > value) flag3 = -1;
1767 else flag3 = 0;
1768 } else {
1769 if (p1[dim] > value) flag1 = 1;
1770 else if (p1[dim] < value) flag1 = -1;
1771 else flag1 = 0;
1772 if (p2[dim] > value) flag2 = 1;
1773 else if (p2[dim] < value) flag2 = -1;
1774 else flag2 = 0;
1775 if (p3[dim] > value) flag3 = 1;
1776 else if (p3[dim] < value) flag3 = -1;
1777 else flag3 = 0;
1778 }
1779
1780 if (flag1 < 0 && flag2 <= 0 && flag3 <= 0) continue;
1781 if (flag1 <= 0 && flag2 < 0 && flag3 <= 0) continue;
1782 if (flag1 <= 0 && flag2 <= 0 && flag3 < 0) continue;
1783
1784 if (flag1 >= 0 && flag2 >= 0 && flag3 >= 0) {
1785 discard[i-nsurf_old] = 1;
1786 discardflag += 1;
1787 continue;
1788 }
1789
1790 // nin = # of inside pts
1791
1792 nin = 0;
1793 if (flag1 < 0) nin++;
1794 if (flag2 < 0) nin++;
1795 if (flag3 < 0) nin++;
1796
1797 // one pt is inside
1798 // one or both of other 2 pts are outside
1799 // make a clip with each other pt that is outside
1800 // no new triangle is formed, existing tri is just changed
1801
1802 if (nin == 1) {
1803 if (flag1 < 0) {
1804 in1 = p1;
1805 out1 = p2;
1806 out2 = p3;
1807 } else if (flag2 < 0) {
1808 in1 = p2;
1809 out1 = p3;
1810 out2 = p1;
1811 } else {
1812 in1 = p3;
1813 out1 = p1;
1814 out2 = p2;
1815 }
1816 if (out1[dim] != value) {
1817 param = (value-in1[dim]) / (out1[dim]-in1[dim]);
1818 out1[0] = in1[0] + param*(out1[0]-in1[0]);
1819 out1[1] = in1[1] + param*(out1[1]-in1[1]);
1820 out1[2] = in1[2] + param*(out1[2]-in1[2]);
1821 out1[dim] = value;
1822 }
1823 if (out2[dim] != value) {
1824 param = (value-in1[dim]) / (out2[dim]-in1[dim]);
1825 out2[0] = in1[0] + param*(out2[0]-in1[0]);
1826 out2[1] = in1[1] + param*(out2[1]-in1[1]);
1827 out2[2] = in1[2] + param*(out2[2]-in1[2]);
1828 out2[dim] = value;
1829 }
1830 }
1831
1832 // two pts are inside, one pt is outside
1833 // set in1,in2,out1 so all 3 of these tris have same consistent normal
1834 // straddle tri = (in1,in2,out1)
1835 // modified tri = (in1,in2,x2)
1836 // added tri = (in1,x2,x1)
1837 // x1 = clip pt between in1 and out1
1838 // x2 = clip pt between in2 and out1
1839 // x1 and x2 will be computed exactly the same by a tri sharing the edge
1840
1841 if (nin == 2) {
1842 if (flag1 > 0) {
1843 out1 = p1;
1844 in1 = p2;
1845 in2 = p3;
1846 } else if (flag2 > 0) {
1847 out1 = p2;
1848 in1 = p3;
1849 in2 = p1;
1850 } else {
1851 out1 = p3;
1852 in1 = p1;
1853 in2 = p2;
1854 }
1855
1856 param = (value-in1[dim]) / (out1[dim]-in1[dim]);
1857 x1[0] = in1[0] + param*(out1[0]-in1[0]);
1858 x1[1] = in1[1] + param*(out1[1]-in1[1]);
1859 x1[2] = in1[2] + param*(out1[2]-in1[2]);
1860 x1[dim] = value;
1861
1862 param = (value-in2[dim]) / (out1[dim]-in2[dim]);
1863 x2[0] = in2[0] + param*(out1[0]-in2[0]);
1864 x2[1] = in2[1] + param*(out1[1]-in2[1]);
1865 x2[2] = in2[2] + param*(out1[2]-in2[2]);
1866 x2[dim] = value;
1867
1868 // reset one point in modified tri
1869
1870 memcpy(out1,x2,3*sizeof(double));
1871
1872 // add a new tri
1873 // use same ID as modified tri for now, will renumber below
1874
1875 if (nsurf_new-nsurf_old+ntri_add == maxdiscard) {
1876 maxdiscard += DELTA_DISCARD;
1877 memory->grow(discard,maxdiscard,"readsurf:discard");
1878 }
1879
1880 // can't use "in1" pointer in surf->add_tri because it points to
1881 // surf->tris, which may be realloc'd in surf->add_tri
1882
1883 double in1_copy[3];
1884 in1_copy[0] = in1[0];
1885 in1_copy[1] = in1[1];
1886 in1_copy[2] = in1[2];
1887
1888 if (distributed) {
1889 surf->add_tri_own_clip(tris[i].id,tris[i].type,in1_copy,x2,x1);
1890 tris = surf->mytris;
1891 } else {
1892 surf->add_tri(tris[i].id,tris[i].type,in1_copy,x2,x1);
1893 tris = surf->tris;
1894 }
1895
1896 discard[nsurf_new-nsurf_old+ntri_add] = 0;
1897 addflag += 1;
1898 ntri_add++;
1899 }
1900 }
1901
1902 // increment nsurf_new by triangles added when clipping on one face
1903
1904 nsurf_new += ntri_add;
1905 }
1906
1907 // remove deleted tris
1908
1909 int n = nsurf_old;
1910 for (i = nsurf_old; i < nsurf_new; i++) {
1911 if (!discard[i-nsurf_old]) {
1912 if (n != i) memcpy(&tris[n],&tris[i],sizeof(Surf::Tri));
1913 n++;
1914 }
1915 }
1916 nsurf_new = n;
1917
1918 // clean up
1919
1920 memory->destroy(discard);
1921
1922 // reset nsurf,nlocal,nown counts in Surf
1923
1924 if (!distributed) surf->nsurf = surf->nlocal = nsurf_new;
1925 else {
1926 surf->nown = nsurf_new;
1927 bigint bnown = surf->nown;
1928 MPI_Allreduce(&bnown,&surf->nsurf,1,MPI_SPARTA_BIGINT,MPI_SUM,world);
1929 }
1930
1931 // if discarded any surfs:
1932 // if non-distributed:
1933 // renumber all IDs for new surfs from nsurf_old to nsurf_new
1934 // if distributed:
1935 // MPI_Scan to find unique IDs for mine,
1936 // reset IDs for new surfs in mytris,
1937 // perform rendezvous to send just new surfs to new owners
1938 // reset nsurf_new, surf->nsurf
1939
1940 int changeflag = discardflag + addflag;
1941 int changeany;
1942 MPI_Allreduce(&changeflag,&changeany,1,MPI_INT,MPI_MAX,world);
1943
1944 if (changeany) {
1945 if (!distributed) {
1946 for (i = nsurf_old; i < nsurf_new; i++) tris[i].id = i+1;
1947
1948 } else {
1949 bigint delta = nsurf_new - nsurf_old;
1950 bigint offset;
1951 MPI_Scan(&delta,&offset,1,MPI_SPARTA_BIGINT,MPI_SUM,world);
1952 offset -= delta;
1953 for (i = nsurf_old; i < nsurf_new; i++)
1954 tris[i].id = static_cast<surfint>
1955 (nsurf_total_old+offset + i-nsurf_old + 1);
1956
1957 delta = nsurf_new;
1958 MPI_Allreduce(&delta,&offset,1,MPI_SPARTA_BIGINT,MPI_SUM,world);
1959 nsurf_new = offset/nprocs;
1960 if (me < offset % nprocs) nsurf_new++;
1961
1962 surf->redistribute_tris_clip(nsurf_old,nsurf_new); // sets surf->nown
1963
1964 nsurf_new = surf->nown;
1965 bigint bnown = surf->nown;
1966 MPI_Allreduce(&bnown,&surf->nsurf,1,MPI_SPARTA_BIGINT,MPI_SUM,world);
1967 }
1968 }
1969
1970 // check that surf IDs are still 1 to N
1971
1972 check_consecutive();
1973
1974 // stats
1975
1976 bigint delta = surf->nsurf - nsurf_total_old;
1977
1978 if (me == 0) {
1979 if (screen) fprintf(screen," clipped to " BIGINT_FORMAT " tris\n",delta);
1980 if (logfile) fprintf(logfile," clipped to " BIGINT_FORMAT " tris\n",delta);
1981 }
1982 }
1983
1984 /* ----------------------------------------------------------------------
1985 set transparent flag of all surface elements read in
1986 ------------------------------------------------------------------------- */
1987
transparent()1988 void ReadSurf::transparent()
1989 {
1990 if (dim == 2) {
1991 Surf::Line *lines;
1992 if (distributed) lines = surf->mylines;
1993 else lines = surf->lines;
1994
1995 for (int i = nsurf_old; i < nsurf_new; i++)
1996 lines[i].transparent = 1;
1997
1998 } else if (dim == 3) {
1999 Surf::Tri *tris;
2000 if (distributed) tris = surf->mytris;
2001 else tris = surf->tris;
2002
2003 for (int i = nsurf_old; i < nsurf_new; i++)
2004 tris[i].transparent = 1;
2005 }
2006 }
2007
2008 /* ----------------------------------------------------------------------
2009 check that all surf IDs are consecutive from 1 to N
2010 whether distributed or not
2011 only checks if min/max surf IDs are valid, not if truly consecutive
2012 ------------------------------------------------------------------------- */
2013
check_consecutive()2014 void ReadSurf::check_consecutive()
2015 {
2016 int n;
2017 surfint id;
2018 Surf::Line *lines;
2019 Surf::Tri *tris;
2020
2021 if (surf->nsurf == 0) return;
2022
2023 bigint smin = surf->nsurf;
2024 bigint smax = 0;
2025
2026 if (distributed) n = surf->nown;
2027 else n = surf->nlocal;
2028
2029 if (dim == 2) {
2030 if (distributed) lines = surf->mylines;
2031 else lines = surf->lines;
2032 for (int i = 0; i < n; i++) {
2033 id = lines[i].id;
2034 smin = MIN(smin,id);
2035 smax = MAX(smax,id);
2036 }
2037 } else {
2038 if (distributed) tris = surf->mytris;
2039 else tris = surf->tris;
2040 for (int i = 0; i < n; i++) {
2041 id = tris[i].id;
2042 smin = MIN(smin,id);
2043 smax = MAX(smax,id);
2044 }
2045 }
2046
2047 bigint sminall,smaxall;
2048 MPI_Allreduce(&smin,&sminall,1,MPI_SPARTA_BIGINT,MPI_MIN,world);
2049 MPI_Allreduce(&smax,&smaxall,1,MPI_SPARTA_BIGINT,MPI_MAX,world);
2050
2051 if (sminall != 1) {
2052 char str[128];
2053 sprintf(str,"Read_surf minimum surface ID is " BIGINT_FORMAT,sminall);
2054 error->all(FLERR,str);
2055 }
2056
2057 if (smaxall != surf->nsurf) {
2058 char str[128];
2059 sprintf(str,"Read_surf maximum surface ID is " BIGINT_FORMAT,smaxall);
2060 error->all(FLERR,str);
2061 }
2062 }
2063
2064 /* ----------------------------------------------------------------------
2065 push all points to box boundary that are just inside
2066 1Dec20 added just outside logic
2067 delta = user-specified frac * (hi-lo)
2068 this avoids tiny clipped surf elements
2069 ------------------------------------------------------------------------- */
2070
push_points_to_boundary(double frac)2071 void ReadSurf::push_points_to_boundary(double frac)
2072 {
2073 int i,j;
2074 double *x;
2075
2076 double *boxlo = domain->boxlo;
2077 double *boxhi = domain->boxhi;
2078
2079 double xdelta = frac * (boxhi[0]-boxlo[0]);
2080 double ydelta = frac * (boxhi[1]-boxlo[1]);
2081 double zdelta = frac * (boxhi[2]-boxlo[2]);
2082
2083 if (dim == 2) {
2084 Surf::Line *lines;
2085 if (distributed) lines = surf->mylines;
2086 else lines = surf->lines;
2087
2088 for (i = nsurf_old; i < nsurf_new; i++) {
2089 for (j = 0; j < 2; j++) {
2090 if (j == 0) x = lines[i].p1;
2091 else x = lines[i].p2;
2092
2093 if (fabs(x[0]-boxlo[0]) < xdelta) x[0] = boxlo[0];
2094 if (fabs(x[0]-boxhi[0]) < xdelta) x[0] = boxhi[0];
2095
2096 if (fabs(x[1]-boxlo[1]) < ydelta) x[1] = boxlo[1];
2097 if (fabs(x[1]-boxhi[1]) < ydelta) x[1] = boxhi[1];
2098
2099 /*
2100 if (x[0] >= boxlo[0] && x[0] <= boxhi[0]) {
2101 if (x[0]-boxlo[0] < xdelta) x[0] = boxlo[0];
2102 else if (boxhi[0]-x[0] < xdelta) x[0] = boxhi[0];
2103 }
2104 if (x[1] >= boxlo[1] && x[1] <= boxhi[1]) {
2105 if (x[1]-boxlo[1] < ydelta) x[1] = boxlo[1];
2106 else if (boxhi[1]-x[1] < ydelta) x[1] = boxhi[1];
2107 }
2108 */
2109 }
2110 }
2111
2112 } else if (dim == 3) {
2113 Surf::Tri *tris;
2114 if (distributed) tris = surf->mytris;
2115 else tris = surf->tris;
2116
2117 for (int i = nsurf_old; i < nsurf_new; i++) {
2118 for (j = 0; j < 3; j++) {
2119 if (j == 0) x = tris[i].p1;
2120 else if (j == 1) x = tris[i].p2;
2121 else x = tris[i].p3;
2122
2123 if (fabs(x[0]-boxlo[0]) < xdelta) x[0] = boxlo[0];
2124 if (fabs(x[0]-boxhi[0]) < xdelta) x[0] = boxhi[0];
2125
2126 if (fabs(x[1]-boxlo[1]) < ydelta) x[1] = boxlo[1];
2127 if (fabs(x[1]-boxhi[1]) < ydelta) x[1] = boxhi[1];
2128
2129 if (fabs(x[2]-boxlo[2]) < zdelta) x[2] = boxlo[2];
2130 if (fabs(x[2]-boxhi[2]) < zdelta) x[2] = boxhi[2];
2131
2132 /*
2133 if (x[0] >= boxlo[0] && x[0] <= boxhi[0]) {
2134 if (x[0]-boxlo[0] < xdelta) x[0] = boxlo[0];
2135 else if (boxhi[0]-x[0] < xdelta) x[0] = boxhi[0];
2136 }
2137 if (x[1] >= boxlo[1] && x[1] <= boxhi[1]) {
2138 if (x[1]-boxlo[1] < ydelta) x[1] = boxlo[1];
2139 else if (boxhi[1]-x[1] < ydelta) x[1] = boxhi[1];
2140 }
2141 if (x[2] >= boxlo[2] && x[2] <= boxhi[2]) {
2142 if (x[2]-boxlo[2] < zdelta) x[2] = boxlo[2];
2143 else if (boxhi[2]-x[2] < zdelta) x[2] = boxhi[2];
2144 }
2145 */
2146 }
2147 }
2148 }
2149 }
2150
2151 /* ----------------------------------------------------------------------
2152 check norms of adjacent lines
2153 error if dot product of 2 norms is -1 -> infinitely thin surf
2154 warn if closer than EPSILON_NORM to -1
2155 ------------------------------------------------------------------------- */
2156
check_neighbor_norm_2d()2157 void ReadSurf::check_neighbor_norm_2d()
2158 {
2159 // NOTE: need to enable this for distributed
2160 // NOTE: and for all, now that surfs are stored with point coords
2161
2162 if (distributed || !distributed) return;
2163
2164 int p1,p2;
2165
2166 // count[I] = # of lines that vertex I is part of
2167
2168 int *count;
2169 int **p2e;
2170 memory->create(count,npoint_file,"readsurf:count");
2171 memory->create(p2e,npoint_file,2,"readsurf:count");
2172 for (int i = 0; i < npoint_file; i++) count[i] = 0;
2173
2174 for (int i = 0; i < nsurf_file; i++) {
2175 //p1 = lines[i].p1;
2176 //p2 = lines[i].p2;
2177 p2e[p1][count[p1]++] = i;
2178 p2e[p2][count[p2]++] = i;
2179 }
2180
2181 // check that norms of adjacent lines are not in opposite directions
2182 // norms are stored in Surf::lines, at end of orignal nsurf_old surfs
2183
2184 Surf::Line *surflines = surf->lines;
2185
2186 double dot;
2187 double *norm1,*norm2;
2188
2189 int nerror = 0;
2190 int nwarn = 0;
2191 for (int i = 0; i < npoint_file; i++) {
2192 if (count[i] == 1) continue;
2193 norm1 = surflines[p2e[i][0] + nsurf_old].norm;
2194 norm2 = surflines[p2e[i][1] + nsurf_old].norm;
2195 dot = MathExtra::dot3(norm1,norm2);
2196 if (dot <= -1.0) nerror++;
2197 else if (dot < -1.0+EPSILON_NORM) nwarn++;
2198 }
2199
2200 if (nerror) {
2201 char str[128];
2202 sprintf(str,"Surface check failed with %d "
2203 "infinitely thin line pairs",nerror);
2204 error->all(FLERR,str);
2205 }
2206 if (nwarn) {
2207 char str[128];
2208 sprintf(str,"Surface check found %d "
2209 "nearly infinitely thin line pairs",nwarn);
2210 if (me == 0) error->warning(FLERR,str);
2211 }
2212
2213 // clean up
2214
2215 memory->destroy(count);
2216 memory->destroy(p2e);
2217 }
2218
2219 /* ----------------------------------------------------------------------
2220 check norms of new adjacent triangles
2221 error if dot product of 2 norms is -1 -> infinitely thin surf
2222 warn if closer than EPSILON_NORM to -1
2223 ------------------------------------------------------------------------- */
2224
check_neighbor_norm_3d()2225 void ReadSurf::check_neighbor_norm_3d()
2226 {
2227 // NOTE: need to enable this for distributed
2228 // NOTE: and for all, now that surfs are stored with point coords
2229
2230 if (distributed || !distributed) return;
2231
2232 int ntri_file;
2233
2234 // hash directed edges of all triangles
2235 // key = directed edge, value = triangle it is part of
2236 // NOTE: could prealloc hash to correct size here
2237
2238 MyHash hash;
2239 MyIterator it;
2240
2241 // insert each edge into hash with triangle index as value
2242
2243 bigint p1,p2,p3,key;
2244
2245 for (int i = 0; i < ntri_file; i++) {
2246 //p1 = tris[i].p1;
2247 //p2 = tris[i].p2;
2248 //p3 = tris[i].p3;
2249 key = (p1 << 32) | p2;
2250 hash[key] = i;
2251 key = (p2 << 32) | p3;
2252 hash[key] = i;
2253 key = (p3 << 32) | p1;
2254 hash[key] = i;
2255 }
2256
2257 // check that norms of adjacent triangles are not in opposite directions
2258 // norms are stored in Surf::tris, at end of orignal nsurf_old surfs
2259
2260 Surf::Tri *surftris = surf->tris;
2261
2262 double dot;
2263 double *norm1,*norm2;
2264
2265 int nerror = 0;
2266 int nwarn = 0;
2267 for (it = hash.begin(); it != hash.end(); ++it) {
2268 p1 = it->first >> 32;
2269 p2 = it->first & MAXSMALLINT;
2270 key = (p2 << 32) | p1;
2271 if (hash.find(key) == hash.end()) continue;
2272 norm1 = surftris[it->second + nsurf_old].norm;
2273 norm2 = surftris[hash[key] + nsurf_old].norm;
2274 dot = MathExtra::dot3(norm1,norm2);
2275 if (dot <= -1.0) nerror++;
2276 else if (dot < -1.0+EPSILON_NORM) nwarn++;
2277 }
2278
2279 if (nerror) {
2280 char str[128];
2281 sprintf(str,"Surface check failed with %d "
2282 "infinitely thin triangle pairs",nerror);
2283 error->all(FLERR,str);
2284 }
2285 if (nwarn) {
2286 char str[128];
2287 sprintf(str,"Surface check found %d "
2288 "nearly infinitely thin triangle pairs",nwarn);
2289 if (me == 0) error->warning(FLERR,str);
2290 }
2291 }
2292
2293 /* ----------------------------------------------------------------------
2294 reading proc opens data file
2295 test if gzipped
2296 sets fp = file pointer
2297 ------------------------------------------------------------------------- */
2298
open(char * file)2299 void ReadSurf::open(char *file)
2300 {
2301 compressed = 0;
2302 char *suffix = file + strlen(file) - 3;
2303 if (suffix > file && strcmp(suffix,".gz") == 0) compressed = 1;
2304 if (!compressed) fp = fopen(file,"r");
2305 else {
2306 #ifdef SPARTA_GZIP
2307 char gunzip[128];
2308 sprintf(gunzip,"gunzip -c %s",file);
2309 fp = popen(gunzip,"r");
2310 #else
2311 error->one(FLERR,"Cannot open gzipped file");
2312 #endif
2313 }
2314
2315 if (fp == NULL) {
2316 char str[128];
2317 sprintf(str,"Cannot open file %s",file);
2318 error->one(FLERR,str);
2319 }
2320 }
2321
2322 /* ----------------------------------------------------------------------
2323 infile contains a "*"
2324 search for all files which match the infile pattern
2325 replace "*" with latest timestep value to create outfile name
2326 search dir referenced by initial pathname of file
2327 if infile also contains "%", use "base" when searching directory
2328 only called by proc 0
2329 ------------------------------------------------------------------------- */
2330
file_search(char * infile,char * outfile)2331 void ReadSurf::file_search(char *infile, char *outfile)
2332 {
2333 char *ptr;
2334
2335 // separate infile into dir + filename
2336
2337 char *dirname = new char[strlen(infile) + 1];
2338 char *filename = new char[strlen(infile) + 1];
2339
2340 if (strchr(infile,'/')) {
2341 ptr = strrchr(infile,'/');
2342 *ptr = '\0';
2343 strcpy(dirname,infile);
2344 strcpy(filename,ptr+1);
2345 *ptr = '/';
2346 } else {
2347 strcpy(dirname,"./");
2348 strcpy(filename,infile);
2349 }
2350
2351 // if filename contains "%" replace "%" with "base"
2352
2353 char *pattern = new char[strlen(filename) + 16];
2354
2355 if ((ptr = strchr(filename,'%'))) {
2356 *ptr = '\0';
2357 sprintf(pattern,"%s%s%s",filename,"base",ptr+1);
2358 *ptr = '%';
2359 } else strcpy(pattern,filename);
2360
2361 // scan all files in directory, searching for files that match pattern
2362 // maxnum = largest int that matches "*"
2363
2364 size_t n = strlen(pattern) + 16;
2365 char *begin = new char[n];
2366 char *middle = new char[n];
2367 char *end = new char[n];
2368
2369 ptr = strchr(pattern,'*');
2370 *ptr = '\0';
2371 strcpy(begin,pattern);
2372 strcpy(end,ptr+1);
2373 int nbegin = strlen(begin);
2374 bigint maxnum = -1;
2375
2376 struct dirent *ep;
2377 DIR *dp = opendir(dirname);
2378 if (dp == NULL)
2379 error->one(FLERR,"Cannot open dir to search for restart file");
2380 while ((ep = readdir(dp))) {
2381 if (strstr(ep->d_name,begin) != ep->d_name) continue;
2382 if ((ptr = strstr(&ep->d_name[nbegin],end)) == NULL) continue;
2383 if (strlen(end) == 0) ptr = ep->d_name + strlen(ep->d_name);
2384 *ptr = '\0';
2385 if (strlen(&ep->d_name[nbegin]) < n) {
2386 strcpy(middle,&ep->d_name[nbegin]);
2387 if (ATOBIGINT(middle) > maxnum) maxnum = ATOBIGINT(middle);
2388 }
2389 }
2390 closedir(dp);
2391 if (maxnum < 0) error->one(FLERR,"Found no restart file matching pattern");
2392
2393 // create outfile with maxint substituted for "*"
2394 // use original infile, not pattern, since need to retain "%" in filename
2395
2396 ptr = strchr(infile,'*');
2397 *ptr = '\0';
2398 sprintf(outfile,"%s" BIGINT_FORMAT "%s",infile,maxnum,ptr+1);
2399 *ptr = '*';
2400
2401 // clean up
2402
2403 delete [] dirname;
2404 delete [] filename;
2405 delete [] pattern;
2406 delete [] begin;
2407 delete [] middle;
2408 delete [] end;
2409 }
2410
2411 /* ----------------------------------------------------------------------
2412 grab next keyword
2413 if first = 1, line holds non-blank line that ended header
2414 else read lines until one is non-blank
2415 keyword is all text on line w/out leading & trailing white space
2416 read one additional line (assumed blank)
2417 if any read hits EOF, set keyword to empty string
2418 ------------------------------------------------------------------------- */
2419
parse_keyword(int first)2420 void ReadSurf::parse_keyword(int first)
2421 {
2422 int eof = 0;
2423
2424 // filereader reads upto non-blank line plus 1 following line
2425 // eof is set to 1 if any read hits end-of-file
2426
2427 if (filereader) {
2428 if (!first) {
2429 if (fgets(line,MAXLINE,fp) == NULL) eof = 1;
2430 }
2431 while (eof == 0 && strspn(line," \t\n\r") == strlen(line)) {
2432 if (fgets(line,MAXLINE,fp) == NULL) eof = 1;
2433 }
2434 if (fgets(buffer,MAXLINE,fp) == NULL) eof = 1;
2435 }
2436
2437 // if eof, set keyword empty and return
2438
2439 MPI_Bcast(&eof,1,MPI_INT,0,filecomm);
2440 if (eof) {
2441 keyword[0] = '\0';
2442 return;
2443 }
2444
2445 // bcast keyword line to all procs
2446
2447 int n;
2448 if (filereader) n = strlen(line) + 1;
2449 MPI_Bcast(&n,1,MPI_INT,0,filecomm);
2450 MPI_Bcast(line,n,MPI_CHAR,0,filecomm);
2451
2452 // copy non-whitespace portion of line into keyword
2453
2454 int start = strspn(line," \t\n\r");
2455 int stop = strlen(line) - 1;
2456 while (line[stop] == ' ' || line[stop] == '\t'
2457 || line[stop] == '\n' || line[stop] == '\r') stop--;
2458 line[stop+1] = '\0';
2459 strcpy(keyword,&line[start]);
2460 }
2461
2462 /* ----------------------------------------------------------------------
2463 unneeded code for now
2464 ------------------------------------------------------------------------- */
2465
2466 /* ----------------------------------------------------------------------
2467 check if any pair of points is closer than epsilon
2468 done in O(N) manner by binning twice with offset bins
2469 //NOTE: check if bins allow for surf points
2470 //NOTE: or maybe should ignore surf points in this test, since clip
2471 // could put them very close together
2472 ------------------------------------------------------------------------- */
2473
2474 /*
2475
2476 void ReadSurf::check_point_pairs()
2477 {
2478 int i,j,k,m,n,ix,iy,iz;
2479 double dx,dy,dz,rsq;
2480 double origin[3];
2481
2482 double *boxlo = domain->boxlo;
2483 double *boxhi = domain->boxhi;
2484
2485 // epsilon = EPSILON fraction of shortest box length
2486 // epssq = epsilon squared
2487
2488 double epsilon = MIN(domain->xprd,domain->yprd);
2489 if (dim == 3) epsilon = MIN(epsilon,domain->zprd);
2490 epsilon *= EPSILON;
2491 double epssq = epsilon * epsilon;
2492
2493 // goal: N roughly cubic bins where N = # of new points
2494 // nbinxyz = # of bins in each dim
2495 // xyzbin = bin size in each dim
2496 // for 2d, nbinz = 1
2497 // after setting bin size, add 1 to nbinxyz
2498 // this allows for 2nd binning via offset origin
2499
2500 int nbinx,nbiny,nbinz;
2501 double xbin,ybin,zbin;
2502 double xbininv,ybininv,zbininv;
2503
2504 if (dim == 2) {
2505 double vol_per_point = domain->xprd * domain->yprd / npoint_new;
2506 xbin = ybin = sqrt(vol_per_point);
2507 nbinx = static_cast<int> (domain->xprd / xbin);
2508 nbiny = static_cast<int> (domain->yprd / ybin);
2509 if (nbinx == 0) nbinx = 1;
2510 if (nbiny == 0) nbiny = 1;
2511 nbinz = 1;
2512 } else {
2513 double vol_per_point = domain->xprd * domain->yprd * domain->zprd /
2514 npoint_new;
2515 xbin = ybin = zbin = pow(vol_per_point,1.0/3.0);
2516 nbinx = static_cast<int> (domain->xprd / xbin);
2517 nbiny = static_cast<int> (domain->yprd / ybin);
2518 nbinz = static_cast<int> (domain->zprd / zbin);
2519 if (nbinx == 0) nbinx = 1;
2520 if (nbiny == 0) nbiny = 1;
2521 if (nbinz == 0) nbinz = 1;
2522 }
2523
2524 xbin = domain->xprd / nbinx;
2525 ybin = domain->yprd / nbiny;
2526 zbin = domain->zprd / nbinz;
2527 xbininv = 1.0/xbin;
2528 ybininv = 1.0/ybin;
2529 zbininv = 1.0/zbin;
2530
2531 if (nbinx > 1) nbinx++;
2532 if (nbiny > 1) nbiny++;
2533 if (nbinz > 1) nbinz++;
2534
2535 // binhead[I][J][K] = point index of 1st point in bin IJK, -1 if none
2536 // bin[I] = index of next point in same bin as point I, -1 if last
2537
2538 int ***binhead;
2539 memory->create(binhead,nbinx,nbiny,nbinz,"readsurf:binhead");
2540 int *bin;
2541 memory->create(bin,npoint_new,"readsurf:bin");
2542
2543 // 1st binning = bins aligned with global box boundaries
2544
2545 for (i = 0; i < nbinx; i++)
2546 for (j = 0; j < nbiny; j++)
2547 for (k = 0; k < nbinz; k++)
2548 binhead[i][j][k] = -1;
2549
2550 origin[0] = boxlo[0];
2551 origin[1] = boxlo[1];
2552 origin[2] = boxlo[2];
2553
2554 m = npoint_old;
2555 for (i = 0; i < npoint_new; i++) {
2556 ix = static_cast<int> ((pts[m].x[0] - origin[0]) * xbininv);
2557 iy = static_cast<int> ((pts[m].x[1] - origin[1]) * ybininv);
2558 iz = static_cast<int> ((pts[m].x[2] - origin[2]) * zbininv);
2559 bin[m] = binhead[ix][iy][iz];
2560 binhead[ix][iy][iz] = m;
2561 m++;
2562 }
2563
2564 // check distances for all pairs of particles in same bin
2565
2566 int nbad = 0;
2567
2568 for (i = 0; i < nbinx; i++)
2569 for (j = 0; j < nbiny; j++)
2570 for (k = 0; k < nbinz; k++) {
2571 m = binhead[i][j][k];
2572 while (m >= 0) {
2573 n = bin[m];
2574 while (n >= 0) {
2575 dx = pts[m].x[0] - pts[n].x[0];
2576 dy = pts[m].x[1] - pts[n].x[1];
2577 dz = pts[m].x[2] - pts[n].x[2];
2578 rsq = dx*dx + dy*dy + dz*dz;
2579 if (rsq < epssq) nbad++;
2580 n = bin[n];
2581 }
2582 m = bin[m];
2583 }
2584 }
2585
2586 if (nbad) {
2587 char str[128];
2588 sprintf(str,"%d read_surf point pairs are too close",nbad);
2589 error->all(FLERR,str);
2590 }
2591
2592 // 2nd binning = bins offset by 1/2 binsize wrt global box boundaries
2593 // do not offset bin origin in a dim with only 1 bin
2594
2595 for (i = 0; i < nbinx; i++)
2596 for (j = 0; j < nbiny; j++)
2597 for (k = 0; k < nbinz; k++)
2598 binhead[i][j][k] = -1;
2599
2600 origin[0] = boxlo[0] - 0.5*xbin;
2601 origin[1] = boxlo[1] - 0.5*ybin;
2602 origin[2] = boxlo[2] - 0.5*zbin;
2603 if (nbinx == 1) origin[0] = boxlo[0];
2604 if (nbiny == 1) origin[1] = boxlo[1];
2605 if (nbinz == 1) origin[2] = boxlo[2];
2606
2607 m = npoint_old;
2608 for (i = 0; i < npoint_new; i++) {
2609 ix = static_cast<int> ((pts[m].x[0] - origin[0]) * xbininv);
2610 iy = static_cast<int> ((pts[m].x[1] - origin[1]) * ybininv);
2611 iz = static_cast<int> ((pts[m].x[2] - origin[2]) * zbininv);
2612 bin[m] = binhead[ix][iy][iz];
2613 binhead[ix][iy][iz] = m;
2614 m++;
2615 }
2616
2617 // check distances for all pairs of particles in same bin
2618
2619 nbad = 0;
2620
2621 for (i = 0; i < nbinx; i++)
2622 for (j = 0; j < nbiny; j++)
2623 for (k = 0; k < nbinz; k++) {
2624 m = binhead[i][j][k];
2625 while (m >= 0) {
2626 n = bin[m];
2627 while (n >= 0) {
2628 dx = pts[m].x[0] - pts[n].x[0];
2629 dy = pts[m].x[1] - pts[n].x[1];
2630 dz = pts[m].x[2] - pts[n].x[2];
2631 rsq = dx*dx + dy*dy + dz*dz;
2632 if (rsq < epssq) nbad++;
2633 n = bin[n];
2634 }
2635 m = bin[m];
2636 }
2637 }
2638
2639 if (nbad) {
2640 char str[128];
2641 sprintf(str,"%d read_surf point pairs are too close",nbad);
2642 error->all(FLERR,str);
2643 }
2644
2645 // clean up
2646
2647 memory->destroy(binhead);
2648 memory->destroy(bin);
2649 }
2650
2651 */
2652