QMCPACK
NESpaceGrid.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) 2023 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 // Peter W. Doak, doakpw@ornl.gov, Oak Ridge National Laboratory
10 //
11 // Some code refactored from: QMCHamiltonian/SpaceGrid.cpp
12 //////////////////////////////////////////////////////////////////////////////////////
13 
14 #include "NESpaceGrid.h"
15 
16 #include <hdf5.h>
17 
18 #include "OhmmsData/AttributeSet.h"
19 #include "Utilities/string_utils.h"
20 #include <cmath>
21 #include "OhmmsPETE/OhmmsArray.h"
22 #include "NEReferencePoints.h"
23 #include "Concurrency/OpenMP.h"
24 
25 namespace qmcplusplus
26 {
27 using std::acos;
28 using std::atan2;
29 using std::cos;
30 using std::floor;
31 using std::sin;
32 using std::sqrt;
33 
34 template<typename REAL>
35 NESpaceGrid<REAL>::NESpaceGrid(SpaceGridInput& sgi,
36  const NEReferencePoints::Points& points,
37  const int nvalues,
38  const bool is_periodic)
39  : NESpaceGrid(sgi, points, 0, nvalues, is_periodic)
40 {}
41 
42 template<typename REAL>
43 NESpaceGrid<REAL>::NESpaceGrid(SpaceGridInput& sgi,
44  const NEReferencePoints::Points& points,
45  const int ndp,
46  const int nvalues,
47  const bool is_periodic)
48  : input_(sgi), ndparticles_(ndp), is_periodic_(is_periodic), points_(points), nvalues_per_domain_(nvalues)
49 {
50  bool init_success = initializeCoordSystem();
51  if (!init_success)
52  throw std::runtime_error("NESpaceGrid initialization failed");
53 }
54 
55 template<typename REAL>
56 NESpaceGrid<REAL>::NESpaceGrid(SpaceGridInput& sgi,
57  const NEReferencePoints::Points& points,
58  ParticlePos& static_particle_positions,
59  std::vector<Real>& Z,
60  const int ndp,
61  const int nvalues,
62  const bool is_periodic)
63  : input_(sgi), ndparticles_(ndp), is_periodic_(is_periodic), points_(points), nvalues_per_domain_(nvalues)
64 {
65  bool init_success = initializeCoordSystem();
66  if (!init_success)
67  throw std::runtime_error("NESpaceGrid initialization failed");
68 }
69 
70 template<typename REAL>
72 {
73  using CoordForm = SpaceGridInput::CoordForm;
74  bool init_success = false;
75  switch (input_.get_coord_form())
76  {
77  case (CoordForm::CARTESIAN):
78  init_success = initializeRectilinear(input_, points_);
79  break;
80  case (CoordForm::CYLINDRICAL):
81  init_success = initializeCylindrical(input_, points_);
82  break;
83  case (CoordForm::SPHERICAL):
84  init_success = initializeSpherical(input_, points_);
85  break;
86  }
87  return init_success;
88 }
89 
90 template<typename REAL>
91 void NESpaceGrid<REAL>::processAxis(const SpaceGridInput& input, const Points& points, AxTensor& axes, AxTensor& axinv)
92 {
93  auto& axis_labels = input.get_axis_labels();
94  auto& axis_p1s = input.get_axis_p1s();
95  auto& axis_p2s = input.get_axis_p2s();
96  auto& axis_scales = input.get_axis_scales();
97  auto& axis_grids = input.get_axis_grids();
98 
99  // SpaceGridInput check particular validity insures the number of axis == OHMMS_DIM
100  for (int iaxis = 0; iaxis < OHMMS_DIM; ++iaxis)
101  {
102  Real frac = axis_scales[iaxis];
103  for (int d = 0; d < OHMMS_DIM; d++)
104  axes(d, iaxis) = frac * (points.at(axis_p1s[iaxis])[d] - points.at(axis_p2s[iaxis])[d]);
105  }
106  axinv = inverse(axes);
107 }
108 
109 template<typename REAL>
111 {
112  const std::string& origin_p1 = input.get_origin_p1();
113  const std::string& origin_p2 = input.get_origin_p2();
114 
115  if (origin_p1.size() > 0 && origin_p2.size() > 0)
116  {
117  return points.at(origin_p1) + input.get_origin_fraction() * (points.at(origin_p2) - points.at(origin_p1));
118  }
119  else if (origin_p1.size() > 0)
120  return points.at(origin_p1);
121  else
122  return points.at("zero");
123 }
124 
125 template<typename REAL>
127 {
128  // This code should be refactored to SpaceGridInput such that a simple map of
129  // axis is available.
130 
131  origin_ = deriveOrigin(input, points);
132  processAxis(input, points, axes_, axinv_);
133 
134  // this should all be done in SpaceGrid input parsing/construction now.
135  // bool succeeded = checkAxisGridValues(input, axes_);
136 
137  someMoreAxisGridStuff();
138 
139  copyToSoA();
140 
141  return true;
142 }
143 
144 template<typename REAL>
146 {
147  // This code should be refactored to SpaceGridInput such that a simple map of
148  // axis is available.
149 
150  origin_ = deriveOrigin(input, points);
151  processAxis(input, points, axes_, axinv_);
152  // bool succeeded = checkAxisGridValues(input, axes_);
153 
154  someMoreAxisGridStuff();
155 
156  copyToSoA();
157 
158  return true;
159 }
160 
161 template<typename REAL>
163 {
164  // This code should be refactored to SpaceGridInput such that a simple map of
165  // axis is available.
166 
167  origin_ = deriveOrigin(input, points);
168  processAxis(input, points, axes_, axinv_);
169  //bool succeeded = checkAxisGridValues(input, axes_);
170 
171  someMoreAxisGridStuff();
172 
173  copyToSoA();
174 
175  return true;
176 }
177 
178 template<typename REAL>
180 {
181  auto& axis_grids = input_.get_axis_grids();
182  // This dates back to the legacy implementation and I'm not sure why both code blocks are here.
183  //set grid dimensions
184  // C/Python style indexing
185  dm_[0] = axis_grids[1].dimensions * axis_grids[2].dimensions;
186  dm_[1] = axis_grids[2].dimensions;
187  dm_[2] = 1;
188  // Fortran/Matlab style indexing
189  //dm[0] = 1;
190  //dm[1] = dimensions[0];
191  //dm[2] = dimensions[0]*dimensions[1];
192 
193  ndomains_ = axis_grids[0].dimensions * axis_grids[1].dimensions * axis_grids[2].dimensions;
194 
195  data_.resize(ndomains_ * nvalues_per_domain_);
196 
197  volume_ = std::abs(det(axes_)) * 8.0; //axes span only one octant
198  //compute domain volumes, centers, and widths
199 
200  domain_volumes_.resize(ndomains_, 1);
201  domain_centers_.resize(ndomains_, OHMMS_DIM);
202  domain_uwidths_.resize(ndomains_, OHMMS_DIM);
203  std::vector<Real> interval_centers[OHMMS_DIM];
204  std::vector<Real> interval_widths[OHMMS_DIM];
205 
206  auto& agr = axis_grids;
207 
208  for (int d = 0; d < OHMMS_DIM; d++)
209  {
210  int nintervals = agr[d].ndu_per_interval.size();
211  app_log() << "nintervals " << d << " " << nintervals << std::endl;
212  interval_centers[d].resize(nintervals);
213  interval_widths[d].resize(nintervals);
214  interval_widths[d][0] = agr[d].ndu_per_interval[0] / agr[d].odu;
215  interval_centers[d][0] = interval_widths[d][0] / 2.0 + agr[d].umin;
216  for (int i = 1; i < nintervals; i++)
217  {
218  interval_widths[d][i] = agr[d].ndu_per_interval[i] / agr[d].odu;
219  interval_centers[d][i] = interval_centers[d][i - 1] + .5 * (interval_widths[d][i] + interval_widths[d][i - 1]);
220  }
221  //app_log()<<" interval widths"<< std::endl;
222  //for(int i=0;i<nintervals;i++)
223  // app_log()<<" "<<i<<" "<<interval_widths[d][i]<< std::endl;
224  //app_log()<<" interval centers"<< std::endl;
225  //for(int i=0;i<nintervals;i++)
226  // app_log()<<" "<<i<<" "<<interval_centers[d][i]<< std::endl;
227  }
228  Point du, uc, ubc, rc;
229  Real vol = 0.0;
230  Real vscale = std::abs(det(axes_));
231  using CoordForm = SpaceGridInput::CoordForm;
232  for (int i = 0; i < agr[0].dimensions; i++)
233  {
234  for (int j = 0; j < agr[1].dimensions; j++)
235  {
236  for (int k = 0; k < agr[2].dimensions; k++)
237  {
238  int idomain = dm_[0] * i + dm_[1] * j + dm_[2] * k;
239  du[0] = interval_widths[0][i];
240  du[1] = interval_widths[1][j];
241  du[2] = interval_widths[2][k];
242  uc[0] = interval_centers[0][i];
243  uc[1] = interval_centers[1][j];
244  uc[2] = interval_centers[2][k];
245  switch (input_.get_coord_form())
246  {
247  case (CoordForm::CARTESIAN):
248  vol = du[0] * du[1] * du[2];
249  ubc = uc;
250  break;
251  case (CoordForm::CYLINDRICAL):
252  uc[1] = 2.0 * M_PI * uc[1] - M_PI;
253  du[1] = 2.0 * M_PI * du[1];
254  vol = uc[0] * du[0] * du[1] * du[2];
255  ubc[0] = uc[0] * cos(uc[1]);
256  ubc[1] = uc[0] * sin(uc[1]);
257  ubc[2] = uc[2];
258  break;
259  case (CoordForm::SPHERICAL):
260  uc[1] = 2.0 * M_PI * uc[1] - M_PI;
261  du[1] = 2.0 * M_PI * du[1];
262  uc[2] = M_PI * uc[2];
263  du[2] = M_PI * du[2];
264  vol = (uc[0] * uc[0] + du[0] * du[0] / 12.0) * du[0] //r
265  * du[1] //theta
266  * 2.0 * sin(uc[2]) * sin(.5 * du[2]); //phi
267  ubc[0] = uc[0] * sin(uc[2]) * cos(uc[1]);
268  ubc[1] = uc[0] * sin(uc[2]) * sin(uc[1]);
269  ubc[2] = uc[0] * cos(uc[2]);
270  break;
271  default:
272  break;
273  }
274  vol *= vscale;
275  rc = dot(axes_, ubc) + origin_;
276  //app_log()<< std::endl;
277  //app_log()<<"umin "<<uc-du/2<< std::endl;
278  //app_log()<<"uc "<<uc<< std::endl;
279  //app_log()<<"umax "<<uc+du/2<< std::endl;
280  //app_log()<<"rc "<<rc<< std::endl;
281  domain_volumes_(idomain, 0) = vol;
282  for (int d = 0; d < OHMMS_DIM; d++)
283  {
284  domain_uwidths_(idomain, d) = du[d];
285  domain_centers_(idomain, d) = rc[d];
286  }
287  }
288  }
289  }
290 
291  //find the actual volume of the grid
292  for (int d = 0; d < OHMMS_DIM; d++)
293  {
294  du[d] = agr[d].umax - agr[d].umin;
295  uc[d] = .5 * (agr[d].umax + agr[d].umin);
296  }
297  switch (input_.get_coord_form())
298  {
299  case CoordForm::CARTESIAN:
300  vol = du[0] * du[1] * du[2];
301  break;
302  case CoordForm::CYLINDRICAL:
303  uc[1] = 2.0 * M_PI * uc[1] - M_PI;
304  du[1] = 2.0 * M_PI * du[1];
305  vol = uc[0] * du[0] * du[1] * du[2];
306  break;
307  case CoordForm::SPHERICAL:
308  uc[1] = 2.0 * M_PI * uc[1] - M_PI;
309  du[1] = 2.0 * M_PI * du[1];
310  uc[2] = M_PI * uc[2];
311  du[2] = M_PI * du[2];
312  vol = (uc[0] * uc[0] + du[0] * du[0] / 12.0) * du[0] //r
313  * du[1] //theta
314  * 2.0 * sin(uc[2]) * sin(.5 * du[2]); //phi
315  break;
316  default:
317  break;
318  }
319  volume_ = vol * det(axes_);
320 
321  return;
322 }
323 
324 // template<typename REAL>
325 // bool NESpaceGrid<REAL>::checkAxisGridValues(const SpaceGridInput& input, const AxTensor& axes)
326 // {
327 // auto& axis_labels = input.get_axis_labels();
328 // auto& axis_grids = input.get_axis_grids();
329 
330 // //check that all axis grid values fall in the allowed intervals for the coord label
331 // bool succeeded = true;
332 // for (int d = 0; d < OHMMS_DIM; d++)
333 // {
334 
335 // if (axis_labels[d] == "phi" || axis_labels[d] == "theta" )
336 // if (axis_grids[d].umin < 0.0 || axis_grids[d].umax > 1.0)
337 // {
338 // app_log() << " grid values for " << axis_labels[d] << " must fall in [0,1]" << std::endl;
339 // app_log() << " interval provided: [" << axis_grids[d].umin << "," << axis_grids[d].umax << "]" << std::endl;
340 // succeeded = false;
341 // }
342 // else
343 // if (axis_grids[d].umin < -1.0 || axis_grids[d].umax > 1.0)
344 // {
345 // app_log() << " grid values for " << axis_labels[d] << " must fall in [-1,1]" << std::endl;
346 // app_log() << " interval provided: [" << axis_grids[d].umin << "," << axis_grids[d].umax << "]" << std::endl;
347 // succeeded = false;
348 // }
349 // return succeeded;
350 // }
351 
352 template<typename REAL>
353 void NESpaceGrid<REAL>::write_description(std::ostream& os, const std::string& indent)
354 {
355  os << indent + "SpaceGrid" << std::endl;
356  std::string s;
357  using CoordForm = SpaceGridInput::CoordForm;
358  switch (input_.get_coord_form())
359  {
360  case CoordForm::CARTESIAN:
361  s = "cartesian";
362  break;
363  case CoordForm::CYLINDRICAL:
364  s = "cylindrical";
365  break;
366  case CoordForm::SPHERICAL:
367  s = "spherical";
368  break;
369  default:
370  break;
371  }
372  auto& agr = input_.get_axis_grids();
373  auto& axis_labels = input_.get_axis_labels();
374  os << indent + " SpaceGridInput::lookup_input_ename_value(input_.get_coord_form() = " + s << std::endl;
375  os << indent + " ndomains_ = " << ndomains_ << std::endl;
376  os << indent + " axes = " << axes_ << std::endl;
377  os << indent + " axinv = " << axinv_ << std::endl;
378  for (int d = 0; d < OHMMS_DIM; d++)
379  {
380  os << indent + " axis " << axis_labels[d] << ":" << std::endl;
381  os << indent + " umin = " << agr[d].umin << std::endl;
382  os << indent + " umax = " << agr[d].umax << std::endl;
383  os << indent + " du = " << 1.0 / static_cast<double>(agr[d].odu) << std::endl;
384  os << indent + " dm = " << dm_[d] << std::endl;
385  os << indent + " gmap = ";
386  for (int g = 0; g < gmap_[d].size(); g++)
387  {
388  os << gmap_[d][g] << " ";
389  }
390  os << std::endl;
391  }
392  os << indent + "end NESpaceGrid" << std::endl;
393 }
394 
395 template<typename REAL>
396 void NESpaceGrid<REAL>::registerGrid(hdf_archive& file, int grid_index)
397 {
398  using iMatrix = Matrix<int>;
399  iMatrix imat;
400  std::vector<int> ng(1);
401  int cshift = 1;
402  std::stringstream ss;
403  ss << grid_index + cshift;
404  hdf_path hdf_name{"spacegrid" + ss.str()};
405  observable_helper_ = std::make_shared<ObservableHelper>(hdf_name);
406  auto& oh = *observable_helper_;
407  ng[0] = nvalues_per_domain_ * ndomains_;
408  oh.set_dimensions(ng, buffer_offset_);
409 
410  // Create a bunch of temporary SoA data from input to write the grid attributes
411  auto& agr = input_.get_axis_grids();
412  std::vector<int> dimensions(OHMMS_DIM);
413  for (int id = 0; id < OHMMS_DIM; ++id)
414  {
415  dimensions[id] = agr[id].dimensions;
416  }
417 
418  int coord = static_cast<int>(input_.get_coord_form());
419  oh.addProperty(const_cast<int&>(coord), "coordinate", file);
420  oh.addProperty(const_cast<int&>(ndomains_), "ndomains", file);
421  oh.addProperty(const_cast<int&>(nvalues_per_domain_), "nvalues_per_domain_", file);
422  oh.addProperty(const_cast<Real&>(volume_), "volume", file);
423  oh.addProperty(const_cast<Matrix<Real>&>(domain_volumes_), "domain_volumes", file);
424  oh.addProperty(const_cast<Matrix<Real>&>(domain_centers_), "domain_centers", file);
425  oh.addProperty(const_cast<Point&>(origin_), "origin", file);
426  oh.addProperty(const_cast<Tensor<Real, OHMMS_DIM>&>(axes_), "axes", file);
427  oh.addProperty(const_cast<Tensor<Real, OHMMS_DIM>&>(axinv_), "axinv", file);
428  oh.addProperty(const_cast<Matrix<Real>&>(domain_uwidths_), "domain_uwidths", file);
429  //add dimensioned quantities
430  std::map<std::string, int> axtmap;
431  axtmap["x"] = 0;
432  axtmap["y"] = 1;
433  axtmap["z"] = 2;
434  axtmap["r"] = 0;
435  axtmap["phi"] = 1;
436  axtmap["theta"] = 2;
437  int axtypes[OHMMS_DIM];
438  auto& axis_labels = input_.get_axis_labels();
439  for (int d = 0; d < OHMMS_DIM; d++)
440  {
441  axtypes[d] = axtmap[axis_labels[d]];
442  }
443  int n;
444  const int ni = 3;
445  // Now we arrive to a bunch of pointers to pointers that assume that all the axis grid
446  // information is laid out soa versus aos
447  int* ivar[ni];
448  std::string iname[ni];
449  n = 0;
450  ivar[n] = (int*)axtypes;
451  iname[n] = "axtypes";
452  n++;
453  ivar[n] = dimensions.data();
454  iname[n] = "dimensions";
455  n++;
456  ivar[n] = (int*)dm_;
457  iname[n] = "dm";
458  n++;
459  const int nr = 3;
460  Real* rvar[nr];
461  std::string rname[nr];
462  n = 0;
463  rvar[n] = (Real*)odu_;
464  rname[n] = "odu";
465  n++;
466  rvar[n] = (Real*)umin_;
467  rname[n] = "umin";
468  n++;
469  rvar[n] = (Real*)umax_;
470  rname[n] = "umax";
471  n++;
472  imat.resize(OHMMS_DIM, 1);
473  for (int i = 0; i < ni; i++)
474  {
475  for (int d = 0; d < OHMMS_DIM; d++)
476  imat(d, 0) = ivar[i][d];
477  oh.addProperty(const_cast<iMatrix&>(imat), iname[i], file);
478  }
479  Matrix<Real> rmat;
480  rmat.resize(OHMMS_DIM, 1);
481  for (int i = 0; i < nr; i++)
482  {
483  for (int d = 0; d < OHMMS_DIM; d++)
484  rmat(d, 0) = rvar[i][d];
485  oh.addProperty(const_cast<Matrix<Real>&>(rmat), rname[i], file);
486  }
487  for (int d = 0; d < OHMMS_DIM; d++)
488  {
489  int gsize = gmap_[d].size();
490  imat.resize(gsize, 1);
491  for (int i = 0; i < gsize; i++)
492  {
493  int gval = gmap_[d][i];
494  imat(i, 0) = gval;
495  }
496  int ival = d + 1;
497  std::string gmname = "gmap" + int2string(ival);
498  oh.addProperty(const_cast<iMatrix&>(imat), gmname, file);
499  }
500  return;
501 }
502 
503 template<typename REAL>
505 {
506  if (observable_helper_)
507  {
508  if constexpr (std::is_same<Real, QMCTraits::FullPrecRealType>::value)
509  {
510  observable_helper_->write(data_.data(), file);
511  }
512  else
513  {
514  std::vector<QMCTraits::FullPrecRealType> expanded_data(data_.size(), 0.0);
515  std::copy_n(data_.begin(), data_.size(), expanded_data.begin());
516  assert(!data_.empty());
517  // auto total = std::accumulate(data_->begin(), data_->end(), 0.0);
518  // std::cout << "data size: " << data_->size() << " : " << total << '\n';
519  observable_helper_->write(expanded_data.data(), file);
520  }
521  file.pop();
522  }
523  return;
524 }
525 
526 #define NESpaceGrid_CHECK
527 
528 template<typename REAL>
530 {
531  auto& agr = input_.get_axis_grids();
532  for (int id = 0; id < OHMMS_DIM; ++id)
533  {
534  odu_[id] = agr[id].odu;
535  umin_[id] = agr[id].umin;
536  umax_[id] = agr[id].umax;
537  gmap_[id].resize(floor((umax_[id] - umin_[id]) * odu_[id] + .5));
538  gmap_[id] = agr[id].gmap;
539  }
540 }
541 
542 template<typename REAL>
544  const Matrix<Real>& values,
545  std::vector<bool>& particles_outside,
546  const DistanceTableAB& dtab)
547 {
548  // //find cell center nearest to each dynamic particle
549  // int nd, nn;
550  // RealType dist;
551  // for (p = 0; p < ndparticles; p++)
552  // {
553  // const auto& dist = dtab.getDistRow(p);
554  // for (nd = 0; nd < ndomains; nd++)
555  // if (dist[nd] < nearcell[p].r)
556  // {
557  // nearcell[p].r = dist[nd];
558  // nearcell[p].i = nd;
559  // }
560  // }
561  // //accumulate values for each dynamic particle
562  // for (p = 0; p < ndparticles; p++)
563  // {
564  // buf_index = buffer_offset + nvalues * nearcell[p].i;
565  // for (v = 0; v < nvalues; v++, buf_index++)
566  // buf[buf_index] += values(p, v);
567  // }
568  // //accumulate values for static particles (static particles == cell centers)
569  // buf_index = buffer_offset;
570  // for (p = ndparticles; p < nparticles; p++)
571  // for (v = 0; v < nvalues; v++, buf_index++)
572  // buf[buf_index] += values(p, v);
573  // //each particle belongs to some voronoi cell
574  // for (p = 0; p < nparticles; p++)
575  // particles_outside[p] = false;
576  // //reset distances
577  // for (p = 0; p < ndparticles; p++)
578  // nearcell[p].r = std::numeric_limits<RealType>::max();
579  accumulate(R, values, particles_outside);
580 }
581 
582 template<typename REAL>
584  const Matrix<Real>& values,
585  std::vector<bool>& particles_outside)
586 {
587  int p, v;
588  int nparticles = values.size1();
589  int nvalues = values.size2();
590  int iu[OHMMS_DIM];
591  int buf_index;
592  const Real o2pi = 1.0 / (2.0 * M_PI);
593  using CoordForm = SpaceGridInput::CoordForm;
594  auto& agr = input_.get_axis_grids();
595  std::fill(particles_outside.begin(),particles_outside.end(), true);
596 
597  switch (input_.get_coord_form())
598  {
599  case CoordForm::CARTESIAN:
600  if (input_.isPeriodic())
601  {
602  for (p = 0; p < nparticles; p++)
603  {
604  particles_outside[p] = false;
605  Point u = dot(axinv_, (R[p] - origin_));
606  try
607  {
608  for (int d = 0; d < OHMMS_DIM; ++d)
609  iu[d] = gmap_[d].at(floor((u[d] - umin_[d]) * odu_[d]));
610  }
611  catch (const std::exception& exc)
612  {
613  std::ostringstream error;
614  error << "NESpaceGrid: particle: " << p << " position: " << R[p]
615  << " falls outside of the cell, for a period system all particle positions must be in the cell!\n";
616  std::throw_with_nested(std::runtime_error(error.str()));
617  }
618  buf_index = buffer_offset_;
619  for (int d = 0; d < OHMMS_DIM; ++d)
620  buf_index += nvalues * dm_[d] * iu[d];
621  for (v = 0; v < nvalues; v++, buf_index++)
622  data_[buf_index] += values(p, v);
623  }
624  }
625  else
626  {
627  for (p = 0; p < nparticles; p++)
628  {
629  Point u = dot(axinv_, (R[p] - origin_));
630  if (u[0] > umin_[0] && u[0] < umax_[0] && u[1] > umin_[1] && u[1] < umax_[1] && u[2] > umin_[2] &&
631  u[2] < umax_[2])
632  {
633  particles_outside[p] = false;
634  iu[0] = gmap_[0][floor((u[0] - umin_[0]) * odu_[0])];
635  iu[1] = gmap_[1][floor((u[1] - umin_[1]) * odu_[1])];
636  iu[2] = gmap_[2][floor((u[2] - umin_[2]) * odu_[2])];
637  buf_index = buffer_offset_ + nvalues * (dm_[0] * iu[0] + dm_[1] * iu[1] + dm_[2] * iu[2]);
638  for (v = 0; v < nvalues; v++, buf_index++)
639  data_[buf_index] += values(p, v);
640  }
641  }
642  }
643  break;
644  case CoordForm::CYLINDRICAL:
645  for (p = 0; p < nparticles; p++)
646  {
647  Point ub = dot(axinv_, (R[p] - origin_));
648  Point u{sqrt(ub[0] * ub[0] + ub[1] * ub[1]), static_cast<Real>(atan2(ub[1], ub[0]) * o2pi + .5), ub[2]};
649  if (u[0] > umin_[0] && u[0] < umax_[0] && u[1] > umin_[1] && u[1] < umax_[1] && u[2] > umin_[2] &&
650  u[2] < umax_[2])
651  {
652  particles_outside[p] = false;
653  iu[0] = gmap_[0][floor((u[0] - umin_[0]) * odu_[0])];
654  iu[1] = gmap_[1][floor((u[1] - umin_[1]) * odu_[1])];
655  iu[2] = gmap_[2][floor((u[2] - umin_[2]) * odu_[2])];
656  buf_index = buffer_offset_ + nvalues * (dm_[0] * iu[0] + dm_[1] * iu[1] + dm_[2] * iu[2]);
657  for (v = 0; v < nvalues; v++, buf_index++)
658  data_[buf_index] += values(p, v);
659  }
660  }
661  break;
662  case CoordForm::SPHERICAL:
663  for (p = 0; p < nparticles; p++)
664  {
665  Point ub = dot(axinv_, (R[p] - origin_));
666  Point u;
667  u[0] = sqrt(ub[0] * ub[0] + ub[1] * ub[1] + ub[2] * ub[2]);
668  u[1] = atan2(ub[1], ub[0]) * o2pi + .5;
669  u[2] = acos(ub[2] / u[0]) * o2pi * 2.0;
670  if (u[0] > umin_[0] && u[0] < umax_[0] && u[1] > umin_[1] && u[1] < umax_[1] && u[2] > umin_[2] &&
671  u[2] < umax_[2])
672  {
673  particles_outside[p] = false;
674  iu[0] = gmap_[0][floor((u[0] - umin_[0]) * odu_[0])];
675  iu[1] = gmap_[1][floor((u[1] - umin_[1]) * odu_[1])];
676  iu[2] = gmap_[2][floor((u[2] - umin_[2]) * odu_[2])];
677  buf_index = buffer_offset_ + nvalues * (dm_[0] * iu[0] + dm_[1] * iu[1] + dm_[2] * iu[2]);
678  for (v = 0; v < nvalues; v++, buf_index++)
679  data_[buf_index] += values(p, v);
680  }
681  }
682  break;
683  default:
684  app_log() << " coordinate type must be cartesian, cylindrical, spherical" << std::endl;
685  throw std::runtime_error("SpaceGrid<REAL>::evaluate received an invalid coordinate type");
686  }
687 }
688 
689 template<typename REAL>
690 void NESpaceGrid<REAL>::sum(const BufferType& buf, Real* vals)
691 {
692  for (int v = 0; v < nvalues_per_domain_; v++)
693  {
694  vals[v] = 0.0;
695  }
696  for (int i = 0, n = buffer_offset_; i < ndomains_; i++, n += nvalues_per_domain_)
697  {
698  for (int v = 0; v < nvalues_per_domain_; v++)
699  {
700  vals[v] += data_[n + v];
701  }
702  }
703 }
704 
705 template<typename REAL>
706 void NESpaceGrid<REAL>::collect(NESpaceGrid& reduction_grid, RefVector<NESpaceGrid> grid_for_each_crowd)
707 {
708  for (NESpaceGrid& crowd_grid : grid_for_each_crowd)
709  {
710  std::transform(reduction_grid.data_.begin(), reduction_grid.data_.end(), crowd_grid.data_.begin(),
711  reduction_grid.data_.begin(), std::plus<>{});
712  crowd_grid.zero();
713  }
714 }
715 
716 template<typename REAL>
718 {
719  data_.clear();
720 }
721 
722 template<typename REAL>
724 {
725  app_log() << "SpaceGrid<REAL>::check_grid" << std::endl;
726  const Real o2pi = 1.0 / (2.0 * M_PI);
727  int iu[OHMMS_DIM];
728  int idomain;
729  bool ok = true;
730  Point dc;
731  auto& agr = input_.get_axis_grids();
732  for (int i = 0; i < ndomains_; i++)
733  {
734  for (int d = 0; d < OHMMS_DIM; d++)
735  dc[d] = domain_centers_(i, d);
736  Point ub = dot(axinv_, (dc - origin_));
737  Point u;
738  using CoordForm = SpaceGridInput::CoordForm;
739  switch (input_.get_coord_form())
740  {
741  case CoordForm::CARTESIAN:
742  u = ub;
743  break;
744  case CoordForm::CYLINDRICAL:
745  u[0] = sqrt(ub[0] * ub[0] + ub[1] * ub[1]);
746  u[1] = atan2(ub[1], ub[0]) * o2pi + .5;
747  u[2] = ub[2];
748  break;
749  case CoordForm::SPHERICAL:
750  u[0] = sqrt(ub[0] * ub[0] + ub[1] * ub[1] + ub[2] * ub[2]);
751  u[1] = atan2(ub[1], ub[0]) * o2pi + .5;
752  u[2] = acos(ub[2] / u[0]) * o2pi * 2.0;
753  break;
754  default:
755  break;
756  }
757  iu[0] = gmap_[0][floor((u[0] - agr[0].umin) * odu_[0])];
758  iu[1] = gmap_[1][floor((u[1] - agr[1].umin) * odu_[1])];
759  iu[2] = gmap_[2][floor((u[2] - agr[2].umin) * odu_[2])];
760  idomain = dm_[0] * iu[0] + dm_[1] * iu[1] + dm_[2] * iu[2];
761  if (idomain != i)
762  {
763  app_log() << " cell mismatch " << i << " " << idomain << std::endl;
764  ok = false;
765  }
766  }
767  if (!ok)
768  {
769  app_log() << " NESpaceGrid cells do not map onto themselves" << std::endl;
770  }
771  app_log() << "end NESpaceGrid<REAL>::check_grid" << std::endl;
772  return ok;
773 }
774 
775 template class NESpaceGrid<float>;
776 template class NESpaceGrid<double>;
777 } // namespace qmcplusplus
bool initializeSpherical(const SpaceGridInput &input, const Points &points)
Initialize NESpaceGrid for cylindrical grid.
static Point deriveOrigin(const SpaceGridInput &input, const Points &points)
return actual origin point based on input
size_type size1() const
Definition: OhmmsMatrix.h:79
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
Tensor< T, D >::Type_t det(const Tensor< T, D > &a)
Definition: TensorOps.h:838
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
typename NEReferencePoints::Point Point
Definition: NESpaceGrid.h:56
std::map< std::string, Point > Points
MakeReturn< UnaryNode< FnSin, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t sin(const Vector< T1, C1 > &l)
typename NEReferencePoints::Points Points
Definition: NESpaceGrid.h:57
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
void resize(size_type n, size_type m)
Resize the container.
Definition: OhmmsMatrix.h:99
Attaches a unit to a Vector for IO.
This is the port of QMCHamiltonian/SpaceGrid to the new Estimator design.
#define OHMMS_DIM
Definition: config.h:64
void copyToSoA()
copy AxisGrid data to SoA layout for evaluation
void accumulate(const ParticlePos &R, const Matrix< Real > &values, std::vector< bool > &particles_outside)
void error(char const *m)
Definition: Standard.h:204
MakeReturn< UnaryNode< FnCos, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t cos(const Vector< T1, C1 > &l)
MakeReturn< UnaryNode< FnArcCos, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t acos(const Vector< T1, C1 > &l)
static void processAxis(const SpaceGridInput &input, const Points &points, AxTensor &axes, AxTensor &axinv)
create axes and axinv tensors
Definition: NESpaceGrid.cpp:91
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.
void write_description(std::ostream &os, const std::string &indent)
bool initializeCylindrical(const SpaceGridInput &input, const Points &points)
Initialize NESpaceGrid for cylindrical grid.
bool initializeRectilinear(const SpaceGridInput &input, const Points &points)
Initialize NESpaceGrid for rectilinear grid.
bool initializeCoordSystem()
dispatch to correct initialize for coord type
Definition: NESpaceGrid.cpp:71
std::vector< std::reference_wrapper< T > > RefVector
MakeReturn< UnaryNode< FnSqrt, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t sqrt(const Vector< T1, C1 > &l)
void registerGrid(hdf_archive &file, int grid_index)
set up Observable helper(s) for this grid almost unchanged from legacy
sycl::event copy_n(sycl::queue &aq, const T1 *restrict VA, size_t array_size, T2 *restrict VC, const std::vector< sycl::event > &events)
Definition: syclBLAS.cpp:548
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
size_type size2() const
Definition: OhmmsMatrix.h:80
const char coord[]
Definition: HDFVersion.h:48
Tensor< typename BinaryReturn< T1, T2, OpMultiply >::Type_t, D > dot(const AntiSymTensor< T1, D > &lhs, const AntiSymTensor< T2, D > &rhs)
static void collect(NESpaceGrid &reduction_grid, RefVector< NESpaceGrid > grid_for_each_crowd)
void write(hdf_archive &file) const
void sum(const BufferType &buf, Real *vals)
void someMoreAxisGridStuff()
Initialize NESpaceGrid for voronoi grid.
ObservableHelper oh
NESpaceGrid(SpaceGridInput &sgi, const Points &points, const int nvalues, const bool is_periodic)
This constructor is used for electron only grids.
std::vector< Real > data_
Definition: NESpaceGrid.h:256
MakeReturn< UnaryNode< FnFloor, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t floor(const Vector< T1, C1 > &l)