QMCPACK
HybridRepSetReader.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: Ye Luo, yeluo@anl.gov, Argonne National Laboratory
8 //
9 // File created by: Ye Luo, yeluo@anl.gov, Argonne National Laboratory
10 //////////////////////////////////////////////////////////////////////////////////////
11 
12 
13 /** @file
14  *
15  * derived from SplineSetReader
16  */
17 
18 #include "HybridRepSetReader.h"
19 #include "Numerics/Quadrature.h"
20 #include "Numerics/Bessel.h"
21 #include "OhmmsData/AttributeSet.h"
22 #include "CPU/math.hpp"
23 #include "Concurrency/OpenMP.h"
24 #include <Timer.h>
25 #include "OneSplineOrbData.hpp"
26 
27 namespace qmcplusplus
28 {
29 template<typename ST, typename LT>
30 struct Gvectors
31 {
33  using ValueType = std::complex<ST>;
34 
35  const LT& Lattice;
36  std::vector<PosType> gvecs_cart; //Cartesian.
37  std::vector<ST> gmag;
38  const size_t NumGvecs;
39 
40  Gvectors(const std::vector<TinyVector<int, 3>>& gvecs_in,
41  const LT& Lattice_in,
42  const TinyVector<int, 3>& HalfG,
43  size_t first,
44  size_t last)
45  : Lattice(Lattice_in), NumGvecs(last - first)
46  {
47  gvecs_cart.resize(NumGvecs);
48  gmag.resize(NumGvecs);
49 #pragma omp parallel for
50  for (size_t ig = 0; ig < NumGvecs; ig++)
51  {
52  TinyVector<ST, 3> gvec_shift;
53  gvec_shift = gvecs_in[ig + first] + HalfG * 0.5;
54  gvecs_cart[ig] = Lattice.k_cart(gvec_shift);
55  gmag[ig] = std::sqrt(dot(gvecs_cart[ig], gvecs_cart[ig]));
56  }
57  }
58 
59  template<typename YLM_ENGINE, typename VVT>
60  void calc_Ylm_G(const size_t ig, YLM_ENGINE& Ylm, VVT& YlmG) const
61  {
62  PosType Ghat(0.0, 0.0, 1.0);
63  if (gmag[ig] > 0)
64  Ghat = gvecs_cart[ig] / gmag[ig];
65  Ylm.evaluateV(Ghat[0], Ghat[1], Ghat[2], YlmG.data());
66  }
67 
68  template<typename VVT>
69  inline void calc_jlm_G(const int lmax, ST& r, const size_t ig, VVT& j_lm_G) const
70  {
71  bessel_steed_array_cpu(lmax, gmag[ig] * r, j_lm_G.data());
72  for (size_t l = lmax; l > 0; l--)
73  for (size_t lm = l * l; lm < (l + 1) * (l + 1); lm++)
74  j_lm_G[lm] = j_lm_G[l];
75  }
76 
77  template<typename PT, typename VT>
78  inline void calc_phase_shift(const PT& RSoA, const size_t ig, VT& phase_shift_real, VT& phase_shift_imag) const
79  {
80  const ST* restrict px = RSoA.data(0);
81  const ST* restrict py = RSoA.data(1);
82  const ST* restrict pz = RSoA.data(2);
83  ST* restrict v_r = phase_shift_real.data();
84  ST* restrict v_i = phase_shift_imag.data();
85  const ST& gv_x = gvecs_cart[ig][0];
86  const ST& gv_y = gvecs_cart[ig][1];
87  const ST& gv_z = gvecs_cart[ig][2];
88 
89 #pragma omp simd aligned(px, py, pz, v_r, v_i : QMC_SIMD_ALIGNMENT)
90  for (size_t iat = 0; iat < RSoA.size(); iat++)
91  qmcplusplus::sincos(px[iat] * gv_x + py[iat] * gv_y + pz[iat] * gv_z, v_i + iat, v_r + iat);
92  }
93 
94  template<typename PT>
95  ValueType evaluate_psi_r(const Vector<std::complex<double>>& cG, const PT& pos)
96  {
97  assert(cG.size() == NumGvecs);
98  std::complex<ST> val(0.0, 0.0);
99  for (size_t ig = 0; ig < NumGvecs; ig++)
100  {
101  ST s, c;
102  qmcplusplus::sincos(dot(gvecs_cart[ig], pos), &s, &c);
103  ValueType pw0(c, s);
104  val += cG[ig] * pw0;
105  }
106  return val;
107  }
108 
109  template<typename PT>
110  void evaluate_psi_r(const Vector<std::complex<double>>& cG, const PT& pos, ValueType& phi, ValueType& d2phi)
111  {
112  assert(cG.size() == NumGvecs);
113  d2phi = phi = 0.0;
114  for (size_t ig = 0; ig < NumGvecs; ig++)
115  {
116  ST s, c;
117  qmcplusplus::sincos(dot(gvecs_cart[ig], pos), &s, &c);
118  ValueType pw0(c, s);
119  phi += cG[ig] * pw0;
120  d2phi += cG[ig] * pw0 * (-dot(gvecs_cart[ig], gvecs_cart[ig]));
121  }
122  }
123 
124  double evaluate_KE(const Vector<std::complex<double>>& cG)
125  {
126  assert(cG.size() == NumGvecs);
127  double KE = 0;
128  for (size_t ig = 0; ig < NumGvecs; ig++)
129  KE += dot(gvecs_cart[ig], gvecs_cart[ig]) * (cG[ig].real() * cG[ig].real() + cG[ig].imag() * cG[ig].imag());
130  return KE / 2.0;
131  }
132 };
133 
134 template<typename SA>
136 {}
137 
138 template<typename SA>
139 std::unique_ptr<SPOSet> HybridRepSetReader<SA>::create_spline_set(const std::string& my_name,
140  int spin,
141  const BandInfoGroup& bandgroup)
142 {
143  auto bspline = std::make_unique<SA>(my_name);
144  app_log() << " ClassName = " << bspline->getClassName() << std::endl;
145  // set info for Hybrid
146  initialize_hybridrep_atomic_centers(*bspline);
147  bool foundspline = spline_reader_.createSplineDataSpaceLookforDumpFile(bandgroup, *bspline);
148  typename SA::HYBRIDBASE& hybrid_center_orbs = *bspline;
149  hybrid_center_orbs.resizeStorage(bspline->myV.size());
150  if (foundspline)
151  {
152  Timer now;
153  hdf_archive h5f(myComm);
154  const auto splinefile = getSplineDumpFileName(bandgroup);
155  h5f.open(splinefile, H5F_ACC_RDONLY);
156  foundspline = bspline->read_splines(h5f);
157  if (foundspline)
158  app_log() << " Successfully restored 3D B-spline coefficients from " << splinefile << ". The reading time is "
159  << now.elapsed() << " sec." << std::endl;
160  }
161 
162  if (!foundspline)
163  {
164  hybrid_center_orbs.flush_zero();
165  initialize_hybrid_pio_gather(spin, bandgroup, *bspline);
166 
167  if (saveSplineCoefs && myComm->rank() == 0)
168  {
169  Timer now;
170  const std::string splinefile(getSplineDumpFileName(bandgroup));
171  hdf_archive h5f;
172  h5f.create(splinefile);
173  std::string classname = bspline->getClassName();
174  h5f.write(classname, "class_name");
175  int sizeD = sizeof(DataType);
176  h5f.write(sizeD, "sizeof");
177  bspline->write_splines(h5f);
178  h5f.close();
179  app_log() << " Stored spline coefficients in " << splinefile << " for potential reuse. The writing time is "
180  << now.elapsed() << " sec." << std::endl;
181  }
182  }
183 
184  {
185  Timer now;
186  bspline->bcast_tables(myComm);
187  app_log() << " Time to bcast the table = " << now.elapsed() << std::endl;
188  }
189  return bspline;
190 }
191 
192 template<typename SA>
194 {
195  auto& mybuilder = spline_reader_.mybuilder;
196 
198  std::string scheme_name("Consistent");
199  std::string s_function_name("LEKS2018");
200  a.add(scheme_name, "smoothing_scheme");
201  a.add(s_function_name, "smoothing_function");
202  a.put(mybuilder->XMLRoot);
203  // assign smooth_scheme
204  if (scheme_name == "Consistent")
205  bspline.smooth_scheme = SA::smoothing_schemes::CONSISTENT;
206  else if (scheme_name == "SmoothAll")
207  bspline.smooth_scheme = SA::smoothing_schemes::SMOOTHALL;
208  else if (scheme_name == "SmoothPartial")
209  bspline.smooth_scheme = SA::smoothing_schemes::SMOOTHPARTIAL;
210  else
211  APP_ABORT("initialize_hybridrep_atomic_centers wrong smoothing_scheme name! Only allows Consistent, SmoothAll or "
212  "SmoothPartial.");
213 
214  // assign smooth_function
215  if (s_function_name == "LEKS2018")
216  bspline.smooth_func_id = smoothing_functions::LEKS2018;
217  else if (s_function_name == "coscos")
218  bspline.smooth_func_id = smoothing_functions::COSCOS;
219  else if (s_function_name == "linear")
220  bspline.smooth_func_id = smoothing_functions::LINEAR;
221  else
222  APP_ABORT(
223  "initialize_hybridrep_atomic_centers wrong smoothing_function name! Only allows LEKS2018, coscos or linear.");
224  app_log() << "Hybrid orbital representation uses " << scheme_name << " smoothing scheme and " << s_function_name
225  << " smoothing function." << std::endl;
226 
227  bspline.set_info(*(mybuilder->SourcePtcl), mybuilder->TargetPtcl, mybuilder->Super2Prim);
228  auto& centers = bspline.AtomicCenters;
229  auto& ACInfo = mybuilder->AtomicCentersInfo;
230  // load atomic center info only when it is not initialized
231  if (centers.size() == 0)
232  {
233  bool success = true;
234  app_log() << "Reading atomic center info for hybrid representation" << std::endl;
235  for (int center_idx = 0; center_idx < ACInfo.Ncenters; center_idx++)
236  {
237  const int my_GroupID = ACInfo.GroupID[center_idx];
238  if (ACInfo.cutoff[center_idx] < 0)
239  {
240  app_error() << "Hybrid orbital representation needs parameter 'cutoff_radius' for atom " << center_idx
241  << std::endl;
242  success = false;
243  }
244 
245  if (ACInfo.inner_cutoff[center_idx] < 0)
246  {
247  const double inner_cutoff = std::max(ACInfo.cutoff[center_idx] - 0.3, 0.0);
248  app_log() << "Hybrid orbital representation setting 'inner_cutoff' to " << inner_cutoff << " for group "
249  << my_GroupID << " as atom " << center_idx << std::endl;
250  // overwrite the inner_cutoff of all the atoms of the same species
251  for (int id = 0; id < ACInfo.Ncenters; id++)
252  if (my_GroupID == ACInfo.GroupID[id])
253  ACInfo.inner_cutoff[id] = inner_cutoff;
254  }
255  else if (ACInfo.inner_cutoff[center_idx] > ACInfo.cutoff[center_idx])
256  {
257  app_error() << "Hybrid orbital representation 'inner_cutoff' must be smaller than 'spline_radius' for atom "
258  << center_idx << std::endl;
259  success = false;
260  }
261 
262  if (ACInfo.cutoff[center_idx] > 0)
263  {
264  if (ACInfo.lmax[center_idx] < 0)
265  {
266  app_error() << "Hybrid orbital representation needs parameter 'lmax' for atom " << center_idx << std::endl;
267  success = false;
268  }
269 
270  if (ACInfo.spline_radius[center_idx] < 0 && ACInfo.spline_npoints[center_idx] < 0)
271  {
272  app_log() << "Parameters 'spline_radius' and 'spline_npoints' for group " << my_GroupID << " as atom "
273  << center_idx << " are not specified." << std::endl;
274  const double delta = std::min(0.02, ACInfo.cutoff[center_idx] / 4.0);
275  const int n_grid_point = std::ceil((ACInfo.cutoff[center_idx] + 1e-4) / delta) + 3;
276  for (int id = 0; id < ACInfo.Ncenters; id++)
277  if (my_GroupID == ACInfo.GroupID[id])
278  {
279  ACInfo.spline_npoints[id] = n_grid_point;
280  ACInfo.spline_radius[id] = (n_grid_point - 1) * delta;
281  }
282  app_log() << " Based on default grid point distance " << delta << std::endl;
283  app_log() << " Setting 'spline_npoints' to " << ACInfo.spline_npoints[center_idx] << std::endl;
284  app_log() << " Setting 'spline_radius' to " << ACInfo.spline_radius[center_idx] << std::endl;
285  }
286  else
287  {
288  if (ACInfo.spline_radius[center_idx] < 0)
289  {
290  app_error() << "Hybrid orbital representation needs parameter 'spline_radius' for atom " << center_idx
291  << std::endl;
292  success = false;
293  }
294 
295  if (ACInfo.spline_npoints[center_idx] < 0)
296  {
297  app_error() << "Hybrid orbital representation needs parameter 'spline_npoints' for atom " << center_idx
298  << std::endl;
299  success = false;
300  }
301  }
302 
303  // check maximally allowed cutoff_radius
304  double max_allowed_cutoff = ACInfo.spline_radius[center_idx] -
305  2.0 * ACInfo.spline_radius[center_idx] / (ACInfo.spline_npoints[center_idx] - 1);
306  if (success && ACInfo.cutoff[center_idx] > max_allowed_cutoff)
307  {
308  app_error() << "Hybrid orbital representation requires cutoff_radius<=" << max_allowed_cutoff
309  << " calculated by spline_radius-2*spline_radius/(spline_npoints-1) for atom " << center_idx
310  << std::endl;
311  success = false;
312  }
313  }
314  else
315  {
316  // no atomic regions for this atom type
317  ACInfo.spline_radius[center_idx] = 0.0;
318  ACInfo.spline_npoints[center_idx] = 0;
319  ACInfo.lmax[center_idx] = 0;
320  }
321  }
322 
323  if (!success)
324  spline_reader_.myComm->barrier_and_abort(
325  "initialize_hybridrep_atomic_centers Failed to initialize atomic centers "
326  "in hybrid orbital representation!");
327 
328  for (int center_idx = 0; center_idx < ACInfo.Ncenters; center_idx++)
329  {
330  AtomicOrbitals<DataType> oneCenter(ACInfo.lmax[center_idx]);
331  oneCenter.set_info(ACInfo.ion_pos[center_idx], ACInfo.cutoff[center_idx], ACInfo.inner_cutoff[center_idx],
332  ACInfo.spline_radius[center_idx], ACInfo.non_overlapping_radius[center_idx],
333  ACInfo.spline_npoints[center_idx]);
334  centers.push_back(oneCenter);
335  }
336  }
337 }
338 
339 template<typename SA>
341  Communicate& band_group_comm,
342  const int iorb,
343  const std::complex<double>& rotate_phase,
344  SA& bspline) const
345 {
346  auto& mybuilder = spline_reader_.mybuilder;
347  double rotate_phase_r = rotate_phase.real();
348  double rotate_phase_i = rotate_phase.imag();
349 
350  band_group_comm.bcast(rotate_phase_r);
351  band_group_comm.bcast(rotate_phase_i);
352  //distribute G-vectors over processor groups
353  const int Ngvecs = mybuilder->Gvecs[0].size();
354  const int Nprocs = band_group_comm.size();
355  const int Ngvecgroups = std::min(Ngvecs, Nprocs);
356  Communicate gvec_group_comm(band_group_comm, Ngvecgroups);
357  std::vector<int> gvec_groups(Ngvecgroups + 1, 0);
358  FairDivideLow(Ngvecs, Ngvecgroups, gvec_groups);
359  const int gvec_first = gvec_groups[gvec_group_comm.getGroupID()];
360  const int gvec_last = gvec_groups[gvec_group_comm.getGroupID() + 1];
361 
362  // prepare Gvecs Ylm(G)
363  using UnitCellType = typename EinsplineSetBuilder::UnitCellType;
364  Gvectors<double, UnitCellType> Gvecs(mybuilder->Gvecs[0], mybuilder->PrimCell, bspline.HalfG, gvec_first, gvec_last);
365  // if(band_group_comm.isGroupLeader()) std::cout << "print band=" << iorb << " KE=" << Gvecs.evaluate_KE(cG) << std::endl;
366 
367  std::vector<AtomicOrbitals<DataType>>& centers = bspline.AtomicCenters;
368  app_log() << "Transforming band " << iorb << " on Rank 0" << std::endl;
369  // collect atomic centers by group
370  std::vector<int> uniq_species;
371  for (int center_idx = 0; center_idx < centers.size(); center_idx++)
372  {
373  auto& ACInfo = mybuilder->AtomicCentersInfo;
374  const int my_GroupID = ACInfo.GroupID[center_idx];
375  int found_idx = -1;
376  for (size_t idx = 0; idx < uniq_species.size(); idx++)
377  if (my_GroupID == uniq_species[idx])
378  {
379  found_idx = idx;
380  break;
381  }
382  if (found_idx < 0)
383  uniq_species.push_back(my_GroupID);
384  }
385  // construct group list
386  std::vector<std::vector<int>> group_list(uniq_species.size());
387  for (int center_idx = 0; center_idx < centers.size(); center_idx++)
388  {
389  auto& ACInfo = mybuilder->AtomicCentersInfo;
390  const int my_GroupID = ACInfo.GroupID[center_idx];
391  for (size_t idx = 0; idx < uniq_species.size(); idx++)
392  if (my_GroupID == uniq_species[idx])
393  {
394  group_list[idx].push_back(center_idx);
395  break;
396  }
397  }
398 
399  for (int group_idx = 0; group_idx < group_list.size(); group_idx++)
400  {
401  const auto& mygroup = group_list[group_idx];
402  const double spline_radius = centers[mygroup[0]].getSplineRadius();
403  const int spline_npoints = centers[mygroup[0]].getSplineNpoints();
404  const int lmax = centers[mygroup[0]].getLmax();
405  const double delta = spline_radius / static_cast<double>(spline_npoints - 1);
406  const int lm_tot = (lmax + 1) * (lmax + 1);
407  const size_t natoms = mygroup.size();
408  const int policy = lm_tot > natoms ? 0 : 1;
409 
410  std::vector<std::complex<double>> i_power(lm_tot);
411  // rotate phase is introduced here.
412  std::complex<double> i_temp(rotate_phase_r, rotate_phase_i);
413  for (size_t l = 0; l <= lmax; l++)
414  {
415  for (size_t lm = l * l; lm < (l + 1) * (l + 1); lm++)
416  i_power[lm] = i_temp;
417  i_temp *= std::complex<double>(0.0, 1.0);
418  }
419 
420  std::vector<Matrix<double>> all_vals(natoms);
421  std::vector<std::vector<aligned_vector<double>>> vals_local(spline_npoints * omp_get_max_threads());
422  VectorSoaContainer<double, 3> myRSoA(natoms);
423  for (size_t idx = 0; idx < natoms; idx++)
424  {
425  all_vals[idx].resize(spline_npoints, lm_tot * 2);
426  all_vals[idx] = 0.0;
427  myRSoA(idx) = centers[mygroup[idx]].getCenterPos();
428  }
429 
430 #pragma omp parallel
431  {
432  const size_t tid = omp_get_thread_num();
433  const size_t nt = omp_get_num_threads();
434 
435  for (int ip = 0; ip < spline_npoints; ip++)
436  {
437  const size_t ip_idx = tid * spline_npoints + ip;
438  if (policy == 1)
439  {
440  vals_local[ip_idx].resize(lm_tot * 2);
441  for (size_t lm = 0; lm < lm_tot * 2; lm++)
442  {
443  auto& vals = vals_local[ip_idx][lm];
444  vals.resize(natoms);
445  std::fill(vals.begin(), vals.end(), 0.0);
446  }
447  }
448  else
449  {
450  vals_local[ip_idx].resize(natoms * 2);
451  for (size_t iat = 0; iat < natoms * 2; iat++)
452  {
453  auto& vals = vals_local[ip_idx][iat];
454  vals.resize(lm_tot);
455  std::fill(vals.begin(), vals.end(), 0.0);
456  }
457  }
458  }
459 
460  const size_t size_pw_tile = 32;
461  const size_t num_pw_tiles = (Gvecs.NumGvecs + size_pw_tile - 1) / size_pw_tile;
462  aligned_vector<double> j_lm_G(lm_tot, 0.0);
463  std::vector<aligned_vector<double>> phase_shift_r(size_pw_tile);
464  std::vector<aligned_vector<double>> phase_shift_i(size_pw_tile);
465  std::vector<aligned_vector<double>> YlmG(size_pw_tile);
466  for (size_t ig = 0; ig < size_pw_tile; ig++)
467  {
468  phase_shift_r[ig].resize(natoms);
469  phase_shift_i[ig].resize(natoms);
470  YlmG[ig].resize(lm_tot);
471  }
473 
474 #pragma omp for
475  for (size_t tile_id = 0; tile_id < num_pw_tiles; tile_id++)
476  {
477  const size_t ig_first = tile_id * size_pw_tile;
478  const size_t ig_last = std::min((tile_id + 1) * size_pw_tile, Gvecs.NumGvecs);
479  for (size_t ig = ig_first; ig < ig_last; ig++)
480  {
481  const size_t ig_local = ig - ig_first;
482  // calculate phase shift for all the centers of this group
483  Gvecs.calc_phase_shift(myRSoA, ig, phase_shift_r[ig_local], phase_shift_i[ig_local]);
484  Gvecs.calc_Ylm_G(ig, Ylm, YlmG[ig_local]);
485  }
486 
487  for (int ip = 0; ip < spline_npoints; ip++)
488  {
489  double r = delta * static_cast<double>(ip);
490  const size_t ip_idx = tid * spline_npoints + ip;
491 
492  for (size_t ig = ig_first; ig < ig_last; ig++)
493  {
494  const size_t ig_local = ig - ig_first;
495  // calculate spherical bessel function
496  Gvecs.calc_jlm_G(lmax, r, ig, j_lm_G);
497  for (size_t lm = 0; lm < lm_tot; lm++)
498  j_lm_G[lm] *= YlmG[ig_local][lm];
499 
500  const double cG_r = cG[ig + gvec_first].real();
501  const double cG_i = cG[ig + gvec_first].imag();
502  if (policy == 1)
503  {
504  for (size_t lm = 0; lm < lm_tot; lm++)
505  {
506  double* restrict vals_r = vals_local[ip_idx][lm * 2].data();
507  double* restrict vals_i = vals_local[ip_idx][lm * 2 + 1].data();
508  const double* restrict ps_r_ptr = phase_shift_r[ig_local].data();
509  const double* restrict ps_i_ptr = phase_shift_i[ig_local].data();
510  double cG_j_r = cG_r * j_lm_G[lm];
511  double cG_j_i = cG_i * j_lm_G[lm];
512 #pragma omp simd aligned(vals_r, vals_i, ps_r_ptr, ps_i_ptr : QMC_SIMD_ALIGNMENT)
513  for (size_t idx = 0; idx < natoms; idx++)
514  {
515  const double ps_r = ps_r_ptr[idx];
516  const double ps_i = ps_i_ptr[idx];
517  vals_r[idx] += cG_j_r * ps_r - cG_j_i * ps_i;
518  vals_i[idx] += cG_j_i * ps_r + cG_j_r * ps_i;
519  }
520  }
521  }
522  else
523  {
524  for (size_t idx = 0; idx < natoms; idx++)
525  {
526  double* restrict vals_r = vals_local[ip_idx][idx * 2].data();
527  double* restrict vals_i = vals_local[ip_idx][idx * 2 + 1].data();
528  const double* restrict j_lm_G_ptr = j_lm_G.data();
529  double cG_ps_r = cG_r * phase_shift_r[ig_local][idx] - cG_i * phase_shift_i[ig_local][idx];
530  double cG_ps_i = cG_i * phase_shift_r[ig_local][idx] + cG_r * phase_shift_i[ig_local][idx];
531 #pragma omp simd aligned(vals_r, vals_i, j_lm_G_ptr : QMC_SIMD_ALIGNMENT)
532  for (size_t lm = 0; lm < lm_tot; lm++)
533  {
534  const double jlm = j_lm_G_ptr[lm];
535  vals_r[lm] += cG_ps_r * jlm;
536  vals_i[lm] += cG_ps_i * jlm;
537  }
538  }
539  }
540  }
541  }
542  }
543 
544 #pragma omp for collapse(2)
545  for (int ip = 0; ip < spline_npoints; ip++)
546  for (size_t idx = 0; idx < natoms; idx++)
547  {
548  double* vals = all_vals[idx][ip];
549  for (size_t tid = 0; tid < nt; tid++)
550  for (size_t lm = 0; lm < lm_tot; lm++)
551  {
552  double vals_th_r, vals_th_i;
553  const size_t ip_idx = tid * spline_npoints + ip;
554  if (policy == 1)
555  {
556  vals_th_r = vals_local[ip_idx][lm * 2][idx];
557  vals_th_i = vals_local[ip_idx][lm * 2 + 1][idx];
558  }
559  else
560  {
561  vals_th_r = vals_local[ip_idx][idx * 2][lm];
562  vals_th_i = vals_local[ip_idx][idx * 2 + 1][lm];
563  }
564  const double real_tmp = 4.0 * M_PI * i_power[lm].real();
565  const double imag_tmp = 4.0 * M_PI * i_power[lm].imag();
566  vals[lm] += vals_th_r * real_tmp - vals_th_i * imag_tmp;
567  vals[lm + lm_tot] += vals_th_i * real_tmp + vals_th_r * imag_tmp;
568  }
569  }
570  }
571  //app_log() << "Building band " << iorb << " at center " << center_idx << std::endl;
572 
573  for (size_t idx = 0; idx < natoms; idx++)
574  {
575  // reduce all_vals
576  band_group_comm.reduce_in_place(all_vals[idx].data(), all_vals[idx].size());
577  if (!band_group_comm.isGroupLeader())
578  continue;
579 #pragma omp parallel for
580  for (int lm = 0; lm < lm_tot; lm++)
581  {
582  auto& mycenter = centers[mygroup[idx]];
583  aligned_vector<double> splineData_r(spline_npoints);
584  UBspline_1d_d* atomic_spline_r = nullptr;
585  for (size_t ip = 0; ip < spline_npoints; ip++)
586  splineData_r[ip] = all_vals[idx][ip][lm];
587  atomic_spline_r = einspline::create(atomic_spline_r, 0.0, spline_radius, spline_npoints, splineData_r.data(),
588  ((lm == 0) || (lm > 3)));
589  if (!bspline.isComplex())
590  {
591  mycenter.set_spline(atomic_spline_r, lm, iorb);
592  einspline::destroy(atomic_spline_r);
593  }
594  else
595  {
596  aligned_vector<double> splineData_i(spline_npoints);
597  UBspline_1d_d* atomic_spline_i = nullptr;
598  for (size_t ip = 0; ip < spline_npoints; ip++)
599  splineData_i[ip] = all_vals[idx][ip][lm + lm_tot];
600  atomic_spline_i = einspline::create(atomic_spline_i, 0.0, spline_radius, spline_npoints, splineData_i.data(),
601  ((lm == 0) || (lm > 3)));
602  mycenter.set_spline(atomic_spline_r, lm, iorb * 2);
603  mycenter.set_spline(atomic_spline_i, lm, iorb * 2 + 1);
604  einspline::destroy(atomic_spline_r);
605  einspline::destroy(atomic_spline_i);
606  }
607  }
608  }
609  }
610 }
611 
612 template<typename SA>
614  const BandInfoGroup& bandgroup,
615  SA& bspline) const
616 {
617  auto& mybuilder = spline_reader_.mybuilder;
618  //distribute bands over processor groups
619  int Nbands = bandgroup.getNumDistinctOrbitals();
620  const int Nprocs = myComm->size();
621  const int Nbandgroups = std::min(Nbands, Nprocs);
622  Communicate band_group_comm(*myComm, Nbandgroups);
623  std::vector<int> band_groups(Nbandgroups + 1, 0);
624  FairDivideLow(Nbands, Nbandgroups, band_groups);
625  int iorb_first = band_groups[band_group_comm.getGroupID()];
626  int iorb_last = band_groups[band_group_comm.getGroupID() + 1];
627 
628  app_log() << "Start transforming plane waves to 3D B-splines and atomic radial orbital 1D B-splines." << std::endl;
629  OneSplineOrbData oneband(mybuilder->MeshSize, bspline.HalfG, bspline.isComplex());
630  hdf_archive h5f(&band_group_comm, false);
631  Vector<std::complex<double>> cG(mybuilder->Gvecs[0].size());
632  const std::vector<BandInfo>& cur_bands = bandgroup.myBands;
633  if (band_group_comm.isGroupLeader())
634  h5f.open(mybuilder->H5FileName, H5F_ACC_RDONLY);
635  for (int iorb = iorb_first; iorb < iorb_last; iorb++)
636  {
637  if (band_group_comm.isGroupLeader())
638  {
639  const auto& cur_band = cur_bands[bspline.BandIndexMap[iorb]];
640  const int ti = cur_band.TwistIndex;
641  spline_reader_.readOneOrbitalCoefs(psi_g_path(ti, spin, cur_band.BandIndex), h5f, cG);
642  oneband.fft_spline(cG, mybuilder->Gvecs[0], mybuilder->primcell_kpoints[ti], rotate);
643  bspline.set_spline(&oneband.get_spline_r(), &oneband.get_spline_i(), cur_band.TwistIndex, iorb, 0);
644  }
645  band_group_comm.bcast(cG);
646  create_atomic_centers_Gspace(cG, band_group_comm, iorb, oneband.getRotatePhase(), bspline);
647  }
648 
649  myComm->barrier();
650  if (band_group_comm.isGroupLeader())
651  {
652  Timer now;
653  bspline.gather_tables(band_group_comm.getGroupLeaderComm());
654  app_log() << " Time to gather the table = " << now.elapsed() << std::endl;
655  }
656 }
657 
658 #if defined(QMC_COMPLEX)
661 #if !defined(QMC_MIXED_PRECISION)
664 #endif
665 #else
669 #if !defined(QMC_MIXED_PRECISION)
673 #endif
674 #endif
675 } // namespace qmcplusplus
double bspline(double x, const std::vector< double > &t, const std::vector< double > &c, int k)
a class that defines a supercell in D-dimensional Euclean space.
Fixed-size array.
Definition: OhmmsTinyMeta.h:30
double elapsed() const
Definition: Timer.h:30
std::vector< T, aligned_allocator< T > > aligned_vector
void write(T &data, const std::string &aname)
write the data to the group aname and check status runtime error is issued on I/O error ...
Definition: hdf_archive.h:259
bool open(const std::filesystem::path &fname, unsigned flags=H5F_ACC_RDWR)
open a file
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
HybridRepSetReader(EinsplineSetBuilder *e)
std::complex< T > Ylm(int l, int m, const TinyVector< T, 3 > &r)
calculates Ylm param[in] l angular momentum param[in] m magnetic quantum number param[in] r position ...
Definition: Ylm.h:89
void calc_Ylm_G(const size_t ig, YLM_ENGINE &Ylm, VVT &YlmG) const
std::ostream & app_log()
Definition: OutputManager.h:65
bool put(xmlNodePtr cur)
assign attributes to the set
Definition: AttributeSet.h:55
void close()
close all the open groups and file
Definition: hdf_archive.cpp:38
std::ostream & app_error()
Definition: OutputManager.h:67
CrystalLattice< ParticleSet::Scalar_t, DIM > UnitCellType
SoA adaptor class for Vector<TinyVector<T,D> >
class to handle hdf file
Definition: hdf_archive.h:51
void calc_phase_shift(const PT &RSoA, const size_t ig, VT &phase_shift_real, VT &phase_shift_imag) const
Timer class.
void set_info(const PT &R, const VT &cutoff_in, const VT &cutoff_buffer_in, const VT &spline_radius_in, const VT &non_overlapping_radius_in, const int spline_npoints_in)
SoaSphericalTensor that evaluates the Real Spherical Harmonics.
Gvectors(const std::vector< TinyVector< int, 3 >> &gvecs_in, const LT &Lattice_in, const TinyVector< int, 3 > &HalfG, size_t first, size_t last)
int size() const
return the number of tasks
Definition: Communicate.h:118
T min(T a, T b)
void FairDivideLow(int ntot, int npart, IV &adist)
partition ntot elements among npart
Definition: FairDivide.h:114
int getNumDistinctOrbitals() const
return the size of this band
Definition: BandInfo.h:85
Wrapping information on parallelism.
Definition: Communicate.h:68
void evaluate_psi_r(const Vector< std::complex< double >> &cG, const PT &pos, ValueType &phi, ValueType &d2phi)
void calc_jlm_G(const int lmax, ST &r, const size_t ig, VVT &j_lm_G) const
SingleParticlePos k_cart(const SingleParticlePos &kin) const
conversion of a reciprocal-vector
omp_int_t omp_get_thread_num()
Definition: OpenMP.h:25
Each SplineC2X needs a reader derived from BsplineReader.
Definition: BsplineReader.h:39
int getGroupID() const
return the group id
Definition: Communicate.h:121
a group of bands
Definition: BandInfo.h:66
MakeReturn< UnaryNode< FnCeil, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t ceil(const Vector< T1, C1 > &l)
omp_int_t omp_get_max_threads()
Definition: OpenMP.h:26
void initialize_hybridrep_atomic_centers(SA &bspline) const
initialize basic parameters of atomic orbitals
class to handle a set of attributes of an xmlNode
Definition: AttributeSet.h:24
std::complex< ST > ValueType
std::vector< PosType > gvecs_cart
void initialize_hybrid_pio_gather(const int spin, const BandInfoGroup &bandgroup, SA &bspline) const
transforming planewave orbitals to 3D B-spline orbitals and 1D B-spline radial orbitals in real space...
bool isGroupLeader()
return true if the current MPI rank is the group lead
Definition: Communicate.h:134
double evaluate_KE(const Vector< std::complex< double >> &cG)
#define APP_ABORT(msg)
Widely used but deprecated fatal error macros from legacy code.
Definition: AppAbort.h:27
ValueType evaluate_psi_r(const Vector< std::complex< double >> &cG, const PT &pos)
omp_int_t omp_get_num_threads()
Definition: OpenMP.h:27
void create_atomic_centers_Gspace(const Vector< std::complex< double >> &cG, Communicate &band_group_comm, const int iorb, const std::complex< double > &rotate_phase, SA &bspline) const
initialize construct atomic orbital radial functions from plane waves
MakeReturn< UnaryNode< FnSqrt, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t sqrt(const Vector< T1, C1 > &l)
bool create(const std::filesystem::path &fname, unsigned flags=H5F_ACC_TRUNC)
create a file
void reduce_in_place(T *restrict, int n)
Communicate * getGroupLeaderComm()
Definition: Communicate.h:230
void sincos(T a, T *restrict s, T *restrict c)
sincos function wrapper
Definition: math.hpp:62
Tensor< typename BinaryReturn< T1, T2, OpMultiply >::Type_t, D > dot(const AntiSymTensor< T1, D > &lhs, const AntiSymTensor< T2, D > &rhs)
void bcast(T &)
hFile create(filename)
General HybridRepSetReader to handle any unitcell.
std::unique_ptr< SPOSet > create_spline_set(const std::string &my_name, int spin, const BandInfoGroup &bandgroup) override
create the actual spline sets
void add(PDT &aparam, const std::string &aname, std::vector< PDT > candidate_values={}, TagStatus status=TagStatus::OPTIONAL)
add a new attribute
Definition: AttributeSet.h:42
derived from BsplineReader
std::vector< BandInfo > myBands
Bands that belong to this group.
Definition: BandInfo.h:79
void bessel_steed_array_cpu(const int lmax, const T x, T *jl)
Compute spherical bessel function from 0 to lmax.
Definition: Bessel.h:25