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