Skip to content

Commit 597b03c

Browse files
authored
Merge pull request QMCPACK#5848 from ye-luo/refactor-splines
Major refactoring of spline SPO related classes
2 parents d7adaad + 6cca203 commit 597b03c

37 files changed

Lines changed: 549 additions & 751 deletions

src/QMCWaveFunctions/BandInfo.cpp

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
#include "BandInfo.h"
1717
#include "QMCWaveFunctions/SPOSetInfo.h"
18+
#include <Message/UniformCommunicateError.h>
19+
1820
namespace qmcplusplus
1921
{
2022
BandInfoGroup::BandInfoGroup() : NumSPOs(0), FirstBand(0) {}
@@ -24,21 +26,11 @@ void BandInfoGroup::selectBands(const std::vector<BandInfo>& bigspace, int first
2426
app_log() << "BandInfoGroup::selectBands bigspace has " << bigspace.size() << " distinct orbitals " << std::endl;
2527
myBands.clear();
2628

27-
int iorb = 0;
28-
int N = bigspace.size();
29-
int n_lower = 0;
30-
do
31-
{
32-
if (iorb >= first_orb)
33-
break;
34-
n_lower += (bigspace[iorb].MakeTwoCopies) ? 2 : 1;
35-
++iorb;
36-
} while (iorb < N);
29+
int iorb = first_orb;
30+
const int N = bigspace.size();
3731

3832
if (iorb >= N)
39-
{
40-
APP_ABORT("BandInfoGroup::selectBands failed due to iorb>=N");
41-
}
33+
throw UniformCommunicateError("BandInfoGroup::selectBands failed due to iorb>=N");
4234

4335
FirstBand = iorb;
4436
NumSPOs = 0;
@@ -55,6 +47,9 @@ void BandInfoGroup::selectBands(const std::vector<BandInfo>& bigspace, int first
5547
app_log() << " Number of distinct bands " << myBands.size() << std::endl;
5648
app_log() << " First Band index " << FirstBand << std::endl;
5749
app_log() << " Size of SPOs " << NumSPOs << std::endl;
50+
51+
if (NumSPOs != num_spos)
52+
throw UniformCommunicateError("Insufficient bands to generate SPOs. Requested amount " + std::to_string(num_spos));
5853
}
5954

6055
} // namespace qmcplusplus

src/QMCWaveFunctions/BandInfo.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,6 @@ struct BandInfoGroup
7171
int NumSPOs;
7272
///starting band
7373
int FirstBand;
74-
///twist index set by the full band not by the subset
75-
int TwistIndex;
7674
///Bands that belong to this group
7775
std::vector<BandInfo> myBands;
7876
///name of this band

src/QMCWaveFunctions/BsplineFactory/BsplineReader.cpp

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,15 @@
2222
#include "OhmmsData/AttributeSet.h"
2323
#include "Message/CommOperators.h"
2424
#include <PlatformSelector.hpp>
25+
#include "einspline_helper.hpp"
2526

2627
#include <array>
2728
#include <filesystem>
2829

2930
namespace qmcplusplus
3031
{
31-
BsplineReader::BsplineReader(EinsplineSetBuilder* e)
32-
: mybuilder(e), checkNorm(true), saveSplineCoefs(false), rotate(true)
32+
BsplineReader::BsplineReader(EinsplineSetBuilder* e, bool use_duplex_splines)
33+
: mybuilder(e), checkNorm(true), saveSplineCoefs(false), rotate(true), use_duplex_splines_(use_duplex_splines)
3334
{ myComm = mybuilder->getCommunicator(); }
3435

3536
BsplineReader::~BsplineReader() = default;
@@ -107,14 +108,61 @@ std::unique_ptr<SPOSet> BsplineReader::create_spline_set(const std::string& spo_
107108
}
108109

109110
BandInfoGroup vals;
110-
vals.TwistIndex = fullband[0].TwistIndex;
111-
vals.GroupID = 0;
112-
vals.myName = make_bandgroup_name(spo_name, spin, mybuilder->twist_num_, mybuilder->TileMatrix, 0, size);
111+
vals.GroupID = 0;
112+
vals.myName = make_bandgroup_name(spo_name, spin, mybuilder->twist_num_, mybuilder->TileMatrix, 0, size);
113113
vals.selectBands(fullband, 0, size);
114114

115115
return create_spline_set(spo_name, spin, vals);
116116
}
117117

118+
bool BsplineReader::lookforSplineDataDumpFile(const BandInfoGroup& bandgroup,
119+
const std::string& keyword,
120+
size_t datatype_size) const
121+
{
122+
int foundspline = 0;
123+
if (myComm->rank() == 0)
124+
{
125+
hdf_archive h5f(myComm);
126+
foundspline = h5f.open(getSplineDumpFileName(bandgroup), H5F_ACC_RDONLY);
127+
if (foundspline)
128+
{
129+
std::string aname("none");
130+
foundspline = h5f.readEntry(aname, "class_name");
131+
foundspline = (aname.find(keyword) != std::string::npos);
132+
}
133+
if (foundspline)
134+
{
135+
int sizeD = 0;
136+
foundspline = h5f.readEntry(sizeD, "sizeof");
137+
foundspline = (sizeD == datatype_size);
138+
}
139+
h5f.close();
140+
}
141+
myComm->bcast(foundspline);
142+
return foundspline;
143+
}
144+
145+
void BsplineReader::readOneOrbitalCoefs(const std::string& s, hdf_archive& h5f, Vector<std::complex<double>>& cG) const
146+
{
147+
if (!h5f.readEntry(cG, s))
148+
{
149+
std::ostringstream msg;
150+
msg << "SplineSetReader Failed to read band(s) from h5 file. " << "Attempted dataset " << s << " with " << cG.size()
151+
<< " complex numbers." << std::endl;
152+
throw std::runtime_error(msg.str());
153+
}
154+
double total_norm = compute_norm(cG);
155+
if ((checkNorm) && (std::abs(total_norm - 1.0) > PW_COEFF_NORM_TOLERANCE))
156+
{
157+
std::ostringstream msg;
158+
msg << "SplineSetReader The orbital dataset " << s << " has a wrong norm " << total_norm
159+
<< ", computed from plane wave coefficients!" << std::endl
160+
<< "This may indicate a problem with the HDF5 library versions used "
161+
<< "during wavefunction conversion or read." << std::endl;
162+
throw std::runtime_error(msg.str());
163+
}
164+
}
165+
118166
std::unique_ptr<SPOSet> BsplineReader::create_spline_set(const std::string& spo_name,
119167
int spin,
120168
SPOSetInputInfo& input_info)
@@ -134,10 +182,9 @@ std::unique_ptr<SPOSet> BsplineReader::create_spline_set(const std::string& spo_
134182
}
135183

136184
BandInfoGroup vals;
137-
vals.TwistIndex = fullband[0].TwistIndex;
138-
vals.GroupID = 0;
139-
vals.myName = make_bandgroup_name(spo_name, spin, mybuilder->twist_num_, mybuilder->TileMatrix,
140-
input_info.min_index(), input_info.max_index());
185+
vals.GroupID = 0;
186+
vals.myName = make_bandgroup_name(spo_name, spin, mybuilder->twist_num_, mybuilder->TileMatrix,
187+
input_info.min_index(), input_info.max_index());
141188
vals.selectBands(fullband, spo2band[spin][input_info.min_index()], input_info.max_index() - input_info.min_index());
142189

143190
return create_spline_set(spo_name, spin, vals);

src/QMCWaveFunctions/BsplineFactory/BsplineReader.h

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class BsplineReader
5252
std::vector<int>& band2spo);
5353

