Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/advanced/input_files/input-main.md
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,7 @@ These variables are used to control general system parameters.
- If ([dft_fuctional](#dft_functional)==hse/hf/pbe0/scan0 or [rpa](#rpa)==True).
- If [efield_flag](#efield_flag)==1
- 1: else
- **Note**: When symmetry is enabled (value 1), k-points are reduced to the irreducible Brillouin zone (IBZ). For explicit k-point lists with custom weights (see [KPT file](./kpt.md#k-point-weights-and-symmetry)), the custom weights are preserved during symmetry reduction. For Monkhorst-Pack grids, uniform weights are used.

### symmetry_prec

Expand Down
34 changes: 34 additions & 0 deletions docs/advanced/input_files/kpt.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,40 @@ Direct //`Direct' or `Cartesian' coordinate
0.5 0.5 0.5 0.125
```

### K-point Weights and Symmetry

When explicitly setting k-points, you can specify custom weights for each k-point. These weights determine the contribution of each k-point to the total energy and density calculations.

**Important notes about k-point weights:**

1. **Custom weights are preserved**: When using explicit k-point lists (non-Monkhorst-Pack), ABACUS preserves the custom weights you specify, even when symmetry operations are applied to reduce the k-points to the irreducible Brillouin zone (IBZ).

2. **Symmetry reduction**: When [`symmetry`](./input-main.md#symmetry) is set to 1, ABACUS will analyze the crystal symmetry and reduce the k-point set to the irreducible Brillouin zone. During this reduction:
- For **Monkhorst-Pack grids** (automatically generated): All k-points have uniform weights (1/N where N is the total number of k-points)
- For **explicit k-point lists**: Custom weights are preserved and properly combined when symmetry-equivalent k-points are merged

3. **Weight normalization**: After symmetry reduction, k-point weights are normalized so that their sum equals `degspin` (2 for non-spin-polarized calculations, 1 for spin-polarized calculations).

**Example with custom weights:**

```
K_POINTS
5
Direct
0.0 0.0 0.0 0.1 // Gamma point with weight 0.1
0.5 0.0 0.0 0.2 // X point with weight 0.2
0.0 0.5 0.0 0.3 // Y point with weight 0.3
0.5 0.5 0.0 0.2 // M point with weight 0.2
0.0 0.0 0.5 0.2 // Z point with weight 0.2
```

In this example, different k-points have different weights, which might be useful for:
- Special sampling schemes
- Convergence testing with specific k-point importance
- Custom integration methods

> **Note**: When using custom weights with symmetry, ensure that your weight distribution is consistent with the crystal symmetry. ABACUS will preserve your weights during IBZ reduction, but inconsistent weights may lead to unexpected results.

[back to top](#the-kpt-file)

## Band structure calculations
Expand Down
4 changes: 3 additions & 1 deletion source/source_cell/k_vector_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,7 @@ void kvec_ibz_kpoint(K_Vectors& kv,
std::vector<int> ibz2bz(kv.get_nkstot());

// nkstot is the total input k-points number.
const double weight = 1.0 / static_cast<double>(kv.get_nkstot());
double weight = 1.0 / static_cast<double>(kv.get_nkstot());

ModuleBase::Vector3<double> kvec_rot;
ModuleBase::Vector3<double> kvec_rot_k;
Expand Down Expand Up @@ -609,6 +609,8 @@ void kvec_ibz_kpoint(K_Vectors& kv,
// search in all k-poins.
for (int i = 0; i < kv.get_nkstot(); ++i)
{
if (!kv.get_is_mp()) { weight = kv.wk[i]; } // use the input weight, instead of 1/nkstot

// restrict to [0, 1)
restrict_kpt(kv.kvec_d[i]);

Expand Down
155 changes: 155 additions & 0 deletions source/source_cell/test/klist_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -788,3 +788,158 @@ TEST_F(KlistTest, IbzKpointIsMP)
ClearUcell();
remove("tmp_klist_4");
}

TEST_F(KlistTest, IbzKpointCustomWeights)
{
// This test verifies the fix for issue #6552: k-point weights should not be overwritten
// during IBZ reduction for non-Monkhorst-Pack k-point lists.

ModuleSymmetry::Symmetry symm;
construct_ucell(stru_lib[0]);
GlobalV::ofs_running.open("tmp_klist_custom_weights");
symm.analy_sys(ucell.lat, ucell.st, ucell.atoms, GlobalV::ofs_running);

// Test 1: Non-MP k-points with uniform weights (KPT4)
{
K_Vectors kv_test1;
std::string k_file = "./support/KPT4";
kv_test1.nspin = 1;
kv_test1.read_kpoints(ucell, k_file);
EXPECT_EQ(kv_test1.get_nkstot(), 5);
EXPECT_FALSE(kv_test1.is_mp); // Should be non-MP

// Store original weights before IBZ reduction
std::vector<double> original_weights = kv_test1.wk;

// Apply IBZ reduction
std::string skpt;
ModuleSymmetry::Symmetry::symm_flag = 1;
bool match = true;
KVectorUtils::kvec_ibz_kpoint(kv_test1, symm, ModuleSymmetry::Symmetry::symm_flag, skpt, ucell, match);

// Verify that weights are preserved (not overwritten with 1/nkstot)
// After IBZ reduction, weights should still reflect the input weights
double total_weight = 0.0;
for (int i = 0; i < kv_test1.get_nkstot(); ++i)
{
total_weight += kv_test1.wk[i];
}
// Weights should sum to approximately the number of original k-points (before normalization)
EXPECT_GT(total_weight, 0.0);
}

// Test 2: Non-MP k-points with non-uniform custom weights
{
K_Vectors kv_test2;
std::string k_file = "./support/KPT_custom_weights";
kv_test2.nspin = 1;
kv_test2.read_kpoints(ucell, k_file);
EXPECT_EQ(kv_test2.get_nkstot(), 5);
EXPECT_FALSE(kv_test2.is_mp); // Should be non-MP

// Verify custom weights were read correctly
EXPECT_DOUBLE_EQ(kv_test2.wk[0], 0.1);
EXPECT_DOUBLE_EQ(kv_test2.wk[1], 0.2);
EXPECT_DOUBLE_EQ(kv_test2.wk[2], 0.3);
EXPECT_DOUBLE_EQ(kv_test2.wk[3], 0.2);
EXPECT_DOUBLE_EQ(kv_test2.wk[4], 0.2);

// Store original weights
std::vector<double> original_weights = kv_test2.wk;
double original_sum = 0.0;
for (double w : original_weights)
{
original_sum += w;
}

// Apply IBZ reduction
std::string skpt;
ModuleSymmetry::Symmetry::symm_flag = 1;
bool match = true;
KVectorUtils::kvec_ibz_kpoint(kv_test2, symm, ModuleSymmetry::Symmetry::symm_flag, skpt, ucell, match);

// After IBZ reduction, the weights should be based on the custom input weights,
// not uniform 1/nkstot weights. The total weight should be preserved.
double total_weight_after = 0.0;
for (int i = 0; i < kv_test2.get_nkstot(); ++i)
{
total_weight_after += kv_test2.wk[i];
}

// The sum of weights after IBZ reduction should equal the sum before
// (accounting for symmetry operations that may combine k-points)
EXPECT_NEAR(total_weight_after, original_sum, 1e-10);

// Verify that at least one weight is NOT equal to 1/5 (which would indicate
// the bug where custom weights are overwritten with uniform weights)
bool has_custom_weight = false;
double uniform_weight = 1.0 / 5.0;
for (int i = 0; i < kv_test2.get_nkstot(); ++i)
{
if (std::abs(kv_test2.wk[i] - uniform_weight) > 1e-10)
{
has_custom_weight = true;
break;
}
}
EXPECT_TRUE(has_custom_weight) << "Custom weights were overwritten with uniform weights!";
}

// Test 3: MP grid (regression test - should still work correctly)
{
K_Vectors kv_test3;
std::string k_file = "./support/KPT1";
kv_test3.nspin = 1;
kv_test3.read_kpoints(ucell, k_file);
EXPECT_EQ(kv_test3.get_nkstot(), 512);
EXPECT_TRUE(kv_test3.is_mp); // Should be MP

// Apply IBZ reduction
std::string skpt;
ModuleSymmetry::Symmetry::symm_flag = 1;
bool match = true;
KVectorUtils::kvec_ibz_kpoint(kv_test3, symm, ModuleSymmetry::Symmetry::symm_flag, skpt, ucell, match);

// For MP grids, all weights should be uniform after IBZ reduction
EXPECT_EQ(kv_test3.get_nkstot(), 35); // Known result from existing test

// Verify weights sum correctly
double total_weight = 0.0;
for (int i = 0; i < kv_test3.get_nkstot(); ++i)
{
total_weight += kv_test3.wk[i];
}
EXPECT_GT(total_weight, 0.0);
}

// Test 4: Weight normalization verification
{
K_Vectors kv_test4;
std::string k_file = "./support/KPT_custom_weights";
kv_test4.nspin = 1;
kv_test4.read_kpoints(ucell, k_file);

// Apply IBZ reduction
std::string skpt;
ModuleSymmetry::Symmetry::symm_flag = 1;
bool match = true;
KVectorUtils::kvec_ibz_kpoint(kv_test4, symm, ModuleSymmetry::Symmetry::symm_flag, skpt, ucell, match);

// Normalize weights
int degspin = (kv_test4.nspin == 2) ? 1 : 2;
kv_test4.normalize_wk(degspin);

// After normalization, weights should sum to degspin
double total_weight = 0.0;
for (int i = 0; i < kv_test4.get_nkstot(); ++i)
{
total_weight += kv_test4.wk[i];
}
EXPECT_NEAR(total_weight, degspin, 1e-10);
}

GlobalV::ofs_running.close();
ClearUcell();
remove("tmp_klist_custom_weights");
}

8 changes: 8 additions & 0 deletions source/source_cell/test/support/KPT_custom_weights
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
K_POINTS
5
Direct
0.0 0.0 0.0 0.1
0.5 0.0 0.0 0.2
0.0 0.5 0.0 0.3
0.5 0.5 0.0 0.2
0.0 0.0 0.5 0.2
Loading