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