5454
public:
55-
BsplineReader(EinsplineSetBuilder* e);
55+
BsplineReader(EinsplineSetBuilder* e, bool use_duplex_splines);
5656

5757
virtual ~BsplineReader();
5858

@@ -86,6 +86,8 @@ class BsplineReader
8686
bool rotate;
8787
///map from spo index to band index
8888
std::vector<std::vector<int>> spo2band;
89+
/// if true, use two real-valued splines for one complex-valued DFT orbital.
90+
const bool use_duplex_splines_;
8991
/// if true, use offload
9092
bool use_offload;
9193

@@ -100,13 +102,13 @@ class BsplineReader
100102
/** read gvectors and set the mesh, and prepare for einspline
101103
*/
102104
template<typename GT, typename BCT>
103-
inline void set_grid(const TinyVector<int, 3>& halfg, GT* xyz_grid, BCT* xyz_bc) const
105+
static void set_grid(const TinyVector<int, 3>& mesh_sizes, const TinyVector<int, 3>& halfg, GT* xyz_grid, BCT* xyz_bc)
104106
{
105107
for (int j = 0; j < 3; ++j)
106108
{
107109
xyz_grid[j].start = 0.0;
108110
xyz_grid[j].end = 1.0;
109-
xyz_grid[j].num = mybuilder->MeshSize[j];
111+
xyz_grid[j].num = mesh_sizes[j];
110112

111113
if (halfg[j])
112114
{
@@ -131,8 +133,6 @@ class BsplineReader
131133
const int N = bandgroup.getNumDistinctOrbitals();
132134
const int numOrbs = bandgroup.getNumSPOs();
133135

134-
bspline.resizeStorage(N);
135-
136136
const std::vector<BandInfo>& cur_bands = bandgroup.myBands;
137137
for (int iorb = 0, num = 0; iorb < N; iorb++)
138138
{
@@ -142,23 +142,27 @@ class BsplineReader
142142
num += bspline.MakeTwoCopies[iorb] ? 2 : 1;
143143
}
144144

145+
bspline.resize_kpoints();
145146
app_log() << "NumDistinctOrbitals " << N << " numOrbs = " << numOrbs << std::endl;
147+
}
146148

147-
bspline.HalfG = 0;
148-
TinyVector<int, 3> bconds = mybuilder->TargetPtcl.getLattice().BoxBConds;
149-
if (!bspline.isComplex())
150-
{
151-
//no k-point folding, single special k point (G, L ...)
152-
TinyVector<double, 3> twist0 = mybuilder->primcell_kpoints[bandgroup.TwistIndex];
153-
for (int i = 0; i < 3; i++)
154-
if (bconds[i] && ((std::abs(std::abs(twist0[i]) - 0.5) < 1.0e-8)))
155-
bspline.HalfG[i] = 1;
156-
else
157-
bspline.HalfG[i] = 0;
158-
app_log() << " TwistIndex = " << cur_bands[0].TwistIndex << " TwistAngle " << twist0 << std::endl;
159-
app_log() << " HalfG = " << bspline.HalfG << std::endl;
160-
}
161-
app_log().flush();
149+
/** compute sign bits at the G/2 boundaries
150+
* no supercell, no k-point folding, single special k point (G, L ...)
151+
*/
152+
static TinyVector<int, 3> computeHalfG(const TinyVector<int, OHMMS_DIM>& bconds,
153+
const std::vector<TinyVector<double, OHMMS_DIM>>& primcell_kpoints,
154+
size_t twist0_index)
155+
{
156+
TinyVector<int, 3> halfG;
157+
const auto& twist0 = primcell_kpoints[twist0_index];
158+
app_log() << " TwistIndex = " << twist0_index << " TwistAngle " << twist0 << std::endl;
159+
for (int i = 0; i < 3; i++)
160+
if (bconds[i] && ((std::abs(std::abs(twist0[i]) - 0.5) < 1.0e-8)))
161+
halfG[i] = 1;
162+
else
163+
halfG[i] = 0;
164+
app_log() << " HalfG = " << halfG << std::endl;
165+
return halfG;
162166
}
163167

164168
/** return the path name in hdf5
@@ -172,6 +176,22 @@ class BsplineReader
172176
path << "/electrons/kpoint_" << ti << "/spin_" << spin << "/state_" << ib << "/psi_g";
173177
return path.str();
174178
}
179+
180+
/** create data space in the spline object and try open spline dump files.
181+
* @param bandgroup band info
182+
* @param bspline the spline object being worked on
183+
* @return true if dumpfile pass class name and data type size check
184+
*/
185+
bool lookforSplineDataDumpFile(const BandInfoGroup& bandgroup,
186+
const std::string& keyword,
187+
size_t datatype_size) const;
188+
189+
/** read planewave coefficients from h5 file
190+
* @param s data set full path in h5
191+
* @param h5f hdf5 file handle
192+
* @param cG vector to store coefficients
193+
*/
194+
void readOneOrbitalCoefs(const std::string& s, hdf_archive& h5f, Vector<std::complex<double>>& cG) const;
175195
};
176196

177197
} // namespace qmcplusplus

