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