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: Ye Luo, yeluo@anl.gov, Argonne National Laboratory
8 // Jaron T. Krogel, krogeljt@ornl.gov, Oak Ridge National Laboratory
9 // Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
10 //
11 // File created by: Ye Luo, yeluo@anl.gov, Argonne National Laboratory
12 //////////////////////////////////////////////////////////////////////////////////////
13
14
15 #include "EnergyDensityEstimator.h"
16 #include "OhmmsData/AttributeSet.h"
17 #include "LongRange/LRCoulombSingleton.h"
18 #include "Particle/DistanceTableData.h"
19 #include "Particle/MCWalkerConfiguration.h"
20 #include "Utilities/string_utils.h"
21 #include <string>
22 #include <vector>
23
24 namespace qmcplusplus
25 {
EnergyDensityEstimator(PSPool & PSP,const std::string & defaultKE)26 EnergyDensityEstimator::EnergyDensityEstimator(PSPool& PSP, const std::string& defaultKE)
27 : psetpool(PSP), Pdynamic(0), Pstatic(0), w_trace(0), Td_trace(0), Vd_trace(0), Vs_trace(0)
28 {
29 UpdateMode.set(COLLECTABLE, 1);
30 defKE = defaultKE;
31 nsamples = 0;
32 ion_points = false;
33 nions = -1;
34 request.request_scalar("weight");
35 request.request_array("Kinetic");
36 request.request_array("LocalPotential");
37 }
38
39
~EnergyDensityEstimator()40 EnergyDensityEstimator::~EnergyDensityEstimator() { delete_iter(spacegrids.begin(), spacegrids.end()); }
41
42
put(xmlNodePtr cur,ParticleSet & Pdyn)43 bool EnergyDensityEstimator::put(xmlNodePtr cur, ParticleSet& Pdyn)
44 {
45 Pdynamic = &Pdyn;
46 return put(cur);
47 }
48
49
50 /** check xml elements
51 */
put(xmlNodePtr cur)52 bool EnergyDensityEstimator::put(xmlNodePtr cur)
53 {
54 input_xml = cur;
55 //initialize simple xml attributes
56 myName = "EnergyDensity";
57 std::string dyn, stat = "";
58 ion_points = false;
59 OhmmsAttributeSet attrib;
60 attrib.add(myName, "name");
61 attrib.add(dyn, "dynamic");
62 attrib.add(stat, "static");
63 attrib.add(ion_points, "ion_points");
64 attrib.put(cur);
65 //collect particle sets
66 if (!Pdynamic)
67 Pdynamic = get_particleset(dyn);
68 if (Pdynamic->SK)
69 Pdynamic->turnOnPerParticleSK();
70 nparticles = Pdynamic->getTotalNum();
71 std::vector<ParticleSet*> Pref;
72 if (stat == "")
73 {
74 Pstatic = 0;
75 dtable_index = -1;
76 }
77 else
78 {
79 Pstatic = get_particleset(stat);
80 if (Pstatic->SK)
81 Pstatic->turnOnPerParticleSK();
82 dtable_index = Pdynamic->addTable(*Pstatic);
83 Pref.resize(1);
84 Pref[0] = Pstatic;
85 if (!ion_points)
86 nparticles += Pstatic->getTotalNum();
87 else
88 nions = Pstatic->getTotalNum();
89 }
90 //size arrays
91 R.resize(nparticles);
92 EDValues.resize(nparticles, nEDValues);
93 if (ion_points)
94 {
95 EDIonValues.resize(nions, nEDValues);
96 Rion.resize(nions, DIM);
97 for (int i = 0; i < nions; i++)
98 for (int d = 0; d < DIM; d++)
99 Rion(i, d) = Pstatic->R[i][d];
100 }
101 particles_outside.resize(nparticles);
102 fill(particles_outside.begin(), particles_outside.end(), true);
103 //read xml element contents
104 xmlNodePtr element;
105 bool stop = false;
106 //initialize reference points
107 app_log() << "Initializing reference points" << std::endl;
108 bool has_ref = false;
109 element = cur->children;
110 while (element != NULL)
111 {
112 std::string name((const char*)element->name);
113 if (name == "reference_points")
114 {
115 if (has_ref)
116 {
117 APP_ABORT("EnergyDensityEstimator::put: EDE can only have one instance of reference_points.");
118 }
119 else
120 {
121 bool ref_succeeded = ref.put(element, *Pdynamic, Pref);
122 stop = stop || !ref_succeeded;
123 has_ref = true;
124 }
125 }
126 element = element->next;
127 }
128 if (!has_ref)
129 {
130 bool ref_succeeded = ref.put(*Pdynamic, Pref);
131 stop = stop || !ref_succeeded;
132 }
133 //initialize grids or other cell partitions
134 bool periodic = Pdynamic->Lattice.SuperCellEnum != SUPERCELL_OPEN;
135 bool grid_succeeded;
136 element = cur->children;
137 int nvalues = (int)nEDValues;
138 int i = 0;
139 while (element != NULL)
140 {
141 std::string name = (const char*)element->name;
142 if (name == "spacegrid")
143 {
144 SpaceGrid* sg = new SpaceGrid(nvalues);
145 spacegrids.push_back(sg);
146 if (Pstatic)
147 {
148 set_ptcl();
149 grid_succeeded = sg->put(element, ref.points, Rptcl, Zptcl, Pdynamic->getTotalNum(), periodic, false);
150 unset_ptcl();
151 }
152 else
153 grid_succeeded = sg->put(element, ref.points, periodic, false);
154 stop = stop || !grid_succeeded;
155 ++i;
156 }
157 element = element->next;
158 }
159 if (stop == true)
160 {
161 APP_ABORT("EnergyDensityEstimator::put");
162 }
163 return true;
164 }
165
166
set_ptcl()167 void EnergyDensityEstimator::set_ptcl()
168 {
169 ParticleSet& P = *Pstatic;
170 SpeciesSet& species(P.getSpeciesSet());
171 int ChargeAttribIndx = species.addAttribute("charge");
172 int nspecies = species.TotalNum;
173 int nps = P.getTotalNum();
174 std::vector<RealType> Zspec;
175 Zspec.resize(nspecies);
176 Zptcl.resize(nps);
177 for (int spec = 0; spec < nspecies; spec++)
178 Zspec[spec] = species(ChargeAttribIndx, spec);
179 for (int i = 0; i < nps; i++)
180 Zptcl[i] = Zspec[P.GroupID[i]];
181 Rptcl.resize(P.R.size());
182 for (int i = 0; i < P.R.size(); i++)
183 Rptcl[i] = P.R[i];
184 if (P.Lattice.SuperCellEnum != SUPERCELL_OPEN)
185 P.applyMinimumImage(Rptcl);
186 }
187
unset_ptcl()188 void EnergyDensityEstimator::unset_ptcl()
189 {
190 Zptcl.clear();
191 Rptcl.clear();
192 }
193
194
get_particleset(std::string & psname)195 ParticleSet* EnergyDensityEstimator::get_particleset(std::string& psname)
196 {
197 if (psetpool.find(psname) == psetpool.end())
198 {
199 app_log() << " ParticleSet " << psname << " does not exist" << std::endl;
200 APP_ABORT("EnergyDensityEstimator::put");
201 }
202 return psetpool[psname];
203 }
204
205
get_required_traces(TraceManager & tm)206 void EnergyDensityEstimator::get_required_traces(TraceManager& tm)
207 {
208 bool write = omp_get_thread_num() == 0;
209 w_trace = tm.get_real_trace("weight");
210 Td_trace = tm.get_real_trace(*Pdynamic, "Kinetic");
211 Vd_trace = tm.get_real_combined_trace(*Pdynamic, "LocalPotential");
212 if (Pstatic)
213 Vs_trace = tm.get_real_combined_trace(*Pstatic, "LocalPotential");
214 have_required_traces = true;
215 }
216
217
write_description(std::ostream & os)218 void EnergyDensityEstimator::write_description(std::ostream& os)
219 {
220 os << "EnergyDensityEstimator::write_description" << std::endl;
221 os << std::endl;
222 os << " EnergyDensityEstimator details" << std::endl;
223 os << std::endl;
224 std::string indent = " ";
225 os << indent + "nparticles = " << nparticles << std::endl;
226 os << indent + "nspacegrids = " << spacegrids.size() << std::endl;
227 os << std::endl;
228 ref.write_description(os, indent);
229 os << std::endl;
230 for (int i = 0; i < spacegrids.size(); i++)
231 {
232 spacegrids[i]->write_description(os, indent);
233 }
234 os << std::endl;
235 os << " end EnergyDensityEstimator details" << std::endl;
236 os << std::endl;
237 os << "end EnergyDensityEstimator::write_description" << std::endl;
238 return;
239 }
240
241
get(std::ostream & os) const242 bool EnergyDensityEstimator::get(std::ostream& os) const
243 {
244 os << "EDM replace this " << std::endl;
245 APP_ABORT("EnergyDensityEstimator::get");
246 return true;
247 }
248
249
resetTargetParticleSet(ParticleSet & P)250 void EnergyDensityEstimator::resetTargetParticleSet(ParticleSet& P)
251 {
252 //remains empty
253 }
254
255
256 //#define ENERGYDENSITY_CHECK
257
evaluate(ParticleSet & P)258 EnergyDensityEstimator::Return_t EnergyDensityEstimator::evaluate(ParticleSet& P)
259 {
260 if (have_required_traces)
261 {
262 Pdynamic = &P;
263 //Collect positions from ParticleSets
264 int p = 0;
265 {
266 const ParticlePos_t& Rs = Pdynamic->R;
267 for (int i = 0; i < Rs.size(); i++)
268 {
269 R[p] = Rs[i];
270 p++;
271 }
272 }
273 if (Pstatic && !ion_points)
274 {
275 const ParticlePos_t& Rs = Pstatic->R;
276 for (int i = 0; i < Rs.size(); i++)
277 {
278 R[p] = Rs[i];
279 p++;
280 }
281 }
282 if (P.Lattice.SuperCellEnum != SUPERCELL_OPEN)
283 P.applyMinimumImage(R);
284 //Convert information accumulated in ParticleSets into EnergyDensity quantities
285 RealType w = w_trace->sample[0];
286 p = 0;
287 {
288 Vd_trace->combine();
289 const ParticleSet& Ps = *Pdynamic;
290 const std::vector<TraceReal>& Ts = Td_trace->sample;
291 const std::vector<TraceReal>& Vs = Vd_trace->sample;
292 for (int i = 0; i < Ps.getTotalNum(); i++)
293 {
294 EDValues(p, W) = w;
295 EDValues(p, T) = w * Ts[i];
296 EDValues(p, V) = w * Vs[i];
297 p++;
298 }
299 }
300 if (Pstatic)
301 {
302 Vs_trace->combine();
303 const ParticleSet& Ps = *Pstatic;
304 const std::vector<TraceReal>& Vs = Vs_trace->sample;
305 if (!ion_points)
306 for (int i = 0; i < Ps.getTotalNum(); i++)
307 {
308 EDValues(p, W) = w;
309 EDValues(p, T) = 0.0;
310 EDValues(p, V) = w * Vs[i];
311 p++;
312 }
313 else
314 for (int i = 0; i < Ps.getTotalNum(); i++)
315 {
316 EDIonValues(i, W) = w;
317 EDIonValues(i, T) = 0.0;
318 EDIonValues(i, V) = w * Vs[i];
319 }
320 }
321 //Accumulate energy density in spacegrids
322 const DistanceTableData& dtab(P.getDistTable(dtable_index));
323 fill(particles_outside.begin(), particles_outside.end(), true);
324 for (int i = 0; i < spacegrids.size(); i++)
325 {
326 SpaceGrid& sg = *spacegrids[i];
327 sg.evaluate(R, EDValues, P.Collectables, particles_outside, dtab);
328 }
329 //Accumulate energy density of particles outside any spacegrid
330 int bi, v;
331 const int bimax = outside_buffer_offset + (int)nEDValues;
332 for (int p = 0; p < particles_outside.size(); p++)
333 {
334 if (particles_outside[p])
335 {
336 for (bi = outside_buffer_offset, v = 0; bi < bimax; bi++, v++)
337 {
338 P.Collectables[bi] += EDValues(p, v);
339 }
340 }
341 }
342 if (ion_points)
343 {
344 // Accumulate energy density for ions at a point field
345 bi = ion_buffer_offset;
346 for (int i = 0; i < nions; i++)
347 for (v = 0; v < (int)nEDValues; v++, bi++)
348 {
349 P.Collectables[bi] += EDIonValues(i, v);
350 }
351 }
352 nsamples++;
353 #if defined(ENERGYDENSITY_CHECK)
354 int thread = omp_get_thread_num();
355 using WP = WalkerProperties::Indexes;
356 RealType Eref = P.PropertyList[WP::LOCALENERGY];
357 RealType Vref = P.PropertyList[WP::LOCALPOTENTIAL];
358 RealType Tref = Eref - Vref;
359 #pragma omp critical(edcheck)
360 {
361 RealType Dsum = 0.0;
362 RealType Tsum = 0.0;
363 RealType Vsum = 0.0;
364 RealType Esum = 0.0;
365 for (int p = 0; p < nparticles; p++)
366 {
367 Dsum += EDValues(p, W);
368 Tsum += EDValues(p, T);
369 Vsum += EDValues(p, V);
370 }
371 if (ion_points)
372 for (int i = 0; i < nions; i++)
373 {
374 Dsum += EDIonValues(i, W);
375 Tsum += EDIonValues(i, T);
376 Vsum += EDIonValues(i, V);
377 }
378 Esum = Tsum + Vsum;
379 static int cnt = 0;
380 //app_log()<<"eval ED Dsum"<<cnt<<" "<<Dsum<< std::endl;
381 app_log() << thread << " eval ED " << cnt << " " << Tsum << " " << Vsum << " " << Esum << std::endl;
382 int nvals = (int)nEDValues;
383 RealType edvals[nvals];
384 RealType edtmp[nvals];
385 for (int v = 0; v < nvals; v++)
386 edvals[v] = 0.0;
387 for (int i = 0; i < spacegrids.size(); i++)
388 {
389 SpaceGrid& sg = *spacegrids[i];
390 sg.sum(P.Collectables, edtmp);
391 for (int v = 0; v < nvals; v++)
392 edvals[v] += edtmp[v];
393 }
394 for (int v = 0; v < nvals; v++)
395 edvals[v] += P.Collectables[outside_buffer_offset + v];
396 if (ion_points)
397 {
398 for (int i = 0; i < nions; i++)
399 for (int v = 0; v < nvals; v++)
400 edvals[v] += P.Collectables[ion_buffer_offset + i * nvals + v];
401 }
402 //app_log()<<"eval ES Dsum"<<cnt<<" "<<edvals[W]<< std::endl;
403 app_log() << thread << " eval ES " << cnt << " " << edvals[T] << " " << edvals[V] << " " << edvals[T] + edvals[V]
404 << std::endl;
405 app_log() << thread << " ref E " << cnt << " " << Tref << " " << Vref << " " << Eref << std::endl;
406 cnt++;
407 }
408 #endif
409 //APP_ABORT("EnergyDensityEstimator::evaluate");
410 }
411
412 return 0.0;
413 }
414
415
write_Collectables(std::string & label,int & cnt,ParticleSet & P)416 void EnergyDensityEstimator::write_Collectables(std::string& label, int& cnt, ParticleSet& P)
417 {
418 //for(int v=0;v<nEDValues;v++){
419 int ii = spacegrids[0]->buffer_offset;
420 int io = outside_buffer_offset;
421 double Ti = P.Collectables[ii + 1] / P.Collectables[ii] * 12.0;
422 double To = P.Collectables[io + 1] / P.Collectables[io] * 12.0;
423 app_log() << "EDcoll " << label << cnt << " " << Ti << " " << To << std::endl;
424 //}
425 }
426
427
write_EDValues(void)428 void EnergyDensityEstimator::write_EDValues(void)
429 {
430 app_log() << "EDValues" << std::endl;
431 for (int p = 0; p < nparticles; p++)
432 fprintf(stdout, " %d %e %e %e\n", p, EDValues(p, 0), EDValues(p, 1), EDValues(p, 2));
433 }
434
write_nonzero_domains(const ParticleSet & P)435 void EnergyDensityEstimator::write_nonzero_domains(const ParticleSet& P)
436 {
437 app_log() << "Nonzero domains" << std::endl;
438 int nd = 1;
439 for (int i = 0; i < spacegrids.size(); i++)
440 nd += spacegrids[i]->nDomains();
441 for (int i = 0; i < nd; i++)
442 {
443 bool nonzero = false;
444 int n = outside_buffer_offset + i * nEDValues;
445 for (int v = 0; v < nEDValues; v++)
446 {
447 nonzero = nonzero || std::abs(P.Collectables[n + v]) > 1e-8;
448 }
449 if (nonzero)
450 {
451 // fprintf(stdout," %d %e %e %e %e %e %e\n",i,P.Collectables[n],
452 fprintf(stdout, " %d %e %e %e \n", i, P.Collectables[n], P.Collectables[n + 1], P.Collectables[n + 2]);
453 }
454 }
455 }
456
457
addObservables(PropertySetType & plist,BufferType & collectables)458 void EnergyDensityEstimator::addObservables(PropertySetType& plist, BufferType& collectables)
459 {
460 myIndex = collectables.size();
461 //allocate space for energy density outside of any spacegrid
462 outside_buffer_offset = collectables.size();
463 int nvalues = (int)nEDValues;
464 std::vector<RealType> tmp(nvalues);
465 collectables.add(tmp.begin(), tmp.end());
466 //allocate space for spacegrids
467 for (int i = 0; i < spacegrids.size(); i++)
468 {
469 spacegrids[i]->allocate_buffer_space(collectables);
470 }
471 if (ion_points)
472 {
473 ion_buffer_offset = collectables.size();
474 nvalues = nions * ((int)nEDValues);
475 std::vector<RealType> tmp2(nvalues);
476 collectables.add(tmp2.begin(), tmp2.end());
477 }
478 }
479
480
registerCollectables(std::vector<observable_helper * > & h5desc,hid_t gid) const481 void EnergyDensityEstimator::registerCollectables(std::vector<observable_helper*>& h5desc, hid_t gid) const
482 {
483 hid_t g = H5Gcreate(gid, myName.c_str(), 0);
484 observable_helper* oh;
485 oh = new observable_helper("variables");
486 oh->open(g);
487 oh->addProperty(const_cast<int&>(nparticles), "nparticles");
488 int nspacegrids = spacegrids.size();
489 oh->addProperty(const_cast<int&>(nspacegrids), "nspacegrids");
490 oh->addProperty(const_cast<int&>(nsamples), "nsamples");
491 if (ion_points)
492 {
493 oh->addProperty(const_cast<int&>(nions), "nions");
494 oh->addProperty(const_cast<Matrix<RealType>&>(Rion), "ion_positions");
495 }
496 h5desc.push_back(oh);
497 ref.save(h5desc, g);
498 oh = new observable_helper("outside");
499 std::vector<int> ng(1);
500 ng[0] = (int)nEDValues;
501 oh->set_dimensions(ng, outside_buffer_offset);
502 oh->open(g);
503 h5desc.push_back(oh);
504 for (int i = 0; i < spacegrids.size(); i++)
505 {
506 SpaceGrid& sg = *spacegrids[i];
507 sg.registerCollectables(h5desc, g, i);
508 }
509 if (ion_points)
510 {
511 oh = new observable_helper("ions");
512 std::vector<int> ng2(2);
513 ng2[0] = nions;
514 ng2[1] = (int)nEDValues;
515 oh->set_dimensions(ng2, ion_buffer_offset);
516 oh->open(g);
517 h5desc.push_back(oh);
518 }
519 }
520
setObservables(PropertySetType & plist)521 void EnergyDensityEstimator::setObservables(PropertySetType& plist)
522 {
523 //remains empty
524 }
525
setParticlePropertyList(PropertySetType & plist,int offset)526 void EnergyDensityEstimator::setParticlePropertyList(PropertySetType& plist, int offset)
527 {
528 //remains empty
529 }
530
531
makeClone(ParticleSet & qp,TrialWaveFunction & psi)532 OperatorBase* EnergyDensityEstimator::makeClone(ParticleSet& qp, TrialWaveFunction& psi)
533 {
534 bool write = omp_get_thread_num() == 0;
535 if (write)
536 app_log() << "EnergyDensityEstimator::makeClone" << std::endl;
537 EnergyDensityEstimator* edclone = new EnergyDensityEstimator(psetpool, defKE);
538 edclone->put(input_xml, qp);
539 //int thread = omp_get_thread_num();
540 //app_log()<<thread<<"make edclone"<< std::endl;
541 //edclone->Pdynamic = Pdynamic->get_clone(thread);
542 //edclone->Pstatic = Pstatic->get_clone(thread);
543 return edclone;
544 }
545
546
547 } // namespace qmcplusplus
548