src/QMCWaveFunctions/BsplineFactory/BsplineSet.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@
2525

2626
namespace qmcplusplus
2727
{
28+
29+
template<class ST>
30+
class SplineSetReader;
31+
template<class ST>
32+
class HybridRepSetReader;
33+
2834
/** BsplineSet is the base class for SplineC2C, SplineC2R, SplineR2R.
2935
* Its derived template classes manage the storage and evaluation at given precision.
3036
* BsplineSet also implements a few fallback routines in case optimized implementation is not necessary in the derived class.
@@ -52,7 +58,6 @@ class BsplineSet : public SPOSet
5258
: SPOSet(my_name, size), prim_lattice_(prim_lattice)
5359
{}
5460

55-
virtual bool isComplex() const = 0;
5661
virtual std::string getKeyword() const = 0;
5762

5863
auto& getHalfG() const { return HalfG; }
@@ -69,6 +74,9 @@ class BsplineSet : public SPOSet
6974
/// resize vectors related to spline evaluaton results.
7075
virtual void resizeStorage(size_t n) = 0;
7176

77+
/** remap kPoints to pack the double copy */
78+
virtual void resize_kpoints() {}
79+
7280
///remap kpoints to group general kpoints & special kpoints
7381
int remap_kpoints()
7482
{
@@ -236,8 +244,10 @@ class BsplineSet : public SPOSet
236244
//Do nothing, since Einsplines don't explicitly depend on ion positions.
237245
}
238246

239-
template<class BSPLINESPO>
247+
template<class ST>
240248
friend class SplineSetReader;
249+
template<class ST>
250+
friend class HybridRepSetReader;
241251
friend class BsplineReader;
242252
};
243253

