Skip to content

Commit 4151f17

Browse files
committed
Refactor: Simplify LCAO partial-charge and wavefunction output
1 parent 5b9f7eb commit 4151f17

4 files changed

Lines changed: 175 additions & 209 deletions

File tree

source/source_esolver/lcao_others.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,12 @@ void ESolver_KS_LCAO<TK, TR>::others(BaseCell& basecell, const int istep)
180180
Get_pchg_lcao get_pchg(*this->psi, this->pv, this->inp_->nspin);
181181
if (gamma_only_local)
182182
{
183-
get_pchg.begin_gamma(ucell, this->Pgrid, this->gd, this->inp_->out_pchg, global_out_dir, GlobalV::ofs_running);
183+
get_pchg.begin_gamma(ucell,
184+
this->Pgrid,
185+
this->gd,
186+
this->inp_->out_pchg,
187+
global_out_dir,
188+
GlobalV::ofs_running);
184189
}
185190
else
186191
{
@@ -199,10 +204,15 @@ void ESolver_KS_LCAO<TK, TR>::others(BaseCell& basecell, const int istep)
199204
else if (cal_type == "get_wf")
200205
{
201206
std::cout << FmtCore::format("\n * * * * * *\n << Start %s.\n", "getting wave function");
202-
Get_wf_lcao get_wf(*this->psi, this->pv, this->inp_->nspin, this->inp_->nelec);
207+
Get_wf_lcao get_wf(*this->psi, this->pv, this->inp_->nspin);
203208
if (gamma_only_local)
204209
{
205-
get_wf.begin_gamma(ucell, this->Pgrid, this->inp_->out_wfc_norm, this->inp_->out_wfc_re_im, global_out_dir, GlobalV::ofs_running);
210+
get_wf.begin_gamma(ucell,
211+
this->Pgrid,
212+
this->inp_->out_wfc_norm,
213+
this->inp_->out_wfc_re_im,
214+
global_out_dir,
215+
GlobalV::ofs_running);
206216
}
207217
else
208218
{

source/source_io/module_chgpot/get_pchg_lcao.cpp

Lines changed: 97 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -35,51 +35,54 @@ void Get_pchg_lcao::begin_gamma(const UnitCell& ucell,
3535
assert(psi_gamma_ != nullptr);
3636
const int nrxx = pgrid.get_nrxx();
3737
const int precision = 11;
38+
const std::vector<int> bands_picked = select_bands(out_pchg);
39+
40+
// LCAO output uses one global process pool after diagonalization.
41+
// Each spin component is accumulated independently on the distributed real-space grid.
3842
std::vector<std::vector<double>> rho(nspin_, std::vector<double>(nrxx));
3943
std::vector<double*> rho_pointers(nspin_);
4044
for (int is = 0; is < nspin_; ++is)
4145
{
4246
rho_pointers[is] = rho[is].data();
4347
}
44-
const std::vector<int> bands_picked = select_bands(out_pchg);
45-
4648
for (int ib = 0; ib < nbands_; ++ib)
4749
{
48-
if (bands_picked[ib])
50+
if (!bands_picked[ib])
4951
{
50-
ModuleBase::matrix state_weights(nspin_, nbands_);
51-
const double spin_degeneracy = nspin_ == 1 ? 2.0 : 1.0;
52-
for (int is = 0; is < nspin_; ++is)
53-
{
54-
state_weights(is, ib) = spin_degeneracy;
55-
}
52+
continue;
53+
}
5654

57-
elecstate::DensityMatrix<double, double> DM(&para_orb_, nspin_);
58-
elecstate::cal_dm_psi(&para_orb_, state_weights, *psi_gamma_, DM);
55+
// Build a complete one-particle state instead of reusing its SCF occupation.
56+
ModuleBase::matrix state_weights(nspin_, nbands_);
57+
const double spin_degeneracy = nspin_ == 1 ? 2.0 : 1.0;
58+
for (int is = 0; is < nspin_; ++is)
59+
{
60+
state_weights(is, ib) = spin_degeneracy;
61+
}
5962

60-
for (int is = 0; is < nspin_; ++is)
61-
{
62-
std::fill(rho[is].begin(), rho[is].end(), 0.0);
63-
}
63+
// Construct a band-resolved density matrix before evaluating its density on the grid.
64+
elecstate::DensityMatrix<double, double> DM(&para_orb_, nspin_);
65+
elecstate::cal_dm_psi(&para_orb_, state_weights, *psi_gamma_, DM);
6466

65-
DM.init_DMR(&grid_driver, &ucell);
66-
DM.cal_DMR();
67-
ModuleGint::cal_gint_rho(DM.get_DMR_vector(), nspin_, rho_pointers.data());
67+
for (int is = 0; is < nspin_; ++is)
68+
{
69+
std::fill(rho[is].begin(), rho[is].end(), 0.0);
70+
}
6871

69-
for (int is = 0; is < nspin_; ++is)
70-
{
71-
// ssc should be inside the inner loop to reset the string stream each time
72-
std::stringstream ssc;
73-
ssc << global_out_dir << "pchgi" << ib + 1 << "s" << is + 1 << ".cube";
72+
DM.init_DMR(&grid_driver, &ucell);
73+
DM.cal_DMR();
74+
ModuleGint::cal_gint_rho(DM.get_DMR_vector(), nspin_, rho_pointers.data());
7475

75-
ofs_running << " Writing cube file " << ssc.str() << std::endl;
76+
for (int is = 0; is < nspin_; ++is)
77+
{
78+
std::stringstream ssc;
79+
ssc << global_out_dir << "pchgi" << ib + 1 << "s" << is + 1 << ".cube";
7680

77-
ModuleIO::write_vdata_palgrid(pgrid, rho[is].data(), is, nspin_, 0, ssc.str(), 0.0, &ucell, precision, 0, false, false);
78-
}
81+
ofs_running << " Writing cube file " << ssc.str() << std::endl;
82+
83+
ModuleIO::write_vdata_palgrid(pgrid, rho[is].data(), is, nspin_, 0, ssc.str(), 0.0, &ucell, precision, 0, false, false);
7984
}
8085
}
81-
82-
return;
8386
}
8487

8588
// For multi-k
@@ -103,13 +106,17 @@ void Get_pchg_lcao::begin_k(const ModulePW::PW_Basis& rho_pw,
103106
assert(pgrid.get_nrxx() == rho_pw.nrxx);
104107
const int nrxx = pgrid.get_nrxx();
105108
const int precision = 11;
109+
const std::vector<int> bands_picked = select_bands(out_pchg);
110+
111+
// LCAO k-point parallelism is temporary; output uses the restored global layout.
106112
std::vector<std::vector<double>> rho(nspin_, std::vector<double>(nrxx));
107113
std::vector<double*> rho_pointers(nspin_);
108114
for (int is = 0; is < nspin_; ++is)
109115
{
110116
rho_pointers[is] = rho[is].data();
111117
}
112118

119+
// A single-k density is not generally invariant under the full crystal symmetry group.
113120
const bool needs_symmetry = !if_separate_k && ModuleSymmetry::Symmetry::symm_flag == 1;
114121
std::vector<std::vector<std::complex<double>>> rhog;
115122
std::vector<std::complex<double>*> rhog_pointers;
@@ -122,106 +129,94 @@ void Get_pchg_lcao::begin_k(const ModulePW::PW_Basis& rho_pw,
122129
rhog_pointers[is] = rhog[is].data();
123130
}
124131
}
125-
const std::vector<int> bands_picked = select_bands(out_pchg);
126-
127132
for (int ib = 0; ib < nbands_; ++ib)
128133
{
129-
if (bands_picked[ib])
134+
if (!bands_picked[ib])
130135
{
131-
ModuleBase::matrix state_weights(kv.get_nks(), nbands_);
132-
const double spin_degeneracy = nspin_ == 1 ? 2.0 : 1.0;
133-
for (int ik = 0; ik < kv.get_nks(); ++ik)
134-
{
135-
state_weights(ik, ib) = if_separate_k ? spin_degeneracy : kv.wk[ik];
136-
}
137-
138-
const int nspin_dm = nspin_ == 2 ? 2 : 1;
139-
const int nk_output = kv.get_nks() / nspin_dm;
140-
elecstate::DensityMatrix<std::complex<double>, double> DM(&para_orb_, nspin_dm, kv.kvec_d, nk_output);
141-
elecstate::cal_dm_psi(&para_orb_, state_weights, *psi_k_, DM);
136+
continue;
137+
}
142138

143-
// If contribution from different k-points need to be output separately
144-
if (if_separate_k)
145-
{
146-
// For multi-k, loop over all real k-points
147-
for (int ik = 0; ik < nk_output; ++ik)
148-
{
149-
for (int is = 0; is < nspin_; ++is)
150-
{
151-
std::fill(rho[is].begin(), rho[is].end(), 0.0);
152-
}
139+
// Separate-k output uses a full state, while merged output retains Brillouin-zone weights.
140+
ModuleBase::matrix state_weights(kv.get_nks(), nbands_);
141+
const double spin_degeneracy = nspin_ == 1 ? 2.0 : 1.0;
142+
for (int ik = 0; ik < kv.get_nks(); ++ik)
143+
{
144+
state_weights(ik, ib) = if_separate_k ? spin_degeneracy : kv.wk[ik];
145+
}
153146

154-
DM.init_DMR(&grid_driver, &ucell);
155-
DM.cal_DMR(ik);
156-
ModuleGint::cal_gint_rho(DM.get_DMR_vector(), nspin_, rho_pointers.data());
147+
// Collinear spin channels are stored as two k blocks; spinors use one block per k point.
148+
const int nspin_dm = nspin_ == 2 ? 2 : 1;
149+
const int nk_output = kv.get_nks() / nspin_dm;
150+
elecstate::DensityMatrix<std::complex<double>, double> DM(&para_orb_, nspin_dm, kv.kvec_d, nk_output);
151+
elecstate::cal_dm_psi(&para_orb_, state_weights, *psi_k_, DM);
157152

158-
for (int is = 0; is < nspin_; ++is)
159-
{
160-
// ssc should be inside the inner loop to reset the string stream each time
161-
std::stringstream ssc;
162-
ssc << global_out_dir << "pchgi" << ib + 1 << "s" << is + 1 << "k" << ik + 1 << ".cube";
163-
164-
ofs_running << " Writing cube file " << ssc.str() << std::endl;
165-
166-
ModuleIO::write_vdata_palgrid(pgrid,
167-
rho[is].data(),
168-
is,
169-
nspin_,
170-
0,
171-
ssc.str(),
172-
0.0,
173-
&ucell,
174-
precision,
175-
0,
176-
false,
177-
false);
178-
}
179-
}
180-
}
181-
else
153+
if (if_separate_k)
154+
{
155+
// Write each physical k point separately.
156+
for (int ik = 0; ik < nk_output; ++ik)
182157
{
183158
for (int is = 0; is < nspin_; ++is)
184159
{
185160
std::fill(rho[is].begin(), rho[is].end(), 0.0);
186161
}
187162

188163
DM.init_DMR(&grid_driver, &ucell);
189-
DM.cal_DMR();
164+
// Transform only the requested real k point to avoid summing different k contributions.
165+
DM.cal_DMR(ik);
190166
ModuleGint::cal_gint_rho(DM.get_DMR_vector(), nspin_, rho_pointers.data());
191167

192-
// Symmetrize the charge density, otherwise the results are incorrect if the symmetry is on
193-
if (needs_symmetry)
194-
{
195-
Symmetry_rho srho;
196-
if (nspin_ == 4)
197-
{
198-
srho.begin(0, rho_pointers.data(), rhog_pointers.data(), rho_pw.npw, nullptr, &rho_pw, ucell.symm);
199-
srho.begin_soc(rho_pointers.data(), rhog_pointers.data(), &rho_pw, ucell.symm);
200-
}
201-
else
202-
{
203-
for (int is = 0; is < nspin_; ++is)
204-
{
205-
srho.begin(is, rho_pointers.data(), rhog_pointers.data(), rho_pw.npw, nullptr, &rho_pw, ucell.symm);
206-
}
207-
}
208-
}
209-
210168
for (int is = 0; is < nspin_; ++is)
211169
{
212-
// ssc should be inside the inner loop to reset the string stream each time
213170
std::stringstream ssc;
214-
ssc << global_out_dir << "pchgi" << ib + 1 << "s" << is + 1 << ".cube";
171+
ssc << global_out_dir << "pchgi" << ib + 1 << "s" << is + 1 << "k" << ik + 1 << ".cube";
215172

216173
ofs_running << " Writing cube file " << ssc.str() << std::endl;
217174

218175
ModuleIO::write_vdata_palgrid(pgrid, rho[is].data(), is, nspin_, 0, ssc.str(), 0.0, &ucell, precision, 0, false, false);
219176
}
220177
}
221178
}
222-
}
179+
else
180+
{
181+
for (int is = 0; is < nspin_; ++is)
182+
{
183+
std::fill(rho[is].begin(), rho[is].end(), 0.0);
184+
}
223185

224-
return;
186+
DM.init_DMR(&grid_driver, &ucell);
187+
// The no-argument transform sums all local k-point contributions into one density.
188+
DM.cal_DMR();
189+
ModuleGint::cal_gint_rho(DM.get_DMR_vector(), nspin_, rho_pointers.data());
190+
191+
// Symmetrize only the merged density, using coupled spin rotations for nspin=4.
192+
if (needs_symmetry)
193+
{
194+
Symmetry_rho srho;
195+
if (nspin_ == 4)
196+
{
197+
srho.begin(0, rho_pointers.data(), rhog_pointers.data(), rho_pw.npw, nullptr, &rho_pw, ucell.symm);
198+
srho.begin_soc(rho_pointers.data(), rhog_pointers.data(), &rho_pw, ucell.symm);
199+
}
200+
else
201+
{
202+
for (int is = 0; is < nspin_; ++is)
203+
{
204+
srho.begin(is, rho_pointers.data(), rhog_pointers.data(), rho_pw.npw, nullptr, &rho_pw, ucell.symm);
205+
}
206+
}
207+
}
208+
209+
for (int is = 0; is < nspin_; ++is)
210+
{
211+
std::stringstream ssc;
212+
ssc << global_out_dir << "pchgi" << ib + 1 << "s" << is + 1 << ".cube";
213+
214+
ofs_running << " Writing cube file " << ssc.str() << std::endl;
215+
216+
ModuleIO::write_vdata_palgrid(pgrid, rho[is].data(), is, nspin_, 0, ssc.str(), 0.0, &ucell, precision, 0, false, false);
217+
}
218+
}
219+
}
225220
}
226221

227222
std::vector<int> Get_pchg_lcao::select_bands(const std::vector<int>& out_pchg) const

0 commit comments

Comments
 (0)