QMCPACK
SpaceGrid.cpp
Go to the documentation of this file.
1 //////////////////////////////////////////////////////////////////////////////////////
2 // This file is distributed under the University of Illinois/NCSA Open Source License.
3 // See LICENSE file in top directory for details.
4 //
5 // Copyright (c) 2016 Jeongnim Kim and QMCPACK developers.
6 //
7 // File developed by: Jaron T. Krogel, krogeljt@ornl.gov, Oak Ridge National Laboratory
8 // Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
9 //
10 // File created by: Jaron T. Krogel, krogeljt@ornl.gov, Oak Ridge National Laboratory
11 //////////////////////////////////////////////////////////////////////////////////////
12 
13 
14 #include "SpaceGrid.h"
15 #include "OhmmsData/AttributeSet.h"
16 #include "Utilities/string_utils.h"
17 #include <cmath>
18 #include "OhmmsPETE/OhmmsArray.h"
19 
20 #include "Concurrency/OpenMP.h"
21 
22 namespace qmcplusplus
23 {
24 using std::acos;
25 using std::atan2;
26 using std::cos;
27 using std::floor;
28 using std::sin;
29 using std::sqrt;
30 
31 
32 SpaceGrid::SpaceGrid(int& nvalues)
33 {
34  nvalues_per_domain = nvalues;
35  Rptcl = 0;
36  ndparticles = 0;
37  periodic = false;
38 }
39 
40 
41 bool SpaceGrid::put(xmlNodePtr cur, std::map<std::string, Point>& points, bool is_periodic, bool abort_on_fail)
42 {
43  periodic = is_periodic;
44  bool succeeded = true;
45  ndomains = -1;
47  std::string coord;
48  int npundef = -100000;
49  npmin = npundef;
50  npmax = npundef;
51  std::string ref("");
52  ga.add(coord, "coord"); //must be cartesian, cylindrical, or spherical
53  ga.add(npmin, "min_part");
54  ga.add(npmax, "max_part");
55  ga.add(ref, "reference");
56  ga.add(periodic, "periodic");
57  ga.put(cur);
58  if (coord == "cartesian")
60  else if (coord == "cylindrical")
62  else if (coord == "spherical")
64  else if (coord == "voronoi")
66  else
67  {
68  app_log() << " Coordinate supplied to spacegrid must be cartesian, cylindrical, spherical, or voronoi"
69  << std::endl;
70  app_log() << " You provided " << coord << std::endl;
71  succeeded = false;
72  }
73  chempot = npmin != npundef && npmax != npundef;
74  if (chempot)
75  {
76  npvalues = npmax - npmin + 1;
77  if (ref == "")
78  reference = noref;
79  else if (ref == "vacuum")
80  reference = vacuum;
81  else if (ref == "neutral")
83  else
84  {
85  app_log() << ref << " is not a valid reference, choose vacuum or neutral." << std::endl;
86  APP_ABORT("SpaceGrid::put()");
87  }
88  if (coordinate == voronoi)
89  {
90  if (reference == noref)
92  }
93  else
94  {
95  if (reference == noref)
96  reference = vacuum;
97  else if (reference == neutral)
98  {
99  APP_ABORT("SpaceGrid::put(): A rectilinear grid must be referenced to vacuum");
100  }
101  }
102  }
103  bool init_success;
104  if (coordinate == voronoi)
105  init_success = initialize_voronoi(points);
106  else
107  init_success = initialize_rectilinear(cur, coord, points);
108  succeeded = succeeded && init_success;
109  if (chempot && succeeded)
110  {
111  cellsamples.resize(ndomains, nvalues_per_domain + 1); //+1 is for count
112  std::fill(cellsamples.begin(), cellsamples.end(), 0.0);
113  }
114  if (abort_on_fail && !succeeded)
115  {
116  APP_ABORT("SpaceGrid::put");
117  }
118  return succeeded;
119 }
120 
121 
122 bool SpaceGrid::initialize_voronoi(std::map<std::string, Point>& points)
123 {
124  bool succeeded = true;
125  if (Rptcl)
126  {
127  const ParticlePos& R = *Rptcl;
128  origin = points["center"];
129  ndomains = R.size();
132  nearcell.resize(ndparticles);
133  for (int i = 0; i < ndomains; i++)
134  domain_volumes(i, 0) = 1.0; //voronoi grid stores values, not densities
135  for (int i = 0; i < ndomains; i++)
136  for (int d = 0; d < DIM; d++)
137  domain_centers(i, d) = R[i][d] - origin[d]; //cell centers are ion positions
138  for (int i = 0; i < ndparticles; i++)
139  nearcell[i].r = std::numeric_limits<RealType>::max();
140  volume = 1.0;
141  if (chempot)
142  {
143  reference_count.resize(ndomains);
144  switch (reference)
145  {
146  case (vacuum):
147  fill(reference_count.begin(), reference_count.end(), 0.0);
148  break;
149  case (neutral): {
150  const std::vector<RealType>& Z = *Zptcl;
151  for (int i = 0; i < ndomains; i++)
152  reference_count[i] = (int)Z[i] + 1; //+1 is for ion itself
153  Zptcl = 0;
154  }
155  break;
156  default:
157  break;
158  }
159  }
160  }
161  else
162  {
163  app_log() << " Pstatic must be specified for a Voronoi grid" << std::endl;
164  succeeded = false;
165  }
166  return succeeded;
167 }
168 
169 
170 bool SpaceGrid::initialize_rectilinear(xmlNodePtr cur, std::string& coord, std::map<std::string, Point>& points)
171 {
172  bool succeeded = true;
173  std::string ax_cartesian[DIM] = {"x", "y", "z"};
174  std::string ax_cylindrical[DIM] = {"r", "phi", "z"};
175  std::string ax_spherical[DIM] = {"r", "phi", "theta"};
176  std::map<std::string, int> cmap;
177  switch (coordinate)
178  {
179  case (cartesian):
180  for (int d = 0; d < DIM; d++)
181  {
182  cmap[ax_cartesian[d]] = d;
183  axlabel[d] = ax_cartesian[d];
184  }
185  break;
186  case (cylindrical):
187  for (int d = 0; d < DIM; d++)
188  {
189  cmap[ax_cylindrical[d]] = d;
190  axlabel[d] = ax_cylindrical[d];
191  periodic = false;
192  }
193  break;
194  case (spherical):
195  for (int d = 0; d < DIM; d++)
196  {
197  cmap[ax_spherical[d]] = d;
198  axlabel[d] = ax_spherical[d];
199  periodic = false;
200  }
201  break;
202  default:
203  break;
204  }
205  //loop over spacegrid xml elements
206  xmlNodePtr element = cur->children;
207  std::string undefined = "";
208  int iaxis = 0;
209  int naxes = 0;
210  bool has_origin = false;
211  origin = points["zero"];
212  // variables for loop
213  RealType utol = 1e-5;
214  std::string grid;
215  std::vector<int> ndu_per_interval[DIM];
216  while (element != NULL)
217  {
218  std::string name = (const char*)element->name;
220  std::string p1 = undefined;
221  std::string p2 = "zero";
222  std::string fraction = undefined;
223  RealType frac = -1.0;
224  std::string scale = undefined;
225  std::string label = undefined;
226  grid = "0 1";
227  astring agrid;
228  ea->add(p1, "p1");
229  ea->add(p2, "p2");
230  ea->add(fraction, "fraction");
231  ea->add(scale, "scale");
232  ea->add(label, "label");
233  //ea->add(grid,"grid");
234  ea->add(agrid, "grid");
235  ea->put(element);
236  grid = agrid.s;
237  if (name == "origin")
238  {
239  if (p1 == undefined)
240  {
241  app_log() << " p1 must be defined in spacegrid element " << name << std::endl;
242  succeeded = false;
243  }
244  if (has_origin)
245  {
246  app_log() << " spacegrid must contain at most one origin element" << std::endl;
247  APP_ABORT("SpaceGrid::put");
248  }
249  else
250  has_origin = true;
251  if (fraction == undefined)
252  frac = 0.0;
253  else
254  frac = string2real(fraction);
255  origin = points[p1] + frac * (points[p2] - points[p1]);
256  }
257  else if (name == "axis")
258  {
259  if (p1 == undefined)
260  {
261  app_log() << " p1 must be defined in spacegrid element " << name << std::endl;
262  succeeded = false;
263  }
264  naxes++;
265  if (naxes > DIM)
266  {
267  app_log() << " spacegrid must contain " << DIM << " axes, " << naxes << "provided" << std::endl;
268  APP_ABORT("SpaceGrid::put");
269  }
270  if (cmap.find(label) == cmap.end())
271  {
272  app_log() << " grid label " << label << " is invalid for " << coord << " coordinates" << std::endl;
273  app_log() << " valid options are: ";
274  for (int d = 0; d < DIM; d++)
275  app_log() << axlabel[d] << ", ";
276  app_log() << std::endl;
277  APP_ABORT("SpaceGrid::put");
278  }
279  iaxis = cmap[label];
280  if (scale == undefined)
281  frac = 1.0;
282  else
283  frac = string2real(scale);
284  for (int d = 0; d < DIM; d++)
285  axes(d, iaxis) = frac * (points[p1][d] - points[p2][d]);
286  //read in the grid contents
287  // remove spaces inside of parentheses
288  std::string gtmp;
289  bool inparen = false;
290  char gc;
291  for (int i = 0; i < grid.size(); i++)
292  {
293  gc = grid[i];
294  if (gc == '(')
295  {
296  inparen = true;
297  gtmp += ' ';
298  }
299  if (!(inparen && gc == ' '))
300  gtmp += gc;
301  if (gc == ')')
302  {
303  inparen = false;
304  gtmp += ' ';
305  }
306  }
307  grid = gtmp;
308  // break into tokens
309  std::vector<std::string> tokens = split(grid, " ");
310  // count the number of intervals
311  int nintervals = 0;
312  for (int i = 0; i < tokens.size(); i++)
313  if (tokens[i][0] != '(')
314  nintervals++;
315  nintervals--;
316  // allocate temporary interval variables
317  std::vector<int> ndom_int, ndu_int;
318  std::vector<RealType> du_int;
319  ndom_int.resize(nintervals);
320  du_int.resize(nintervals);
321  ndu_int.resize(nintervals);
322  // determine number of domains in each interval and the width of each domain
323  RealType u1 = string2real(tokens[0]);
324  umin[iaxis] = u1;
325  if (std::abs(u1) > 1.0000001)
326  {
327  app_log() << " interval endparticles cannot be greater than " << 1 << std::endl;
328  app_log() << " endpoint provided: " << u1 << std::endl;
329  succeeded = false;
330  }
331  bool is_int = false;
332  bool has_paren_val = false;
333  RealType du_i;
334  int ndom_i = 1;
335  int interval = -1;
336  for (int i = 1; i < tokens.size(); i++)
337  {
338  if (tokens[i][0] != '(')
339  {
340  RealType u2 = string2real(tokens[i]);
341  umax[iaxis] = u2;
342  if (!has_paren_val)
343  du_i = u2 - u1;
344  has_paren_val = false;
345  interval++;
346  if (u2 < u1)
347  {
348  app_log() << " interval (" << u1 << "," << u2 << ") is negative" << std::endl;
349  succeeded = false;
350  }
351  if (std::abs(u2) > 1.0000001)
352  {
353  app_log() << " interval endparticles cannot be greater than " << 1 << std::endl;
354  app_log() << " endpoint provided: " << u2 << std::endl;
355  succeeded = false;
356  }
357  if (is_int)
358  {
359  du_int[interval] = (u2 - u1) / ndom_i;
360  ndom_int[interval] = ndom_i;
361  }
362  else
363  {
364  du_int[interval] = du_i;
365  ndom_int[interval] = floor((u2 - u1) / du_i + .5);
366  if (std::abs(u2 - u1 - du_i * ndom_int[interval]) > utol)
367  {
368  app_log() << " interval (" << u1 << "," << u2 << ") not divisible by du=" << du_i << std::endl;
369  succeeded = false;
370  }
371  }
372  u1 = u2;
373  }
374  else
375  {
376  has_paren_val = true;
377  std::string paren_val = tokens[i].substr(1, tokens[i].length() - 2);
378  is_int = tokens[i].find(".") == std::string::npos;
379  if (is_int)
380  {
381  ndom_i = string2int(paren_val);
382  du_i = -1.0;
383  }
384  else
385  {
386  ndom_i = 0;
387  du_i = string2real(paren_val);
388  }
389  }
390  }
391  // find the smallest domain width
392  RealType du_min = 1.0;
393  for (int i = 0; i < du_int.size(); i++)
394  du_min = std::min(du_min, du_int[i]);
395  odu[iaxis] = 1.0 / du_min;
396  // make sure it divides into all other domain widths
397  for (int i = 0; i < du_int.size(); i++)
398  {
399  ndu_int[i] = floor(du_int[i] / du_min + .5);
400  if (std::abs(du_int[i] - ndu_int[i] * du_min) > utol)
401  {
402  app_log() << "interval " << i + 1 << " of axis " << iaxis + 1 << " is not divisible by smallest subinterval "
403  << du_min << std::endl;
404  succeeded = false;
405  }
406  }
407  // set up the interval map such that gmap[u/du]==domain index
408  gmap[iaxis].resize(floor((umax[iaxis] - umin[iaxis]) * odu[iaxis] + .5));
409  int n = 0;
410  int nd = -1;
411  for (int i = 0; i < ndom_int.size(); i++)
412  for (int j = 0; j < ndom_int[i]; j++)
413  {
414  nd++;
415  for (int k = 0; k < ndu_int[i]; k++)
416  {
417  //app_log()<<" accessing gmap "<<iaxis<<" "<<n<< std::endl;
418  gmap[iaxis][n] = nd;
419  n++;
420  }
421  }
422  dimensions[iaxis] = nd + 1;
423  //end read in the grid contents
424  //save interval width information
425  int ndom_tot = 0;
426  for (int i = 0; i < ndom_int.size(); i++)
427  ndom_tot += ndom_int[i];
428  ndu_per_interval[iaxis].resize(ndom_tot);
429  int idom = 0;
430  for (int i = 0; i < ndom_int.size(); i++)
431  for (int ii = 0; ii < ndom_int[i]; ii++)
432  {
433  ndu_per_interval[iaxis][idom] = ndu_int[i];
434  idom++;
435  }
436  }
437  delete ea;
438  element = element->next;
439  }
440  if (naxes != DIM)
441  {
442  app_log() << " spacegrid must contain " << DIM << " axes, " << iaxis + 1 << "provided" << std::endl;
443  succeeded = false;
444  }
445  axinv = inverse(axes);
446  //check that all axis grid values fall in the allowed intervals
447  std::map<std::string, int> cartmap;
448  for (int d = 0; d < DIM; d++)
449  {
450  cartmap[ax_cartesian[d]] = d;
451  }
452  for (int d = 0; d < DIM; d++)
453  {
454  if (cartmap.find(axlabel[d]) != cartmap.end())
455  {
456  if (umin[d] < -1.0 || umax[d] > 1.0)
457  {
458  app_log() << " grid values for " << axlabel[d] << " must fall in [-1,1]" << std::endl;
459  app_log() << " interval provided: [" << umin[d] << "," << umax[d] << "]" << std::endl;
460  succeeded = false;
461  }
462  }
463  else if (axlabel[d] == "phi")
464  {
465  if (std::abs(umin[d]) + std::abs(umax[d]) > 1.0)
466  {
467  app_log() << " phi interval cannot be longer than 1" << std::endl;
468  app_log() << " interval length provided: " << std::abs(umin[d]) + std::abs(umax[d]) << std::endl;
469  succeeded = false;
470  }
471  }
472  else
473  {
474  if (umin[d] < 0.0 || umax[d] > 1.0)
475  {
476  app_log() << " grid values for " << axlabel[d] << " must fall in [0,1]" << std::endl;
477  app_log() << " interval provided: [" << umin[d] << "," << umax[d] << "]" << std::endl;
478  succeeded = false;
479  }
480  }
481  }
482  //set grid dimensions
483  // C/Python style indexing
484  dm[0] = dimensions[1] * dimensions[2];
485  dm[1] = dimensions[2];
486  dm[2] = 1;
487  // Fortran/Matlab style indexing
488  //dm[0] = 1;
489  //dm[1] = dimensions[0];
490  //dm[2] = dimensions[0]*dimensions[1];
491  ndomains = dimensions[0] * dimensions[1] * dimensions[2];
492  volume = std::abs(det(axes)) * 8.0; //axes span only one octant
493  //compute domain volumes, centers, and widths
497  std::vector<RealType> interval_centers[DIM];
498  std::vector<RealType> interval_widths[DIM];
499  for (int d = 0; d < DIM; d++)
500  {
501  int nintervals = ndu_per_interval[d].size();
502  app_log() << "nintervals " << d << " " << nintervals << std::endl;
503  interval_centers[d].resize(nintervals);
504  interval_widths[d].resize(nintervals);
505  interval_widths[d][0] = ndu_per_interval[d][0] / odu[d];
506  interval_centers[d][0] = interval_widths[d][0] / 2.0 + umin[d];
507  for (int i = 1; i < nintervals; i++)
508  {
509  interval_widths[d][i] = ndu_per_interval[d][i] / odu[d];
510  interval_centers[d][i] = interval_centers[d][i - 1] + .5 * (interval_widths[d][i] + interval_widths[d][i - 1]);
511  }
512  //app_log()<<" interval widths"<< std::endl;
513  //for(int i=0;i<nintervals;i++)
514  // app_log()<<" "<<i<<" "<<interval_widths[d][i]<< std::endl;
515  //app_log()<<" interval centers"<< std::endl;
516  //for(int i=0;i<nintervals;i++)
517  // app_log()<<" "<<i<<" "<<interval_centers[d][i]<< std::endl;
518  }
519  Point du, uc, ubc, rc;
520  RealType vol = 0.0;
521  RealType vscale = std::abs(det(axes));
522  for (int i = 0; i < dimensions[0]; i++)
523  {
524  for (int j = 0; j < dimensions[1]; j++)
525  {
526  for (int k = 0; k < dimensions[2]; k++)
527  {
528  int idomain = dm[0] * i + dm[1] * j + dm[2] * k;
529  du[0] = interval_widths[0][i];
530  du[1] = interval_widths[1][j];
531  du[2] = interval_widths[2][k];
532  uc[0] = interval_centers[0][i];
533  uc[1] = interval_centers[1][j];
534  uc[2] = interval_centers[2][k];
535  switch (coordinate)
536  {
537  case (cartesian):
538  vol = du[0] * du[1] * du[2];
539  ubc = uc;
540  break;
541  case (cylindrical):
542  uc[1] = 2.0 * M_PI * uc[1] - M_PI;
543  du[1] = 2.0 * M_PI * du[1];
544  vol = uc[0] * du[0] * du[1] * du[2];
545  ubc[0] = uc[0] * cos(uc[1]);
546  ubc[1] = uc[0] * sin(uc[1]);
547  ubc[2] = uc[2];
548  break;
549  case (spherical):
550  uc[1] = 2.0 * M_PI * uc[1] - M_PI;
551  du[1] = 2.0 * M_PI * du[1];
552  uc[2] = M_PI * uc[2];
553  du[2] = M_PI * du[2];
554  vol = (uc[0] * uc[0] + du[0] * du[0] / 12.0) * du[0] //r
555  * du[1] //theta
556  * 2.0 * sin(uc[2]) * sin(.5 * du[2]); //phi
557  ubc[0] = uc[0] * sin(uc[2]) * cos(uc[1]);
558  ubc[1] = uc[0] * sin(uc[2]) * sin(uc[1]);
559  ubc[2] = uc[0] * cos(uc[2]);
560  break;
561  default:
562  break;
563  }
564  vol *= vscale;
565  rc = dot(axes, ubc) + origin;
566  //app_log()<< std::endl;
567  //app_log()<<"umin "<<uc-du/2<< std::endl;
568  //app_log()<<"uc "<<uc<< std::endl;
569  //app_log()<<"umax "<<uc+du/2<< std::endl;
570  //app_log()<<"rc "<<rc<< std::endl;
571  domain_volumes(idomain, 0) = vol;
572  for (int d = 0; d < DIM; d++)
573  {
574  domain_uwidths(idomain, d) = du[d];
575  domain_centers(idomain, d) = rc[d];
576  }
577  }
578  }
579  }
580  ////the following check is only valid if grid spans maximum amount
581  ////check that the amount of space the grid takes up is correct
582  //RealType vfrac;
583  //switch(coordinate){
584  //case(cartesian):
585  // vfrac=1.0;
586  // break;
587  //case(cylindrical):
588  // vfrac=M_PI/4.0;
589  // break;
590  //case(spherical):
591  // vfrac=M_PI/6.0;
592  // break;
593  //default:
594  // vfrac=vol_tot/volume;
595  //}
596  //if(std::abs(vol_tot/volume-vfrac)>1e-6){
597  // app_log()<<" "<<coord<<" relative volume"<< std::endl;
598  // app_log()<<" spacegrid volume fraction "<<vol_tot/volume<< std::endl;
599  // app_log()<<" should be "<<vfrac<< std::endl;
600  // succeeded=false;
601  //}
602  //find the actual volume of the grid
603  for (int d = 0; d < DIM; d++)
604  {
605  du[d] = umax[d] - umin[d];
606  uc[d] = .5 * (umax[d] + umin[d]);
607  }
608  switch (coordinate)
609  {
610  case (cartesian):
611  vol = du[0] * du[1] * du[2];
612  break;
613  case (cylindrical):
614  uc[1] = 2.0 * M_PI * uc[1] - M_PI;
615  du[1] = 2.0 * M_PI * du[1];
616  vol = uc[0] * du[0] * du[1] * du[2];
617  break;
618  case (spherical):
619  uc[1] = 2.0 * M_PI * uc[1] - M_PI;
620  du[1] = 2.0 * M_PI * du[1];
621  uc[2] = M_PI * uc[2];
622  du[2] = M_PI * du[2];
623  vol = (uc[0] * uc[0] + du[0] * du[0] / 12.0) * du[0] //r
624  * du[1] //theta
625  * 2.0 * sin(uc[2]) * sin(.5 * du[2]); //phi
626  break;
627  default:
628  break;
629  }
630  volume = vol * det(axes);
631  if (chempot)
632  {
633  reference_count.resize(ndomains);
634  //rectilinear is referenced to vacuum for now
635  fill(reference_count.begin(), reference_count.end(), 0.0);
636  }
637  succeeded = succeeded && check_grid();
638  return succeeded;
639 }
640 
641 
642 void SpaceGrid::write_description(std::ostream& os, std::string& indent)
643 {
644  os << indent + "SpaceGrid" << std::endl;
645  std::string s;
646  switch (coordinate)
647  {
648  case cartesian:
649  s = "cartesian";
650  break;
651  case cylindrical:
652  s = "cylindrical";
653  break;
654  case spherical:
655  s = "spherical";
656  break;
657  default:
658  break;
659  }
660  os << indent + " coordinates = " + s << std::endl;
661  os << indent + " buffer_offset = " << buffer_offset << std::endl;
662  os << indent + " ndomains = " << ndomains << std::endl;
663  os << indent + " axes = " << axes << std::endl;
664  os << indent + " axinv = " << axinv << std::endl;
665  for (int d = 0; d < DIM; d++)
666  {
667  os << indent + " axis " << axlabel[d] << ":" << std::endl;
668  os << indent + " umin = " << umin[d] << std::endl;
669  os << indent + " umax = " << umax[d] << std::endl;
670  os << indent + " du = " << 1.0 / odu[d] << std::endl;
671  os << indent + " dm = " << dm[d] << std::endl;
672  os << indent + " gmap = ";
673  for (int g = 0; g < gmap[d].size(); g++)
674  {
675  os << gmap[d][g] << " ";
676  }
677  os << std::endl;
678  }
679  os << indent + "end SpaceGrid" << std::endl;
680 }
681 
682 
684 {
685  buffer_offset = buf.size();
686  if (!chempot)
687  {
688  std::vector<RealType> tmp(nvalues_per_domain * ndomains);
689  buf.add(tmp.begin(), tmp.end());
692  }
693  else
694  {
695  std::vector<RealType> tmp(nvalues_per_domain * npvalues * ndomains);
696  buf.add(tmp.begin(), tmp.end());
699  }
700  return buffer_offset;
701 }
702 
703 
704 void SpaceGrid::registerCollectables(std::vector<ObservableHelper>& h5desc, hdf_archive& file, int grid_index) const
705 {
706  using iMatrix = Matrix<int>;
707  iMatrix imat;
708  std::vector<int> ng(1);
709  int cshift = 1;
710  std::stringstream ss;
711  ss << grid_index + cshift;
712  std::string name = "spacegrid" + ss.str();
713  h5desc.push_back({{name}});
714  auto& oh = h5desc.back();
715  if (!chempot)
716  ng[0] = nvalues_per_domain * ndomains;
717  else
720  int coord = (int)coordinate;
721  oh.addProperty(const_cast<int&>(coord), "coordinate", file);
722  oh.addProperty(const_cast<int&>(ndomains), "ndomains", file);
723  oh.addProperty(const_cast<int&>(nvalues_per_domain), "nvalues_per_domain", file);
724  oh.addProperty(const_cast<RealType&>(volume), "volume", file);
725  oh.addProperty(const_cast<Matrix_t&>(domain_volumes), "domain_volumes", file);
726  oh.addProperty(const_cast<Matrix_t&>(domain_centers), "domain_centers", file);
727  if (chempot)
728  {
729  oh.addProperty(const_cast<int&>(npmin), "min_part", file);
730  oh.addProperty(const_cast<int&>(npmax), "max_part", file);
731  int ref = (int)reference;
732  oh.addProperty(const_cast<int&>(ref), "reference", file);
733  imat.resize(reference_count.size(), 1);
734  for (int i = 0; i < reference_count.size(); i++)
735  imat(i, 0) = reference_count[i];
736  oh.addProperty(const_cast<iMatrix&>(imat), "reference_count", file);
737  }
738  if (coordinate != voronoi)
739  {
740  oh.addProperty(const_cast<Point&>(origin), "origin", file);
741  oh.addProperty(const_cast<Tensor_t&>(axes), "axes", file);
742  oh.addProperty(const_cast<Tensor_t&>(axinv), "axinv", file);
743  oh.addProperty(const_cast<Matrix_t&>(domain_uwidths), "domain_uwidths", file);
744  //add dimensioned quantities
745  std::map<std::string, int> axtmap;
746  axtmap["x"] = 0;
747  axtmap["y"] = 1;
748  axtmap["z"] = 2;
749  axtmap["r"] = 3;
750  axtmap["phi"] = 4;
751  axtmap["theta"] = 5;
752  int axtypes[DIM];
753  for (int d = 0; d < DIM; d++)
754  {
755  axtypes[d] = axtmap[axlabel[d]];
756  }
757  int n;
758  const int ni = 3;
759  int* ivar[ni];
760  std::string iname[ni];
761  n = 0;
762  ivar[n] = (int*)axtypes;
763  iname[n] = "axtypes";
764  n++;
765  ivar[n] = (int*)dimensions;
766  iname[n] = "dimensions";
767  n++;
768  ivar[n] = (int*)dm;
769  iname[n] = "dm";
770  n++;
771  const int nr = 3;
772  RealType* rvar[nr];
773  std::string rname[nr];
774  n = 0;
775  rvar[n] = (RealType*)odu;
776  rname[n] = "odu";
777  n++;
778  rvar[n] = (RealType*)umin;
779  rname[n] = "umin";
780  n++;
781  rvar[n] = (RealType*)umax;
782  rname[n] = "umax";
783  n++;
784  imat.resize(DIM, 1);
785  for (int i = 0; i < ni; i++)
786  {
787  for (int d = 0; d < DIM; d++)
788  imat(d, 0) = ivar[i][d];
789  oh.addProperty(const_cast<iMatrix&>(imat), iname[i], file);
790  }
791  Matrix_t rmat;
792  rmat.resize(DIM, 1);
793  for (int i = 0; i < nr; i++)
794  {
795  for (int d = 0; d < DIM; d++)
796  rmat(d, 0) = rvar[i][d];
797  oh.addProperty(const_cast<Matrix_t&>(rmat), rname[i], file);
798  }
799  for (int d = 0; d < DIM; d++)
800  {
801  int gsize = gmap[d].size();
802  imat.resize(gsize, 1);
803  for (int i = 0; i < gsize; i++)
804  {
805  int gval = gmap[d][i];
806  imat(i, 0) = gval;
807  }
808  int ival = d + 1;
809  std::string gmname = "gmap" + int2string(ival);
810  oh.addProperty(const_cast<iMatrix&>(imat), gmname, file);
811  }
812  }
813 
814  return;
815 }
816 
817 
818 #define SPACEGRID_CHECK
819 
820 
822  const Matrix<RealType>& values,
823  BufferType& buf,
824  std::vector<bool>& particles_outside,
825  const DistanceTableAB& dtab)
826 {
827  int p, v;
828  int nparticles = values.size1();
829  int nvalues = values.size2();
830  int iu[DIM];
831  int buf_index;
832  const RealType o2pi = 1.0 / (2.0 * M_PI);
833  if (!chempot)
834  {
835  switch (coordinate)
836  {
837  case cartesian:
838  if (periodic)
839  {
840  for (p = 0; p < nparticles; p++)
841  {
842  particles_outside[p] = false;
843  u = dot(axinv, (R[p] - origin));
844  for (int d = 0; d < DIM; ++d)
845  iu[d] = gmap[d][floor((u[d] - umin[d]) * odu[d])];
846  buf_index = buffer_offset;
847  for (int d = 0; d < DIM; ++d)
848  buf_index += nvalues * dm[d] * iu[d];
849  for (v = 0; v < nvalues; v++, buf_index++)
850  buf[buf_index] += values(p, v);
851  }
852  }
853  else
854  {
855  for (p = 0; p < nparticles; p++)
856  {
857  u = dot(axinv, (R[p] - origin));
858  if (u[0] > umin[0] && u[0] < umax[0] && u[1] > umin[1] && u[1] < umax[1] && u[2] > umin[2] && u[2] < umax[2])
859  {
860  particles_outside[p] = false;
861  iu[0] = gmap[0][floor((u[0] - umin[0]) * odu[0])];
862  iu[1] = gmap[1][floor((u[1] - umin[1]) * odu[1])];
863  iu[2] = gmap[2][floor((u[2] - umin[2]) * odu[2])];
864  buf_index = buffer_offset + nvalues * (dm[0] * iu[0] + dm[1] * iu[1] + dm[2] * iu[2]);
865  for (v = 0; v < nvalues; v++, buf_index++)
866  buf[buf_index] += values(p, v);
867  }
868  }
869  }
870  break;
871  case cylindrical:
872  for (p = 0; p < nparticles; p++)
873  {
874  ub = dot(axinv, (R[p] - origin));
875  u[0] = sqrt(ub[0] * ub[0] + ub[1] * ub[1]);
876  u[1] = atan2(ub[1], ub[0]) * o2pi + .5;
877  u[2] = ub[2];
878  if (u[0] > umin[0] && u[0] < umax[0] && u[1] > umin[1] && u[1] < umax[1] && u[2] > umin[2] && u[2] < umax[2])
879  {
880  particles_outside[p] = false;
881  iu[0] = gmap[0][floor((u[0] - umin[0]) * odu[0])];
882  iu[1] = gmap[1][floor((u[1] - umin[1]) * odu[1])];
883  iu[2] = gmap[2][floor((u[2] - umin[2]) * odu[2])];
884  buf_index = buffer_offset + nvalues * (dm[0] * iu[0] + dm[1] * iu[1] + dm[2] * iu[2]);
885  for (v = 0; v < nvalues; v++, buf_index++)
886  buf[buf_index] += values(p, v);
887  }
888  }
889  break;
890  case spherical:
891  for (p = 0; p < nparticles; p++)
892  {
893  ub = dot(axinv, (R[p] - origin));
894  u[0] = sqrt(ub[0] * ub[0] + ub[1] * ub[1] + ub[2] * ub[2]);
895  u[1] = atan2(ub[1], ub[0]) * o2pi + .5;
896  u[2] = acos(ub[2] / u[0]) * o2pi * 2.0;
897  if (u[0] > umin[0] && u[0] < umax[0] && u[1] > umin[1] && u[1] < umax[1] && u[2] > umin[2] && u[2] < umax[2])
898  {
899  particles_outside[p] = false;
900  iu[0] = gmap[0][floor((u[0] - umin[0]) * odu[0])];
901  iu[1] = gmap[1][floor((u[1] - umin[1]) * odu[1])];
902  iu[2] = gmap[2][floor((u[2] - umin[2]) * odu[2])];
903  buf_index = buffer_offset + nvalues * (dm[0] * iu[0] + dm[1] * iu[1] + dm[2] * iu[2]);
904  for (v = 0; v < nvalues; v++, buf_index++)
905  buf[buf_index] += values(p, v);
906  }
907  }
908  break;
909  case voronoi:
910  //find cell center nearest to each dynamic particle
911  int nd, nn;
912  RealType dist;
913  for (p = 0; p < ndparticles; p++)
914  {
915  const auto& dist = dtab.getDistRow(p);
916  for (nd = 0; nd < ndomains; nd++)
917  if (dist[nd] < nearcell[p].r)
918  {
919  nearcell[p].r = dist[nd];
920  nearcell[p].i = nd;
921  }
922  }
923  //accumulate values for each dynamic particle
924  for (p = 0; p < ndparticles; p++)
925  {
926  buf_index = buffer_offset + nvalues * nearcell[p].i;
927  for (v = 0; v < nvalues; v++, buf_index++)
928  buf[buf_index] += values(p, v);
929  }
930  //accumulate values for static particles (static particles == cell centers)
931  buf_index = buffer_offset;
932  for (p = ndparticles; p < nparticles; p++)
933  for (v = 0; v < nvalues; v++, buf_index++)
934  buf[buf_index] += values(p, v);
935  //each particle belongs to some voronoi cell
936  for (p = 0; p < nparticles; p++)
937  particles_outside[p] = false;
938  //reset distances
939  for (p = 0; p < ndparticles; p++)
940  nearcell[p].r = std::numeric_limits<RealType>::max();
941  break;
942  default:
943  app_log() << " coordinate type must be cartesian, cylindrical, spherical, or voronoi" << std::endl;
944  APP_ABORT("SpaceGrid::evaluate");
945  }
946  }
947  else
948  //chempot: sort values by particle count in volumes
949  {
950  int cell_index;
951  int nd;
952  std::fill(cellsamples.begin(), cellsamples.end(), 0.0);
953  switch (coordinate)
954  {
955  case cartesian:
956  for (p = 0; p < nparticles; p++)
957  {
958  u = dot(axinv, (R[p] - origin));
959  if (u[0] > umin[0] && u[0] < umax[0] && u[1] > umin[1] && u[1] < umax[1] && u[2] > umin[2] && u[2] < umax[2])
960  {
961  particles_outside[p] = false;
962  iu[0] = gmap[0][floor((u[0] - umin[0]) * odu[0])];
963  iu[1] = gmap[1][floor((u[1] - umin[1]) * odu[1])];
964  iu[2] = gmap[2][floor((u[2] - umin[2]) * odu[2])];
965  cell_index = dm[0] * iu[0] + dm[1] * iu[1] + dm[2] * iu[2];
966  for (v = 0; v < nvalues; v++)
967  cellsamples(cell_index, v) += values(p, v);
968  cellsamples(cell_index, nvalues) += 1.0;
969  }
970  }
971  break;
972  case cylindrical:
973  for (p = 0; p < nparticles; p++)
974  {
975  ub = dot(axinv, (R[p] - origin));
976  u[0] = sqrt(ub[0] * ub[0] + ub[1] * ub[1]);
977  u[1] = atan2(ub[1], ub[0]) * o2pi + .5;
978  u[2] = ub[2];
979  if (u[0] > umin[0] && u[0] < umax[0] && u[1] > umin[1] && u[1] < umax[1] && u[2] > umin[2] && u[2] < umax[2])
980  {
981  particles_outside[p] = false;
982  iu[0] = gmap[0][floor((u[0] - umin[0]) * odu[0])];
983  iu[1] = gmap[1][floor((u[1] - umin[1]) * odu[1])];
984  iu[2] = gmap[2][floor((u[2] - umin[2]) * odu[2])];
985  cell_index = dm[0] * iu[0] + dm[1] * iu[1] + dm[2] * iu[2];
986  for (v = 0; v < nvalues; v++)
987  cellsamples(cell_index, v) += values(p, v);
988  cellsamples(cell_index, nvalues) += 1.0;
989  }
990  }
991  break;
992  case spherical:
993  for (p = 0; p < nparticles; p++)
994  {
995  ub = dot(axinv, (R[p] - origin));
996  u[0] = sqrt(ub[0] * ub[0] + ub[1] * ub[1] + ub[2] * ub[2]);
997  u[1] = atan2(ub[1], ub[0]) * o2pi + .5;
998  u[2] = acos(ub[2] / u[0]) * o2pi * 2.0;
999  if (u[0] > umin[0] && u[0] < umax[0] && u[1] > umin[1] && u[1] < umax[1] && u[2] > umin[2] && u[2] < umax[2])
1000  {
1001  particles_outside[p] = false;
1002  iu[0] = gmap[0][floor((u[0] - umin[0]) * odu[0])];
1003  iu[1] = gmap[1][floor((u[1] - umin[1]) * odu[1])];
1004  iu[2] = gmap[2][floor((u[2] - umin[2]) * odu[2])];
1005  cell_index = dm[0] * iu[0] + dm[1] * iu[1] + dm[2] * iu[2];
1006  for (v = 0; v < nvalues; v++)
1007  cellsamples(cell_index, v) += values(p, v);
1008  cellsamples(cell_index, nvalues) += 1.0;
1009  }
1010  }
1011  break;
1012  case voronoi:
1013  //find cell center nearest to each dynamic particle
1014  int nn;
1015  RealType dist;
1016  APP_ABORT("SoA transformation needed for Voronoi grids")
1017  //for (nd = 0; nd < ndomains; nd++)
1018  // for (nn = dtab.M[nd], p = 0; nn < dtab.M[nd + 1]; ++nn, ++p)
1019  // {
1020  // dist = dtab.r(nn);
1021  // if (dist < nearcell[p].r)
1022  // {
1023  // nearcell[p].r = dist;
1024  // nearcell[p].i = nd;
1025  // }
1026  // }
1027  //accumulate values for each dynamic particle
1028  for (p = 0; p < ndparticles; p++)
1029  {
1030  cell_index = nearcell[p].i;
1031  for (v = 0; v < nvalues; v++)
1032  cellsamples(cell_index, v) += values(p, v);
1033  cellsamples(cell_index, nvalues) += 1.0;
1034  }
1035  //accumulate values for static particles (static particles == cell centers)
1036  for (p = ndparticles, cell_index = 0; p < nparticles; p++, cell_index++)
1037  {
1038  for (v = 0; v < nvalues; v++)
1039  cellsamples(cell_index, v) += values(p, v);
1040  cellsamples(cell_index, nvalues) += 1.0;
1041  }
1042  //each particle belongs to some voronoi cell
1043  for (p = 0; p < nparticles; p++)
1044  particles_outside[p] = false;
1045  //reset distances
1046  for (p = 0; p < ndparticles; p++)
1047  nearcell[p].r = std::numeric_limits<RealType>::max();
1048  break;
1049  default:
1050  app_log() << " coordinate type must be cartesian, cylindrical, spherical, or voronoi" << std::endl;
1051  APP_ABORT("SpaceGrid::evaluate");
1052  }
1053  //now place samples in the buffer according to how
1054  // many particles are in each cell
1055  int nincell;
1056  buf_index = buffer_offset;
1057  for (nd = 0; nd < ndomains; nd++)
1058  {
1059  nincell = cellsamples(nd, nvalues) - reference_count[nd];
1060  if (nincell >= npmin && nincell <= npmax)
1061  {
1062  buf_index = buffer_offset + (nd * npvalues + nincell - npmin) * nvalues;
1063  for (v = 0; v < nvalues; v++, buf_index++)
1064  buf[buf_index] += cellsamples(nd, v);
1065  }
1066  }
1067  }
1068 }
1069 
1070 
1071 void SpaceGrid::sum(const BufferType& buf, RealType* vals)
1072 {
1073  for (int v = 0; v < nvalues_per_domain; v++)
1074  {
1075  vals[v] = 0.0;
1076  }
1077  for (int i = 0, n = buffer_offset; i < ndomains; i++, n += nvalues_per_domain)
1078  {
1079  for (int v = 0; v < nvalues_per_domain; v++)
1080  {
1081  vals[v] += buf[n + v];
1082  }
1083  }
1084 }
1085 
1086 
1088 {
1089  app_log() << "SpaceGrid::check_grid" << std::endl;
1090  const RealType o2pi = 1.0 / (2.0 * M_PI);
1091  int iu[DIM];
1092  int idomain;
1093  bool ok = true;
1094  Point dc;
1095  for (int i = 0; i < ndomains; i++)
1096  {
1097  for (int d = 0; d < DIM; d++)
1098  dc[d] = domain_centers(i, d);
1099  ub = dot(axinv, (dc - origin));
1100  switch (coordinate)
1101  {
1102  case cartesian:
1103  u = ub;
1104  break;
1105  case cylindrical:
1106  u[0] = sqrt(ub[0] * ub[0] + ub[1] * ub[1]);
1107  u[1] = atan2(ub[1], ub[0]) * o2pi + .5;
1108  u[2] = ub[2];
1109  break;
1110  case spherical:
1111  u[0] = sqrt(ub[0] * ub[0] + ub[1] * ub[1] + ub[2] * ub[2]);
1112  u[1] = atan2(ub[1], ub[0]) * o2pi + .5;
1113  u[2] = acos(ub[2] / u[0]) * o2pi * 2.0;
1114  break;
1115  default:
1116  break;
1117  }
1118  iu[0] = gmap[0][floor((u[0] - umin[0]) * odu[0])];
1119  iu[1] = gmap[1][floor((u[1] - umin[1]) * odu[1])];
1120  iu[2] = gmap[2][floor((u[2] - umin[2]) * odu[2])];
1121  idomain = dm[0] * iu[0] + dm[1] * iu[1] + dm[2] * iu[2];
1122  if (idomain != i)
1123  {
1124  app_log() << " cell mismatch " << i << " " << idomain << std::endl;
1125  ok = false;
1126  }
1127  }
1128  if (!ok)
1129  {
1130  app_log() << " SpaceGrid cells do not map onto themselves" << std::endl;
1131  }
1132  app_log() << "end SpaceGrid::check_grid" << std::endl;
1133  return ok;
1134 }
1135 
1136 } // namespace qmcplusplus
RealType odu[DIM]
Definition: SpaceGrid.h:105
Tensor< RealType, DIM > axinv
Definition: SpaceGrid.h:100
Container_t::iterator begin()
Definition: OhmmsMatrix.h:89
size_type size1() const
Definition: OhmmsMatrix.h:79
size_type size() const
return the size of the data
Definition: PooledData.h:48
enum qmcplusplus::SpaceGrid::@61 coordinate
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
std::vector< int > reference_count
Definition: SpaceGrid.h:95
Tensor< T, D >::Type_t det(const Tensor< T, D > &a)
Definition: TensorOps.h:838
const DistRow & getDistRow(int iel) const
return a row of distances for a given target particle
MakeReturn< UnaryNode< FnFabs, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t abs(const Vector< T1, C1 > &l)
std::ostream & app_log()
Definition: OutputManager.h:65
bool put(xmlNodePtr cur)
assign attributes to the set
Definition: AttributeSet.h:55
MakeReturn< UnaryNode< FnSin, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t sin(const Vector< T1, C1 > &l)
std::string int2string(const int &i)
Definition: string_utils.h:119
class to handle hdf file
Definition: hdf_archive.h:51
void addProperty(T &p, const std::string &pname, hdf_archive &file)
add named property to describe the collectable this helper class handles
ParticlePos * Rptcl
Definition: SpaceGrid.h:113
void resize(size_type n, size_type m)
Resize the container.
Definition: OhmmsMatrix.h:99
Attaches a unit to a Vector for IO.
Matrix< RealType > cellsamples
Definition: SpaceGrid.h:88
T min(T a, T b)
void write_description(std::ostream &os, std::string &indent)
Definition: SpaceGrid.cpp:642
void sum(const BufferType &buf, RealType *vals)
Definition: SpaceGrid.cpp:1071
void evaluate(const ParticlePos &R, const Matrix< RealType > &values, BufferType &buf, std::vector< bool > &particles_outside, const DistanceTableAB &dtab)
Definition: SpaceGrid.cpp:821
int string2int(const std::string &s)
Definition: string_utils.h:115
size_type size() const
return the current size
Definition: OhmmsVector.h:162
MakeReturn< UnaryNode< FnCos, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t cos(const Vector< T1, C1 > &l)
std::vector< std::string > split(const std::string &s)
Definition: string_utils.h:57
void add(T &x)
Definition: PooledData.h:88
MakeReturn< UnaryNode< FnArcCos, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t acos(const Vector< T1, C1 > &l)
MakeReturn< BinaryNode< FnArcTan2, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t, typename CreateLeaf< Vector< T2, C2 > >::Leaf_t > >::Expression_t atan2(const Vector< T1, C1 > &l, const Vector< T2, C2 > &r)
AB type of DistanceTable containing storage.
Matrix< RealType > domain_volumes
Definition: SpaceGrid.h:81
class to handle a set of attributes of an xmlNode
Definition: AttributeSet.h:24
double string2real(const std::string &s)
Definition: string_utils.h:117
int allocate_buffer_space(BufferType &buf)
Definition: SpaceGrid.cpp:683
#define APP_ABORT(msg)
Widely used but deprecated fatal error macros from legacy code.
Definition: AppAbort.h:27
std::string axlabel[DIM]
Definition: SpaceGrid.h:103
std::vector< int > gmap[DIM]
Definition: SpaceGrid.h:104
void registerCollectables(std::vector< ObservableHelper > &h5desc, hdf_archive &file, int grid_index) const
Definition: SpaceGrid.cpp:704
MakeReturn< UnaryNode< FnSqrt, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t sqrt(const Vector< T1, C1 > &l)
std::vector< RealType > * Zptcl
Definition: SpaceGrid.h:114
std::vector< irpair > nearcell
Definition: SpaceGrid.h:120
Tensor< T, D > inverse(const Tensor< T, D > &a)
Definition: TensorOps.h:879
void set_dimensions(const std::vector< int > &dims, int first)
set the shape of this observable
RealType umin[DIM]
Definition: SpaceGrid.h:106
size_type size2() const
Definition: OhmmsMatrix.h:80
const char coord[]
Definition: HDFVersion.h:48
enum qmcplusplus::SpaceGrid::@62 reference
Tensor< typename BinaryReturn< T1, T2, OpMultiply >::Type_t, D > dot(const AntiSymTensor< T1, D > &lhs, const AntiSymTensor< T2, D > &rhs)
Container_t::iterator end()
Definition: OhmmsMatrix.h:90
void add(PDT &aparam, const std::string &aname, std::vector< PDT > candidate_values={}, TagStatus status=TagStatus::OPTIONAL)
add a new attribute
Definition: AttributeSet.h:42
Matrix< RealType > domain_centers
Definition: SpaceGrid.h:82
RealType umax[DIM]
Definition: SpaceGrid.h:107
SpaceGrid(int &nvalues)
Definition: SpaceGrid.cpp:32
bool initialize_voronoi(std::map< std::string, Point > &points)
Definition: SpaceGrid.cpp:122
bool initialize_rectilinear(xmlNodePtr cur, std::string &coord, std::map< std::string, Point > &points)
Definition: SpaceGrid.cpp:170
Matrix< RealType > domain_uwidths
Definition: SpaceGrid.h:102
Tensor< RealType, DIM > axes
Definition: SpaceGrid.h:99
ObservableHelper oh
bool put(xmlNodePtr cur, std::map< std::string, Point > &points, ParticlePos &R, std::vector< RealType > &Z, int ndp, bool is_periodic, bool abort_on_fail=true)
Definition: SpaceGrid.h:34
MakeReturn< UnaryNode< FnFloor, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t floor(const Vector< T1, C1 > &l)