Skip to content

Commit 74d75b7

Browse files
Feature: Support nspin=4 PW partial-charge and wavefunction .cube output (Useful Information to know how to use out_pchg, out_wfc_norm, and out_wfc_re_im functions) (#7841)
* Feature: Support nspin=4 PW partial-charge and wavefunction `.cube` output * Modify CI/CD reference --------- Co-authored-by: Mohan Chen <mohanchen@pku.edu.cn>
1 parent fac9330 commit 74d75b7

124 files changed

Lines changed: 2292 additions & 1098 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎docs/advanced/input_files/input-main.md‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2374,28 +2374,30 @@
23742374

23752375
- **Type**: String
23762376
- **Availability**: *[`basis_type`](#basis_type)==pw or ([`basis_type`](#basis_type)==lcao and [`calculation`](#calculation)==get_pchg)*
2377-
- **Description**: Specifies the electronic states to calculate the charge densities with state index for, using a space-separated string of 0s and 1s. Each digit in the string corresponds to a state, starting from the first state. A 1 indicates that the charge density should be calculated for that state, while a 0 means the state will be ignored. The parameter allows a compact and flexible notation (similar to ocp_set), for example the syntax 1 4*0 5*1 0 is used to denote the selection of states: 1 means calculate for the first state, 4*0 skips the next four states, 5*1 means calculate for the following five states, and the final 0 skips the next state. It's essential that the total count of states does not exceed the total number of states (nbands); otherwise, it results in an error, and the process exits. The input string must contain only numbers and the asterisk (*) for repetition, ensuring correct format and intention of state selection. The outputs comprise multiple .cube files following the naming convention pchgi[state]s[spin]k[kpoint].cube.
2377+
- **Description**: Selects electronic states for partial (band-decomposed) charge-density output using a space-separated string of `0`s and `1`s, where `1` selects a state and `0` skips it. Repetition follows the `ocp_set` syntax, for example `1 4*0 5*1 0`; the expanded list must not exceed `nbands`. Each output represents a complete one-particle state rather than its SCF occupation. The spin degeneracy is 2 for `nspin=1` and 1 for `nspin=2` or `nspin=4`. For `nspin=1`, `s1` contains the charge density. For `nspin=2`, `s1` and `s2` contain the spin-up and spin-down charge densities, respectively. For `nspin=4`, `s1`, `s2`, `s3`, and `s4` respectively contain $\rho_0$, $m_x$, $m_y$, and $m_z$. With `if_separate_k=true`, files are named `pchgi[state]s[component]k[kpoint].cube`; otherwise, the weighted k-point sum is named `pchgi[state]s[component].cube`.
2378+
2379+
> Note: Enabling symmetry may produce unintended partial charge densities because of reduced k-point weights and real-space symmetry operations. If the desired symmetry treatment is uncertain, set `symmetry = -1`. Use the same symmetry setting as in the SCF calculation.
23782380
- **Default**: none
23792381

23802382
### out_wfc_norm
23812383

23822384
- **Type**: String
23832385
- **Availability**: *[`basis_type`](#basis_type)==pw or ([`basis_type`](#basis_type)==lcao and [`calculation`](#calculation)==get_wf)*
2384-
- **Description**: Specifies the electronic states to calculate the real-space wave function modulus (norm, or known as the envelope function) with state index. The syntax and state selection rules are identical to out_pchg, but the output is the norm of the wave function. The outputs comprise multiple .cube files following the naming convention wfi[state]s[spin]k[kpoint].cube.
2386+
- **Description**: Selects electronic states for real-space wavefunction-modulus output using the selection syntax and complete-state normalization of `out_pchg`. For `nspin=1`, `s1` contains the wavefunction modulus. For `nspin=2`, `s1` and `s2` contain the spin-up and spin-down wavefunction moduli, respectively. For `nspin=4`, `s1` contains the total spinor modulus. Files are named `wfi[state]s[spin]k[kpoint].cube`.
23852387
- **Default**: none
23862388

23872389
### out_wfc_re_im
23882390

23892391
- **Type**: String
23902392
- **Availability**: *[`basis_type`](#basis_type)==pw or ([`basis_type`](#basis_type)==lcao and [`calculation`](#calculation)==get_wf)*
2391-
- **Description**: Specifies the electronic states to calculate the real and imaginary parts of the wave function with state index. The syntax and state selection rules are identical to out_pchg, but the output contains both the real and imaginary components of the wave function. The outputs comprise multiple .cube files following the naming convention wfi[state]s[spin]k[kpoint][re/im].cube.
2393+
- **Description**: Selects electronic states for real-space wavefunction real- and imaginary-part output using the selection syntax and complete-state normalization of `out_pchg`. For `nspin=1`, `s1` contains the wavefunction. For `nspin=2`, `s1` and `s2` contain the spin-up and spin-down wavefunctions, respectively. For `nspin=4`, `s1` and `s2` contain the upper and lower spinor components, respectively. Files are named `wfi[state]s[spin]k[kpoint][re/im].cube`.
23922394
- **Default**: none
23932395

23942396
### if_separate_k
23952397

23962398
- **Type**: Boolean
23972399
- **Availability**: *([`basis_type`](#basis_type)==pw and [`out_pchg`](#out_pchg)!=none) or ([`basis_type`](#basis_type)==lcao and [`calculation`](#calculation)==get_pchg and [`gamma_only`](#gamma_only)==0)*
2398-
- **Description**: Specifies whether to write the partial charge densities for all k-points to individual files or merge them. Warning: Enabling symmetry may produce unwanted results due to reduced k-point weights and symmetry operations in real space. Therefore when calculating partial charge densities, if you are not sure what you want exactly, it is strongly recommended to set symmetry = -1. It is noteworthy that your symmetry setting should remain the same as that in the SCF procedure.
2400+
- **Description**: Specifies whether to write partial charge densities for individual k-points or merge them.
23992401
- **Default**: false
24002402

24012403
### out_elf

‎docs/parameters.yaml‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3624,31 +3624,33 @@ parameters:
36243624
category: Output information
36253625
type: String
36263626
description: |
3627-
Specifies the electronic states to calculate the charge densities with state index for, using a space-separated string of 0s and 1s. Each digit in the string corresponds to a state, starting from the first state. A 1 indicates that the charge density should be calculated for that state, while a 0 means the state will be ignored. The parameter allows a compact and flexible notation (similar to ocp_set), for example the syntax 1 4*0 5*1 0 is used to denote the selection of states: 1 means calculate for the first state, 4*0 skips the next four states, 5*1 means calculate for the following five states, and the final 0 skips the next state. It's essential that the total count of states does not exceed the total number of states (nbands); otherwise, it results in an error, and the process exits. The input string must contain only numbers and the asterisk (*) for repetition, ensuring correct format and intention of state selection. The outputs comprise multiple .cube files following the naming convention pchgi[state]s[spin]k[kpoint].cube.
3627+
Selects electronic states for partial (band-decomposed) charge-density output using a space-separated string of `0`s and `1`s, where `1` selects a state and `0` skips it. Repetition follows the `ocp_set` syntax, for example `1 4*0 5*1 0`; the expanded list must not exceed `nbands`. Each output represents a complete one-particle state rather than its SCF occupation. The spin degeneracy is 2 for `nspin=1` and 1 for `nspin=2` or `nspin=4`. For `nspin=1`, `s1` contains the charge density. For `nspin=2`, `s1` and `s2` contain the spin-up and spin-down charge densities, respectively. For `nspin=4`, `s1`, `s2`, `s3`, and `s4` respectively contain $\rho_0$, $m_x$, $m_y$, and $m_z$. With `if_separate_k=true`, files are named `pchgi[state]s[component]k[kpoint].cube`; otherwise, the weighted k-point sum is named `pchgi[state]s[component].cube`.
3628+
3629+
[NOTE] Enabling symmetry may produce unintended partial charge densities because of reduced k-point weights and real-space symmetry operations. If the desired symmetry treatment is uncertain, set `symmetry = -1`. Use the same symmetry setting as in the SCF calculation.
36283630
default_value: none
36293631
unit: ""
36303632
availability: basis_type==pw or (basis_type==lcao and calculation==get_pchg)
36313633
- name: out_wfc_norm
36323634
category: Output information
36333635
type: String
36343636
description: |
3635-
Specifies the electronic states to calculate the real-space wave function modulus (norm, or known as the envelope function) with state index. The syntax and state selection rules are identical to out_pchg, but the output is the norm of the wave function. The outputs comprise multiple .cube files following the naming convention wfi[state]s[spin]k[kpoint].cube.
3637+
Selects electronic states for real-space wavefunction-modulus output using the selection syntax and complete-state normalization of `out_pchg`. For `nspin=1`, `s1` contains the wavefunction modulus. For `nspin=2`, `s1` and `s2` contain the spin-up and spin-down wavefunction moduli, respectively. For `nspin=4`, `s1` contains the total spinor modulus. Files are named `wfi[state]s[spin]k[kpoint].cube`.
36363638
default_value: none
36373639
unit: ""
36383640
availability: basis_type==pw or (basis_type==lcao and calculation==get_wf)
36393641
- name: out_wfc_re_im
36403642
category: Output information
36413643
type: String
36423644
description: |
3643-
Specifies the electronic states to calculate the real and imaginary parts of the wave function with state index. The syntax and state selection rules are identical to out_pchg, but the output contains both the real and imaginary components of the wave function. The outputs comprise multiple .cube files following the naming convention wfi[state]s[spin]k[kpoint][re/im].cube.
3645+
Selects electronic states for real-space wavefunction real- and imaginary-part output using the selection syntax and complete-state normalization of `out_pchg`. For `nspin=1`, `s1` contains the wavefunction. For `nspin=2`, `s1` and `s2` contain the spin-up and spin-down wavefunctions, respectively. For `nspin=4`, `s1` and `s2` contain the upper and lower spinor components, respectively. Files are named `wfi[state]s[spin]k[kpoint][re/im].cube`.
36443646
default_value: none
36453647
unit: ""
36463648
availability: basis_type==pw or (basis_type==lcao and calculation==get_wf)
36473649
- name: if_separate_k
36483650
category: Output information
36493651
type: Boolean
36503652
description: |
3651-
Specifies whether to write the partial charge densities for all k-points to individual files or merge them. Warning: Enabling symmetry may produce unwanted results due to reduced k-point weights and symmetry operations in real space. Therefore when calculating partial charge densities, if you are not sure what you want exactly, it is strongly recommended to set symmetry = -1. It is noteworthy that your symmetry setting should remain the same as that in the SCF procedure.
3653+
Specifies whether to write partial charge densities for individual k-points or merge them.
36523654
default_value: "false"
36533655
unit: ""
36543656
availability: "(basis_type==pw and out_pchg!=none) or (basis_type==lcao and calculation==get_pchg and gamma_only==0)"

‎source/source_base/parallel_grid.cpp‎

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
#include "parallel_grid.h"
2+
23
#include "source_base/global_function.h"
34
#include "source_base/global_variable.h"
45

56
#ifdef __MPI
67
#include "source_base/parallel_comm.h" // use POOL_WORLD
8+
79
#include <mpi.h>
810
#endif
911

@@ -167,6 +169,95 @@ void Parallel_Grid::z_distribution()
167169
return;
168170
}
169171

172+
void Parallel_Grid::reduce_across_pools(double* data) const
173+
{
174+
#ifdef __MPI
175+
if (GlobalV::KPAR <= 1)
176+
{
177+
return;
178+
}
179+
180+
assert(data != nullptr);
181+
if (KP_WORLD != MPI_COMM_NULL)
182+
{
183+
// Equal-sized pools give corresponding ranks identical z-slab layouts,
184+
// so their local buffers can be summed directly without redistribution.
185+
MPI_Allreduce(MPI_IN_PLACE, data, this->nrxx, MPI_DOUBLE, MPI_SUM, KP_WORLD);
186+
return;
187+
}
188+
189+
// Uneven pool sizes have no KP_WORLD and may assign different z-slabs to
190+
// corresponding ranks. Validate the local distribution before rebuilding
191+
// a common global layout for the cross-pool reduction.
192+
assert(!this->numz.empty());
193+
assert(GlobalV::MY_POOL >= 0 && GlobalV::MY_POOL < static_cast<int>(this->numz.size()));
194+
assert(GlobalV::RANK_IN_POOL >= 0 && GlobalV::RANK_IN_POOL < static_cast<int>(this->numz[GlobalV::MY_POOL].size()));
195+
assert(this->nczp == this->numz[GlobalV::MY_POOL][GlobalV::RANK_IN_POOL]);
196+
assert(this->nrxx == this->ncxy * this->nczp);
197+
198+
const int pool_size = this->nproc_in_pool[GlobalV::MY_POOL];
199+
std::vector<int> receive_counts(pool_size);
200+
std::vector<int> displacements(pool_size);
201+
for (int ip = 0; ip < pool_size; ++ip)
202+
{
203+
receive_counts[ip] = this->numz[GlobalV::MY_POOL][ip] * this->ncxy;
204+
displacements[ip] = this->startz[GlobalV::MY_POOL][ip] * this->ncxy;
205+
}
206+
207+
std::vector<double> local_data(this->nrxx);
208+
// The allgather below replicates one complete pool grid on every rank in
209+
// that pool. INT_BGROUP then sums all of those replicas, so divide each
210+
// local slab by the pool size to make each pool contribute exactly once.
211+
const double pool_normalization = 1.0 / static_cast<double>(pool_size);
212+
for (int ir = 0; ir < this->nrxx; ++ir)
213+
{
214+
local_data[ir] = data[ir] * pool_normalization;
215+
}
216+
217+
std::vector<double> pool_data(this->ncxyz);
218+
// Collect the rank-local [xy][local_z] slabs into rank-contiguous blocks.
219+
MPI_Allgatherv(local_data.data(),
220+
this->nrxx,
221+
MPI_DOUBLE,
222+
pool_data.data(),
223+
receive_counts.data(),
224+
displacements.data(),
225+
MPI_DOUBLE,
226+
POOL_WORLD);
227+
228+
std::vector<double> global_layout(this->ncxyz);
229+
// Convert the rank-contiguous allgather result to the canonical
230+
// [xy][global_z] order required for element-wise reduction across pools.
231+
for (int ip = 0; ip < pool_size; ++ip)
232+
{
233+
const int local_nz = this->numz[GlobalV::MY_POOL][ip];
234+
const int global_z_start = this->startz[GlobalV::MY_POOL][ip];
235+
const int gathered_start = global_z_start * this->ncxy;
236+
for (int ixy = 0; ixy < this->ncxy; ++ixy)
237+
{
238+
for (int iz = 0; iz < local_nz; ++iz)
239+
{
240+
global_layout[ixy * this->ncz + global_z_start + iz] = pool_data[gathered_start + ixy * local_nz + iz];
241+
}
242+
}
243+
}
244+
245+
MPI_Allreduce(MPI_IN_PLACE, global_layout.data(), this->ncxyz, MPI_DOUBLE, MPI_SUM, INT_BGROUP);
246+
247+
// Return only the z-slab owned by this rank under its pool's distribution.
248+
const int local_z_start = this->startz[GlobalV::MY_POOL][GlobalV::RANK_IN_POOL];
249+
for (int ixy = 0; ixy < this->ncxy; ++ixy)
250+
{
251+
for (int iz = 0; iz < this->nczp; ++iz)
252+
{
253+
data[ixy * this->nczp + iz] = global_layout[ixy * this->ncz + local_z_start + iz];
254+
}
255+
}
256+
#else
257+
(void)data;
258+
#endif
259+
}
260+
170261
#ifdef __MPI
171262
void Parallel_Grid::bcast(const double* const data_global, double* data_local, const int& rank, const bool is_sdft) const
172263
{

‎source/source_base/parallel_grid.h‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@ class Parallel_Grid
2121
const int &nczp, const int &nrxx, const int &nbz, const int &bz,
2222
const int nprocgroup);
2323

24+
/**
25+
* @brief Sum a distributed real-space grid across k-point pools.
26+
*
27+
* Uses a direct local-slab reduction for equal-sized pools. For uneven
28+
* pools, reconstructs a common global layout before the cross-pool sum.
29+
*
30+
* @param data Local real-space grid data ordered as [x][y][z].
31+
*/
32+
void reduce_across_pools(double* data) const;
33+
2434
#ifdef __MPI
2535
/// @brief Broadcast data from root to all processors. The index order is [x][y][z].
2636
void bcast(const double* const data_global, double* data_local, const int& rank, const bool is_sdft) const;

‎source/source_estate/module_charge/charge.cpp‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,6 @@ Charge::Charge()
4242
Charge::~Charge()
4343
{
4444
this->destroy();
45-
#ifdef __MPI
46-
delete[] rec;
47-
delete[] dis;
48-
#endif
4945
}
5046

5147
void Charge::set_rhopw(ModulePW::PW_Basis* rhopw_in)

‎source/source_estate/module_charge/charge.h‎

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,6 @@ class Charge
124124
void init_final_scf(); //LiuXh add 20180619
125125

126126
public:
127-
/**
128-
* @brief init some arrays for mpi_inter_pools, rho_mpi
129-
*/
130-
void init_chgmpi();
131-
132127
/**
133128
* @brief Sum rho at different pools (k-point parallelism).
134129
* Only used when GlobalV::KPAR > 1
@@ -169,12 +164,6 @@ class Charge
169164
bool allocate_rho;
170165

171166
bool allocate_rho_final_scf; // LiuXh add 20180606
172-
173-
#ifdef __MPI
174-
int *rec = nullptr; //The number of elements each process should receive into the receive buffer.
175-
int *dis = nullptr; //The displacement (relative to recvbuf) for each process in the receive buffer.
176-
#endif
177-
178167
};
179168

180169
#endif // charge

‎source/source_estate/module_charge/charge_init.cpp‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,9 +249,6 @@ void Charge::init_rho(const UnitCell& ucell,
249249
GlobalC::restart.info_load.load_charge_finish = true;
250250
}
251251

252-
#ifdef __MPI
253-
this->init_chgmpi();
254-
#endif
255252
if (PARAM.inp.init_chg == "wfc")
256253
{
257254
if (wfcpw == nullptr)

0 commit comments

Comments
 (0)