Skip to content

Commit 369ac5b

Browse files
author
abacus_fixer
committed
solve conflicts
2 parents 156e887 + 3b22343 commit 369ac5b

30 files changed

Lines changed: 2023 additions & 119 deletions

File tree

docs/advanced/elec_properties/hs_matrix.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,12 @@ The output of $H(R)$ and $S(R)$ matrices is controlled by [out_hsr](../input_fil
6565
| --- | --- |
6666
| `0` | Disabled |
6767
| `1` | Text CSR; an optional second value controls precision, for example `out_hsr 1 12` |
68-
| `2` | Reserved for future binary output; not implemented |
68+
| `2` | Native binary CSR using `.dat` files |
6969
| `3` | NPZ: `hrs1_nao.npz`, `hrs2_nao.npz` when needed, and `sr_nao.npz` |
7070

7171
The legacy keywords `out_mat_hs2 1 [precision]` and `out_hsr_npz 1` remain supported as aliases for text and NPZ output respectively. If `out_hsr` is present together with either legacy keyword, `out_hsr` takes precedence.
7272

73-
For a multi-k calculation, the files contain the individual real-space blocks stored for the Bravais lattice vectors $R$. For a gamma-only calculation, ABACUS stores the real-space contributions in a folded representation. Both text CSR and NPZ output write this internal representation directly: all stored $R$-space contributions are summed into a single block labelled `R = (0, 0, 0)`.
73+
For a multi-k calculation, the files contain the individual real-space blocks stored for the Bravais lattice vectors $R$. For a gamma-only calculation, ABACUS stores the real-space contributions in a folded representation. Text CSR, native binary, and NPZ output write this internal representation directly: all stored $R$-space contributions are summed into a single block labelled `R = (0, 0, 0)`.
7474

7575
The folded gamma-only output is sufficient to inspect the matrix used by the gamma-only real-space container, but it does not retain the original lattice-vector resolution and cannot be used to interpolate matrices at arbitrary k points. Terms that are added only while constructing $H(k)$, rather than stored in the internal $H(R)$ container, are not guaranteed to be present. Use [out_hsk](../input_files/input-main.md#out_hsk) when the final $H(\Gamma)$ and $S(\Gamma)$ matrices are required.
7676

@@ -89,6 +89,22 @@ In gamma-only mode, every generated file reports one Bravais lattice vector and
8989
# representation: gamma-only folded matrix; stored R-space contributions are summed into R = (0, 0, 0)
9090
```
9191

92+
### Native Binary CSR Format
93+
94+
Set `out_hsr 2` to write the same H(R) and S(R) matrix sets with a `.dat` suffix. For example, an `nspin = 2` calculation writes `hrs1_nao.dat`, `hrs2_nao.dat`, and `sr_nao.dat`. When `out_app_flag` is false, the one-based ionic step is included before `_nao`, for example `hrs1g1_nao.dat` and `srg1_nao.dat`.
95+
96+
Each ionic step is a complete record with no padding or self-describing header:
97+
98+
1. Native `int`: zero-based ionic step, matrix dimension, number of R blocks.
99+
2. For every R block in lexicographic `(Rx, Ry, Rz)` order, four native `int` values: `Rx`, `Ry`, `Rz`, and `nnz`.
100+
3. `nnz` matrix values in CSR order. Real matrices use one native `double`; complex matrices use consecutive real and imaginary `double` values.
101+
4. `nnz` native `int` column indices.
102+
5. `dimension + 1` native `long long` row pointers.
103+
104+
All R blocks stored by the internal HContainer are present, including blocks with zero nonzero values. The sparse threshold is `1e-10`, matching text CSR output. The format uses the host integer representation and byte order and therefore requires a compatible ABI. It does not contain unit-cell, spin, or matrix-label metadata; those are determined by the calculation input and filename.
105+
106+
When `out_app_flag` is true, the first ionic step truncates the shared file and later ionic steps append complete records. Otherwise every ionic step is written to its own file.
107+
92108
### NPZ Format
93109

94110
Set `out_hsr 3` to write `hrs1_nao.npz`, `hrs2_nao.npz` when a second spin channel is present, and `sr_nao.npz`. Matrix entry names include the atom-pair indices and the three components of $R$. Multi-k calculations retain the stored $R$ blocks, while gamma-only calculations contain only matrix entry names ending in `_0_0_0`.
@@ -125,7 +141,7 @@ The CSR format stores a sparse m × n matrix M in row form using three arrays (v
125141

126142
### Precision Control
127143

128-
Use `out_hsr 1 12` to output text CSR files with 12-digit precision (default is 8). Precision is ignored for NPZ output.
144+
Use `out_hsr 1 12` to output text CSR files with 12-digit precision (default is 8). Precision is ignored for native binary and NPZ output.
129145

130146
For calculations involving ionic movements, the output frequency of the matrix is controlled by [out_freq_ion](../input_files/input-main.md#out_freq_ion) and [out_app_flag](../input_files/input-main.md#out_app_flag).
131147

docs/advanced/input_files/input-main.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2037,11 +2037,13 @@
20372037
- **Description**: Output Hamiltonian and overlap matrices in real space, indexed by the Bravais lattice vector R, in the directory OUT.${suffix}. The first integer selects the format:
20382038
- 0: disabled;
20392039
- 1: text CSR output; the optional second integer controls precision and defaults to 8;
2040-
- 2: reserved for binary output, which is not implemented yet;
2040+
- 2: native binary CSR output using .dat files;
20412041
- 3: NPZ output using hrs1_nao.npz, hrs2_nao.npz when needed, and sr_nao.npz.
20422042

20432043
For multi-k calculations, the output contains the individual real-space blocks stored for the Bravais lattice vectors R. For gamma-only calculations, the internal real-space contributions are folded into a single R = (0, 0, 0) block. This folded result cannot recover the original R-resolved contributions or interpolate arbitrary k points. Terms added only while constructing H(k) are not guaranteed to be present.
20442044

2045+
For binary output, each file uses the same basename as text output with a .dat suffix. Every native record contains the zero-based ionic step, matrix dimension, and number of R blocks as ints. Each R block contains three int coordinates, an int nonzero count, native double values (real/imaginary double pairs for complex matrices), int column indices, and long long row pointers. Native integer representation and byte order are used. When out_app_flag is true, the first ionic step truncates the file and later steps append complete records.
2046+
20452047
> Note: In the 3.10-LTS version, the file names are data-HR-sparse_SPIN0.csr and data-SR-sparse_SPIN0.csr, etc.
20462048
- **Default**: 0 8
20472049
- **Unit**: Ry

docs/parameters.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3145,11 +3145,13 @@ parameters:
31453145
Output Hamiltonian and overlap matrices in real space, indexed by the Bravais lattice vector R, in the directory OUT.${suffix}. The first integer selects the format:
31463146
* 0: disabled;
31473147
* 1: text CSR output; the optional second integer controls precision and defaults to 8;
3148-
* 2: reserved for binary output, which is not implemented yet;
3148+
* 2: native binary CSR output using .dat files;
31493149
* 3: NPZ output using hrs1_nao.npz, hrs2_nao.npz when needed, and sr_nao.npz.
31503150
31513151
For multi-k calculations, the output contains the individual real-space blocks stored for the Bravais lattice vectors R. For gamma-only calculations, the internal real-space contributions are folded into a single R = (0, 0, 0) block. This folded result cannot recover the original R-resolved contributions or interpolate arbitrary k points. Terms added only while constructing H(k) are not guaranteed to be present.
31523152
3153+
For binary output, each file uses the same basename as text output with a .dat suffix. Every native record contains the zero-based ionic step, matrix dimension, and number of R blocks as ints. Each R block contains three int coordinates, an int nonzero count, native double values (real/imaginary double pairs for complex matrices), int column indices, and long long row pointers. Native integer representation and byte order are used. When out_app_flag is true, the first ionic step truncates the file and later steps append complete records.
3154+
31533155
[NOTE] In the 3.10-LTS version, the file names are data-HR-sparse_SPIN0.csr and data-SR-sparse_SPIN0.csr, etc.
31543156
default_value: 0 8
31553157
unit: Ry

source/source_cell/module_neighlist/bin_manager.cpp

Lines changed: 112 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@
55
#include <stdexcept>
66
#include "bin_manager.h"
77

8+
#ifdef _OPENMP
9+
#include <omp.h>
10+
#endif
11+
12+
namespace
13+
{
14+
constexpr int neighbor_build_openmp_threshold = 256;
15+
}
16+
817
// ========== Bin class implementation ==========
918

1019
const std::vector<ModuleNeighList::LocalAtomIndex>& Bin::get_atom_indices() const {
@@ -176,6 +185,63 @@ int BinManager::bin_index(int ix, int iy, int iz) const {
176185
return ix * nbiny_ * nbinz_ + iy * nbinz_ + iz;
177186
}
178187

188+
template <typename Emit>
189+
void BinManager::visit_neighbors(const NeighborAtom& atom,
190+
const std::vector<NeighborAtom>& binned_atoms,
191+
double sradius2,
192+
const Emit& emit) const
193+
{
194+
const int ix = std::min(
195+
std::max(int((atom.position_x - x_min_) / bin_sizex_), 0),
196+
nbinx_ - 1
197+
);
198+
199+
const int iy = std::min(
200+
std::max(int((atom.position_y - y_min_) / bin_sizey_), 0),
201+
nbiny_ - 1
202+
);
203+
204+
const int iz = std::min(
205+
std::max(int((atom.position_z - z_min_) / bin_sizez_), 0),
206+
nbinz_ - 1
207+
);
208+
209+
for (int dx = -1; dx <= 1; dx++)
210+
{
211+
for (int dy = -1; dy <= 1; dy++)
212+
{
213+
for (int dz = -1; dz <= 1; dz++)
214+
{
215+
const int jx = ix + dx;
216+
const int jy = iy + dy;
217+
const int jz = iz + dz;
218+
219+
if (jx < 0 || jx >= nbinx_ ||
220+
jy < 0 || jy >= nbiny_ ||
221+
jz < 0 || jz >= nbinz_)
222+
{
223+
continue;
224+
}
225+
226+
const int nidx = bin_index(jx, jy, jz);
227+
for (const ModuleNeighList::LocalAtomIndex binned_atom_index : bins_[nidx].get_atom_indices())
228+
{
229+
const NeighborAtom& natom = binned_atoms[static_cast<std::size_t>(binned_atom_index)];
230+
const double delta_x = atom.position_x - natom.position_x;
231+
const double delta_y = atom.position_y - natom.position_y;
232+
const double delta_z = atom.position_z - natom.position_z;
233+
const double dist2 = delta_x * delta_x + delta_y * delta_y + delta_z * delta_z;
234+
235+
if (natom.atom_id != atom.atom_id && dist2 <= sradius2)
236+
{
237+
emit(natom.atom_id);
238+
}
239+
}
240+
}
241+
}
242+
}
243+
}
244+
179245
void BinManager::build_atom_neighbors(
180246
NeighborList& neighbor_list,
181247
const std::vector<NeighborAtom>& atoms,
@@ -184,71 +250,63 @@ void BinManager::build_atom_neighbors(
184250
{
185251
assert(atoms.size() == static_cast<size_t>(neighbor_list.get_nlocal()));
186252

187-
double sradius2 = sradius_ * sradius_;
253+
const double sradius2 = sradius_ * sradius_;
188254

189255
neighbor_list.reset();
190256

191-
std::vector<int> neigh_tmp;
192-
193257
const int nlocal = neighbor_list.get_nlocal();
194-
for (int i = 0; i < nlocal; i++)
195-
{
196-
neigh_tmp.clear();
197-
const NeighborAtom& atom = atoms[i];
198-
199-
int ix = std::min(
200-
std::max(int((atom.position_x - x_min_) / bin_sizex_), 0),
201-
nbinx_ - 1
202-
);
203258

204-
int iy = std::min(
205-
std::max(int((atom.position_y - y_min_) / bin_sizey_), 0),
206-
nbiny_ - 1
207-
);
208-
209-
int iz = std::min(
210-
std::max(int((atom.position_z - z_min_) / bin_sizez_), 0),
211-
nbinz_ - 1
212-
);
259+
#ifdef _OPENMP
260+
const bool use_parallel = nlocal >= neighbor_build_openmp_threshold && omp_get_max_threads() > 1;
261+
if (use_parallel)
262+
{
263+
std::vector<std::size_t> neighbor_counts(static_cast<std::size_t>(nlocal), 0);
213264

214-
for (int dx = -1; dx <= 1; dx++)
265+
#pragma omp parallel for schedule(static)
266+
for (int i = 0; i < nlocal; i++)
215267
{
216-
for (int dy = -1; dy <= 1; dy++)
217-
{
218-
for (int dz = -1; dz <= 1; dz++)
219-
{
220-
int jx = ix + dx;
221-
int jy = iy + dy;
222-
int jz = iz + dz;
223-
224-
if (jx < 0 || jx >= nbinx_ ||
225-
jy < 0 || jy >= nbiny_ ||
226-
jz < 0 || jz >= nbinz_)
227-
continue;
228-
229-
int nidx = bin_index(jx, jy, jz);
268+
std::size_t count = 0;
269+
visit_neighbors(atoms[i], binned_atoms, sradius2,
270+
[&count](ModuleNeighList::LocalAtomIndex) { ++count; });
271+
neighbor_counts[static_cast<std::size_t>(i)] = count;
272+
}
230273

231-
for (const ModuleNeighList::LocalAtomIndex binned_atom_index : bins_[nidx].get_atom_indices())
232-
{
233-
const NeighborAtom& natom = binned_atoms[static_cast<std::size_t>(binned_atom_index)];
234-
double dx = atom.position_x - natom.position_x;
235-
double dy = atom.position_y - natom.position_y;
236-
double dz = atom.position_z - natom.position_z;
274+
for (int i = 0; i < nlocal; i++)
275+
{
276+
const int n = ModuleNeighList::checked_int_size(
277+
neighbor_counts[static_cast<std::size_t>(i)],
278+
"BinManager neighbor count"
279+
);
280+
neighbor_list.firstneigh_[i] = neighbor_list.allocator_.allocate(n);
281+
neighbor_list.numneigh_[i] = n;
282+
}
237283

238-
double dist2 = dx * dx + dy * dy + dz * dz;
284+
#pragma omp parallel for schedule(static)
285+
for (int i = 0; i < nlocal; i++)
286+
{
287+
int* ptr = neighbor_list.firstneigh_[i];
288+
int k = 0;
289+
visit_neighbors(atoms[i], binned_atoms, sradius2,
290+
[&](ModuleNeighList::LocalAtomIndex atom_id)
291+
{
292+
assert(ptr != nullptr);
293+
ptr[k++] = atom_id;
294+
});
295+
assert(k == neighbor_list.numneigh_[i]);
296+
}
297+
return;
298+
}
299+
#endif
239300

240-
if (natom.atom_id == atom.atom_id)
241-
{
242-
continue;
243-
}
244-
if (dist2 <= sradius2)
301+
std::vector<int> neigh_tmp;
302+
for (int i = 0; i < nlocal; i++)
303+
{
304+
neigh_tmp.clear();
305+
visit_neighbors(atoms[i], binned_atoms, sradius2,
306+
[&neigh_tmp](ModuleNeighList::LocalAtomIndex atom_id)
245307
{
246-
neigh_tmp.push_back(natom.atom_id);
247-
}
248-
}
249-
}
250-
}
251-
}
308+
neigh_tmp.push_back(atom_id);
309+
});
252310

253311
const int n = ModuleNeighList::checked_int_size(neigh_tmp.size(), "BinManager neighbor count");
254312

source/source_cell/module_neighlist/bin_manager.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,21 @@ class BinManager
198198
* @return Flat index in the bins_ array.
199199
*/
200200
int bin_index(int ix, int iy, int iz) const;
201+
202+
/**
203+
* @brief Visit neighbors of one atom in the existing deterministic bin order.
204+
*
205+
* @tparam Emit Callable accepting a rank-local neighbor atom ID.
206+
* @param atom Atom used as the neighbor-list center.
207+
* @param binned_atoms All atoms assigned to bins by do_binning().
208+
* @param sradius2 Squared search radius.
209+
* @param emit Callback invoked once for every accepted neighbor.
210+
*/
211+
template <typename Emit>
212+
void visit_neighbors(const NeighborAtom& atom,
213+
const std::vector<NeighborAtom>& binned_atoms,
214+
double sradius2,
215+
const Emit& emit) const;
201216
};
202217

203218
#endif // BIN_MANAGER_H

0 commit comments

Comments
 (0)