src/QMCWaveFunctions/BsplineFactory/EinsplineSetBuilder_createSPOs.cpp

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
#include "einspline_helper.hpp"
3030
#include "BsplineReader.h"
3131
#include "BsplineSet.h"
32-
#include "createBsplineReader.h"
32+
#include "SplineSetReader.h"
33+
#include "HybridRepSetReader.h"
3334

3435
#include <array>
3536
#include <string_view>
@@ -115,12 +116,8 @@ std::unique_ptr<SPOSet> EinsplineSetBuilder::createSPOSetFromXML(xmlNodePtr cur)
115116
std::string sourceName;
116117
std::string spo_prec("double");
117118
std::string truncate("no");
118-
std::string hybrid_rep("no");
119+
std::string hybrid_rep;
119120
std::string skip_checks("no");
120-
std::string use_einspline_set_extended(
121-
"no"); // use old spline library for high-order derivatives, e.g. needed for backflow optimization
122-
std::string useGPU;
123-
std::string GPUsharing = "no";
124121

125122
ScopedTimer spo_timer_scope(createGlobalTimer("einspline::CreateSPOSetFromXML", timer_level_medium));
126123

@@ -136,9 +133,7 @@ std::unique_ptr<SPOSet> EinsplineSetBuilder::createSPOSetFromXML(xmlNodePtr cur)
136133
a_root.add(twist_inp, "twist");
137134
a_root.add(sourceName, "source");
138135
a_root.add(MeshFactor, "meshfactor");
139-
a_root.add(hybrid_rep, "hybridrep");
140-
a_root.add(useGPU, "gpu", CPUOMPTargetSelector::candidate_values);
141-
a_root.add(GPUsharing, "gpusharing"); // split spline across GPUs visible per rank
136+
a_root.add(hybrid_rep, "hybridrep", {"no", "yes"});
142137
a_root.add(spo_prec, "precision");
143138
a_root.add(truncate, "truncate");
144139
a_root.add(skip_checks, "skip_checks");
@@ -244,24 +239,30 @@ std::unique_ptr<SPOSet> EinsplineSetBuilder::createSPOSetFromXML(xmlNodePtr cur)
244239
if (!ReadGvectors_ESHDF())
245240
myComm->barrier_and_abort("Failed to load g-vectors.");
246241

247-
bool use_single = (spo_prec == "single" || spo_prec == "float");
242+
const bool use_single = (spo_prec == "single" || spo_prec == "float");
243+
app_summary() << " Using " << (use_single ? "single" : "double") << " precision B-spline coefficients."
244+
<< std::endl;
245+
246+
const bool use_hybridrep = hybrid_rep == "yes";
247+
app_summary() << " Using " << (use_hybridrep ? "hybrid" : "regular 3D cublic B-spline")
248+
<< " orbital representation." << std::endl;
248249

249250
// safeguard for a removed feature
250251
if (truncate == "yes")
251252
myComm->barrier_and_abort(
252253
"The 'truncate' feature of spline SPO has been removed. Please use hybrid orbital representation.");
253254

254-
#if !defined(QMC_COMPLEX)
255-
if (use_real_splines_)
256-
{
257-
if (MixedSplineReader == 0)
258-
MixedSplineReader = createBsplineReal(this, use_single, hybrid_rep == "yes");
259-
}
260-
else
261-
#endif
255+
if (!MixedSplineReader)
262256
{
263-
if (MixedSplineReader == 0)
264-
MixedSplineReader = createBsplineComplex(this, use_single, hybrid_rep == "yes", useGPU);
257+
if (use_hybridrep)
258+
if (use_single)
259+
MixedSplineReader = std::make_unique<HybridRepSetReader<float>>(this, !use_real_splines_);
260+
else
261+
MixedSplineReader = std::make_unique<HybridRepSetReader<double>>(this, !use_real_splines_);
262+
else if (use_single)
263+
MixedSplineReader = std::make_unique<SplineSetReader<float>>(this, !use_real_splines_);
264+
else
265+
MixedSplineReader = std::make_unique<SplineSetReader<double>>(this, !use_real_splines_);
265266
}
266267

267268
MixedSplineReader->setCommon(XMLRoot);

0 commit comments

Comments
 (0)