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 "string.h"
16 #include "compute_grid.h"
17 #include "particle.h"
18 #include "mixture.h"
19 #include "grid.h"
20 #include "update.h"
21 #include "modify.h"
22 #include "memory.h"
23 #include "error.h"
24 #include "comm.h"
25
26 using namespace SPARTA_NS;
27
28 // user keywords
29
30 enum{NUM,NRHO,NFRAC,MASS,MASSRHO,MASSFRAC,
31 U,V,W,USQ,VSQ,WSQ,KE,TEMPERATURE,EROT,TROT,EVIB,TVIB,
32 PXRHO,PYRHO,PZRHO,KERHO};
33
34 // internal accumulators
35
36 enum{COUNT,MASSSUM,MVX,MVY,MVZ,MVXSQ,MVYSQ,MVZSQ,MVSQ,
37 ENGROT,ENGVIB,DOFROT,DOFVIB,CELLCOUNT,CELLMASS,LASTSIZE};
38
39 // max # of quantities to accumulate for any user value
40
41 #define MAXACCUMULATE 2
42
43 /* ---------------------------------------------------------------------- */
44
ComputeGrid(SPARTA * sparta,int narg,char ** arg)45 ComputeGrid::ComputeGrid(SPARTA *sparta, int narg, char **arg) :
46 Compute(sparta, narg, arg)
47 {
48 if (narg < 5) error->all(FLERR,"Illegal compute grid command");
49
50 int igroup = grid->find_group(arg[2]);
51 if (igroup < 0) error->all(FLERR,"Compute grid group ID does not exist");
52 groupbit = grid->bitmask[igroup];
53
54 imix = particle->find_mixture(arg[3]);
55 if (imix < 0) error->all(FLERR,"Compute grid mixture ID does not exist");
56 ngroup = particle->mixture[imix]->ngroup;
57
58 nvalue = narg - 4;
59 value = new int[nvalue];
60
61 npergroup = cellmass = cellcount = 0;
62 unique = new int[LASTSIZE];
63 nmap = new int[nvalue];
64 memory->create(map,ngroup*nvalue,MAXACCUMULATE,"grid:map");
65 for (int i = 0; i < nvalue; i++) nmap[i] = 0;
66
67 int ivalue = 0;
68 int iarg = 4;
69 while (iarg < narg) {
70 if (strcmp(arg[iarg],"n") == 0) {
71 value[ivalue] = NUM;
72 set_map(ivalue,COUNT);
73 } else if (strcmp(arg[iarg],"nrho") == 0) {
74 value[ivalue] = NRHO;
75 set_map(ivalue,COUNT);
76 } else if (strcmp(arg[iarg],"nfrac") == 0) {
77 value[ivalue] = NFRAC;
78 set_map(ivalue,COUNT);
79 set_map(ivalue,CELLCOUNT);
80 cellcount = 1;
81 } else if (strcmp(arg[iarg],"mass") == 0) {
82 value[ivalue] = MASS;
83 set_map(ivalue,MASSSUM);
84 set_map(ivalue,COUNT);
85 } else if (strcmp(arg[iarg],"massrho") == 0) {
86 value[ivalue] = MASSRHO;
87 set_map(ivalue,MASSSUM);
88 } else if (strcmp(arg[iarg],"massfrac") == 0) {
89 value[ivalue] = MASSFRAC;
90 set_map(ivalue,MASSSUM);
91 set_map(ivalue,CELLMASS);
92 cellmass = 1;
93 } else if (strcmp(arg[iarg],"u") == 0) {
94 value[ivalue] = U;
95 set_map(ivalue,MVX);
96 set_map(ivalue,MASSSUM);
97 } else if (strcmp(arg[iarg],"v") == 0) {
98 value[ivalue] = V;
99 set_map(ivalue,MVY);
100 set_map(ivalue,MASSSUM);
101 } else if (strcmp(arg[iarg],"w") == 0) {
102 value[ivalue] = W;
103 set_map(ivalue,MVZ);
104 set_map(ivalue,MASSSUM);
105 } else if (strcmp(arg[iarg],"usq") == 0) {
106 value[ivalue] = USQ;
107 set_map(ivalue,MVXSQ);
108 set_map(ivalue,MASSSUM);
109 } else if (strcmp(arg[iarg],"vsq") == 0) {
110 value[ivalue] = VSQ;
111 set_map(ivalue,MVYSQ);
112 set_map(ivalue,MASSSUM);
113 } else if (strcmp(arg[iarg],"wsq") == 0) {
114 value[ivalue] = WSQ;
115 set_map(ivalue,MVZSQ);
116 set_map(ivalue,MASSSUM);
117 } else if (strcmp(arg[iarg],"ke") == 0) {
118 value[ivalue] = KE;
119 set_map(ivalue,MVSQ);
120 set_map(ivalue,COUNT);
121 } else if (strcmp(arg[iarg],"temp") == 0) {
122 value[ivalue] = TEMPERATURE;
123 set_map(ivalue,MVSQ);
124 set_map(ivalue,COUNT);
125 } else if (strcmp(arg[iarg],"erot") == 0) {
126 value[ivalue] = EROT;
127 set_map(ivalue,ENGROT);
128 set_map(ivalue,COUNT);
129 } else if (strcmp(arg[iarg],"trot") == 0) {
130 value[ivalue] = TROT;
131 set_map(ivalue,ENGROT);
132 set_map(ivalue,DOFROT);
133 } else if (strcmp(arg[iarg],"evib") == 0) {
134 value[ivalue] = EVIB;
135 set_map(ivalue,ENGVIB);
136 set_map(ivalue,COUNT);
137 } else if (strcmp(arg[iarg],"tvib") == 0) {
138 value[ivalue] = TVIB;
139 set_map(ivalue,ENGVIB);
140 set_map(ivalue,DOFVIB);
141 } else if (strcmp(arg[iarg],"pxrho") == 0) {
142 value[ivalue] = PXRHO;
143 set_map(ivalue,MVX);
144 } else if (strcmp(arg[iarg],"pyrho") == 0) {
145 value[ivalue] = PYRHO;
146 set_map(ivalue,MVY);
147 } else if (strcmp(arg[iarg],"pzrho") == 0) {
148 value[ivalue] = PZRHO;
149 set_map(ivalue,MVZ);
150 } else if (strcmp(arg[iarg],"kerho") == 0) {
151 value[ivalue] = KERHO;
152 set_map(ivalue,MVSQ);
153 } else error->all(FLERR,"Illegal compute grid command");
154
155 ivalue++;
156 iarg++;
157 }
158
159 // ntotal = total # of columns in tally array
160 // reset_map() adjusts indices in initial map() using final npergroup
161 // also adds columns to tally array for CELLCOUNT/CELLMASS
162
163 ntotal = ngroup*npergroup;
164 reset_map();
165
166 per_grid_flag = 1;
167 size_per_grid_cols = ngroup*nvalue;
168 post_process_grid_flag = 1;
169
170 nglocal = 0;
171 vector_grid = NULL;
172 tally = NULL;
173 }
174
175 /* ---------------------------------------------------------------------- */
176
~ComputeGrid()177 ComputeGrid::~ComputeGrid()
178 {
179 if (copymode) return;
180
181 delete [] value;
182 delete [] unique;
183
184 delete [] nmap;
185 memory->destroy(map);
186
187 memory->destroy(vector_grid);
188 memory->destroy(tally);
189 }
190
191 /* ---------------------------------------------------------------------- */
192
init()193 void ComputeGrid::init()
194 {
195 if (ngroup != particle->mixture[imix]->ngroup)
196 error->all(FLERR,"Number of groups in compute grid mixture has changed");
197
198 if (particle->find_custom((char *) "vibmode") >= 0)
199 if (comm->me == 0)
200 error->warning(FLERR,"Using compute grid tvib with fix vibmode may give "
201 "incorrect temperature, use compute tvib/grid instead");
202
203 eprefactor = 0.5*update->mvv2e;
204 tprefactor = update->mvv2e / (3.0*update->boltz);
205 rvprefactor = 2.0*update->mvv2e / update->boltz;
206
207 reallocate();
208 }
209
210 /* ---------------------------------------------------------------------- */
211
compute_per_grid()212 void ComputeGrid::compute_per_grid()
213 {
214 invoked_per_grid = update->ntimestep;
215
216 Grid::ChildInfo *cinfo = grid->cinfo;
217 Particle::Species *species = particle->species;
218 Particle::OnePart *particles = particle->particles;
219 int *s2g = particle->mixture[imix]->species2group;
220 int nlocal = particle->nlocal;
221
222 int i,j,k,m,ispecies,igroup,icell;
223 double mass;
224 double *v,*vec;
225
226 // zero all accumulators - could do this with memset()
227
228 for (i = 0; i < nglocal; i++)
229 for (j = 0; j < ntotal; j++)
230 tally[i][j] = 0.0;
231
232 // loop over all particles, skip species not in mixture group
233 // skip cells not in grid group
234 // perform all tallies needed for each particle
235 // depends on its species group and the user-requested values
236
237 for (i = 0; i < nlocal; i++) {
238 ispecies = particles[i].ispecies;
239 igroup = s2g[ispecies];
240 if (igroup < 0) continue;
241 icell = particles[i].icell;
242 if (!(cinfo[icell].mask & groupbit)) continue;
243
244 mass = species[ispecies].mass;
245 v = particles[i].v;
246
247 vec = tally[icell];
248 if (cellmass) vec[cellmass] += mass;
249 if (cellcount) vec[cellcount] += 1.0;
250
251 // loop has all possible values particle needs to accumulate
252 // subset defined by user values are indexed by accumulate vector
253
254 k = igroup*npergroup;
255
256 for (m = 0; m < npergroup; m++) {
257 switch (unique[m]) {
258 case COUNT:
259 vec[k++] += 1.0;
260 break;
261 case MASSSUM:
262 vec[k++] += mass;
263 break;
264 case MVX:
265 vec[k++] += mass*v[0];
266 break;
267 case MVY:
268 vec[k++] += mass*v[1];
269 break;
270 case MVZ:
271 vec[k++] += mass*v[2];
272 break;
273 case MVXSQ:
274 vec[k++] += mass*v[0]*v[0];
275 break;
276 case MVYSQ:
277 vec[k++] += mass*v[1]*v[1];
278 break;
279 case MVZSQ:
280 vec[k++] += mass*v[2]*v[2];
281 break;
282 case MVSQ:
283 vec[k++] += mass * (v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
284 break;
285 case ENGROT:
286 vec[k++] += particles[i].erot;
287 break;
288 case ENGVIB:
289 vec[k++] += particles[i].evib;
290 break;
291 case DOFROT:
292 vec[k++] += species[ispecies].rotdof;
293 break;
294 case DOFVIB:
295 vec[k++] += species[ispecies].vibdof;
296 break;
297 }
298 }
299 }
300 }
301
302 /* ----------------------------------------------------------------------
303 query info about internal tally array for this compute
304 index = which column of output (0 for vec, 1 to N for array)
305 return # of tally quantities for this index
306 also return array = ptr to tally array
307 also return cols = ptr to list of columns in tally for this index
308 ------------------------------------------------------------------------- */
309
query_tally_grid(int index,double ** & array,int * & cols)310 int ComputeGrid::query_tally_grid(int index, double **&array, int *&cols)
311 {
312 index--;
313 int ivalue = index % nvalue;
314 array = tally;
315 cols = map[index];
316 return nmap[ivalue];
317 }
318
319 /* ----------------------------------------------------------------------
320 tally accumulated info to compute final normalized values
321 index = which column of output (0 for vec, 1 to N for array)
322 for etally = NULL:
323 use internal tallied info for single timestep, set nsample = 1
324 compute values for all grid cells
325 store results in vector_grid with nstride = 1 (single col of array_grid)
326 for etally = ptr to caller array:
327 use external tallied info for many timesteps
328 nsample = additional normalization factor used by some values
329 emap = list of etally columns to use, # of columns determined by index
330 store results in caller's vec, spaced by nstride
331 if norm = 0.0, set result to 0.0 directly so do not divide by 0.0
332 ------------------------------------------------------------------------- */
333
post_process_grid(int index,int nsample,double ** etally,int * emap,double * vec,int nstride)334 void ComputeGrid::post_process_grid(int index, int nsample,
335 double **etally, int *emap,
336 double *vec, int nstride)
337 {
338 index--;
339 int ivalue = index % nvalue;
340
341 int lo = 0;
342 int hi = nglocal;
343 int k = 0;
344
345 if (!etally) {
346 nsample = 1;
347 etally = tally;
348 emap = map[index];
349 vec = vector_grid;
350 nstride = 1;
351 }
352
353 // compute normalized final value for each grid cell
354
355 switch (value[ivalue]) {
356
357 case NUM:
358 {
359 int count = emap[0];
360 for (int icell = lo; icell < hi; icell++) {
361 vec[k] = etally[icell][count] / nsample;
362 k += nstride;
363 }
364 break;
365 }
366
367 case MASS:
368 {
369 double norm;
370 int mass = emap[0];
371 int count = emap[1];
372 for (int icell = lo; icell < hi; icell++) {
373 norm = etally[icell][count];
374 if (norm == 0.0) vec[k] = 0.0;
375 else vec[k] = etally[icell][mass] / norm;
376 k += nstride;
377 }
378 break;
379 }
380
381 case NRHO:
382 {
383 double wt;
384 double fnum = update->fnum;
385 Grid::ChildInfo *cinfo = grid->cinfo;
386
387 double norm;
388 int count = emap[0];
389 for (int icell = lo; icell < hi; icell++) {
390 norm = cinfo[icell].volume;
391 if (norm == 0.0) vec[k] = 0.0;
392 else {
393 wt = fnum * cinfo[icell].weight / norm;
394 vec[k] = wt * etally[icell][count] / nsample;
395 }
396 k += nstride;
397 }
398 break;
399 }
400
401 case MASSRHO:
402 {
403 double wt;
404 double fnum = update->fnum;
405 Grid::ChildInfo *cinfo = grid->cinfo;
406
407 double norm;
408 int mass = emap[0];
409 for (int icell = lo; icell < hi; icell++) {
410 norm = cinfo[icell].volume;
411 if (norm == 0.0) vec[k] = 0.0;
412 else {
413 wt = fnum * cinfo[icell].weight / norm;
414 vec[k] = wt * etally[icell][mass] / nsample;
415 }
416 k += nstride;
417 }
418 break;
419 }
420
421 case NFRAC:
422 case MASSFRAC:
423 {
424 double norm;
425 int count_or_mass = emap[0];
426 int cell_count_or_mass = emap[1];
427 for (int icell = lo; icell < hi; icell++) {
428 norm = etally[icell][cell_count_or_mass];
429 if (norm == 0.0) vec[k] = 0.0;
430 else vec[k] = etally[icell][count_or_mass] / norm;
431 k += nstride;
432 }
433 break;
434 }
435
436 case U:
437 case V:
438 case W:
439 case USQ:
440 case VSQ:
441 case WSQ:
442 {
443 double norm;
444 int velocity = emap[0];
445 int mass = emap[1];
446 for (int icell = lo; icell < hi; icell++) {
447 norm = etally[icell][mass];
448 if (norm == 0.0) vec[k] = 0.0;
449 else vec[k] = etally[icell][velocity] / norm;
450 k += nstride;
451 }
452 break;
453 }
454
455 case KE:
456 {
457 double norm;
458 int mvsq = emap[0];
459 int count = emap[1];
460 for (int icell = lo; icell < hi; icell++) {
461 norm = etally[icell][count];
462 if (norm == 0.0) vec[k] = 0.0;
463 else vec[k] = eprefactor * etally[icell][mvsq] / norm;
464 k += nstride;
465 }
466 break;
467 }
468
469 case TEMPERATURE:
470 {
471 double norm;
472 int mvsq = emap[0];
473 int count = emap[1];
474 for (int icell = lo; icell < hi; icell++) {
475 norm = etally[icell][count];
476 if (norm == 0.0) vec[k] = 0.0;
477 else vec[k] = tprefactor * etally[icell][mvsq] / norm;
478 k += nstride;
479 }
480 break;
481 }
482
483 case EROT:
484 case EVIB:
485 {
486 double norm;
487 int eng = emap[0];
488 int count = emap[1];
489 for (int icell = lo; icell < hi; icell++) {
490 norm = etally[icell][count];
491 if (norm == 0.0) vec[k] = 0.0;
492 else vec[k] = etally[icell][eng] / norm;
493 k += nstride;
494 }
495 break;
496 }
497
498 case TROT:
499 case TVIB:
500 {
501 double norm;
502 int eng = emap[0];
503 int dof = emap[1];
504 for (int icell = lo; icell < hi; icell++) {
505 norm = etally[icell][dof];
506 if (norm == 0.0) vec[k] = 0.0;
507 else vec[k] = rvprefactor * etally[icell][eng] / norm;
508 k += nstride;
509 }
510 break;
511 }
512
513 case PXRHO:
514 case PYRHO:
515 case PZRHO:
516 {
517 double wt;
518 double fnum = update->fnum;
519 Grid::ChildInfo *cinfo = grid->cinfo;
520
521 double norm;
522 int mom = emap[0];
523 for (int icell = lo; icell < hi; icell++) {
524 norm = cinfo[icell].volume;
525 if (norm == 0.0) vec[k] = 0.0;
526 else {
527 wt = fnum * cinfo[icell].weight / norm;
528 vec[k] = wt * etally[icell][mom] / nsample;
529 }
530 k += nstride;
531 }
532 break;
533 }
534
535 case KERHO:
536 {
537 double wt;
538 double fnum = update->fnum;
539 Grid::ChildInfo *cinfo = grid->cinfo;
540
541 double norm;
542 int ke = emap[0];
543 for (int icell = lo; icell < hi; icell++) {
544 norm = cinfo[icell].volume;
545 if (norm == 0.0) vec[k] = 0.0;
546 else {
547 wt = fnum * cinfo[icell].weight / norm;
548 vec[k] = eprefactor * wt * etally[icell][ke] / nsample;
549 }
550 k += nstride;
551 }
552 break;
553 }
554 }
555 }
556
557 /* ----------------------------------------------------------------------
558 add a tally quantity to all groups for ivalue
559 also add it to unique list if first time this name is used
560 name = name of tally quantity from enum{} at top of file
561 nmap[i] = # of tally quantities for user value I
562 map[i][k] = index of Kth tally quantity for output value I
563 npergroup = length of unique list
564 do not add CELLCOUNT/CELLMASS to unique, since not a pergroup tally
565 ------------------------------------------------------------------------- */
566
set_map(int ivalue,int name)567 void ComputeGrid::set_map(int ivalue, int name)
568 {
569 // index = loc of name in current unique list if there, else npergroup
570
571 int index = 0;
572 for (index = 0; index < npergroup; index++)
573 if (unique[index] == name) break;
574
575 // if name = CELLCOUNT/CELLMASS, just set index to name for now
576 // if name is not already in unique, add it and increment npergroup
577
578 if (name == CELLCOUNT || name == CELLMASS) index = name;
579 else if (index == npergroup) {
580 index = npergroup;
581 unique[npergroup++] = name;
582 }
583
584 // add index to map and nmap for all groups
585 // will add group offset in reset_map()
586
587 for (int igroup = 0; igroup < ngroup; igroup++)
588 map[igroup*nvalue+ivalue][nmap[ivalue]] = index;
589 nmap[ivalue]++;
590 }
591
592 /* ----------------------------------------------------------------------
593 increment ntotal = # of tally quantities for CELLCOUNT/CELLMASS
594 reset map indices to reflect final npergroup = unique quantities/group
595 ------------------------------------------------------------------------- */
596
reset_map()597 void ComputeGrid::reset_map()
598 {
599 if (cellcount) cellcount = ntotal++;
600 if (cellmass) cellmass = ntotal++;
601
602 for (int i = 0; i < ngroup*nvalue; i++) {
603 int igroup = i / nvalue;
604 int ivalue = i % nvalue;
605 for (int k = 0; k < nmap[ivalue]; k++) {
606 if (map[i][k] == CELLCOUNT) map[i][k] = cellcount;
607 else if (map[i][k] == CELLMASS) map[i][k] = cellmass;
608 else map[i][k] += igroup*npergroup;
609 }
610 }
611 }
612
613 /* ----------------------------------------------------------------------
614 reallocate data storage if nglocal has changed
615 called by init() and whenever grid changes
616 ------------------------------------------------------------------------- */
617
reallocate()618 void ComputeGrid::reallocate()
619 {
620 if (grid->nlocal == nglocal) return;
621
622 memory->destroy(vector_grid);
623 memory->destroy(tally);
624 nglocal = grid->nlocal;
625 memory->create(vector_grid,nglocal,"grid:vector_grid");
626 memory->create(tally,nglocal,ntotal,"grid:tally");
627 }
628
629 /* ----------------------------------------------------------------------
630 memory usage of local grid-based data
631 ------------------------------------------------------------------------- */
632
memory_usage()633 bigint ComputeGrid::memory_usage()
634 {
635 bigint bytes;
636 bytes = nglocal * sizeof(double);
637 bytes = ntotal*nglocal * sizeof(double);
638 return bytes;
639 }
640