diff --git a/docs/advanced/elec_properties/wfc.md b/docs/advanced/elec_properties/wfc.md
index dc96eb88844..ef43e834c7a 100644
--- a/docs/advanced/elec_properties/wfc.md
+++ b/docs/advanced/elec_properties/wfc.md
@@ -7,12 +7,14 @@ ABACUS is able to output electron wave functions in both PW and LCAO basis calcu
To output wave functions in G-space, add one of the following keywords to the `INPUT` file while performing SCF calculation:
- **PW basis**: Set [`out_wfc_pw`](https://abacus-rtd.readthedocs.io/en/latest/advanced/input_files/input-main.html#out-wfc-pw) to `1`. Output file format: `wfs[spin]k[kpoint]_pw.txt`, where `[spin]` is the spin channel index, and `[kpoint]` the k-point index.
-- **LCAO basis**: Set [`out_wfc_lcao`](https://abacus-rtd.readthedocs.io/en/latest/advanced/input_files/input-main.html#out-wfc-lcao) to `1`.
- - **Multi-k calculations**: Generates multiple files `wfs[spin]k[kpoint]_nao.txt`.
- - **Gamma-only calculations**: `wfs[spin]_nao.txt` instead.
+- **LCAO basis**: Set [`out_wfc_lcao`](https://abacus-rtd.readthedocs.io/en/latest/advanced/input_files/input-main.html#out-wfc-lcao) to `1` for text or `2` for binary output.
+ - **Multi-k calculations**: Generates multiple files `wfs[spin]k[kpoint]_nao.txt` or `.dat`.
+ - **Gamma-only calculations**: Generates `wfs[spin]_nao.txt` or `.dat` instead.
+
+To reuse LCAO coefficients, set `init_wfc file`, point `read_file_dir` to the coefficient files, and set `read_wfc_lcao` to `1` for text or `2` for binary input. The selected extension is required; there is no automatic format fallback.
## Wave Function in Real Space
One can also choose to output real-space wave functions with the keyword [`out_wfc_norm`](https://abacus-rtd.readthedocs.io/en/latest/advanced/input_files/input-main.html#out-wfc-norm) or [`out_wfc_re_im`](https://abacus-rtd.readthedocs.io/en/latest/advanced/input_files/input-main.html#out-wfc-re-im).
-Notice: When the [`basis_type`](https://abacus-rtd.readthedocs.io/en/latest/advanced/input_files/input-main.html#basis-type) is `lcao`, only `get_wf` [`calculation`](https://abacus-rtd.readthedocs.io/en/latest/advanced/input_files/input-main.html#calculation) is effective. An example is [examples/11_wfc/lcao_ienvelope_Si2](https://github.com/deepmodeling/abacus-develop/tree/develop/examples/11_wfc/lcao_ienvelope_Si2).
\ No newline at end of file
+Notice: When the [`basis_type`](https://abacus-rtd.readthedocs.io/en/latest/advanced/input_files/input-main.html#basis-type) is `lcao`, only `get_wf` [`calculation`](https://abacus-rtd.readthedocs.io/en/latest/advanced/input_files/input-main.html#calculation) is effective. An example is [examples/11_wfc/lcao_ienvelope_Si2](https://github.com/deepmodeling/abacus-develop/tree/develop/examples/11_wfc/lcao_ienvelope_Si2).
diff --git a/docs/advanced/input_files/input-main.md b/docs/advanced/input_files/input-main.md
index e4b44876ca4..9cd943b7cff 100644
--- a/docs/advanced/input_files/input-main.md
+++ b/docs/advanced/input_files/input-main.md
@@ -19,6 +19,7 @@
- [latname](#latname)
- [assume\_isolated](#assume_isolated)
- [init\_wfc](#init_wfc)
+ - [read\_wfc\_lcao](#read_wfc_lcao)
- [init\_chg](#init_chg)
- [init\_vel](#init_vel)
- [mem\_saver](#mem_saver)
@@ -737,7 +738,7 @@
- atomic: from atomic pseudo wave functions. If they are not enough, other wave functions are initialized with random numbers.
- atomic+random: add small random numbers on atomic pseudo-wavefunctions
- - file: from binary files wf*.dat, which are output by setting out_wfc_pw to 2.
+ - file: from wave function coefficient files. For PW calculations, binary `wf*.dat` files are generated by setting `out_wfc_pw` to 2. For LCAO calculations, the text or binary format is selected by `read_wfc_lcao` and generated by setting `out_wfc_lcao` to the corresponding value.
- random: random numbers
- nao: from numerical atomic orbitals. If they are not enough, other wave functions are initialized with random numbers.
- nao+random: add small random numbers on numerical atomic orbitals
@@ -745,6 +746,20 @@
> Note: Only the file option is useful for the lcao basis set, which is mostly used when calculation is set to get_wf and get_pchg.
- **Default**: atomic
+### read_wfc_lcao
+
+- **Type**: Integer
+- **Availability**: *[`basis_type`](#basis_type)==lcao*
+- **Description**: The file format used when reading LCAO wave function coefficients.
+
+ Available options are:
+
+ - 1: text files (`.txt`) generated by setting `out_wfc_lcao` to 1.
+ - 2: binary files (`.dat`) generated by setting `out_wfc_lcao` to 2.
+
+ The selected format is used directly; ABACUS does not automatically detect or fall back to the other format. Only independent wave function files are supported, not files accumulated with `out_app_flag`.
+- **Default**: 1
+
### init_chg
- **Type**: String
diff --git a/docs/advanced/scf/initialization.md b/docs/advanced/scf/initialization.md
index c01d1f2bb8a..bead5975127 100644
--- a/docs/advanced/scf/initialization.md
+++ b/docs/advanced/scf/initialization.md
@@ -21,4 +21,4 @@ Atomic wave function is read from pseudopotential file under keyword `PP_PSWFC`,
When `basis_type=lcao`, we further support reading of initial wavefunction by setting `init_wfc` to `file`.
In LCAO code, wave function is used to initialize density matrix and real-space charge density.
-For such purpose, a file containing wavefunction must be prepared. Such files can be generated from previous calculations with [`out_wfc_lcao 1`](../elec_properties/wfc.md).
+For such purpose, files containing wavefunction coefficients must be prepared. They can be generated by a previous calculation with [`out_wfc_lcao 1`](../elec_properties/wfc.md) for text files or `out_wfc_lcao 2` for binary files. Set `read_wfc_lcao` to the same value when reading them; ABACUS does not automatically switch between formats.
diff --git a/docs/parameters.yaml b/docs/parameters.yaml
index 2df3f8fc18d..b792e87458c 100644
--- a/docs/parameters.yaml
+++ b/docs/parameters.yaml
@@ -168,7 +168,7 @@ parameters:
Available options are:
* atomic: from atomic pseudo wave functions. If they are not enough, other wave functions are initialized with random numbers.
* atomic+random: add small random numbers on atomic pseudo-wavefunctions
- * file: from binary files wf*.dat, which are output by setting out_wfc_pw to 2.
+ * file: from wave function coefficient files. For PW calculations, binary `wf*.dat` files are generated by setting `out_wfc_pw` to 2. For LCAO calculations, the text or binary format is selected by `read_wfc_lcao` and generated by setting `out_wfc_lcao` to the corresponding value.
* random: random numbers
* nao: from numerical atomic orbitals. If they are not enough, other wave functions are initialized with random numbers.
* nao+random: add small random numbers on numerical atomic orbitals
@@ -177,6 +177,20 @@ parameters:
default_value: atomic
unit: ""
availability: ""
+ - name: read_wfc_lcao
+ category: System variables
+ type: Integer
+ description: |
+ The file format used when reading LCAO wave function coefficients.
+
+ Available options are:
+ * 1: text files (`.txt`) generated by setting `out_wfc_lcao` to 1.
+ * 2: binary files (`.dat`) generated by setting `out_wfc_lcao` to 2.
+
+ The selected format is used directly; ABACUS does not automatically detect or fall back to the other format. Only independent wave function files are supported, not files accumulated with `out_app_flag`.
+ default_value: "1"
+ unit: ""
+ availability: basis_type==lcao
- name: init_chg
category: System variables
type: String
diff --git a/source/source_esolver/esolver_ks_lcao_tddft.cpp b/source/source_esolver/esolver_ks_lcao_tddft.cpp
index f767c4b2107..f7f9ca0f560 100644
--- a/source/source_esolver/esolver_ks_lcao_tddft.cpp
+++ b/source/source_esolver/esolver_ks_lcao_tddft.cpp
@@ -114,6 +114,7 @@ void ESolver_KS_LCAO_TDDFT
::before_all_runners(BaseCell& basecell, c
this->kv.ik2iktot,
this->kv.get_nkstot(),
this->inp_->nspin,
+ this->inp_->read_wfc_lcao,
0,
TD_info::estep_shift))
{
diff --git a/source/source_esolver/esolver_lr_lcao_tddft.cpp b/source/source_esolver/esolver_lr_lcao_tddft.cpp
index 52bd6ad0e89..fbfd735ace3 100644
--- a/source/source_esolver/esolver_lr_lcao_tddft.cpp
+++ b/source/source_esolver/esolver_lr_lcao_tddft.cpp
@@ -805,6 +805,7 @@ void ModuleESolver::ESolver_LR::read_ks_wfc()
this->kv.ik2iktot,
this->kv.get_nkstot(),
this->inp_->nspin,
+ this->inp_->read_wfc_lcao,
/*skip_bands=*/this->nocc_max - this->nocc_in)) {
ModuleBase::WARNING_QUIT("ESolver_LR", "read ground-state wavefunction failed.");
}
diff --git a/source/source_io/module_parameter/input_parameter.h b/source/source_io/module_parameter/input_parameter.h
index 196b11fad9f..7b0ed8cf0e2 100644
--- a/source/source_io/module_parameter/input_parameter.h
+++ b/source/source_io/module_parameter/input_parameter.h
@@ -46,6 +46,7 @@ struct Input_para
double erf_sigma = 0.1; ///< the width of the energy step for reciprocal vectors
int fft_mode = 0; ///< fftw mode 0: estimate, 1: measure, 2: patient, 3: exhaustive
std::string init_wfc = "atomic"; ///< "file","atomic","random"
+ int read_wfc_lcao = 1; ///< LCAO wavefunction input format: 1 text, 2 binary
int pw_seed = 0; ///< random seed for initializing wave functions
std::string init_chg = "atomic"; ///< "file","atomic"
bool dm_to_rho = false; ///< read density matrix from npz format and calculate charge density
diff --git a/source/source_io/module_parameter/read_inp_sys.cpp b/source/source_io/module_parameter/read_inp_sys.cpp
index 3c9bff3935a..03037d0fb12 100644
--- a/source/source_io/module_parameter/read_inp_sys.cpp
+++ b/source/source_io/module_parameter/read_inp_sys.cpp
@@ -448,7 +448,7 @@ Theory: G. Makov and M. C. Payne, Phys. Rev. B 51, 4014 (1995).)";
Available options are:
* atomic: from atomic pseudo wave functions. If they are not enough, other wave functions are initialized with random numbers.
* atomic+random: add small random numbers on atomic pseudo-wavefunctions
-* file: from binary files wf*.dat, which are output by setting out_wfc_pw to 2.
+* file: from wave function coefficient files. For PW calculations, binary `wf*.dat` files are generated by setting `out_wfc_pw` to 2. For LCAO calculations, the text or binary format is selected by `read_wfc_lcao` and generated by setting `out_wfc_lcao` to the corresponding value.
* random: random numbers
* nao: from numerical atomic orbitals. If they are not enough, other wave functions are initialized with random numbers.
* nao+random: add small random numbers on numerical atomic orbitals
@@ -474,6 +474,30 @@ Available options are:
read_sync_string(input.init_wfc);
this->add_item(item);
}
+ {
+ Input_Item item("read_wfc_lcao");
+ item.annotation = "LCAO wave function input format: 1 text, 2 binary";
+ item.category = "System variables";
+ item.type = "Integer";
+ item.description = R"(The file format used when reading LCAO wave function coefficients.
+
+Available options are:
+* 1: text files (`.txt`) generated by setting `out_wfc_lcao` to 1.
+* 2: binary files (`.dat`) generated by setting `out_wfc_lcao` to 2.
+
+The selected format is used directly; ABACUS does not automatically detect or fall back to the other format. Only independent wave function files are supported, not files accumulated with `out_app_flag`.)";
+ item.default_value = "1";
+ item.unit = "";
+ item.set_availability("basis_type==lcao");
+ read_sync_int(input.read_wfc_lcao);
+ item.check_value = [](const Input_Item& item, const Parameter& para) {
+ if (para.input.read_wfc_lcao != 1 && para.input.read_wfc_lcao != 2)
+ {
+ ModuleBase::WARNING_QUIT("ReadInput", "read_wfc_lcao should be 1 or 2");
+ }
+ };
+ this->add_item(item);
+ }
{
Input_Item item("init_chg");
item.annotation = "start charge is from 'atomic' or file";
diff --git a/source/source_io/module_wf/read_wfc_nao.cpp b/source/source_io/module_wf/read_wfc_nao.cpp
index 662b39778d2..1e318bb2922 100644
--- a/source/source_io/module_wf/read_wfc_nao.cpp
+++ b/source/source_io/module_wf/read_wfc_nao.cpp
@@ -2,14 +2,76 @@
#include "source_base/parallel_common.h"
#include "source_base/timer.h"
-#include "source_io/module_wf/write_wfc_nao.h"
-
-#include "source_io/module_wf/write_wfc_nao.h"
#include "source_base/module_external/scalapack_connector.h"
#include "source_base/module_out/filename.h"
#include "source_base/tool_title.h" // use title
#include "source_base/global_function.h" // use READ_VALUE
+#include
+
+namespace
+{
+
+template
+bool read_binary_value(std::ifstream& ifs, T& value)
+{
+ ifs.read(reinterpret_cast(&value), sizeof(T));
+ return static_cast(ifs);
+}
+
+template
+bool read_record_value(std::ifstream& ifs, T& value, const bool binary)
+{
+ if (binary)
+ {
+ return read_binary_value(ifs, value);
+ }
+ ModuleBase::GlobalFunc::READ_VALUE(ifs, value);
+ return static_cast(ifs);
+}
+
+bool read_binary_wfc_data(std::ifstream& ifs, double& data)
+{
+ return read_binary_value(ifs, data);
+}
+
+bool read_binary_wfc_data(std::ifstream& ifs, float& data)
+{
+ double value = 0.0;
+ if (!read_binary_value(ifs, value))
+ {
+ return false;
+ }
+ data = static_cast(value);
+ return true;
+}
+
+bool read_binary_wfc_data(std::ifstream& ifs, std::complex& data)
+{
+ double real = 0.0;
+ double imag = 0.0;
+ if (!read_binary_value(ifs, real) || !read_binary_value(ifs, imag))
+ {
+ return false;
+ }
+ data = std::complex(real, imag);
+ return true;
+}
+
+bool read_binary_wfc_data(std::ifstream& ifs, std::complex& data)
+{
+ double real = 0.0;
+ double imag = 0.0;
+ if (!read_binary_value(ifs, real) || !read_binary_value(ifs, imag))
+ {
+ return false;
+ }
+ data = std::complex(static_cast(real), static_cast(imag));
+ return true;
+}
+
+} // namespace
+
// mohan add 2025-10-19
void ModuleIO::read_wfc_nao_one_data(std::ifstream& ifs, float& data)
{
@@ -47,6 +109,7 @@ bool ModuleIO::read_wfc_nao(
const std::vector &ik2iktot,
const int nkstot,
const int nspin,
+ const int read_type,
const int skip_band,
const int istep)
{
@@ -55,10 +118,34 @@ bool ModuleIO::read_wfc_nao(
const int nk = ekb.nr;
- const bool gamma_only = std::is_same::value;
- const int out_type = 1; // only support .txt file now
+ const bool gamma_only = std::is_same::value || std::is_same::value;
+ const bool binary = (read_type == 2);
bool read_success = true;
int myrank = 0;
+#ifdef __MPI
+ MPI_Comm_rank(ParaV.comm(), &myrank);
+#endif
+ if (read_type != 1 && read_type != 2)
+ {
+ if (myrank == 0)
+ {
+ std::cout << " Error in reading wave function files!\n"
+ << " read_wfc_lcao should be 1 or 2, but got " << read_type << std::endl;
+ }
+ ModuleBase::timer::end("ModuleIO", "read_wfc_nao");
+ return false;
+ }
+ if (skip_band < 0)
+ {
+ if (myrank == 0)
+ {
+ std::cout << " Error in reading wave function files!\n"
+ << " skip_band should not be negative, but got " << skip_band << std::endl;
+ }
+ ModuleBase::timer::end("ModuleIO", "read_wfc_nao");
+ return false;
+ }
+
int nbands = ParaV.get_wfc_global_nbands(); // the global number of bands
int nlocal = ParaV.get_wfc_global_nbasis(); // the global number of basis functions
int nbands_local = ParaV.ncol_bands; // the number of bands in the local process
@@ -72,10 +159,6 @@ bool ModuleIO::read_wfc_nao(
}
psid.resize(nk, nbands_local, nlocal_local);
-#ifdef __MPI
- MPI_Comm_rank(ParaV.comm(), &myrank);
-#endif
-
// lambda function to read one file
auto read_one_file = [&](const std::string& ss,
std::stringstream& error_message,
@@ -83,7 +166,9 @@ bool ModuleIO::read_wfc_nao(
std::vector& ctot)
{
std::ifstream ifs;
- ifs.open(ss.c_str());
+ const std::ios_base::openmode mode
+ = binary ? (std::ios::in | std::ios::binary) : std::ios::in;
+ ifs.open(ss.c_str(), mode);
if (!ifs)
{
error_message << " Can't open file:" << ss << std::endl;
@@ -94,14 +179,39 @@ bool ModuleIO::read_wfc_nao(
std::cout << " Read NAO wave functions from " << ss << std::endl;
}
+ const auto incomplete_file = [&](const std::string& field) {
+ error_message << "The wave function file is incomplete or corrupted while reading "
+ << field << ": " << ss << std::endl;
+ ifs.close();
+ return false;
+ };
+
if (!gamma_only)
{
int ik_file = 0;
double kx = 0.0;
double ky = 0.0;
double kz = 0.0;
- ModuleBase::GlobalFunc::READ_VALUE(ifs, ik_file);
- ifs >> kx >> ky >> kz;
+ if (!read_record_value(ifs, ik_file, binary))
+ {
+ return incomplete_file("the k-point index");
+ }
+ if (binary)
+ {
+ if (!read_binary_value(ifs, kx) || !read_binary_value(ifs, ky)
+ || !read_binary_value(ifs, kz))
+ {
+ return incomplete_file("the k-point vector");
+ }
+ }
+ else
+ {
+ ifs >> kx >> ky >> kz;
+ if (!ifs)
+ {
+ return incomplete_file("the k-point vector");
+ }
+ }
if (ik_file != ik + 1)
{
error_message << "The k index read in from file do not match the k index generated by ABACUS!\n";
@@ -112,12 +222,16 @@ bool ModuleIO::read_wfc_nao(
}
}
int nbands_file = 0, nlocal_file = 0;
- ModuleBase::GlobalFunc::READ_VALUE(ifs, nbands_file);
- ModuleBase::GlobalFunc::READ_VALUE(ifs, nlocal_file);
- if (nbands > nbands_file)
+ if (!read_record_value(ifs, nbands_file, binary)
+ || !read_record_value(ifs, nlocal_file, binary))
+ {
+ return incomplete_file("the dimensions");
+ }
+ if (nbands_file < 0 || skip_band > nbands_file || nbands > nbands_file - skip_band)
{
error_message << "The number of bands to be read exceeds the number of bands in the file generated by ABACUS!\n";
error_message << " nbands in the existing file=" << nbands_file;
+ error_message << " skip_band=" << skip_band;
error_message << " nbands to be read into ABACUS=" << nbands << std::endl;
ifs.close();
return false;
@@ -135,9 +249,12 @@ bool ModuleIO::read_wfc_nao(
// the first skip_bands useless bands are read into 0th band to be overwritten
const int ib_read = std::max(i - skip_band, 0);
int ib = 0;
- ModuleBase::GlobalFunc::READ_VALUE(ifs, ib);
- ModuleBase::GlobalFunc::READ_VALUE(ifs, ekb(ik, ib_read));
- ModuleBase::GlobalFunc::READ_VALUE(ifs, wg(ik, ib_read));
+ if (!read_record_value(ifs, ib, binary)
+ || !read_record_value(ifs, ekb(ik, ib_read), binary)
+ || !read_record_value(ifs, wg(ik, ib_read), binary))
+ {
+ return incomplete_file("band " + std::to_string(i + 1) + " metadata");
+ }
if (i+1 != ib)
{
error_message << "The band index read in from file do not match the global parameter band index!\n";
@@ -148,7 +265,20 @@ bool ModuleIO::read_wfc_nao(
}
for (int j = 0; j < nlocal; j++)
{
- read_wfc_nao_one_data(ifs, ctot[ib_read * nlocal + j]);
+ bool data_read = false;
+ if (binary)
+ {
+ data_read = read_binary_wfc_data(ifs, ctot[ib_read * nlocal + j]);
+ }
+ else
+ {
+ read_wfc_nao_one_data(ifs, ctot[ib_read * nlocal + j]);
+ data_read = static_cast(ifs);
+ }
+ if (!data_read)
+ {
+ return incomplete_file("band " + std::to_string(i + 1) + " coefficients");
+ }
}
}
ifs.close();
@@ -180,7 +310,7 @@ bool ModuleIO::read_wfc_nao(
readin_dir = readin_dir + "WFC/";
}
std::string ss = ModuleIO::filename_output(readin_dir,"wf","nao",
- ik,ik2iktot,nspin,nkstot,out_type,out_app_flag,gamma_only,istep);
+ ik,ik2iktot,nspin,nkstot,read_type,out_app_flag,gamma_only,istep);
read_success = read_one_file(ss, error_message, ik, ctot);
errors = error_message.str();
@@ -231,8 +361,9 @@ template bool ModuleIO::read_wfc_nao(const std::string& global_readin_di
const std::vector &ik2iktot,
const int nkstot,
const int nspin,
- const int istep,
- const int skip_band);
+ const int read_type,
+ const int skip_band,
+ const int istep);
// mohan add 2025-10-19
template bool ModuleIO::read_wfc_nao(const std::string& global_readin_dir,
@@ -243,8 +374,9 @@ template bool ModuleIO::read_wfc_nao(const std::string& global_readin_dir
const std::vector &ik2iktot,
const int nkstot,
const int nspin,
- const int istep,
- const int skip_band);
+ const int read_type,
+ const int skip_band,
+ const int istep);
template bool ModuleIO::read_wfc_nao>(const std::string& global_readin_dir,
const Parallel_Orbitals& ParaV,
@@ -254,8 +386,9 @@ template bool ModuleIO::read_wfc_nao>(const std::string& gl
const std::vector &ik2iktot,
const int nkstot,
const int nspin,
- const int istep,
- const int skip_band);
+ const int read_type,
+ const int skip_band,
+ const int istep);
// mohan add 2025-10-19
template bool ModuleIO::read_wfc_nao>(const std::string& global_readin_dir,
@@ -266,5 +399,6 @@ template bool ModuleIO::read_wfc_nao>(const std::string& glo
const std::vector &ik2iktot,
const int nkstot,
const int nspin,
- const int istep,
- const int skip_band);
+ const int read_type,
+ const int skip_band,
+ const int istep);
diff --git a/source/source_io/module_wf/read_wfc_nao.h b/source/source_io/module_wf/read_wfc_nao.h
index 4abf06ae007..80c27e33ef4 100644
--- a/source/source_io/module_wf/read_wfc_nao.h
+++ b/source/source_io/module_wf/read_wfc_nao.h
@@ -34,6 +34,7 @@ void read_wfc_nao_one_data(std::ifstream& ifs, std::complex& data);
* @param ParaV The parallel orbitals object.
* @param psid The Psi object to store the wavefunction coefficients.
* @param pelec Pointer to the ElecState object.
+ * @param read_type The input file type: 1 for text and 2 for binary.
* @param skip_band From which band to start reading.
* @return True if the wavefunction coefficients are successfully read, false otherwise.
*/
@@ -47,6 +48,7 @@ bool read_wfc_nao(
const std::vector &ik2iktot,
const int nkstot,
const int nspin,
+ const int read_type,
const int skip_band = 0,
const int istep = -1);
diff --git a/source/source_io/test/CMakeLists.txt b/source/source_io/test/CMakeLists.txt
index 4849f0a6621..0e31ae783ce 100644
--- a/source/source_io/test/CMakeLists.txt
+++ b/source/source_io/test/CMakeLists.txt
@@ -242,7 +242,7 @@ add_test(
AddTest(
TARGET MODULE_IO_read_wfc_nao_test
LIBS parameter base device
- SOURCES read_wfc_nao_test.cpp ../module_wf/read_wfc_nao.cpp ../../source_psi/psi.cpp ../../source_basis/module_ao/parallel_orbitals.cpp
+ SOURCES read_wfc_nao_test.cpp ../module_wf/read_wfc_nao.cpp ../module_wf/write_wfc_nao.cpp ../../source_psi/psi.cpp ../../source_basis/module_ao/parallel_orbitals.cpp
)
add_test(
diff --git a/source/source_io/test/read_wfc_nao_test.cpp b/source/source_io/test/read_wfc_nao_test.cpp
index bf3c31adec1..71165948e4c 100644
--- a/source/source_io/test/read_wfc_nao_test.cpp
+++ b/source/source_io/test/read_wfc_nao_test.cpp
@@ -7,6 +7,9 @@
#include "source_basis/module_ao/parallel_orbitals.h"
#include "source_io/module_wf/write_wfc_nao.h"
#include "source_base/module_out/filename.h"
+#include "source_base/global_function.h"
+
+#include
/************************************************
* unit test of functions in read_wfc_nao.cpp
@@ -23,6 +26,53 @@
class ReadWfcNaoTest : public ::testing::Test
{
protected:
+ int my_rank = 0;
+ int nproc = 1;
+ std::string binary_test_dir;
+
+ void SetUp() override
+ {
+#ifdef __MPI
+ MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+#endif
+ binary_test_dir = "./read_wfc_nao_binary_np" + std::to_string(nproc) + "/";
+ ModuleBase::GlobalFunc::MAKE_DIR(binary_test_dir);
+#ifdef __MPI
+ MPI_Barrier(MPI_COMM_WORLD);
+#endif
+ }
+
+ void TearDown() override
+ {
+#ifdef __MPI
+ MPI_Barrier(MPI_COMM_WORLD);
+#endif
+ if (my_rank == 0)
+ {
+ std::remove((binary_test_dir + "wf_nao.dat").c_str());
+ std::remove((binary_test_dir + "wf_nao.txt").c_str());
+ std::remove((binary_test_dir + "wfk1_nao.dat").c_str());
+ std::remove(binary_test_dir.substr(0, binary_test_dir.size() - 1).c_str());
+ }
+#ifdef __MPI
+ MPI_Barrier(MPI_COMM_WORLD);
+#endif
+ }
+
+ void initialize_parallel_orbitals(Parallel_Orbitals& para, const int nlocal, const int nbands)
+ {
+#ifdef __MPI
+ std::ofstream ofs_running, ofs_warning;
+ para.init(nlocal, nlocal, 1, MPI_COMM_WORLD);
+ para.set_nloc_wfc_Eij(nbands, ofs_running, ofs_warning);
+ para.set_desc_wfc_Eij(nlocal, nbands, para.nrow);
+#else
+ para.set_serial(nlocal, nlocal);
+ para.nrow_bands = nlocal;
+ para.ncol_bands = nbands;
+#endif
+ }
};
@@ -60,7 +110,7 @@ TEST_F(ReadWfcNaoTest,ReadWfcNao)
// Act
ModuleIO::read_wfc_nao(PARAM.sys.global_readin_dir, ParaV, psid,
- ekb, wg, ik2iktot, nkstot, nspin);
+ ekb, wg, ik2iktot, nkstot, nspin, 1);
// Assert
EXPECT_NEAR(ekb(0,1),0.31482195194888534794941393,1e-5);
EXPECT_NEAR(wg(0,1),0.0,1e-5);
@@ -106,7 +156,7 @@ TEST_F(ReadWfcNaoTest, ReadWfcNaoPart)
// Act
ModuleIO::read_wfc_nao(PARAM.sys.global_readin_dir, ParaV, psid,
- ekb, wg, ik2iktot, nkstot, nspin, skip_band, nstep);
+ ekb, wg, ik2iktot, nkstot, nspin, 1, skip_band, nstep);
// Assert
EXPECT_NEAR(ekb(0, 1), 7.4141254894954844445464914e-01, 1e-5);
@@ -116,6 +166,294 @@ TEST_F(ReadWfcNaoTest, ReadWfcNaoPart)
}
}
+TEST_F(ReadWfcNaoTest, ReadBinaryGamma)
+{
+ const int nbands = 2;
+ const int nlocal = 3;
+ Parallel_Orbitals para;
+ initialize_parallel_orbitals(para, nlocal, nbands);
+
+ const std::vector coefficients = {0.1, 0.2, 0.3, 1.1, 1.2, 1.3};
+ ModuleBase::matrix ekb_source(1, nbands);
+ ModuleBase::matrix wg_source(1, nbands);
+ ekb_source(0, 0) = -0.5;
+ ekb_source(0, 1) = 0.7;
+ wg_source(0, 0) = 2.0;
+ wg_source(0, 1) = 0.0;
+ if (my_rank == 0)
+ {
+ ModuleIO::wfc_nao_write2file(binary_test_dir + "wf_nao.dat",
+ coefficients.data(),
+ nlocal,
+ 0,
+ ekb_source,
+ wg_source,
+ true,
+ false);
+ }
+#ifdef __MPI
+ MPI_Barrier(MPI_COMM_WORLD);
+#endif
+
+ psi::Psi psi_read;
+ ModuleBase::matrix ekb(1, nbands);
+ ModuleBase::matrix wg(1, nbands);
+ const std::vector ik2iktot = {0};
+ EXPECT_TRUE(ModuleIO::read_wfc_nao(binary_test_dir,
+ para,
+ psi_read,
+ ekb,
+ wg,
+ ik2iktot,
+ 1,
+ 1,
+ 2));
+ EXPECT_DOUBLE_EQ(ekb(0, 0), ekb_source(0, 0));
+ EXPECT_DOUBLE_EQ(ekb(0, 1), ekb_source(0, 1));
+ EXPECT_DOUBLE_EQ(wg(0, 0), wg_source(0, 0));
+ EXPECT_DOUBLE_EQ(wg(0, 1), wg_source(0, 1));
+ if (my_rank == 0)
+ {
+ EXPECT_DOUBLE_EQ(psi_read(0, 0, 0), coefficients[0]);
+ }
+}
+
+TEST_F(ReadWfcNaoTest, ReadBinaryGammaFloat)
+{
+ const int nbands = 2;
+ const int nlocal = 3;
+ Parallel_Orbitals para;
+ initialize_parallel_orbitals(para, nlocal, nbands);
+
+ const std::vector coefficients = {0.1, 0.2, 0.3, 1.1, 1.2, 1.3};
+ ModuleBase::matrix ekb_source(1, nbands);
+ ModuleBase::matrix wg_source(1, nbands);
+ ekb_source(0, 0) = -0.5;
+ ekb_source(0, 1) = 0.7;
+ wg_source(0, 0) = 2.0;
+ wg_source(0, 1) = 0.0;
+ if (my_rank == 0)
+ {
+ ModuleIO::wfc_nao_write2file(binary_test_dir + "wf_nao.dat",
+ coefficients.data(),
+ nlocal,
+ 0,
+ ekb_source,
+ wg_source,
+ true,
+ false);
+ }
+#ifdef __MPI
+ MPI_Barrier(MPI_COMM_WORLD);
+#endif
+
+ psi::Psi psi_read;
+ ModuleBase::matrix ekb(1, nbands);
+ ModuleBase::matrix wg(1, nbands);
+ const std::vector ik2iktot = {0};
+ EXPECT_TRUE(ModuleIO::read_wfc_nao(binary_test_dir,
+ para,
+ psi_read,
+ ekb,
+ wg,
+ ik2iktot,
+ 1,
+ 1,
+ 2));
+ EXPECT_DOUBLE_EQ(ekb(0, 0), ekb_source(0, 0));
+ EXPECT_DOUBLE_EQ(ekb(0, 1), ekb_source(0, 1));
+ EXPECT_DOUBLE_EQ(wg(0, 0), wg_source(0, 0));
+ EXPECT_DOUBLE_EQ(wg(0, 1), wg_source(0, 1));
+ if (my_rank == 0)
+ {
+ EXPECT_FLOAT_EQ(psi_read(0, 0, 0), static_cast(coefficients[0]));
+ }
+}
+
+TEST_F(ReadWfcNaoTest, ReadBinaryComplex)
+{
+ const int nbands = 2;
+ const int nlocal = 3;
+ Parallel_Orbitals para;
+ initialize_parallel_orbitals(para, nlocal, nbands);
+
+ const std::vector> coefficients
+ = {{0.1, -0.1}, {0.2, -0.2}, {0.3, -0.3}, {1.1, 0.4}, {1.2, 0.5}, {1.3, 0.6}};
+ ModuleBase::matrix ekb_source(1, nbands);
+ ModuleBase::matrix wg_source(1, nbands);
+ ekb_source(0, 0) = -0.4;
+ ekb_source(0, 1) = 0.8;
+ wg_source(0, 0) = 1.0;
+ wg_source(0, 1) = 0.0;
+ if (my_rank == 0)
+ {
+ ModuleIO::wfc_nao_write2file_complex(binary_test_dir + "wfk1_nao.dat",
+ coefficients.data(),
+ nlocal,
+ 0,
+ ModuleBase::Vector3(0.25, 0.0, 0.0),
+ ekb_source,
+ wg_source,
+ true,
+ false);
+ }
+#ifdef __MPI
+ MPI_Barrier(MPI_COMM_WORLD);
+#endif
+
+ psi::Psi> psi_read;
+ ModuleBase::matrix ekb(1, nbands);
+ ModuleBase::matrix wg(1, nbands);
+ const std::vector ik2iktot = {0};
+ EXPECT_TRUE(ModuleIO::read_wfc_nao(binary_test_dir,
+ para,
+ psi_read,
+ ekb,
+ wg,
+ ik2iktot,
+ 1,
+ 1,
+ 2));
+ EXPECT_DOUBLE_EQ(ekb(0, 0), ekb_source(0, 0));
+ EXPECT_DOUBLE_EQ(ekb(0, 1), ekb_source(0, 1));
+ EXPECT_DOUBLE_EQ(wg(0, 0), wg_source(0, 0));
+ EXPECT_DOUBLE_EQ(wg(0, 1), wg_source(0, 1));
+ if (my_rank == 0)
+ {
+ EXPECT_DOUBLE_EQ(psi_read(0, 0, 0).real(), coefficients[0].real());
+ EXPECT_DOUBLE_EQ(psi_read(0, 0, 0).imag(), coefficients[0].imag());
+ }
+}
+
+TEST_F(ReadWfcNaoTest, ReadBinaryPart)
+{
+ const int nbands_file = 3;
+ const int nbands = 2;
+ const int skip_band = 1;
+ const int nlocal = 3;
+ Parallel_Orbitals para;
+ initialize_parallel_orbitals(para, nlocal, nbands);
+
+ const std::vector coefficients
+ = {0.1, 0.2, 0.3, 1.1, 1.2, 1.3, 2.1, 2.2, 2.3};
+ ModuleBase::matrix ekb_source(1, nbands_file);
+ ModuleBase::matrix wg_source(1, nbands_file);
+ for (int ib = 0; ib < nbands_file; ++ib)
+ {
+ ekb_source(0, ib) = -0.5 + ib;
+ wg_source(0, ib) = 2.0 - ib;
+ }
+ if (my_rank == 0)
+ {
+ ModuleIO::wfc_nao_write2file(binary_test_dir + "wf_nao.dat",
+ coefficients.data(),
+ nlocal,
+ 0,
+ ekb_source,
+ wg_source,
+ true,
+ false);
+ }
+#ifdef __MPI
+ MPI_Barrier(MPI_COMM_WORLD);
+#endif
+
+ psi::Psi psi_read;
+ ModuleBase::matrix ekb(1, nbands);
+ ModuleBase::matrix wg(1, nbands);
+ const std::vector ik2iktot = {0};
+ EXPECT_TRUE(ModuleIO::read_wfc_nao(binary_test_dir,
+ para,
+ psi_read,
+ ekb,
+ wg,
+ ik2iktot,
+ 1,
+ 1,
+ 2,
+ skip_band));
+ EXPECT_DOUBLE_EQ(ekb(0, 0), ekb_source(0, 1));
+ EXPECT_DOUBLE_EQ(ekb(0, 1), ekb_source(0, 2));
+ EXPECT_DOUBLE_EQ(wg(0, 0), wg_source(0, 1));
+ EXPECT_DOUBLE_EQ(wg(0, 1), wg_source(0, 2));
+ if (my_rank == 0)
+ {
+ EXPECT_DOUBLE_EQ(psi_read(0, 0, 0), coefficients[nlocal]);
+ }
+}
+
+TEST_F(ReadWfcNaoTest, BinaryDoesNotFallBackToText)
+{
+ const int nbands = 2;
+ const int nlocal = 2;
+ Parallel_Orbitals para;
+ initialize_parallel_orbitals(para, nlocal, nbands);
+
+ const std::vector coefficients = {0.25, 0.5, 0.75, 1.0};
+ ModuleBase::matrix ekb_source(1, nbands);
+ ModuleBase::matrix wg_source(1, nbands);
+ if (my_rank == 0)
+ {
+ ModuleIO::wfc_nao_write2file(binary_test_dir + "wf_nao.txt",
+ coefficients.data(),
+ nlocal,
+ 0,
+ ekb_source,
+ wg_source,
+ false,
+ false);
+ }
+#ifdef __MPI
+ MPI_Barrier(MPI_COMM_WORLD);
+#endif
+
+ psi::Psi psi_read;
+ ModuleBase::matrix ekb(1, nbands);
+ ModuleBase::matrix wg(1, nbands);
+ const std::vector ik2iktot = {0};
+ EXPECT_FALSE(ModuleIO::read_wfc_nao(binary_test_dir,
+ para,
+ psi_read,
+ ekb,
+ wg,
+ ik2iktot,
+ 1,
+ 1,
+ 2));
+}
+
+TEST_F(ReadWfcNaoTest, RejectTruncatedBinary)
+{
+ const int nbands = 2;
+ const int nlocal = 2;
+ Parallel_Orbitals para;
+ initialize_parallel_orbitals(para, nlocal, nbands);
+
+ if (my_rank == 0)
+ {
+ std::ofstream ofs(binary_test_dir + "wf_nao.dat", std::ios::binary);
+ ofs.write(reinterpret_cast(&nbands), sizeof(nbands));
+ ofs.write(reinterpret_cast(&nlocal), sizeof(nlocal));
+ }
+#ifdef __MPI
+ MPI_Barrier(MPI_COMM_WORLD);
+#endif
+
+ psi::Psi psi_read;
+ ModuleBase::matrix ekb(1, nbands);
+ ModuleBase::matrix wg(1, nbands);
+ const std::vector ik2iktot = {0};
+ EXPECT_FALSE(ModuleIO::read_wfc_nao(binary_test_dir,
+ para,
+ psi_read,
+ ekb,
+ wg,
+ ik2iktot,
+ 1,
+ 1,
+ 2));
+}
+
#ifdef __MPI
diff --git a/source/source_io/test_serial/read_input_item_test.cpp b/source/source_io/test_serial/read_input_item_test.cpp
index c5815f858ae..5e3d74a6500 100644
--- a/source/source_io/test_serial/read_input_item_test.cpp
+++ b/source/source_io/test_serial/read_input_item_test.cpp
@@ -373,6 +373,28 @@ TEST_F(InputTest, Item_test)
it->second.reset_value(it->second, param);
EXPECT_EQ(param.input.init_wfc, "nao");
}
+ { // read_wfc_lcao
+ auto it = find_label("read_wfc_lcao", readinput.input_lists);
+ EXPECT_NE(it, readinput.input_lists.end());
+ EXPECT_EQ(param.input.read_wfc_lcao, 1);
+ EXPECT_EQ(it->second.get_availability(), "basis_type==lcao");
+
+ it->second.str_values = {"2"};
+ it->second.read_value(it->second, param);
+ EXPECT_EQ(param.input.read_wfc_lcao, 2);
+
+ param.input.read_wfc_lcao = 0;
+ testing::internal::CaptureStdout();
+ EXPECT_EXIT(it->second.check_value(it->second, param), ::testing::ExitedWithCode(1), "");
+ output = testing::internal::GetCapturedStdout();
+ EXPECT_THAT(output, testing::HasSubstr("NOTICE"));
+
+ param.input.read_wfc_lcao = 3;
+ testing::internal::CaptureStdout();
+ EXPECT_EXIT(it->second.check_value(it->second, param), ::testing::ExitedWithCode(1), "");
+ output = testing::internal::GetCapturedStdout();
+ EXPECT_THAT(output, testing::HasSubstr("NOTICE"));
+ }
{ // init_chg
auto it = find_label("init_chg", readinput.input_lists);
param.input.init_chg = "get_pchg";
diff --git a/source/source_lcao/lcao_set.cpp b/source/source_lcao/lcao_set.cpp
index dda20f80580..206409b0d8f 100644
--- a/source/source_lcao/lcao_set.cpp
+++ b/source/source_lcao/lcao_set.cpp
@@ -27,7 +27,7 @@ void LCAO_domain::set_psi_occ_dm_chg(
{
if (!ModuleIO::read_wfc_nao(PARAM.globalv.global_readin_dir,
pv, *psi, pelec->ekb, pelec->wg, kv.ik2iktot,
- kv.get_nkstot(), inp.nspin))
+ kv.get_nkstot(), inp.nspin, inp.read_wfc_lcao))
{
ModuleBase::WARNING_QUIT("set_psi_occ_dm_chg", "read electronic wave functions failed");
}