From 98e3f81cf425070fe58e8dd191dfbfbb7be51e6d Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Tue, 6 Oct 2026 07:22:02 +0800 Subject: [PATCH 01/18] Fix #5021 #5939: warn on ignored x/y magnetization and remove nspin=4 autoset When nspin=4 with noncolin=0, the x/y components of the initial magnetization from STRU are silently zeroed. Now a warning is printed to both stdout and running_scf.log, telling the user that x/y are ignored and suggesting to set noncolin=1. When nspin=4 and no initial magnetization is set in STRU, the code previously auto-assigned (1,1,1) to all atoms. This is removed; the calculation now starts from zero magnetic moment with a warning, letting the user decide explicitly. nspin=2 autoset behavior is unchanged. Also adds unit tests for both behaviors and updates parameter docs. --- docs/advanced/input_files/input-main.md | 2 + docs/parameters.yaml | 2 + source/source_cell/read_atoms_helper.cpp | 33 +-- .../source_cell/test/read_atoms_hlp_test.cpp | 204 ++++++++++++++++++ 4 files changed, 228 insertions(+), 13 deletions(-) diff --git a/docs/advanced/input_files/input-main.md b/docs/advanced/input_files/input-main.md index 4e5456899d3..bacad14219c 100644 --- a/docs/advanced/input_files/input-main.md +++ b/docs/advanced/input_files/input-main.md @@ -1604,6 +1604,8 @@ - noncolin=0, lspinorb=1: SOC with z-axis magnetism only (for non-magnetic materials with SOC) - noncolin=1, lspinorb=0: Non-collinear magnetism without SOC - noncolin=1, lspinorb=1: Both non-collinear magnetism and SOC + - Note: When nspin=4 and noncolin=0, only the z component of the initial magnetization in STRU is used; x/y components are ignored and a warning is printed. + - Note: When nspin=4 and no initial magnetization is set in STRU, the calculation starts from zero magnetic moment; no automatic magnetization is assigned. - **Default**: False ### soc_lambda diff --git a/docs/parameters.yaml b/docs/parameters.yaml index 813d25e3b0a..02b5e0d5e91 100644 --- a/docs/parameters.yaml +++ b/docs/parameters.yaml @@ -996,6 +996,8 @@ parameters: * noncolin=0, lspinorb=1: SOC with z-axis magnetism only (for non-magnetic materials with SOC) * noncolin=1, lspinorb=0: Non-collinear magnetism without SOC * noncolin=1, lspinorb=1: Both non-collinear magnetism and SOC + * Note: When nspin=4 and noncolin=0, only the z component of the initial magnetization in STRU is used; x/y components are ignored and a warning is printed. + * Note: When nspin=4 and no initial magnetization is set in STRU, the calculation starts from zero magnetic moment; no automatic magnetization is assigned. default_value: "False" unit: "" availability: "" diff --git a/source/source_cell/read_atoms_helper.cpp b/source/source_cell/read_atoms_helper.cpp index 8e5e75e6c9a..c440d7ef8af 100644 --- a/source/source_cell/read_atoms_helper.cpp +++ b/source/source_cell/read_atoms_helper.cpp @@ -102,19 +102,14 @@ void autoset_magnetization(UnitCell& ucell, int nspin, { if(nspin==4) { - for (int it = 0; it < ntype; it++) - { - for (int ia = 0; ia < ucell.atoms[it].na; ia++) - { - ucell.atoms[it].m_loc_[ia].x = 1.0; - ucell.atoms[it].m_loc_[ia].y = 1.0; - ucell.atoms[it].m_loc_[ia].z = 1.0; - ucell.atoms[it].mag[ia] = sqrt(pow(ucell.atoms[it].m_loc_[ia].x,2) - +pow(ucell.atoms[it].m_loc_[ia].y,2) - +pow(ucell.atoms[it].m_loc_[ia].z,2)); - ModuleBase::GlobalFunc::OUT(ofs_running,"Autoset magnetism for this atom", 1.0, 1.0, 1.0); - } - } + // nspin=4 with all-zero magnetization: do NOT autoset, + // start from zero and let the user decide explicitly. + std::string msg = "nspin=4 but no initial magnetization is set in STRU.\n" + " All atoms start from zero magnetic moment.\n" + " If a magnetic ground state is expected, set 'mag' explicitly " + "in STRU for the magnetic atoms."; + std::cout << " Warning: " << msg << std::endl; + ModuleBase::GlobalFunc::OUT(ofs_running, "Warning", msg); } else if(nspin==2) { @@ -307,6 +302,18 @@ void process_magnetization(Atom& atom, int it, int ia, if(!noncolin) { // collinear case with nspin = 4, only z component is used + if(std::abs(atom.m_loc_[ia].x) > 1e-5 || std::abs(atom.m_loc_[ia].y) > 1e-5) + { + std::stringstream ss; + ss << "Atom " << ia+1 << " of type " << atom.label + << ": STRU gives non-zero x/y magnetization (" + << atom.m_loc_[ia].x << ", " << atom.m_loc_[ia].y << ", " + << atom.m_loc_[ia].z << "), but nspin=4 with noncolin=0 " + << "is a collinear calculation; only the z component is used.\n" + << " x/y components are IGNORED. Set 'noncolin 1' to use the full vector."; + std::cout << " Warning: " << ss.str() << std::endl; + ModuleBase::GlobalFunc::OUT(ofs_running, "Warning", ss.str()); + } atom.m_loc_[ia].x = 0; atom.m_loc_[ia].y = 0; } diff --git a/source/source_cell/test/read_atoms_hlp_test.cpp b/source/source_cell/test/read_atoms_hlp_test.cpp index 77e6c49dc11..9d0e8b15b11 100644 --- a/source/source_cell/test/read_atoms_hlp_test.cpp +++ b/source/source_cell/test/read_atoms_hlp_test.cpp @@ -478,3 +478,207 @@ int main(int argc, char **argv) ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } + +// ============================================================ +// Tests for issue #5021: nspin=4 with noncolin=0 should warn +// when x/y components are non-zero +// ============================================================ + +TEST_F(ReadAtomsHelperTest, ProcessMagnetizationNspin4CollinearWarnsOnXY) +{ + Atom atom; + atom.label = "Fe"; + atom.mag.resize(1); + atom.m_loc_.resize(1); + atom.angle1.resize(1); + atom.angle2.resize(1); + + atom.m_loc_[0].set(1.0, 0.5, 0.3); + atom.mag[0] = sqrt(1.0 + 0.25 + 0.09); + + const int nspin = 4; + const bool input_vec_mag = true; + const bool input_angle_mag = false; + const bool noncolin = false; + + // Capture stdout + testing::internal::CaptureStdout(); + unitcell::process_magnetization(atom, 0, 0, nspin, input_vec_mag, input_angle_mag, ofs_running, noncolin); + std::string stdout_output = testing::internal::GetCapturedStdout(); + + // x/y should be zeroed + EXPECT_DOUBLE_EQ(atom.m_loc_[0].x, 0.0); + EXPECT_DOUBLE_EQ(atom.m_loc_[0].y, 0.0); + EXPECT_DOUBLE_EQ(atom.m_loc_[0].z, 0.3); + + // Warning should appear on stdout + EXPECT_NE(stdout_output.find("Warning"), std::string::npos); + EXPECT_NE(stdout_output.find("x/y components are IGNORED"), std::string::npos); + + // Warning should appear in running log + ofs_running.flush(); + std::ifstream ifs("test_running.log"); + std::stringstream buffer; + buffer << ifs.rdbuf(); + std::string log_content = buffer.str(); + ifs.close(); + EXPECT_NE(log_content.find("Warning"), std::string::npos); + EXPECT_NE(log_content.find("x/y components are IGNORED"), std::string::npos); +} + +TEST_F(ReadAtomsHelperTest, ProcessMagnetizationNspin4CollinearNoWarnOnZeroXY) +{ + Atom atom; + atom.label = "Fe"; + atom.mag.resize(1); + atom.m_loc_.resize(1); + atom.angle1.resize(1); + atom.angle2.resize(1); + + atom.m_loc_[0].set(0.0, 0.0, 0.3); + atom.mag[0] = 0.3; + + const int nspin = 4; + const bool input_vec_mag = true; + const bool input_angle_mag = false; + const bool noncolin = false; + + testing::internal::CaptureStdout(); + unitcell::process_magnetization(atom, 0, 0, nspin, input_vec_mag, input_angle_mag, ofs_running, noncolin); + std::string stdout_output = testing::internal::GetCapturedStdout(); + + EXPECT_DOUBLE_EQ(atom.m_loc_[0].x, 0.0); + EXPECT_DOUBLE_EQ(atom.m_loc_[0].y, 0.0); + EXPECT_DOUBLE_EQ(atom.m_loc_[0].z, 0.3); + + // No warning should appear + EXPECT_EQ(stdout_output.find("Warning"), std::string::npos); +} + +TEST_F(ReadAtomsHelperTest, ProcessMagnetizationNspin4NoncolinNoWarn) +{ + Atom atom; + atom.label = "Fe"; + atom.mag.resize(1); + atom.m_loc_.resize(1); + atom.angle1.resize(1); + atom.angle2.resize(1); + + atom.m_loc_[0].set(1.0, 0.5, 0.3); + atom.mag[0] = sqrt(1.0 + 0.25 + 0.09); + + const int nspin = 4; + const bool input_vec_mag = true; + const bool input_angle_mag = false; + const bool noncolin = true; + + testing::internal::CaptureStdout(); + unitcell::process_magnetization(atom, 0, 0, nspin, input_vec_mag, input_angle_mag, ofs_running, noncolin); + std::string stdout_output = testing::internal::GetCapturedStdout(); + + // All components should be preserved + EXPECT_DOUBLE_EQ(atom.m_loc_[0].x, 1.0); + EXPECT_DOUBLE_EQ(atom.m_loc_[0].y, 0.5); + EXPECT_DOUBLE_EQ(atom.m_loc_[0].z, 0.3); + + // No warning should appear + EXPECT_EQ(stdout_output.find("Warning"), std::string::npos); +} + +// ============================================================ +// Tests for issue #5939: nspin=4 autoset should not force (1,1,1) +// ============================================================ + +TEST_F(ReadAtomsHelperTest, AutosetMagnetizationNspin4NoAutoset) +{ + UnitCell ucell; + ucell.ntype = 1; + ucell.atoms = new Atom[1]; + ucell.atoms[0].label = "Fe"; + ucell.atoms[0].na = 1; + ucell.atoms[0].mag.resize(1, 0.0); + ucell.atoms[0].m_loc_.resize(1); + ucell.atoms[0].m_loc_[0].set(0.0, 0.0, 0.0); + + const int nspin = 4; + + testing::internal::CaptureStdout(); + unitcell::autoset_magnetization(ucell, nspin, ofs_running); + std::string stdout_output = testing::internal::GetCapturedStdout(); + + // Magnetization should remain zero (NOT autoset to (1,1,1)) + EXPECT_DOUBLE_EQ(ucell.atoms[0].m_loc_[0].x, 0.0); + EXPECT_DOUBLE_EQ(ucell.atoms[0].m_loc_[0].y, 0.0); + EXPECT_DOUBLE_EQ(ucell.atoms[0].m_loc_[0].z, 0.0); + EXPECT_DOUBLE_EQ(ucell.atoms[0].mag[0], 0.0); + + // Warning should appear on stdout + EXPECT_NE(stdout_output.find("Warning"), std::string::npos); + EXPECT_NE(stdout_output.find("no initial magnetization is set in STRU"), std::string::npos); + + // Warning should appear in running log + ofs_running.flush(); + std::ifstream ifs("test_running.log"); + std::stringstream buffer; + buffer << ifs.rdbuf(); + std::string log_content = buffer.str(); + ifs.close(); + EXPECT_NE(log_content.find("Warning"), std::string::npos); + EXPECT_NE(log_content.find("no initial magnetization is set in STRU"), std::string::npos); + + delete[] ucell.atoms; +} + +TEST_F(ReadAtomsHelperTest, AutosetMagnetizationNspin4NoWarnWhenMagSet) +{ + UnitCell ucell; + ucell.ntype = 1; + ucell.atoms = new Atom[1]; + ucell.atoms[0].label = "Fe"; + ucell.atoms[0].na = 1; + ucell.atoms[0].mag.resize(1, 1.5); + ucell.atoms[0].m_loc_.resize(1); + ucell.atoms[0].m_loc_[0].set(0.0, 0.0, 1.5); + + const int nspin = 4; + + testing::internal::CaptureStdout(); + unitcell::autoset_magnetization(ucell, nspin, ofs_running); + std::string stdout_output = testing::internal::GetCapturedStdout(); + + // No autoset should happen + EXPECT_DOUBLE_EQ(ucell.atoms[0].mag[0], 1.5); + EXPECT_DOUBLE_EQ(ucell.atoms[0].m_loc_[0].z, 1.5); + + // No warning should appear + EXPECT_EQ(stdout_output.find("Warning"), std::string::npos); + + delete[] ucell.atoms; +} + +TEST_F(ReadAtomsHelperTest, AutosetMagnetizationNspin2StillAutoset) +{ + UnitCell ucell; + ucell.ntype = 1; + ucell.atoms = new Atom[1]; + ucell.atoms[0].label = "Fe"; + ucell.atoms[0].na = 1; + ucell.atoms[0].mag.resize(1, 0.0); + ucell.atoms[0].m_loc_.resize(1); + ucell.atoms[0].m_loc_[0].set(0.0, 0.0, 0.0); + + const int nspin = 2; + + testing::internal::CaptureStdout(); + unitcell::autoset_magnetization(ucell, nspin, ofs_running); + std::string stdout_output = testing::internal::GetCapturedStdout(); + + // nspin=2 should still autoset to 1.0 (VASP-compatible behavior) + EXPECT_DOUBLE_EQ(ucell.atoms[0].mag[0], 1.0); + EXPECT_DOUBLE_EQ(ucell.atoms[0].m_loc_[0].z, 1.0); + + // No warning for nspin=2 autoset + EXPECT_EQ(stdout_output.find("Warning"), std::string::npos); + + delete[] ucell.atoms; +} From 9d8317cb1f7334752d085cc57454a3b2e2173c3e Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Tue, 6 Oct 2026 09:57:00 +0800 Subject: [PATCH 02/18] Fix parameters.yaml sync: add noncolin notes to C++ description source docs/parameters.yaml is generated from item.description in C++ source. Commit 98e3f81cf added two noncolin notes to the generated yaml and input-main.md but omitted the generator source, making the yaml consistency CI check fail. Add the same two notes to the noncolin description in read_inp_estruc.cpp so regeneration matches. --- source/source_io/module_parameter/read_inp_estruc.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/source_io/module_parameter/read_inp_estruc.cpp b/source/source_io/module_parameter/read_inp_estruc.cpp index 49c5fec46b3..11247ebea7f 100644 --- a/source/source_io/module_parameter/read_inp_estruc.cpp +++ b/source/source_io/module_parameter/read_inp_estruc.cpp @@ -1006,7 +1006,9 @@ Note: If gamma_only is set to 1, the KPT file will be overwritten. So make sure * Relationship with lspinorb: * noncolin=0, lspinorb=1: SOC with z-axis magnetism only (for non-magnetic materials with SOC) * noncolin=1, lspinorb=0: Non-collinear magnetism without SOC - * noncolin=1, lspinorb=1: Both non-collinear magnetism and SOC)"; + * noncolin=1, lspinorb=1: Both non-collinear magnetism and SOC +* Note: When nspin=4 and noncolin=0, only the z component of the initial magnetization in STRU is used; x/y components are ignored and a warning is printed. +* Note: When nspin=4 and no initial magnetization is set in STRU, the calculation starts from zero magnetic moment; no automatic magnetization is assigned.)"; item.default_value = "False"; item.unit = ""; read_sync_bool(input.noncolin); From ffaeba6ec16d5dbcf3ce1cd5d866264fbf728fba Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Tue, 6 Oct 2026 11:52:14 +0800 Subject: [PATCH 03/18] Test: update ReadAtomPositionsAutosetMag for nspin=4 zero-moment start Follow-up to #5939: nspin=4 with no mag in STRU no longer autosets (1,1,1); the unit test still expected the old forced moments. Assert zero magnetization instead and verify the new warning on both stdout and the running log. --- source/source_cell/test/unitcell_test.cpp | 26 +++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/source/source_cell/test/unitcell_test.cpp b/source/source_cell/test/unitcell_test.cpp index 22ed1fd421c..a633263a21f 100644 --- a/source/source_cell/test/unitcell_test.cpp +++ b/source/source_cell/test/unitcell_test.cpp @@ -1582,21 +1582,39 @@ TEST_F(UcellTestReadStru, ReadAtomPositionsAutosetMag) } } // for nspin == 4 + // Issue #5939: nspin=4 with no mag in STRU no longer autosets (1,1,1); + // all moments stay zero and a warning is emitted instead. nspin = 4; + testing::internal::CaptureStdout(); unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, basis_type, orbital_dir, init_wfc, onsite_radius, fixed_atoms, noncolin, calculation, esolver_type, 0); + const std::string stdout_output = testing::internal::GetCapturedStdout(); for (int it = 0; it < ucell->ntype; it++) { for (int ia = 0; ia < ucell->atoms[it].na; ia++) { - EXPECT_DOUBLE_EQ(ucell->atoms[it].mag[ia], sqrt(pow(1.0, 2) + pow(1.0, 2) + pow(1.0, 2))); - EXPECT_DOUBLE_EQ(ucell->atoms[it].m_loc_[ia].x, 1.0); - EXPECT_DOUBLE_EQ(ucell->atoms[it].m_loc_[ia].y, 1.0); - EXPECT_DOUBLE_EQ(ucell->atoms[it].m_loc_[ia].z, 1.0); + EXPECT_DOUBLE_EQ(ucell->atoms[it].mag[ia], 0.0); + EXPECT_DOUBLE_EQ(ucell->atoms[it].m_loc_[ia].x, 0.0); + EXPECT_DOUBLE_EQ(ucell->atoms[it].m_loc_[ia].y, 0.0); + EXPECT_DOUBLE_EQ(ucell->atoms[it].m_loc_[ia].z, 0.0); } } + // The zero-moment warning must reach both stdout and the running log. + EXPECT_NE(stdout_output.find("no initial magnetization is set in STRU"), + std::string::npos); + ofs_running.flush(); + std::ifstream ifs_log("read_atom_positions.tmp"); + std::string log_content; + std::string log_line; + while (std::getline(ifs_log, log_line)) + { + log_content += log_line; + } + ifs_log.close(); + EXPECT_NE(log_content.find("no initial magnetization is set in STRU"), + std::string::npos); ofs_running.close(); ofs_warning.close(); ifa.close(); From 5306acf61e2d8614b7cb63723bc8ea3e8c17bd5d Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Tue, 6 Oct 2026 12:06:37 +0800 Subject: [PATCH 04/18] Test: split cal_ux tests out of MODULE_CELL_unitcell_test Move JudgeParallel, CalUx1 and CalUx2 to the new test_cal_ux.cpp / MODULE_CELL_cal_ux_test target, one test file per source file. The new target compiles ../cal_ux.cpp directly like the old target did; unitcell_test no longer needs it. --- source/source_cell/test/CMakeLists.txt | 8 ++- source/source_cell/test/test_cal_ux.cpp | 87 +++++++++++++++++++++++ source/source_cell/test/unitcell_test.cpp | 49 ------------- 3 files changed, 94 insertions(+), 50 deletions(-) create mode 100644 source/source_cell/test/test_cal_ux.cpp diff --git a/source/source_cell/test/CMakeLists.txt b/source/source_cell/test/CMakeLists.txt index e0db610c5bf..44fd1466832 100644 --- a/source/source_cell/test/CMakeLists.txt +++ b/source/source_cell/test/CMakeLists.txt @@ -173,7 +173,13 @@ add_test(NAME MODULE_CELL_parallel_kpoints_test AddTest( TARGET MODULE_CELL_unitcell_test LIBS base device cell_info symmetry - SOURCES unitcell_test.cpp ../cal_ux.cpp + SOURCES unitcell_test.cpp +) + +AddTest( + TARGET MODULE_CELL_cal_ux_test + LIBS base device cell_info + SOURCES test_cal_ux.cpp ../cal_ux.cpp ) AddTest( diff --git a/source/source_cell/test/test_cal_ux.cpp b/source/source_cell/test/test_cal_ux.cpp new file mode 100644 index 00000000000..4ee3c864456 --- /dev/null +++ b/source/source_cell/test/test_cal_ux.cpp @@ -0,0 +1,87 @@ +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include +#include +#include + +#include "source_base/global_variable.h" +#include "source_base/mathzone.h" +#include "source_cell/unitcell.h" +#include "source_cell/cal_ux.h" +#include "prepare_unitcell.h" + +// The test-only cell_info object library does not contain magnetism.cpp, +// so the Magnetism constructor/destructor must be provided locally. +Magnetism::Magnetism() +{ + this->tot_mag = 0.0; + this->abs_mag = 0.0; +} +Magnetism::~Magnetism() +{ +} + +/************************************************ + * unit test of cal_ux.cpp + ***********************************************/ + +/** + * - Tested Functions: + * - JudgeParallel + * - judge_parallel: judge if two vectors a[3] and Vector3 b are parallel + * - CalUx1 + * - cal_ux: non-parallel initial moments, no common direction + * - CalUx2 + * - cal_ux: parallel moments, normalized common direction (1,1,1)/sqrt(3) + */ + +class CalUxTest : public ::testing::Test +{ + protected: + std::unique_ptr ucell; +}; + +TEST_F(CalUxTest, JudgeParallel) +{ + ModuleBase::Vector3 b(1.0, 1.0, 1.0); + double a[3] = {1.0, 1.0, 1.0}; + EXPECT_TRUE(unitcell::judge_parallel(a, b)); + + // the negative case, moved here from MagnetismTest.JudgeParallel when the + // duplicate Magnetism::judge_parallel was deleted + double c[3] = {1.0, 0.0, 0.0}; + ModuleBase::Vector3 d(0.0, 1.0, 0.0); + EXPECT_FALSE(unitcell::judge_parallel(c, d)); +} + +TEST_F(CalUxTest, CalUx1) +{ + UcellTestPrepare utp = UcellTestLib["C1H2-Read"]; + ucell = utp.SetUcellInfo(); + ucell->atoms[0].m_loc_[0].set(0, -1, 0); + ucell->atoms[1].m_loc_[0].set(1, 1, 1); + ucell->atoms[1].m_loc_[1].set(0, 0, 0); + const int nspin = 4; + unitcell::cal_ux(*ucell, nspin); + EXPECT_FALSE(ucell->magnet.lsign_); + EXPECT_DOUBLE_EQ(ucell->magnet.ux_[0], 0); + EXPECT_DOUBLE_EQ(ucell->magnet.ux_[1], -1); + EXPECT_DOUBLE_EQ(ucell->magnet.ux_[2], 0); +} + +TEST_F(CalUxTest, CalUx2) +{ + UcellTestPrepare utp = UcellTestLib["C1H2-Read"]; + ucell = utp.SetUcellInfo(); + ucell->atoms[0].m_loc_[0].set(0, 0, 0); + ucell->atoms[1].m_loc_[0].set(1, 1, 1); + ucell->atoms[1].m_loc_[1].set(0, 0, 0); + //(0,0,0) is also parallel to (1,1,1) + const int nspin = 4; + unitcell::cal_ux(*ucell, nspin); + EXPECT_TRUE(ucell->magnet.lsign_); + EXPECT_NEAR(ucell->magnet.ux_[0], 0.57735, 1e-5); + EXPECT_NEAR(ucell->magnet.ux_[1], 0.57735, 1e-5); + EXPECT_NEAR(ucell->magnet.ux_[2], 0.57735, 1e-5); +} diff --git a/source/source_cell/test/unitcell_test.cpp b/source/source_cell/test/unitcell_test.cpp index a633263a21f..278be9dd0af 100644 --- a/source/source_cell/test/unitcell_test.cpp +++ b/source/source_cell/test/unitcell_test.cpp @@ -1,7 +1,6 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "source_cell/cal_ux.h" #include "source_cell/read_orb.h" #include "source_cell/read_pp_ucell.h" #include "source_cell/read_stru.h" @@ -43,8 +42,6 @@ Magnetism::~Magnetism() * - remake_cell(): rebuild cell according to its latName * - RemakeCellWarnings * - remake_cell(): deliver warnings when find wrong latname or cos12 - * - JudgeParallel - * - judge_parallel: judge if two vectors a[3] and Vector3 b are parallel * - Index * - set_iat2iait(): set index relations in two arrays of Unitcell: iat2it[nat], iat2ia[nat] * - iat2iait(): depends on the above function, but can find both ia & it from iat @@ -73,8 +70,6 @@ Magnetism::~Magnetism() * - Actually an integrated function to call unitcell::print_cell and Atom::print_Atom * - UpdateVel * - update_vel(const ModuleBase::Vector3* vel_in) - * - CalUx - * - cal_ux(UnitCell& ucell): calculate magnetic moments of cell * - ReadOrbFile * - read_orb_file(): read header part of orbital file * - ReadOrbFileWarning @@ -539,19 +534,6 @@ TEST_F(UcellDeathTest, RemakeCellWarnings) } } -TEST_F(UcellTest, JudgeParallel) -{ - ModuleBase::Vector3 b(1.0, 1.0, 1.0); - double a[3] = {1.0, 1.0, 1.0}; - EXPECT_TRUE(unitcell::judge_parallel(a, b)); - - // the negative case, moved here from MagnetismTest.JudgeParallel when the - // duplicate Magnetism::judge_parallel was deleted - double c[3] = {1.0, 0.0, 0.0}; - ModuleBase::Vector3 d(0.0, 1.0, 0.0); - EXPECT_FALSE(unitcell::judge_parallel(c, d)); -} - TEST_F(UcellTest, Index) { UcellTestPrepare utp = UcellTestLib["C1H2-Index"]; @@ -855,37 +837,6 @@ TEST_F(UcellTest, UpdateVel) delete[] vel_in; } -TEST_F(UcellTest, CalUx1) -{ - UcellTestPrepare utp = UcellTestLib["C1H2-Read"]; - ucell = utp.SetUcellInfo(); - ucell->atoms[0].m_loc_[0].set(0, -1, 0); - ucell->atoms[1].m_loc_[0].set(1, 1, 1); - ucell->atoms[1].m_loc_[1].set(0, 0, 0); - const int nspin = 4; - unitcell::cal_ux(*ucell, nspin); - EXPECT_FALSE(ucell->magnet.lsign_); - EXPECT_DOUBLE_EQ(ucell->magnet.ux_[0], 0); - EXPECT_DOUBLE_EQ(ucell->magnet.ux_[1], -1); - EXPECT_DOUBLE_EQ(ucell->magnet.ux_[2], 0); -} - -TEST_F(UcellTest, CalUx2) -{ - UcellTestPrepare utp = UcellTestLib["C1H2-Read"]; - ucell = utp.SetUcellInfo(); - ucell->atoms[0].m_loc_[0].set(0, 0, 0); - ucell->atoms[1].m_loc_[0].set(1, 1, 1); - ucell->atoms[1].m_loc_[1].set(0, 0, 0); - //(0,0,0) is also parallel to (1,1,1) - const int nspin = 4; - unitcell::cal_ux(*ucell, nspin); - EXPECT_TRUE(ucell->magnet.lsign_); - EXPECT_NEAR(ucell->magnet.ux_[0], 0.57735, 1e-5); - EXPECT_NEAR(ucell->magnet.ux_[1], 0.57735, 1e-5); - EXPECT_NEAR(ucell->magnet.ux_[2], 0.57735, 1e-5); -} - #ifdef __LCAO TEST_F(UcellTest, ReadOrbFile) { From 18fb06b38791628d27f5425663cf1b0cd328fc39 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Tue, 6 Oct 2026 12:23:05 +0800 Subject: [PATCH 05/18] Test: split read_orb tests out of MODULE_CELL_unitcell_test Move ReadOrbFile (kept under the __LCAO guard as before) and ReadOrbFileWarning to the new test_read_orb.cpp / MODULE_CELL_read_orb_test target. read_orb.cpp is already part of the test-only cell_info object library, so no extra source is compiled in. --- source/source_cell/test/CMakeLists.txt | 6 ++ source/source_cell/test/test_read_orb.cpp | 79 +++++++++++++++++++++++ source/source_cell/test/unitcell_test.cpp | 37 ----------- 3 files changed, 85 insertions(+), 37 deletions(-) create mode 100644 source/source_cell/test/test_read_orb.cpp diff --git a/source/source_cell/test/CMakeLists.txt b/source/source_cell/test/CMakeLists.txt index 44fd1466832..fd80397a14a 100644 --- a/source/source_cell/test/CMakeLists.txt +++ b/source/source_cell/test/CMakeLists.txt @@ -182,6 +182,12 @@ AddTest( SOURCES test_cal_ux.cpp ../cal_ux.cpp ) +AddTest( + TARGET MODULE_CELL_read_orb_test + LIBS base device cell_info + SOURCES test_read_orb.cpp +) + AddTest( TARGET MODULE_CELL_print_cell_test LIBS base device cell_info symmetry diff --git a/source/source_cell/test/test_read_orb.cpp b/source/source_cell/test/test_read_orb.cpp new file mode 100644 index 00000000000..1d8281268b0 --- /dev/null +++ b/source/source_cell/test/test_read_orb.cpp @@ -0,0 +1,79 @@ +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include +#include +#include +#include +#include +#include + +#include "source_base/mathzone.h" +#include "source_cell/unitcell.h" +#include "source_cell/read_orb.h" +#include "prepare_unitcell.h" + +// The test-only cell_info object library does not contain magnetism.cpp, +// so the Magnetism constructor/destructor must be provided locally. +Magnetism::Magnetism() +{ + this->tot_mag = 0.0; + this->abs_mag = 0.0; +} +Magnetism::~Magnetism() +{ +} + +/************************************************ + * unit test of read_orb.cpp + ***********************************************/ + +/** + * - Tested Functions: + * - ReadOrbFile + * - read_orb_file(): read header part of orbital file + * - ReadOrbFileWarning + * - read_orb_file(): ABACUS cannot find the ORBITAL file + */ + +class ReadOrbTest : public ::testing::Test +{ + protected: + std::unique_ptr ucell; + std::string output; +}; + +#ifdef __LCAO +TEST_F(ReadOrbTest, ReadOrbFile) +{ + UcellTestPrepare utp = UcellTestLib["C1H2-Read"]; + ucell = utp.SetUcellInfo(); + std::string orb_file = "./support/C.orb"; + std::ofstream ofs_running; + ofs_running.open("tmp_readorbfile"); + bool result = unitcell::read_orb_file(0, orb_file, ofs_running, &(ucell->atoms[0])); + ofs_running << " result=" << result << std::endl; + EXPECT_TRUE(result); + ofs_running.close(); + EXPECT_EQ(ucell->atoms[0].nw, 25); + remove("tmp_readorbfile"); +} +#endif + +TEST_F(ReadOrbTest, ReadOrbFileWarning) +{ + UcellTestPrepare utp = UcellTestLib["C1H2-Read"]; + ucell = utp.SetUcellInfo(); + std::string orb_file = "./support/CC.orb"; + std::ofstream ofs_running; + ofs_running.open("tmp_readorbfilewarning"); + testing::internal::CaptureStdout(); + bool result = unitcell::read_orb_file(0, orb_file, ofs_running, &(ucell->atoms[0])); + output = testing::internal::GetCapturedStdout(); + ofs_running << output << std::endl; + EXPECT_FALSE(result); + EXPECT_THAT(output, testing::HasSubstr("Element index 1")); + EXPECT_THAT(output, testing::HasSubstr("orbital file: ./support/CC.orb")); + ofs_running.close(); + remove("tmp_readorbfilewarning"); +} diff --git a/source/source_cell/test/unitcell_test.cpp b/source/source_cell/test/unitcell_test.cpp index 278be9dd0af..588d62b2dff 100644 --- a/source/source_cell/test/unitcell_test.cpp +++ b/source/source_cell/test/unitcell_test.cpp @@ -1,7 +1,6 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "source_cell/read_orb.h" #include "source_cell/read_pp_ucell.h" #include "source_cell/read_stru.h" #include "source_cell/cell_tools.h" @@ -70,10 +69,6 @@ Magnetism::~Magnetism() * - Actually an integrated function to call unitcell::print_cell and Atom::print_Atom * - UpdateVel * - update_vel(const ModuleBase::Vector3* vel_in) - * - ReadOrbFile - * - read_orb_file(): read header part of orbital file - * - ReadOrbFileWarning - * - read_orb_file(): ABACUS Cannot find the ORBITAL file * - ReadAtomSpecies * - read_atom_species(): a successful case * - ReadAtomSpeciesWarning1 @@ -838,21 +833,6 @@ TEST_F(UcellTest, UpdateVel) } #ifdef __LCAO -TEST_F(UcellTest, ReadOrbFile) -{ - UcellTestPrepare utp = UcellTestLib["C1H2-Read"]; - ucell = utp.SetUcellInfo(); - std::string orb_file = "./support/C.orb"; - std::ofstream ofs_running; - ofs_running.open("tmp_readorbfile"); - bool result = unitcell::read_orb_file(0, orb_file, ofs_running, &(ucell->atoms[0])); - ofs_running << " result=" << result << std::endl; - EXPECT_TRUE(result); - ofs_running.close(); - EXPECT_EQ(ucell->atoms[0].nw, 25); - remove("tmp_readorbfile"); -} - class UcellTestReadStru : public ::testing::Test { protected: @@ -1812,20 +1792,3 @@ TEST_F(UcellTestReadStru, ReadAtomPositionsWarning5) remove("read_atom_positions.warn"); } #endif -TEST_F(UcellTest, ReadOrbFileWarning) -{ - UcellTestPrepare utp = UcellTestLib["C1H2-Read"]; - ucell = utp.SetUcellInfo(); - std::string orb_file = "./support/CC.orb"; - std::ofstream ofs_running; - ofs_running.open("tmp_readorbfilewarning"); - testing::internal::CaptureStdout(); - bool result = unitcell::read_orb_file(0, orb_file, ofs_running, &(ucell->atoms[0])); - output = testing::internal::GetCapturedStdout(); - ofs_running << output << std::endl; - EXPECT_FALSE(result); - EXPECT_THAT(output, testing::HasSubstr("Element index 1")); - EXPECT_THAT(output, testing::HasSubstr("orbital file: ./support/CC.orb")); - ofs_running.close(); - remove("tmp_readorbfilewarning"); -} From cda48b0675dc0d647d3257bdbd697df462c696fb Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Tue, 6 Oct 2026 12:45:01 +0800 Subject: [PATCH 06/18] Test: move compare_atom_labels/print_unitcell_pseudo tests to readpp suite CompareAatomLabel and PrintUnitcellPseudo exercise read_pp_ucell.cpp, so move them from MODULE_CELL_unitcell_test into the existing MODULE_CELL_unitcell_test_readpp target. The rebuilt cell needed by PrintUnitcellPseudo uses the C1H2-Index prepare entry. Drop the now unused read_pp_ucell.h include from unitcell_test.cpp. --- source/source_cell/test/unitcell_test.cpp | 47 ----------------- .../source_cell/test/unitcell_test_readpp.cpp | 51 +++++++++++++++++++ 2 files changed, 51 insertions(+), 47 deletions(-) diff --git a/source/source_cell/test/unitcell_test.cpp b/source/source_cell/test/unitcell_test.cpp index 588d62b2dff..72158df889d 100644 --- a/source/source_cell/test/unitcell_test.cpp +++ b/source/source_cell/test/unitcell_test.cpp @@ -1,7 +1,6 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "source_cell/read_pp_ucell.h" #include "source_cell/read_stru.h" #include "source_cell/cell_tools.h" #include "source_cell/print_cell.h" @@ -65,8 +64,6 @@ Magnetism::~Magnetism() * - PrintTauDirect * - PrintTauCartesian * - print_tau(): print atomic coordinates, magmom and initial velocities - * - PrintUnitcellPseudo - * - Actually an integrated function to call unitcell::print_cell and Atom::print_Atom * - UpdateVel * - update_vel(const ModuleBase::Vector3* vel_in) * - ReadAtomSpecies @@ -218,27 +215,6 @@ TEST_F(UcellTest, Setup) } } -TEST_F(UcellDeathTest, CompareAatomLabel) -{ - std::string stru_label[] - = {"Ag", "Ag", "Ag", "47", "47", "47", "Silver", "Silver", "Silver", "Ag", "Ag", "Ag", "Ag_empty"}; - std::string pseudo_label[] - = {"Ag", "47", "Silver", "Ag", "47", "Silver", "Ag", "47", "Silver", "Ag1", "ag", "ag_locpsp", "Ag"}; - for (int it = 0; it < 12; it++) - { - unitcell::compare_atom_labels(stru_label[it], pseudo_label[it]); - } - stru_label[0] = "Fe"; - pseudo_label[0] = "O"; - std::string atom_label_in_orbtial = "atom label in orbital file "; - std::string mismatch_with_pseudo = " mismatch with pseudo file of "; - testing::internal::CaptureStdout(); - EXPECT_EXIT(unitcell::compare_atom_labels(stru_label[0], pseudo_label[0]), ::testing::ExitedWithCode(1), ""); - output = testing::internal::GetCapturedStdout(); - EXPECT_THAT(output, - testing::HasSubstr(atom_label_in_orbtial + stru_label[0] + mismatch_with_pseudo + pseudo_label[0])); -} - TEST_F(UcellTest, RemakeCell) { std::vector latname_in = {"sc", @@ -740,29 +716,6 @@ TEST_F(UcellTest, PrintCell) remove("printcell.log"); } -TEST_F(UcellTest, PrintUnitcellPseudo) -{ - UcellTestPrepare utp = UcellTestLib["C1H2-Index"]; - ucell = utp.SetUcellInfo(); - std::string fn = "printcell.log"; - unitcell::print_unitcell_pseudo(fn, *ucell); - std::ifstream ifs; - ifs.open("printcell.log"); - std::string str((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); - EXPECT_THAT(str, testing::HasSubstr("latName = bcc")); - EXPECT_THAT(str, testing::HasSubstr("ntype = 2")); - EXPECT_THAT(str, testing::HasSubstr("nat = 3")); - EXPECT_THAT(str, testing::HasSubstr("GGT :")); - EXPECT_THAT(str, testing::HasSubstr("omega = 6748.33")); - EXPECT_THAT(str, testing::HasSubstr("label = C")); - EXPECT_THAT(str, testing::HasSubstr("mass = 12")); - EXPECT_THAT(str, testing::HasSubstr("atom_position(cartesian) Dimension = 1")); - EXPECT_THAT(str, testing::HasSubstr("label = H")); - EXPECT_THAT(str, testing::HasSubstr("mass = 1")); - EXPECT_THAT(str, testing::HasSubstr("atom_position(cartesian) Dimension = 2")); - remove("printcell.log"); -} - // Comments and suggestions on the refactor of UnitCell class // NOTE: PrintSTRU tests have been moved to test_print_cell.cpp diff --git a/source/source_cell/test/unitcell_test_readpp.cpp b/source/source_cell/test/unitcell_test_readpp.cpp index 7c53673e045..abd7bb41aa3 100644 --- a/source/source_cell/test/unitcell_test_readpp.cpp +++ b/source/source_cell/test/unitcell_test_readpp.cpp @@ -7,6 +7,7 @@ #include "source_cell/unitcell.h" #include "source_cell/cal_nelec_nband.h" #include "source_cell/read_pp_ucell.h" +#include #include #include #include "string.h" @@ -83,6 +84,10 @@ Magnetism::~Magnetism() { } * - calculate the total number of valence electrons from psp files * - CalNbands: unitcell::cal_nbands() * - calculate the number of bands + * - CompareAatomLabel + * - compare_atom_labels(): accept equivalent element names and quit on mismatch + * - PrintUnitcellPseudo + * - print_unitcell_pseudo(): print basic cell and atom info to a pseudo log */ class UcellTest : public ::testing::Test { @@ -763,6 +768,52 @@ TEST_F(UcellTest, CalNbandsGaussWarning) EXPECT_THAT(output, testing::HasSubstr("for smearing, num. of bands > num. of occupied bands")); } +TEST_F(UcellDeathTest, CompareAatomLabel) +{ + std::string stru_label[] + = {"Ag", "Ag", "Ag", "47", "47", "47", "Silver", "Silver", "Silver", "Ag", "Ag", "Ag", "Ag_empty"}; + std::string pseudo_label[] + = {"Ag", "47", "Silver", "Ag", "47", "Silver", "Ag", "47", "Silver", "Ag1", "ag", "ag_locpsp", "Ag"}; + for (int it = 0; it < 12; it++) + { + unitcell::compare_atom_labels(stru_label[it], pseudo_label[it]); + } + stru_label[0] = "Fe"; + pseudo_label[0] = "O"; + std::string atom_label_in_orbtial = "atom label in orbital file "; + std::string mismatch_with_pseudo = " mismatch with pseudo file of "; + testing::internal::CaptureStdout(); + EXPECT_EXIT(unitcell::compare_atom_labels(stru_label[0], pseudo_label[0]), ::testing::ExitedWithCode(1), ""); + output = testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, + testing::HasSubstr(atom_label_in_orbtial + stru_label[0] + mismatch_with_pseudo + pseudo_label[0])); +} + +TEST_F(UcellTest, PrintUnitcellPseudo) +{ + // The fixture builds the C1H2-Read cell in SetUp; this test needs the + // C1H2-Index variant, so rebuild the cell here. + UcellTestPrepare utp_index = UcellTestLib["C1H2-Index"]; + ucell = utp_index.SetUcellInfo(); + std::string fn = "printcell.log"; + unitcell::print_unitcell_pseudo(fn, *ucell); + std::ifstream ifs; + ifs.open("printcell.log"); + std::string str((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); + EXPECT_THAT(str, testing::HasSubstr("latName = bcc")); + EXPECT_THAT(str, testing::HasSubstr("ntype = 2")); + EXPECT_THAT(str, testing::HasSubstr("nat = 3")); + EXPECT_THAT(str, testing::HasSubstr("GGT :")); + EXPECT_THAT(str, testing::HasSubstr("omega = 6748.33")); + EXPECT_THAT(str, testing::HasSubstr("label = C")); + EXPECT_THAT(str, testing::HasSubstr("mass = 12")); + EXPECT_THAT(str, testing::HasSubstr("atom_position(cartesian) Dimension = 1")); + EXPECT_THAT(str, testing::HasSubstr("label = H")); + EXPECT_THAT(str, testing::HasSubstr("mass = 1")); + EXPECT_THAT(str, testing::HasSubstr("atom_position(cartesian) Dimension = 2")); + remove("printcell.log"); +} + #ifdef __MPI #include "mpi.h" int main(int argc, char** argv) { From 27ae2da15b403c90de2dddab2ffa09c174817d89 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Tue, 6 Oct 2026 12:55:58 +0800 Subject: [PATCH 07/18] Test: split update_cell tests out of MODULE_CELL_unitcell_test Move RemakeCell, RemakeCellWarnings, PeriodicBoundaryAdjustment2 and UpdateVel to the new test_update_cell.cpp / MODULE_CELL_update_cell_test target. The commented-out PeriodicBoundaryAdjustment1 block moves as well and stays commented. update_cell.cpp is already part of the test-only cell_info library. Drop the now unused update_cell.h include from unitcell_test.cpp. --- source/source_cell/test/CMakeLists.txt | 6 + source/source_cell/test/test_update_cell.cpp | 383 +++++++++++++++++++ source/source_cell/test/unitcell_test.cpp | 341 ----------------- 3 files changed, 389 insertions(+), 341 deletions(-) create mode 100644 source/source_cell/test/test_update_cell.cpp diff --git a/source/source_cell/test/CMakeLists.txt b/source/source_cell/test/CMakeLists.txt index fd80397a14a..b1e0bc66f14 100644 --- a/source/source_cell/test/CMakeLists.txt +++ b/source/source_cell/test/CMakeLists.txt @@ -188,6 +188,12 @@ AddTest( SOURCES test_read_orb.cpp ) +AddTest( + TARGET MODULE_CELL_update_cell_test + LIBS base device cell_info + SOURCES test_update_cell.cpp +) + AddTest( TARGET MODULE_CELL_print_cell_test LIBS base device cell_info symmetry diff --git a/source/source_cell/test/test_update_cell.cpp b/source/source_cell/test/test_update_cell.cpp new file mode 100644 index 00000000000..df888e989c8 --- /dev/null +++ b/source/source_cell/test/test_update_cell.cpp @@ -0,0 +1,383 @@ +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include +#include +#include +#include + +#include "source_base/global_variable.h" +#include "source_base/mathzone.h" +#include "source_cell/unitcell.h" +#include "source_cell/update_cell.h" +#include "prepare_unitcell.h" + +// The test-only cell_info object library does not contain magnetism.cpp, +// so the Magnetism constructor/destructor must be provided locally. +Magnetism::Magnetism() +{ + this->tot_mag = 0.0; + this->abs_mag = 0.0; +} +Magnetism::~Magnetism() +{ +} + +/************************************************ + * unit test of update_cell.cpp + ***********************************************/ + +/** + * - Tested Functions: + * - RemakeCell + * - remake_cell(): rebuild cell according to its latName + * - RemakeCellWarnings + * - remake_cell(): deliver warnings when find wrong latname or cos12 + * - PeriodicBoundaryAdjustment + * - periodic_boundary_adjustment(): move atoms inside the unitcell after relaxation + * - UpdateVel + * - update_vel(const ModuleBase::Vector3* vel_in) + */ + +class UpdateCellTest : public ::testing::Test +{ + protected: + std::unique_ptr ucell{new UnitCell}; + std::string output; +}; + +using UpdateCellDeathTest = UpdateCellTest; + + +TEST_F(UpdateCellTest, RemakeCell) +{ + std::vector latname_in = {"sc", + "fcc", + "bcc", + "hexagonal", + "trigonal", + "st", + "bct", + "so", + "baco", + "fco", + "bco", + "sm", + "bacm", + "triclinic"}; + for (int i = 0; i < latname_in.size(); ++i) + { + ucell->latvec.e11 = 10.0; + ucell->latvec.e12 = 0.00; + ucell->latvec.e13 = 0.00; + ucell->latvec.e21 = 0.00; + ucell->latvec.e22 = 10.0; + ucell->latvec.e23 = 0.00; + ucell->latvec.e31 = 0.00; + ucell->latvec.e32 = 0.00; + ucell->latvec.e33 = 10.0; + ucell->latName = latname_in[i]; + unitcell::remake_cell(ucell->lat); + if (latname_in[i] == "sc") + { + double celldm + = std::sqrt(pow(ucell->latvec.e11, 2) + pow(ucell->latvec.e12, 2) + pow(ucell->latvec.e13, 2)); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, celldm); + } + else if (latname_in[i] == "fcc") + { + double celldm = std::sqrt(pow(ucell->latvec.e11, 2) + pow(ucell->latvec.e12, 2) + pow(ucell->latvec.e13, 2)) + / std::sqrt(2.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, -celldm); + EXPECT_DOUBLE_EQ(ucell->latvec.e12, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e13, celldm); + EXPECT_DOUBLE_EQ(ucell->latvec.e21, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, celldm); + EXPECT_DOUBLE_EQ(ucell->latvec.e23, celldm); + EXPECT_DOUBLE_EQ(ucell->latvec.e31, -celldm); + EXPECT_DOUBLE_EQ(ucell->latvec.e32, celldm); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, 0.0); + } + else if (latname_in[i] == "bcc") + { + double celldm = std::sqrt(pow(ucell->latvec.e11, 2) + pow(ucell->latvec.e12, 2) + pow(ucell->latvec.e13, 2)) + / std::sqrt(3.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, celldm); + EXPECT_DOUBLE_EQ(ucell->latvec.e12, celldm); + EXPECT_DOUBLE_EQ(ucell->latvec.e13, celldm); + EXPECT_DOUBLE_EQ(ucell->latvec.e21, -celldm); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, celldm); + EXPECT_DOUBLE_EQ(ucell->latvec.e23, celldm); + EXPECT_DOUBLE_EQ(ucell->latvec.e31, -celldm); + EXPECT_DOUBLE_EQ(ucell->latvec.e32, -celldm); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, celldm); + } + else if (latname_in[i] == "hexagonal") + { + double celldm1 + = std::sqrt(pow(ucell->latvec.e11, 2) + pow(ucell->latvec.e12, 2) + pow(ucell->latvec.e13, 2)); + double celldm3 + = std::sqrt(pow(ucell->latvec.e31, 2) + pow(ucell->latvec.e32, 2) + pow(ucell->latvec.e33, 2)); + double mathfoo = sqrt(3.0) / 2.0; + EXPECT_DOUBLE_EQ(ucell->latvec.e11, celldm1); + EXPECT_DOUBLE_EQ(ucell->latvec.e12, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e13, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e21, -0.5 * celldm1); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, celldm1 * mathfoo); + EXPECT_DOUBLE_EQ(ucell->latvec.e23, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e31, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e32, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, celldm3); + } + else if (latname_in[i] == "trigonal") + { + double a1 = std::sqrt(pow(ucell->latvec.e11, 2) + pow(ucell->latvec.e12, 2) + pow(ucell->latvec.e13, 2)); + double a2 = std::sqrt(pow(ucell->latvec.e21, 2) + pow(ucell->latvec.e22, 2) + pow(ucell->latvec.e23, 2)); + double a1da2 = (ucell->latvec.e11 * ucell->latvec.e21 + ucell->latvec.e12 * ucell->latvec.e22 + + ucell->latvec.e13 * ucell->latvec.e23); + double cosgamma = a1da2 / (a1 * a2); + double tx = std::sqrt((1.0 - cosgamma) / 2.0); + double ty = std::sqrt((1.0 - cosgamma) / 6.0); + double tz = std::sqrt((1.0 + 2.0 * cosgamma) / 3.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, a1 * tx); + EXPECT_DOUBLE_EQ(ucell->latvec.e12, -a1 * ty); + EXPECT_DOUBLE_EQ(ucell->latvec.e13, a1 * tz); + EXPECT_DOUBLE_EQ(ucell->latvec.e21, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, 2.0 * a1 * ty); + EXPECT_DOUBLE_EQ(ucell->latvec.e23, a1 * tz); + EXPECT_DOUBLE_EQ(ucell->latvec.e31, -a1 * tx); + EXPECT_DOUBLE_EQ(ucell->latvec.e32, -a1 * ty); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, a1 * tz); + } + else if (latname_in[i] == "st") + { + double a1 = std::sqrt(pow(ucell->latvec.e11, 2) + pow(ucell->latvec.e12, 2) + pow(ucell->latvec.e13, 2)); + double a3 = std::sqrt(pow(ucell->latvec.e31, 2) + pow(ucell->latvec.e32, 2) + pow(ucell->latvec.e33, 2)); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, a1); + EXPECT_DOUBLE_EQ(ucell->latvec.e12, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e13, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e21, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, a1); + EXPECT_DOUBLE_EQ(ucell->latvec.e23, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e31, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e32, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, a3); + } + else if (latname_in[i] == "bct") + { + double d1 = std::abs(ucell->latvec.e11); + double d2 = std::abs(ucell->latvec.e13); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, d1); + EXPECT_DOUBLE_EQ(ucell->latvec.e12, -d1); + EXPECT_DOUBLE_EQ(ucell->latvec.e13, d2); + EXPECT_DOUBLE_EQ(ucell->latvec.e21, d1); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, d1); + EXPECT_DOUBLE_EQ(ucell->latvec.e23, d2); + EXPECT_DOUBLE_EQ(ucell->latvec.e31, -d1); + EXPECT_DOUBLE_EQ(ucell->latvec.e32, -d1); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, d2); + } + else if (latname_in[i] == "so") + { + double a1 = std::sqrt(pow(ucell->latvec.e11, 2) + pow(ucell->latvec.e12, 2) + pow(ucell->latvec.e13, 2)); + double a2 = std::sqrt(pow(ucell->latvec.e21, 2) + pow(ucell->latvec.e22, 2) + pow(ucell->latvec.e23, 2)); + double a3 = std::sqrt(pow(ucell->latvec.e31, 2) + pow(ucell->latvec.e32, 2) + pow(ucell->latvec.e33, 2)); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, a1); + EXPECT_DOUBLE_EQ(ucell->latvec.e12, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e13, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e21, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, a2); + EXPECT_DOUBLE_EQ(ucell->latvec.e23, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e31, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e32, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, a3); + } + else if (latname_in[i] == "baco") + { + double d1 = std::abs(ucell->latvec.e11); + double d2 = std::abs(ucell->latvec.e22); + double d3 = std::abs(ucell->latvec.e33); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, d1); + EXPECT_DOUBLE_EQ(ucell->latvec.e12, d2); + EXPECT_DOUBLE_EQ(ucell->latvec.e13, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e21, -d1); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, d2); + EXPECT_DOUBLE_EQ(ucell->latvec.e23, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e31, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e32, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, d3); + } + else if (latname_in[i] == "fco") + { + double d1 = std::abs(ucell->latvec.e11); + double d2 = std::abs(ucell->latvec.e22); + double d3 = std::abs(ucell->latvec.e33); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, d1); + EXPECT_DOUBLE_EQ(ucell->latvec.e12, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e13, d3); + EXPECT_DOUBLE_EQ(ucell->latvec.e21, d1); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, d2); + EXPECT_DOUBLE_EQ(ucell->latvec.e23, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e31, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e32, d2); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, d3); + } + else if (latname_in[i] == "bco") + { + double d1 = std::abs(ucell->latvec.e11); + double d2 = std::abs(ucell->latvec.e22); + double d3 = std::abs(ucell->latvec.e33); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, d1); + EXPECT_DOUBLE_EQ(ucell->latvec.e12, d2); + EXPECT_DOUBLE_EQ(ucell->latvec.e13, d3); + EXPECT_DOUBLE_EQ(ucell->latvec.e21, -d1); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, d2); + EXPECT_DOUBLE_EQ(ucell->latvec.e23, d3); + EXPECT_DOUBLE_EQ(ucell->latvec.e31, -d1); + EXPECT_DOUBLE_EQ(ucell->latvec.e32, -d2); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, d3); + } + else if (latname_in[i] == "sm") + { + double a1 = std::sqrt(pow(ucell->latvec.e11, 2) + pow(ucell->latvec.e12, 2) + pow(ucell->latvec.e13, 2)); + double a2 = std::sqrt(pow(ucell->latvec.e21, 2) + pow(ucell->latvec.e22, 2) + pow(ucell->latvec.e23, 2)); + double a3 = std::sqrt(pow(ucell->latvec.e31, 2) + pow(ucell->latvec.e32, 2) + pow(ucell->latvec.e33, 2)); + double a1da2 = (ucell->latvec.e11 * ucell->latvec.e21 + ucell->latvec.e12 * ucell->latvec.e22 + + ucell->latvec.e13 * ucell->latvec.e23); + double cosgamma = a1da2 / (a1 * a2); + double d1 = a2 * cosgamma; + double d2 = a2 * std::sqrt(1.0 - cosgamma * cosgamma); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, a1); + EXPECT_DOUBLE_EQ(ucell->latvec.e12, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e13, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e21, d1); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, d2); + EXPECT_DOUBLE_EQ(ucell->latvec.e23, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e31, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e32, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, a3); + } + else if (latname_in[i] == "bacm") + { + double d1 = std::abs(ucell->latvec.e11); + double a2 = std::sqrt(pow(ucell->latvec.e21, 2) + pow(ucell->latvec.e22, 2) + pow(ucell->latvec.e23, 2)); + double d3 = std::abs(ucell->latvec.e13); + double cosgamma = ucell->latvec.e21 / a2; + double f1 = a2 * cosgamma; + double f2 = a2 * std::sqrt(1.0 - cosgamma * cosgamma); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, d1); + EXPECT_DOUBLE_EQ(ucell->latvec.e12, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e13, -d3); + EXPECT_DOUBLE_EQ(ucell->latvec.e21, f1); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, f2); + EXPECT_DOUBLE_EQ(ucell->latvec.e23, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e31, d1); + EXPECT_DOUBLE_EQ(ucell->latvec.e32, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, d3); + } + else if (latname_in[i] == "triclinic") + { + double a1 = std::sqrt(pow(ucell->latvec.e11, 2) + pow(ucell->latvec.e12, 2) + pow(ucell->latvec.e13, 2)); + double a2 = std::sqrt(pow(ucell->latvec.e21, 2) + pow(ucell->latvec.e22, 2) + pow(ucell->latvec.e23, 2)); + double a3 = std::sqrt(pow(ucell->latvec.e31, 2) + pow(ucell->latvec.e32, 2) + pow(ucell->latvec.e33, 2)); + double a1da2 = (ucell->latvec.e11 * ucell->latvec.e21 + ucell->latvec.e12 * ucell->latvec.e22 + + ucell->latvec.e13 * ucell->latvec.e23); + double a1da3 = (ucell->latvec.e11 * ucell->latvec.e31 + ucell->latvec.e12 * ucell->latvec.e32 + + ucell->latvec.e13 * ucell->latvec.e33); + double a2da3 = (ucell->latvec.e21 * ucell->latvec.e31 + ucell->latvec.e22 * ucell->latvec.e32 + + ucell->latvec.e23 * ucell->latvec.e33); + double cosgamma = a1da2 / a1 / a2; + double singamma = std::sqrt(1.0 - cosgamma * cosgamma); + double cosbeta = a1da3 / a1 / a3; + double cosalpha = a2da3 / a2 / a3; + double d1 = std::sqrt(1.0 + 2.0 * cosgamma * cosbeta * cosalpha - cosgamma * cosgamma - cosbeta * cosbeta + - cosalpha * cosalpha) + / singamma; + EXPECT_DOUBLE_EQ(ucell->latvec.e11, a1); + EXPECT_DOUBLE_EQ(ucell->latvec.e12, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e13, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e21, a2 * cosgamma); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, a2 * singamma); + EXPECT_DOUBLE_EQ(ucell->latvec.e23, 0.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e31, a3 * cosbeta); + EXPECT_DOUBLE_EQ(ucell->latvec.e32, a3 * (cosalpha - cosbeta * cosgamma) / singamma); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, a3 * d1); + } + } +} + +TEST_F(UpdateCellDeathTest, RemakeCellWarnings) +{ + std::vector latname_in = {"user_defined_lattice", "trigonal", "bacm", "triclinic", "arbitrary"}; + for (int i = 0; i < latname_in.size(); ++i) + { + ucell->latvec.e11 = 10.0; + ucell->latvec.e12 = 0.00; + ucell->latvec.e13 = 0.00; + ucell->latvec.e21 = 10.0; + ucell->latvec.e22 = 0.00; + ucell->latvec.e23 = 0.00; + ucell->latvec.e31 = 0.00; + ucell->latvec.e32 = 0.00; + ucell->latvec.e33 = 10.0; + ucell->latName = latname_in[i]; + testing::internal::CaptureStdout(); + EXPECT_EXIT(unitcell::remake_cell(ucell->lat), ::testing::ExitedWithCode(1), ""); + std::string output = testing::internal::GetCapturedStdout(); + if (latname_in[i] == "user_defined_lattice") + { + EXPECT_THAT(output, testing::HasSubstr("to use fixed_ibrav, latname must be provided")); + } + else if (latname_in[i] == "trigonal" || latname_in[i] == "bacm" || latname_in[i] == "triclinic") + { + EXPECT_THAT(output, testing::HasSubstr("wrong cos12!")); + } + else + { + EXPECT_THAT(output, testing::HasSubstr("latname type not supported!")); + } + } +} + +// mohan comment out 2025-07-14 +/* +TEST_F(UpdateCellDeathTest, PeriodicBoundaryAdjustment1) +{ + UcellTestPrepare utp = UcellTestLib["C1H2-PBA"]; + ucell = utp.SetUcellInfo(); + testing::internal::CaptureStdout(); + EXPECT_EXIT(unitcell::periodic_boundary_adjustment( + ucell->atoms,ucell->latvec,ucell->ntype), + ::testing::ExitedWithCode(1), ""); + std::string output = testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, testing::HasSubstr("the movement of atom is larger than the length of cell")); +} +*/ + +TEST_F(UpdateCellTest, PeriodicBoundaryAdjustment2) +{ + UcellTestPrepare utp = UcellTestLib["C1H2-Index"]; + ucell = utp.SetUcellInfo(); + EXPECT_NO_THROW(unitcell::periodic_boundary_adjustment( + ucell->atoms,ucell->latvec,ucell->ntype)); +} + +TEST_F(UpdateCellTest, UpdateVel) +{ + UcellTestPrepare utp = UcellTestLib["C1H2-Index"]; + ucell = utp.SetUcellInfo(); + ModuleBase::Vector3* vel_in = new ModuleBase::Vector3[ucell->nat]; + for (int iat = 0; iat < ucell->nat; ++iat) + { + vel_in[iat].set(iat * 0.1, iat * 0.1, iat * 0.1); + } + unitcell::update_vel(vel_in,ucell->ntype,ucell->nat,ucell->atoms); + for (int iat = 0; iat < ucell->nat; ++iat) + { + EXPECT_DOUBLE_EQ(vel_in[iat].x, 0.1 * iat); + EXPECT_DOUBLE_EQ(vel_in[iat].y, 0.1 * iat); + EXPECT_DOUBLE_EQ(vel_in[iat].z, 0.1 * iat); + } + delete[] vel_in; +} + diff --git a/source/source_cell/test/unitcell_test.cpp b/source/source_cell/test/unitcell_test.cpp index 72158df889d..ef54b87a9b8 100644 --- a/source/source_cell/test/unitcell_test.cpp +++ b/source/source_cell/test/unitcell_test.cpp @@ -9,7 +9,6 @@ #include "source_base/global_variable.h" #include "source_base/mathzone.h" #include "prepare_unitcell.h" -#include "source_cell/update_cell.h" #include "source_cell/read_stru.h" #include #include @@ -36,10 +35,6 @@ Magnetism::~Magnetism() * - Setup: * - setup_from_input(): to set latname, ntype, lmaxmax, init_vel, and lc * - if_cell_can_change(): judge if any lattice vector can change - * - RemakeCell - * - remake_cell(): rebuild cell according to its latName - * - RemakeCellWarnings - * - remake_cell(): deliver warnings when find wrong latname or cos12 * - Index * - set_iat2iait(): set index relations in two arrays of Unitcell: iat2it[nat], iat2ia[nat] * - iat2iait(): depends on the above function, but can find both ia & it from iat @@ -55,8 +50,6 @@ Magnetism::~Magnetism() * - check_tau(): check if any "two atoms are too close" * - SelectiveDynamics * - if_atoms_can_move():it is true if any coordinates of any atom can move, i.e. mbl = 1 - * - PeriodicBoundaryAdjustment - * - periodic_boundary_adjustment(): move atoms inside the unitcell after relaxation * - PrintCell * - print_cell(ofs): print basic cell info into ofs * - PrintSTRU @@ -64,8 +57,6 @@ Magnetism::~Magnetism() * - PrintTauDirect * - PrintTauCartesian * - print_tau(): print atomic coordinates, magmom and initial velocities - * - UpdateVel - * - update_vel(const ModuleBase::Vector3* vel_in) * - ReadAtomSpecies * - read_atom_species(): a successful case * - ReadAtomSpeciesWarning1 @@ -215,296 +206,6 @@ TEST_F(UcellTest, Setup) } } -TEST_F(UcellTest, RemakeCell) -{ - std::vector latname_in = {"sc", - "fcc", - "bcc", - "hexagonal", - "trigonal", - "st", - "bct", - "so", - "baco", - "fco", - "bco", - "sm", - "bacm", - "triclinic"}; - for (int i = 0; i < latname_in.size(); ++i) - { - ucell->latvec.e11 = 10.0; - ucell->latvec.e12 = 0.00; - ucell->latvec.e13 = 0.00; - ucell->latvec.e21 = 0.00; - ucell->latvec.e22 = 10.0; - ucell->latvec.e23 = 0.00; - ucell->latvec.e31 = 0.00; - ucell->latvec.e32 = 0.00; - ucell->latvec.e33 = 10.0; - ucell->latName = latname_in[i]; - unitcell::remake_cell(ucell->lat); - if (latname_in[i] == "sc") - { - double celldm - = std::sqrt(pow(ucell->latvec.e11, 2) + pow(ucell->latvec.e12, 2) + pow(ucell->latvec.e13, 2)); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, celldm); - } - else if (latname_in[i] == "fcc") - { - double celldm = std::sqrt(pow(ucell->latvec.e11, 2) + pow(ucell->latvec.e12, 2) + pow(ucell->latvec.e13, 2)) - / std::sqrt(2.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, -celldm); - EXPECT_DOUBLE_EQ(ucell->latvec.e12, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e13, celldm); - EXPECT_DOUBLE_EQ(ucell->latvec.e21, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, celldm); - EXPECT_DOUBLE_EQ(ucell->latvec.e23, celldm); - EXPECT_DOUBLE_EQ(ucell->latvec.e31, -celldm); - EXPECT_DOUBLE_EQ(ucell->latvec.e32, celldm); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, 0.0); - } - else if (latname_in[i] == "bcc") - { - double celldm = std::sqrt(pow(ucell->latvec.e11, 2) + pow(ucell->latvec.e12, 2) + pow(ucell->latvec.e13, 2)) - / std::sqrt(3.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, celldm); - EXPECT_DOUBLE_EQ(ucell->latvec.e12, celldm); - EXPECT_DOUBLE_EQ(ucell->latvec.e13, celldm); - EXPECT_DOUBLE_EQ(ucell->latvec.e21, -celldm); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, celldm); - EXPECT_DOUBLE_EQ(ucell->latvec.e23, celldm); - EXPECT_DOUBLE_EQ(ucell->latvec.e31, -celldm); - EXPECT_DOUBLE_EQ(ucell->latvec.e32, -celldm); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, celldm); - } - else if (latname_in[i] == "hexagonal") - { - double celldm1 - = std::sqrt(pow(ucell->latvec.e11, 2) + pow(ucell->latvec.e12, 2) + pow(ucell->latvec.e13, 2)); - double celldm3 - = std::sqrt(pow(ucell->latvec.e31, 2) + pow(ucell->latvec.e32, 2) + pow(ucell->latvec.e33, 2)); - double mathfoo = sqrt(3.0) / 2.0; - EXPECT_DOUBLE_EQ(ucell->latvec.e11, celldm1); - EXPECT_DOUBLE_EQ(ucell->latvec.e12, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e13, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e21, -0.5 * celldm1); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, celldm1 * mathfoo); - EXPECT_DOUBLE_EQ(ucell->latvec.e23, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e31, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e32, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, celldm3); - } - else if (latname_in[i] == "trigonal") - { - double a1 = std::sqrt(pow(ucell->latvec.e11, 2) + pow(ucell->latvec.e12, 2) + pow(ucell->latvec.e13, 2)); - double a2 = std::sqrt(pow(ucell->latvec.e21, 2) + pow(ucell->latvec.e22, 2) + pow(ucell->latvec.e23, 2)); - double a1da2 = (ucell->latvec.e11 * ucell->latvec.e21 + ucell->latvec.e12 * ucell->latvec.e22 - + ucell->latvec.e13 * ucell->latvec.e23); - double cosgamma = a1da2 / (a1 * a2); - double tx = std::sqrt((1.0 - cosgamma) / 2.0); - double ty = std::sqrt((1.0 - cosgamma) / 6.0); - double tz = std::sqrt((1.0 + 2.0 * cosgamma) / 3.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, a1 * tx); - EXPECT_DOUBLE_EQ(ucell->latvec.e12, -a1 * ty); - EXPECT_DOUBLE_EQ(ucell->latvec.e13, a1 * tz); - EXPECT_DOUBLE_EQ(ucell->latvec.e21, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, 2.0 * a1 * ty); - EXPECT_DOUBLE_EQ(ucell->latvec.e23, a1 * tz); - EXPECT_DOUBLE_EQ(ucell->latvec.e31, -a1 * tx); - EXPECT_DOUBLE_EQ(ucell->latvec.e32, -a1 * ty); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, a1 * tz); - } - else if (latname_in[i] == "st") - { - double a1 = std::sqrt(pow(ucell->latvec.e11, 2) + pow(ucell->latvec.e12, 2) + pow(ucell->latvec.e13, 2)); - double a3 = std::sqrt(pow(ucell->latvec.e31, 2) + pow(ucell->latvec.e32, 2) + pow(ucell->latvec.e33, 2)); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, a1); - EXPECT_DOUBLE_EQ(ucell->latvec.e12, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e13, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e21, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, a1); - EXPECT_DOUBLE_EQ(ucell->latvec.e23, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e31, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e32, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, a3); - } - else if (latname_in[i] == "bct") - { - double d1 = std::abs(ucell->latvec.e11); - double d2 = std::abs(ucell->latvec.e13); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, d1); - EXPECT_DOUBLE_EQ(ucell->latvec.e12, -d1); - EXPECT_DOUBLE_EQ(ucell->latvec.e13, d2); - EXPECT_DOUBLE_EQ(ucell->latvec.e21, d1); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, d1); - EXPECT_DOUBLE_EQ(ucell->latvec.e23, d2); - EXPECT_DOUBLE_EQ(ucell->latvec.e31, -d1); - EXPECT_DOUBLE_EQ(ucell->latvec.e32, -d1); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, d2); - } - else if (latname_in[i] == "so") - { - double a1 = std::sqrt(pow(ucell->latvec.e11, 2) + pow(ucell->latvec.e12, 2) + pow(ucell->latvec.e13, 2)); - double a2 = std::sqrt(pow(ucell->latvec.e21, 2) + pow(ucell->latvec.e22, 2) + pow(ucell->latvec.e23, 2)); - double a3 = std::sqrt(pow(ucell->latvec.e31, 2) + pow(ucell->latvec.e32, 2) + pow(ucell->latvec.e33, 2)); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, a1); - EXPECT_DOUBLE_EQ(ucell->latvec.e12, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e13, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e21, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, a2); - EXPECT_DOUBLE_EQ(ucell->latvec.e23, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e31, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e32, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, a3); - } - else if (latname_in[i] == "baco") - { - double d1 = std::abs(ucell->latvec.e11); - double d2 = std::abs(ucell->latvec.e22); - double d3 = std::abs(ucell->latvec.e33); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, d1); - EXPECT_DOUBLE_EQ(ucell->latvec.e12, d2); - EXPECT_DOUBLE_EQ(ucell->latvec.e13, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e21, -d1); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, d2); - EXPECT_DOUBLE_EQ(ucell->latvec.e23, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e31, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e32, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, d3); - } - else if (latname_in[i] == "fco") - { - double d1 = std::abs(ucell->latvec.e11); - double d2 = std::abs(ucell->latvec.e22); - double d3 = std::abs(ucell->latvec.e33); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, d1); - EXPECT_DOUBLE_EQ(ucell->latvec.e12, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e13, d3); - EXPECT_DOUBLE_EQ(ucell->latvec.e21, d1); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, d2); - EXPECT_DOUBLE_EQ(ucell->latvec.e23, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e31, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e32, d2); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, d3); - } - else if (latname_in[i] == "bco") - { - double d1 = std::abs(ucell->latvec.e11); - double d2 = std::abs(ucell->latvec.e22); - double d3 = std::abs(ucell->latvec.e33); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, d1); - EXPECT_DOUBLE_EQ(ucell->latvec.e12, d2); - EXPECT_DOUBLE_EQ(ucell->latvec.e13, d3); - EXPECT_DOUBLE_EQ(ucell->latvec.e21, -d1); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, d2); - EXPECT_DOUBLE_EQ(ucell->latvec.e23, d3); - EXPECT_DOUBLE_EQ(ucell->latvec.e31, -d1); - EXPECT_DOUBLE_EQ(ucell->latvec.e32, -d2); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, d3); - } - else if (latname_in[i] == "sm") - { - double a1 = std::sqrt(pow(ucell->latvec.e11, 2) + pow(ucell->latvec.e12, 2) + pow(ucell->latvec.e13, 2)); - double a2 = std::sqrt(pow(ucell->latvec.e21, 2) + pow(ucell->latvec.e22, 2) + pow(ucell->latvec.e23, 2)); - double a3 = std::sqrt(pow(ucell->latvec.e31, 2) + pow(ucell->latvec.e32, 2) + pow(ucell->latvec.e33, 2)); - double a1da2 = (ucell->latvec.e11 * ucell->latvec.e21 + ucell->latvec.e12 * ucell->latvec.e22 - + ucell->latvec.e13 * ucell->latvec.e23); - double cosgamma = a1da2 / (a1 * a2); - double d1 = a2 * cosgamma; - double d2 = a2 * std::sqrt(1.0 - cosgamma * cosgamma); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, a1); - EXPECT_DOUBLE_EQ(ucell->latvec.e12, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e13, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e21, d1); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, d2); - EXPECT_DOUBLE_EQ(ucell->latvec.e23, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e31, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e32, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, a3); - } - else if (latname_in[i] == "bacm") - { - double d1 = std::abs(ucell->latvec.e11); - double a2 = std::sqrt(pow(ucell->latvec.e21, 2) + pow(ucell->latvec.e22, 2) + pow(ucell->latvec.e23, 2)); - double d3 = std::abs(ucell->latvec.e13); - double cosgamma = ucell->latvec.e21 / a2; - double f1 = a2 * cosgamma; - double f2 = a2 * std::sqrt(1.0 - cosgamma * cosgamma); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, d1); - EXPECT_DOUBLE_EQ(ucell->latvec.e12, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e13, -d3); - EXPECT_DOUBLE_EQ(ucell->latvec.e21, f1); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, f2); - EXPECT_DOUBLE_EQ(ucell->latvec.e23, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e31, d1); - EXPECT_DOUBLE_EQ(ucell->latvec.e32, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, d3); - } - else if (latname_in[i] == "triclinic") - { - double a1 = std::sqrt(pow(ucell->latvec.e11, 2) + pow(ucell->latvec.e12, 2) + pow(ucell->latvec.e13, 2)); - double a2 = std::sqrt(pow(ucell->latvec.e21, 2) + pow(ucell->latvec.e22, 2) + pow(ucell->latvec.e23, 2)); - double a3 = std::sqrt(pow(ucell->latvec.e31, 2) + pow(ucell->latvec.e32, 2) + pow(ucell->latvec.e33, 2)); - double a1da2 = (ucell->latvec.e11 * ucell->latvec.e21 + ucell->latvec.e12 * ucell->latvec.e22 - + ucell->latvec.e13 * ucell->latvec.e23); - double a1da3 = (ucell->latvec.e11 * ucell->latvec.e31 + ucell->latvec.e12 * ucell->latvec.e32 - + ucell->latvec.e13 * ucell->latvec.e33); - double a2da3 = (ucell->latvec.e21 * ucell->latvec.e31 + ucell->latvec.e22 * ucell->latvec.e32 - + ucell->latvec.e23 * ucell->latvec.e33); - double cosgamma = a1da2 / a1 / a2; - double singamma = std::sqrt(1.0 - cosgamma * cosgamma); - double cosbeta = a1da3 / a1 / a3; - double cosalpha = a2da3 / a2 / a3; - double d1 = std::sqrt(1.0 + 2.0 * cosgamma * cosbeta * cosalpha - cosgamma * cosgamma - cosbeta * cosbeta - - cosalpha * cosalpha) - / singamma; - EXPECT_DOUBLE_EQ(ucell->latvec.e11, a1); - EXPECT_DOUBLE_EQ(ucell->latvec.e12, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e13, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e21, a2 * cosgamma); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, a2 * singamma); - EXPECT_DOUBLE_EQ(ucell->latvec.e23, 0.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e31, a3 * cosbeta); - EXPECT_DOUBLE_EQ(ucell->latvec.e32, a3 * (cosalpha - cosbeta * cosgamma) / singamma); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, a3 * d1); - } - } -} - -TEST_F(UcellDeathTest, RemakeCellWarnings) -{ - std::vector latname_in = {"user_defined_lattice", "trigonal", "bacm", "triclinic", "arbitrary"}; - for (int i = 0; i < latname_in.size(); ++i) - { - ucell->latvec.e11 = 10.0; - ucell->latvec.e12 = 0.00; - ucell->latvec.e13 = 0.00; - ucell->latvec.e21 = 10.0; - ucell->latvec.e22 = 0.00; - ucell->latvec.e23 = 0.00; - ucell->latvec.e31 = 0.00; - ucell->latvec.e32 = 0.00; - ucell->latvec.e33 = 10.0; - ucell->latName = latname_in[i]; - testing::internal::CaptureStdout(); - EXPECT_EXIT(unitcell::remake_cell(ucell->lat), ::testing::ExitedWithCode(1), ""); - std::string output = testing::internal::GetCapturedStdout(); - if (latname_in[i] == "user_defined_lattice") - { - EXPECT_THAT(output, testing::HasSubstr("to use fixed_ibrav, latname must be provided")); - } - else if (latname_in[i] == "trigonal" || latname_in[i] == "bacm" || latname_in[i] == "triclinic") - { - EXPECT_THAT(output, testing::HasSubstr("wrong cos12!")); - } - else - { - EXPECT_THAT(output, testing::HasSubstr("latname type not supported!")); - } - } -} - TEST_F(UcellTest, Index) { UcellTestPrepare utp = UcellTestLib["C1H2-Index"]; @@ -674,29 +375,6 @@ TEST_F(UcellTest, SelectiveDynamics) } -// mohan comment out 2025-07-14 -/* -TEST_F(UcellDeathTest, PeriodicBoundaryAdjustment1) -{ - UcellTestPrepare utp = UcellTestLib["C1H2-PBA"]; - ucell = utp.SetUcellInfo(); - testing::internal::CaptureStdout(); - EXPECT_EXIT(unitcell::periodic_boundary_adjustment( - ucell->atoms,ucell->latvec,ucell->ntype), - ::testing::ExitedWithCode(1), ""); - std::string output = testing::internal::GetCapturedStdout(); - EXPECT_THAT(output, testing::HasSubstr("the movement of atom is larger than the length of cell")); -} -*/ - -TEST_F(UcellTest, PeriodicBoundaryAdjustment2) -{ - UcellTestPrepare utp = UcellTestLib["C1H2-Index"]; - ucell = utp.SetUcellInfo(); - EXPECT_NO_THROW(unitcell::periodic_boundary_adjustment( - ucell->atoms,ucell->latvec,ucell->ntype)); -} - TEST_F(UcellTest, PrintCell) { UcellTestPrepare utp = UcellTestLib["C1H2-Index"]; @@ -766,25 +444,6 @@ TEST_F(UcellTest, PrintTauCartesian) remove("print_tau_Cartesian"); } -TEST_F(UcellTest, UpdateVel) -{ - UcellTestPrepare utp = UcellTestLib["C1H2-Index"]; - ucell = utp.SetUcellInfo(); - ModuleBase::Vector3* vel_in = new ModuleBase::Vector3[ucell->nat]; - for (int iat = 0; iat < ucell->nat; ++iat) - { - vel_in[iat].set(iat * 0.1, iat * 0.1, iat * 0.1); - } - unitcell::update_vel(vel_in,ucell->ntype,ucell->nat,ucell->atoms); - for (int iat = 0; iat < ucell->nat; ++iat) - { - EXPECT_DOUBLE_EQ(vel_in[iat].x, 0.1 * iat); - EXPECT_DOUBLE_EQ(vel_in[iat].y, 0.1 * iat); - EXPECT_DOUBLE_EQ(vel_in[iat].z, 0.1 * iat); - } - delete[] vel_in; -} - #ifdef __LCAO class UcellTestReadStru : public ::testing::Test { From 974ba84649ef63c51e10911b87d3c3c45beece0c Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Tue, 6 Oct 2026 13:18:52 +0800 Subject: [PATCH 08/18] Test: move print_cell/print_tau tests into MODULE_CELL_print_cell_test PrintCell, PrintTauDirect and PrintTauCartesian exercise print_cell.cpp, the same source as the PrintSTRU tests already living in test_print_cell.cpp. Move them into that file/target and reuse the PrintCellTest fixture. Drop the now unused print_cell.h include and the stale PrintSTRU navigation comment from unitcell_test.cpp. --- source/source_cell/test/test_print_cell.cpp | 65 +++++++++++++++++ source/source_cell/test/unitcell_test.cpp | 77 --------------------- 2 files changed, 65 insertions(+), 77 deletions(-) diff --git a/source/source_cell/test/test_print_cell.cpp b/source/source_cell/test/test_print_cell.cpp index 9c6de5e94da..d9277fb4ae8 100644 --- a/source/source_cell/test/test_print_cell.cpp +++ b/source/source_cell/test/test_print_cell.cpp @@ -280,3 +280,68 @@ TEST_F(PrintCellTest, PrintSTRU_with_force) ifs.close(); remove(fn.c_str()); } + +TEST_F(PrintCellTest, PrintCell) +{ + UcellTestPrepare utp = UcellTestLib["C1H2-Index"]; + ucell = utp.SetUcellInfo(); + std::ofstream ofs; + ofs.open("printcell.log"); + unitcell::print_cell(*ucell, ofs); + ofs.close(); + std::ifstream ifs; + ifs.open("printcell.log"); + std::string str((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); + EXPECT_THAT(str, testing::HasSubstr("latName = bcc")); + EXPECT_THAT(str, testing::HasSubstr("ntype = 2")); + EXPECT_THAT(str, testing::HasSubstr("nat = 3")); + EXPECT_THAT(str, testing::HasSubstr("GGT :")); + EXPECT_THAT(str, testing::HasSubstr("omega = 6748.33")); + remove("printcell.log"); +} +TEST_F(PrintCellTest, PrintTauDirect) +{ + UcellTestPrepare utp = UcellTestLib["C1H2-Index"]; + ucell = utp.SetUcellInfo(); + EXPECT_EQ(ucell->Coordinate, "Direct"); + + // open a file + std::ofstream ofs("print_tau_direct"); + unitcell::print_tau(ucell->atoms,ucell->Coordinate,ucell->ntype,ucell->lat0,ofs); + ofs.close(); + + // readin the data + std::ifstream ifs; + ifs.open("print_tau_direct"); + std::string str((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); + EXPECT_THAT(str, testing::HasSubstr("DIRECT COORDINATES")); + EXPECT_THAT(str, testing::HasSubstr(" C 0.100000000000 0.100000000000 0.100000000000 0.0000")); + EXPECT_THAT(str, testing::HasSubstr(" H 0.150000000000 0.150000000000 0.150000000000 0.0000")); + ifs.close(); + + remove("print_tau_direct"); +} + +TEST_F(PrintCellTest, PrintTauCartesian) +{ + UcellTestPrepare utp = UcellTestLib["C1H2-Cartesian"]; + ucell = utp.SetUcellInfo(); + EXPECT_EQ(ucell->Coordinate, "Cartesian"); + + // open a file + std::ofstream ofs("print_tau_Cartesian"); + unitcell::print_tau(ucell->atoms,ucell->Coordinate,ucell->ntype,ucell->lat0,ofs); + ofs.close(); + + // readin the data + std::ifstream ifs; + ifs.open("print_tau_Cartesian"); + std::string str((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); + EXPECT_THAT(str, testing::HasSubstr("CARTESIAN COORDINATES")); + EXPECT_THAT(str, testing::HasSubstr(" C 1.000000000000 1.000000000000 1.000000000000 0.0000")); + EXPECT_THAT(str, testing::HasSubstr(" H 1.500000000000 1.500000000000 1.500000000000 0.0000")); + ifs.close(); + + // remove the file + remove("print_tau_Cartesian"); +} diff --git a/source/source_cell/test/unitcell_test.cpp b/source/source_cell/test/unitcell_test.cpp index ef54b87a9b8..c5013bf2676 100644 --- a/source/source_cell/test/unitcell_test.cpp +++ b/source/source_cell/test/unitcell_test.cpp @@ -3,7 +3,6 @@ #include "source_cell/read_stru.h" #include "source_cell/cell_tools.h" -#include "source_cell/print_cell.h" #include "memory" #include "source_cell/read_stru.h" #include "source_base/global_variable.h" @@ -50,13 +49,6 @@ Magnetism::~Magnetism() * - check_tau(): check if any "two atoms are too close" * - SelectiveDynamics * - if_atoms_can_move():it is true if any coordinates of any atom can move, i.e. mbl = 1 - * - PrintCell - * - print_cell(ofs): print basic cell info into ofs - * - PrintSTRU - * - print_stru_file(): print STRU file of ABACUS - * - PrintTauDirect - * - PrintTauCartesian - * - print_tau(): print atomic coordinates, magmom and initial velocities * - ReadAtomSpecies * - read_atom_species(): a successful case * - ReadAtomSpeciesWarning1 @@ -375,75 +367,6 @@ TEST_F(UcellTest, SelectiveDynamics) } -TEST_F(UcellTest, PrintCell) -{ - UcellTestPrepare utp = UcellTestLib["C1H2-Index"]; - ucell = utp.SetUcellInfo(); - std::ofstream ofs; - ofs.open("printcell.log"); - unitcell::print_cell(*ucell, ofs); - ofs.close(); - std::ifstream ifs; - ifs.open("printcell.log"); - std::string str((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); - EXPECT_THAT(str, testing::HasSubstr("latName = bcc")); - EXPECT_THAT(str, testing::HasSubstr("ntype = 2")); - EXPECT_THAT(str, testing::HasSubstr("nat = 3")); - EXPECT_THAT(str, testing::HasSubstr("GGT :")); - EXPECT_THAT(str, testing::HasSubstr("omega = 6748.33")); - remove("printcell.log"); -} - -// Comments and suggestions on the refactor of UnitCell class -// NOTE: PrintSTRU tests have been moved to test_print_cell.cpp - -TEST_F(UcellTest, PrintTauDirect) -{ - UcellTestPrepare utp = UcellTestLib["C1H2-Index"]; - ucell = utp.SetUcellInfo(); - EXPECT_EQ(ucell->Coordinate, "Direct"); - - // open a file - std::ofstream ofs("print_tau_direct"); - unitcell::print_tau(ucell->atoms,ucell->Coordinate,ucell->ntype,ucell->lat0,ofs); - ofs.close(); - - // readin the data - std::ifstream ifs; - ifs.open("print_tau_direct"); - std::string str((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); - EXPECT_THAT(str, testing::HasSubstr("DIRECT COORDINATES")); - EXPECT_THAT(str, testing::HasSubstr(" C 0.100000000000 0.100000000000 0.100000000000 0.0000")); - EXPECT_THAT(str, testing::HasSubstr(" H 0.150000000000 0.150000000000 0.150000000000 0.0000")); - ifs.close(); - - remove("print_tau_direct"); -} - -TEST_F(UcellTest, PrintTauCartesian) -{ - UcellTestPrepare utp = UcellTestLib["C1H2-Cartesian"]; - ucell = utp.SetUcellInfo(); - EXPECT_EQ(ucell->Coordinate, "Cartesian"); - - // open a file - std::ofstream ofs("print_tau_Cartesian"); - unitcell::print_tau(ucell->atoms,ucell->Coordinate,ucell->ntype,ucell->lat0,ofs); - ofs.close(); - - // readin the data - std::ifstream ifs; - ifs.open("print_tau_Cartesian"); - std::string str((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); - EXPECT_THAT(str, testing::HasSubstr("CARTESIAN COORDINATES")); - EXPECT_THAT(str, testing::HasSubstr(" C 1.000000000000 1.000000000000 1.000000000000 0.0000")); - EXPECT_THAT(str, testing::HasSubstr(" H 1.500000000000 1.500000000000 1.500000000000 0.0000")); - ifs.close(); - - // remove the file - remove("print_tau_Cartesian"); -} - #ifdef __LCAO class UcellTestReadStru : public ::testing::Test { From 016e69e66ea5125b348bf0da653177640550e1f6 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Tue, 6 Oct 2026 14:18:02 +0800 Subject: [PATCH 09/18] Test: split cell_tools free-function tests out of MODULE_CELL_unitcell_test Add test_cell_tools.cpp / MODULE_CELL_cell_tools_test for the unitcell:: free functions in cell_tools.cpp: - new IfCellCanChange truth-table case over the lattice-axis flags - vector get_atomCounts/get_lnchiCounts cases split out of the mixed member/free GetAtomCounts and GetLnchiCounts tests (the member get_atom_Counts/get_lnchi_Counts map assertions stay in unitcell_test) - SelectiveDynamics (if_atoms_can_move) moved verbatim Setup keeps only the setup_from_input member assertions; its if_cell_can_change checks are now covered by the dedicated truth table. Drop the unused cell_tools.h include from unitcell_test.cpp. --- source/source_cell/test/CMakeLists.txt | 6 ++ source/source_cell/test/test_cell_tools.cpp | 91 +++++++++++++++++++++ source/source_cell/test/unitcell_test.cpp | 34 +------- 3 files changed, 98 insertions(+), 33 deletions(-) create mode 100644 source/source_cell/test/test_cell_tools.cpp diff --git a/source/source_cell/test/CMakeLists.txt b/source/source_cell/test/CMakeLists.txt index b1e0bc66f14..4a99c48dd03 100644 --- a/source/source_cell/test/CMakeLists.txt +++ b/source/source_cell/test/CMakeLists.txt @@ -194,6 +194,12 @@ AddTest( SOURCES test_update_cell.cpp ) +AddTest( + TARGET MODULE_CELL_cell_tools_test + LIBS base device cell_info + SOURCES test_cell_tools.cpp +) + AddTest( TARGET MODULE_CELL_print_cell_test LIBS base device cell_info symmetry diff --git a/source/source_cell/test/test_cell_tools.cpp b/source/source_cell/test/test_cell_tools.cpp new file mode 100644 index 00000000000..267849f2b57 --- /dev/null +++ b/source/source_cell/test/test_cell_tools.cpp @@ -0,0 +1,91 @@ +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include +#include +#include + +#include "source_base/global_variable.h" +#include "source_base/mathzone.h" +#include "source_cell/unitcell.h" +#include "source_cell/cell_tools.h" +#include "prepare_unitcell.h" + +// The test-only cell_info object library does not contain magnetism.cpp, +// so the Magnetism constructor/destructor must be provided locally. +Magnetism::Magnetism() +{ + this->tot_mag = 0.0; + this->abs_mag = 0.0; +} +Magnetism::~Magnetism() +{ +} + +/************************************************ + * unit test of cell_tools.cpp + ***********************************************/ + +/** + * - Tested Functions: + * - IfCellCanChange + * - if_cell_can_change(): truth table over the three lattice-axis flags + * - GetAtomCounts + * - get_atomCounts(): number of atoms per type as a vector + * - GetLnchiCounts + * - get_lnchiCounts(): number of chi functions per L per type + * - SelectiveDynamics + * - if_atoms_can_move(): true if any atom has a movable coordinate + */ + +class CellToolsTest : public ::testing::Test +{ + protected: + std::unique_ptr ucell{new UnitCell}; +}; + +TEST_F(CellToolsTest, IfCellCanChange) +{ + // Mirror the fixed_axes -> lat_axis_free mapping produced by + // UnitCell::setup_from_input: the cell can change whenever at least one + // lattice axis is free; only "abc" (all axes fixed) returns false. + std::vector> axes_free = { + {1, 1, 1}, {0, 1, 1}, {1, 0, 1}, {1, 1, 0}, + {0, 0, 1}, {0, 1, 0}, {1, 0, 0}, {0, 0, 0}}; + for (int i = 0; i < 7; ++i) + { + EXPECT_TRUE(unitcell::if_cell_can_change(axes_free[i])); + } + EXPECT_FALSE(unitcell::if_cell_can_change(axes_free[7])); +} + +TEST_F(CellToolsTest, GetAtomCounts) +{ + UcellTestPrepare utp = UcellTestLib["C1H2-Index"]; + ucell = utp.SetUcellInfo(); + ucell->set_iat2itia(); + std::vector atomCounts = unitcell::get_atomCounts(ucell->atoms, ucell->ntype); + EXPECT_EQ(atomCounts[0], 1); + EXPECT_EQ(atomCounts[1], 2); +} + +TEST_F(CellToolsTest, GetLnchiCounts) +{ + UcellTestPrepare utp = UcellTestLib["C1H2-Index"]; + ucell = utp.SetUcellInfo(); + ucell->set_iat2itia(); + std::vector> lnchiCounts = unitcell::get_lnchiCounts(ucell->atoms, ucell->ntype); + EXPECT_EQ(lnchiCounts[0][0], 1); + EXPECT_EQ(lnchiCounts[0][1], 1); + EXPECT_EQ(lnchiCounts[0][2], 1); + EXPECT_EQ(lnchiCounts[1][0], 1); + EXPECT_EQ(lnchiCounts[1][1], 1); + EXPECT_EQ(lnchiCounts[1][2], 1); +} + +TEST_F(CellToolsTest, SelectiveDynamics) +{ + UcellTestPrepare utp = UcellTestLib["C1H2-SD"]; + ucell = utp.SetUcellInfo(); + EXPECT_TRUE(unitcell::if_atoms_can_move(ucell->atoms, ucell->ntype)); +} diff --git a/source/source_cell/test/unitcell_test.cpp b/source/source_cell/test/unitcell_test.cpp index c5013bf2676..a3418c8bb3e 100644 --- a/source/source_cell/test/unitcell_test.cpp +++ b/source/source_cell/test/unitcell_test.cpp @@ -2,7 +2,6 @@ #include "gtest/gtest.h" #include "source_cell/read_stru.h" -#include "source_cell/cell_tools.h" #include "memory" #include "source_cell/read_stru.h" #include "source_base/global_variable.h" @@ -33,22 +32,19 @@ Magnetism::~Magnetism() * - UnitCell() and ~UnitCell() * - Setup: * - setup_from_input(): to set latname, ntype, lmaxmax, init_vel, and lc - * - if_cell_can_change(): judge if any lattice vector can change * - Index * - set_iat2iait(): set index relations in two arrays of Unitcell: iat2it[nat], iat2ia[nat] * - iat2iait(): depends on the above function, but can find both ia & it from iat * - ijat2iaitjajt(): find ia, it, ja, jt from ijat (ijat_max = nat*nat) * which collapses it, ia, jt, ja loop into a single loop * - GetAtomCounts - * - get_atomCounts(): get atomCounts, which is a map from atom type to atom number + * - get_atom_Counts(): get atomCounts, which is a map from atom type to atom number * - GetOrbitalCounts * - get_orbitalCounts(): get orbitalCounts, which is a map from atom type to orbital number * - CheckDTau * - check_dtau(): move all atomic coordinates into the first unitcell, i.e. in between [0,1) * - CheckTau * - check_tau(): check if any "two atoms are too close" - * - SelectiveDynamics - * - if_atoms_can_move():it is true if any coordinates of any atom can move, i.e. mbl = 1 * - ReadAtomSpecies * - read_atom_species(): a successful case * - ReadAtomSpeciesWarning1 @@ -144,56 +140,48 @@ TEST_F(UcellTest, Setup) EXPECT_EQ(ucell->lat_axis_free[0], 1); EXPECT_EQ(ucell->lat_axis_free[1], 1); EXPECT_EQ(ucell->lat_axis_free[2], 1); - EXPECT_TRUE(unitcell::if_cell_can_change(ucell->lat_axis_free)); } else if (fixed_axes_in[i] == "a") { EXPECT_EQ(ucell->lat_axis_free[0], 0); EXPECT_EQ(ucell->lat_axis_free[1], 1); EXPECT_EQ(ucell->lat_axis_free[2], 1); - EXPECT_TRUE(unitcell::if_cell_can_change(ucell->lat_axis_free)); } else if (fixed_axes_in[i] == "b") { EXPECT_EQ(ucell->lat_axis_free[0], 1); EXPECT_EQ(ucell->lat_axis_free[1], 0); EXPECT_EQ(ucell->lat_axis_free[2], 1); - EXPECT_TRUE(unitcell::if_cell_can_change(ucell->lat_axis_free)); } else if (fixed_axes_in[i] == "c") { EXPECT_EQ(ucell->lat_axis_free[0], 1); EXPECT_EQ(ucell->lat_axis_free[1], 1); EXPECT_EQ(ucell->lat_axis_free[2], 0); - EXPECT_TRUE(unitcell::if_cell_can_change(ucell->lat_axis_free)); } else if (fixed_axes_in[i] == "ab") { EXPECT_EQ(ucell->lat_axis_free[0], 0); EXPECT_EQ(ucell->lat_axis_free[1], 0); EXPECT_EQ(ucell->lat_axis_free[2], 1); - EXPECT_TRUE(unitcell::if_cell_can_change(ucell->lat_axis_free)); } else if (fixed_axes_in[i] == "ac") { EXPECT_EQ(ucell->lat_axis_free[0], 0); EXPECT_EQ(ucell->lat_axis_free[1], 1); EXPECT_EQ(ucell->lat_axis_free[2], 0); - EXPECT_TRUE(unitcell::if_cell_can_change(ucell->lat_axis_free)); } else if (fixed_axes_in[i] == "bc") { EXPECT_EQ(ucell->lat_axis_free[0], 1); EXPECT_EQ(ucell->lat_axis_free[1], 0); EXPECT_EQ(ucell->lat_axis_free[2], 0); - EXPECT_TRUE(unitcell::if_cell_can_change(ucell->lat_axis_free)); } else if (fixed_axes_in[i] == "abc") { EXPECT_EQ(ucell->lat_axis_free[0], 0); EXPECT_EQ(ucell->lat_axis_free[1], 0); EXPECT_EQ(ucell->lat_axis_free[2], 0); - EXPECT_FALSE(unitcell::if_cell_can_change(ucell->lat_axis_free)); } } } @@ -259,10 +247,6 @@ TEST_F(UcellTest, GetAtomCounts) std::map atomCounts = ucell->get_atom_Counts(); EXPECT_EQ(atomCounts[0], 1); EXPECT_EQ(atomCounts[1], 2); - /// atomCounts as vector - std::vector atomCounts2 = unitcell::get_atomCounts(ucell->atoms, ucell->ntype); - EXPECT_EQ(atomCounts2[0], 1); - EXPECT_EQ(atomCounts2[1], 2); } TEST_F(UcellTest, GetOrbitalCounts) @@ -289,14 +273,6 @@ TEST_F(UcellTest, GetLnchiCounts) EXPECT_EQ(LnchiCounts[1][0], 1); EXPECT_EQ(LnchiCounts[1][1], 1); EXPECT_EQ(LnchiCounts[1][2], 1); - /// LnchiCounts as vector - std::vector> LnchiCounts2 = unitcell::get_lnchiCounts(ucell->atoms, ucell->ntype); - EXPECT_EQ(LnchiCounts2[0][0], 1); - EXPECT_EQ(LnchiCounts2[0][1], 1); - EXPECT_EQ(LnchiCounts2[0][2], 1); - EXPECT_EQ(LnchiCounts2[1][0], 1); - EXPECT_EQ(LnchiCounts2[1][1], 1); - EXPECT_EQ(LnchiCounts2[1][2], 1); } TEST_F(UcellTest, CheckDTau) @@ -359,14 +335,6 @@ TEST_F(UcellTest, CheckTauTrue) GlobalV::ofs_warning.close(); } -TEST_F(UcellTest, SelectiveDynamics) -{ - UcellTestPrepare utp = UcellTestLib["C1H2-SD"]; - ucell = utp.SetUcellInfo(); - EXPECT_TRUE(unitcell::if_atoms_can_move(ucell->atoms, ucell->ntype)); -} - - #ifdef __LCAO class UcellTestReadStru : public ::testing::Test { From 5d6950f8aa3930799a37bff970d27d234809f3a9 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Tue, 6 Oct 2026 14:32:00 +0800 Subject: [PATCH 10/18] Test: split read_atom_species tests out of MODULE_CELL_unitcell_test Move the 7 STRU header-parsing cases (read_atom_species and read_lattice_constant, both in read_atom_species.cpp) to the new test_read_atom_species.cpp / MODULE_CELL_read_atom_species_test target, kept under the __LCAO guard as before. ReadAtomSpeciesWarning5 uses the death-test fixture alias; the rest use the new ReadAtomSpeciesTest fixture. Drop the stale doc entries from unitcell_test.cpp. --- source/source_cell/test/CMakeLists.txt | 6 + .../test/test_read_atom_species.cpp | 236 ++++++++++++++++++ source/source_cell/test/unitcell_test.cpp | 182 -------------- 3 files changed, 242 insertions(+), 182 deletions(-) create mode 100644 source/source_cell/test/test_read_atom_species.cpp diff --git a/source/source_cell/test/CMakeLists.txt b/source/source_cell/test/CMakeLists.txt index 4a99c48dd03..740a6fbe242 100644 --- a/source/source_cell/test/CMakeLists.txt +++ b/source/source_cell/test/CMakeLists.txt @@ -200,6 +200,12 @@ AddTest( SOURCES test_cell_tools.cpp ) +AddTest( + TARGET MODULE_CELL_read_atom_species_test + LIBS base device cell_info + SOURCES test_read_atom_species.cpp +) + AddTest( TARGET MODULE_CELL_print_cell_test LIBS base device cell_info symmetry diff --git a/source/source_cell/test/test_read_atom_species.cpp b/source/source_cell/test/test_read_atom_species.cpp new file mode 100644 index 00000000000..104697b614d --- /dev/null +++ b/source/source_cell/test/test_read_atom_species.cpp @@ -0,0 +1,236 @@ +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include +#include +#include +#include + +#include "source_base/global_variable.h" +#include "source_base/mathzone.h" +#include "source_cell/unitcell.h" +#include "source_cell/read_stru.h" + +// The test-only cell_info object library does not contain magnetism.cpp, +// so the Magnetism constructor/destructor must be provided locally. +Magnetism::Magnetism() +{ + this->tot_mag = 0.0; + this->abs_mag = 0.0; +} +Magnetism::~Magnetism() +{ +} + +#ifdef __LCAO +/************************************************ + * unit test of read_atom_species.cpp + ***********************************************/ + +/** + * - Tested Functions: + * - ReadAtomSpecies + * - read_atom_species(): a successful case + * - ReadAtomSpeciesWarning1 + * - read_atom_species(): unrecognized pseudopotential type + * - ReadAtomSpeciesLatName + * - read_lattice_constant(): all supported lattice names + * - ReadLatticeConstantWarning1 + * - read_lattice_constant(): lattice constant <= 0 + * - ReadLatticeConstantWarning2 + * - read_lattice_constant(): LATTICE_PARAMETERS without lattice type + * - ReadLatticeConstantWarning3 + * - read_lattice_constant(): LATTICE_VECTORS with explicit lattice type + * - ReadAtomSpeciesWarning5 + * - read_lattice_constant(): unsupported lattice name + */ + +class ReadAtomSpeciesTest : public ::testing::Test +{ + protected: + std::unique_ptr ucell{new UnitCell}; + std::string output; + void SetUp() override + { + ucell->ntype = 2; + ucell->pseudo_fn.resize(ucell->ntype); + ucell->pseudo_type.resize(ucell->ntype); + ucell->orbital_fn.resize(ucell->ntype); + } + void TearDown() override + { + ucell->orbital_fn.shrink_to_fit(); + } +}; + +using ReadAtomSpeciesDeathTest = ReadAtomSpeciesTest; + +TEST_F(ReadAtomSpeciesTest, ReadAtomSpecies) +{ + std::string fn = "./support/STRU_MgO"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + ofs_running.open("read_atom_species.tmp"); + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->set_atom_flag = true; + const std::string basis_type = "lcao"; + const std::string orbital_dir = ""; + const std::string init_wfc = ""; + const double onsite_radius = 0.0; + const bool deepks_setorb = true; + const bool rpa = false; + EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, + basis_type, orbital_dir, init_wfc, + onsite_radius, deepks_setorb, rpa)); + EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running, ucell->lat)); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); + ofs_running.close(); + ifa.close(); + remove("read_atom_species.tmp"); +} + +TEST_F(ReadAtomSpeciesTest, ReadAtomSpeciesWarning1) +{ + std::string fn = "./support/STRU_MgO_Warning1"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + ofs_running.open("read_atom_species.txt"); + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->set_atom_flag = true; + const std::string basis_type = "lcao"; + const std::string orbital_dir = ""; + const std::string init_wfc = ""; + const double onsite_radius = 0.0; + const bool deepks_setorb = true; + const bool rpa = false; + testing::internal::CaptureStdout(); + EXPECT_EXIT(unitcell::read_atom_species(ifa, ofs_running, *ucell, + basis_type, orbital_dir, init_wfc, + onsite_radius, deepks_setorb, rpa), ::testing::ExitedWithCode(1), ""); + output = testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, testing::HasSubstr("unrecognized pseudopotential type.")); + ofs_running.close(); + ifa.close(); + //remove("read_atom_species.txt"); +} + +TEST_F(ReadAtomSpeciesTest, ReadLatticeConstantWarning1) +{ + std::string fn = "./support/STRU_MgO_Warning2"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + ofs_running.open("read_atom_species1.tmp"); + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->set_atom_flag = true; + testing::internal::CaptureStdout(); + EXPECT_EXIT(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat), ::testing::ExitedWithCode(1), ""); + output = testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, testing::HasSubstr("Lattice constant <= 0.0")); + ofs_running.close(); + ifa.close(); + remove("read_atom_species1.tmp"); +} + +TEST_F(ReadAtomSpeciesTest, ReadLatticeConstantWarning2) +{ + std::string fn = "./support/STRU_MgO_Warning3"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + ofs_running.open("read_atom_species.tmp"); + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->set_atom_flag = true; + testing::internal::CaptureStdout(); + EXPECT_EXIT(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat), ::testing::ExitedWithCode(1), ""); + output = testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, + testing::HasSubstr("do not use LATTICE_PARAMETERS without explicit specification of lattice type")); + ofs_running.close(); + ifa.close(); + remove("read_atom_species.tmp"); +} + +TEST_F(ReadAtomSpeciesTest, ReadLatticeConstantWarning3) +{ + std::string fn = "./support/STRU_MgO_Warning4"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + ofs_running.open("read_atom_species.tmp"); + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->set_atom_flag = true; + ucell->latName = "bcc"; + testing::internal::CaptureStdout(); + EXPECT_EXIT(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat), ::testing::ExitedWithCode(1), ""); + output = testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, + testing::HasSubstr("do not use LATTICE_VECTORS along with explicit specification of lattice type")); + ofs_running.close(); + ifa.close(); + remove("read_atom_species.tmp"); +} + +TEST_F(ReadAtomSpeciesTest, ReadAtomSpeciesLatName) +{ + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->set_atom_flag = true; + std::vector latName_in = {"sc", + "fcc", + "bcc", + "hexagonal", + "trigonal", + "st", + "bct", + "so", + "baco", + "fco", + "bco", + "sm", + "bacm", + "triclinic"}; + for (int i = 0; i < latName_in.size(); ++i) + { + std::string fn = "./support/STRU_MgO_LatName"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + ofs_running.open("read_atom_species.tmp"); + ucell->latName = latName_in[i]; + EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); + if (ucell->latName == "sc") + { + EXPECT_DOUBLE_EQ(ucell->latvec.e11, 1.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, 1.0); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, 1.0); + } + ofs_running.close(); + ifa.close(); + remove("read_atom_species.tmp"); + } +} + +TEST_F(ReadAtomSpeciesDeathTest, ReadAtomSpeciesWarning5) +{ + std::string fn = "./support/STRU_MgO_LatName"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + ofs_running.open("read_atom_species.tmp"); + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->set_atom_flag = true; + ucell->latName = "arbitrary"; + testing::internal::CaptureStdout(); + EXPECT_EXIT(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat), ::testing::ExitedWithCode(1), ""); + output = testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, testing::HasSubstr("latname not supported")); + ofs_running.close(); + ifa.close(); + remove("read_atom_species.tmp"); +} + +#endif // __LCAO diff --git a/source/source_cell/test/unitcell_test.cpp b/source/source_cell/test/unitcell_test.cpp index a3418c8bb3e..f78cf0239fc 100644 --- a/source/source_cell/test/unitcell_test.cpp +++ b/source/source_cell/test/unitcell_test.cpp @@ -45,20 +45,6 @@ Magnetism::~Magnetism() * - check_dtau(): move all atomic coordinates into the first unitcell, i.e. in between [0,1) * - CheckTau * - check_tau(): check if any "two atoms are too close" - * - ReadAtomSpecies - * - read_atom_species(): a successful case - * - ReadAtomSpeciesWarning1 - * - read_atom_species(): unrecognized pseudopotential type. - * - ReadAtomSpeciesWarning2 - * - read_atom_species(): lat0<=0.0 - * - ReadAtomSpeciesWarning3 - * - read_atom_species(): do not use LATTICE_PARAMETERS without explicit specification of lattice type - * - ReadAtomSpeciesWarning4 - * - read_atom_species():do not use LATTICE_VECTORS along with explicit specification of lattice type - * - ReadAtomSpeciesWarning5 - * - read_atom_species():latname not supported - * - ReadAtomSpeciesLatName - * - read_atom_species(): various latname * - ReadAtomPositionsS1 * - read_atom_positions(): spin 1 case * - ReadAtomPositionsS2 @@ -354,174 +340,6 @@ class UcellTestReadStru : public ::testing::Test } }; -TEST_F(UcellTestReadStru, ReadAtomSpecies) -{ - std::string fn = "./support/STRU_MgO"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - ofs_running.open("read_atom_species.tmp"); - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->set_atom_flag = true; - const std::string basis_type = "lcao"; - const std::string orbital_dir = ""; - const std::string init_wfc = ""; - const double onsite_radius = 0.0; - const bool deepks_setorb = true; - const bool rpa = false; - EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, - basis_type, orbital_dir, init_wfc, - onsite_radius, deepks_setorb, rpa)); - EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running, ucell->lat)); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); - ofs_running.close(); - ifa.close(); - remove("read_atom_species.tmp"); -} - -TEST_F(UcellTestReadStru, ReadAtomSpeciesWarning1) -{ - std::string fn = "./support/STRU_MgO_Warning1"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - ofs_running.open("read_atom_species.txt"); - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->set_atom_flag = true; - const std::string basis_type = "lcao"; - const std::string orbital_dir = ""; - const std::string init_wfc = ""; - const double onsite_radius = 0.0; - const bool deepks_setorb = true; - const bool rpa = false; - testing::internal::CaptureStdout(); - EXPECT_EXIT(unitcell::read_atom_species(ifa, ofs_running, *ucell, - basis_type, orbital_dir, init_wfc, - onsite_radius, deepks_setorb, rpa), ::testing::ExitedWithCode(1), ""); - output = testing::internal::GetCapturedStdout(); - EXPECT_THAT(output, testing::HasSubstr("unrecognized pseudopotential type.")); - ofs_running.close(); - ifa.close(); - //remove("read_atom_species.txt"); -} - -TEST_F(UcellTestReadStru, ReadLatticeConstantWarning1) -{ - std::string fn = "./support/STRU_MgO_Warning2"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - ofs_running.open("read_atom_species1.tmp"); - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->set_atom_flag = true; - testing::internal::CaptureStdout(); - EXPECT_EXIT(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat), ::testing::ExitedWithCode(1), ""); - output = testing::internal::GetCapturedStdout(); - EXPECT_THAT(output, testing::HasSubstr("Lattice constant <= 0.0")); - ofs_running.close(); - ifa.close(); - remove("read_atom_species1.tmp"); -} - -TEST_F(UcellTestReadStru, ReadLatticeConstantWarning2) -{ - std::string fn = "./support/STRU_MgO_Warning3"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - ofs_running.open("read_atom_species.tmp"); - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->set_atom_flag = true; - testing::internal::CaptureStdout(); - EXPECT_EXIT(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat), ::testing::ExitedWithCode(1), ""); - output = testing::internal::GetCapturedStdout(); - EXPECT_THAT(output, - testing::HasSubstr("do not use LATTICE_PARAMETERS without explicit specification of lattice type")); - ofs_running.close(); - ifa.close(); - remove("read_atom_species.tmp"); -} - -TEST_F(UcellTestReadStru, ReadLatticeConstantWarning3) -{ - std::string fn = "./support/STRU_MgO_Warning4"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - ofs_running.open("read_atom_species.tmp"); - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->set_atom_flag = true; - ucell->latName = "bcc"; - testing::internal::CaptureStdout(); - EXPECT_EXIT(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat), ::testing::ExitedWithCode(1), ""); - output = testing::internal::GetCapturedStdout(); - EXPECT_THAT(output, - testing::HasSubstr("do not use LATTICE_VECTORS along with explicit specification of lattice type")); - ofs_running.close(); - ifa.close(); - remove("read_atom_species.tmp"); -} - -TEST_F(UcellTestReadStru, ReadAtomSpeciesLatName) -{ - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->set_atom_flag = true; - std::vector latName_in = {"sc", - "fcc", - "bcc", - "hexagonal", - "trigonal", - "st", - "bct", - "so", - "baco", - "fco", - "bco", - "sm", - "bacm", - "triclinic"}; - for (int i = 0; i < latName_in.size(); ++i) - { - std::string fn = "./support/STRU_MgO_LatName"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - ofs_running.open("read_atom_species.tmp"); - ucell->latName = latName_in[i]; - EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); - if (ucell->latName == "sc") - { - EXPECT_DOUBLE_EQ(ucell->latvec.e11, 1.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, 1.0); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, 1.0); - } - ofs_running.close(); - ifa.close(); - remove("read_atom_species.tmp"); - } -} - -TEST_F(UcellDeathTest, ReadAtomSpeciesWarning5) -{ - std::string fn = "./support/STRU_MgO_LatName"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - ofs_running.open("read_atom_species.tmp"); - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->set_atom_flag = true; - ucell->latName = "arbitrary"; - testing::internal::CaptureStdout(); - EXPECT_EXIT(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat), ::testing::ExitedWithCode(1), ""); - output = testing::internal::GetCapturedStdout(); - EXPECT_THAT(output, testing::HasSubstr("latname not supported")); - ofs_running.close(); - ifa.close(); - remove("read_atom_species.tmp"); -} - TEST_F(UcellTestReadStru, ReadAtomPositionsS1) { std::string fn = "./support/STRU_MgO"; From 55c4f5f063d35078da2e5001f9411e04a2a67a14 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Tue, 6 Oct 2026 14:43:27 +0800 Subject: [PATCH 11/18] Test: split read_atoms tests out of MODULE_CELL_unitcell_test Move the 17 read_atom_positions cases (spin/coordinate modes plus the five warning cases) to the new test_read_atoms.cpp / MODULE_CELL_read_atoms_test target, kept under the __LCAO guard. This removes the LCAO block and UcellTestReadStru fixture from unitcell_test.cpp, which now holds only the 9 UnitCell member-function tests. Also de-duplicate the triple read_stru.h include. The 6 GlobalV references are migration-neutral (added = removed). --- source/source_cell/test/CMakeLists.txt | 6 + source/source_cell/test/test_read_atoms.cpp | 860 ++++++++++++++++++++ source/source_cell/test/unitcell_test.cpp | 826 ------------------- 3 files changed, 866 insertions(+), 826 deletions(-) create mode 100644 source/source_cell/test/test_read_atoms.cpp diff --git a/source/source_cell/test/CMakeLists.txt b/source/source_cell/test/CMakeLists.txt index 740a6fbe242..d681868cc7b 100644 --- a/source/source_cell/test/CMakeLists.txt +++ b/source/source_cell/test/CMakeLists.txt @@ -206,6 +206,12 @@ AddTest( SOURCES test_read_atom_species.cpp ) +AddTest( + TARGET MODULE_CELL_read_atoms_test + LIBS base device cell_info + SOURCES test_read_atoms.cpp +) + AddTest( TARGET MODULE_CELL_print_cell_test LIBS base device cell_info symmetry diff --git a/source/source_cell/test/test_read_atoms.cpp b/source/source_cell/test/test_read_atoms.cpp new file mode 100644 index 00000000000..d70c267e8ab --- /dev/null +++ b/source/source_cell/test/test_read_atoms.cpp @@ -0,0 +1,860 @@ +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include +#include +#include +#include + +#include "source_base/global_variable.h" +#include "source_base/mathzone.h" +#include "source_cell/unitcell.h" +#include "source_cell/read_stru.h" + +// The test-only cell_info object library does not contain magnetism.cpp, +// so the Magnetism constructor/destructor must be provided locally. +Magnetism::Magnetism() +{ + this->tot_mag = 0.0; + this->abs_mag = 0.0; +} +Magnetism::~Magnetism() +{ +} + +#ifdef __LCAO +/************************************************ + * unit test of read_atoms.cpp + ***********************************************/ + +/** + * - Tested Functions: + * - ReadAtomPositionsS1 + * - read_atom_positions(): spin 1 case + * - ReadAtomPositionsS2 + * - read_atom_positions(): spin 2 case + * - ReadAtomPositionsS4Noncolin + * - read_atom_positions(): spin 4 noncolinear case + * - ReadAtomPositionsS4Colin + * - read_atom_positions(): spin 4 colinear case + * - ReadAtomPositionsC + * - read_atom_positions(): Cartesian coordinates + * - ReadAtomPositionsCA + * - read_atom_positions(): Cartesian_angstrom coordinates + * - ReadAtomPositionsCACXY + * - read_atom_positions(): Cartesian_angstrom_center_xy coordinates + * - ReadAtomPositionsCACXZ + * - read_atom_positions(): Cartesian_angstrom_center_xz coordinates + * - ReadAtomPositionsCACYZ + * - read_atom_positions(): Cartesian_angstrom_center_yz coordinates + * - ReadAtomPositionsCACXYZ + * - read_atom_positions(): Cartesian_angstrom_center_xyz coordinates + * - ReadAtomPositionsCAU + * - read_atom_positions(): Cartesian_au coordinates + * - ReadAtomPositionsAutosetMag + * - read_atom_positions(): zero-moment start with warning for nspin=4 + * - ReadAtomPositionsWarning1 + * - read_atom_positions(): unknown type of coordinates + * - ReadAtomPositionsWarning2 + * - read_atom_positions(): atomic label inconsistency between ATOM_POSITIONS + * and ATOM_SPECIES + * - ReadAtomPositionsWarning3 + * - read_atom_positions(): warning : atom number < 0 + * - ReadAtomPositionsWarning4 + * - read_atom_positions(): mismatch in atom number for atom type + * - ReadAtomPositionsWarning5 + * - read_atom_positions(): no atoms can move in MD simulations! + */ + +class ReadAtomsTest : public ::testing::Test +{ + protected: + std::unique_ptr ucell{new UnitCell}; + std::string output; + void SetUp() override + { + ucell->ntype = 2; + ucell->pseudo_fn.resize(ucell->ntype); + ucell->pseudo_type.resize(ucell->ntype); + ucell->orbital_fn.resize(ucell->ntype); + } + void TearDown() override + { + ucell->orbital_fn.shrink_to_fit(); + } +}; + +TEST_F(ReadAtomsTest, ReadAtomPositionsS1) +{ + std::string fn = "./support/STRU_MgO"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + std::ofstream ofs_warning; + ofs_running.open("read_atom_positions.tmp"); + ofs_warning.open("read_atom_positions.warn"); + // mandatory preliminaries + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->set_atom_flag = true; + const std::string basis_type = "lcao"; + const std::string orbital_dir = ""; + const std::string init_wfc = ""; + const double onsite_radius = 0.0; + const bool deepks_setorb = true; + const bool rpa = false; + const int nspin = 1; + const bool fixed_atoms = false; + const bool noncolin = false; + const std::string calculation = "scf"; + const std::string esolver_type = "ksdft"; + EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, + basis_type, orbital_dir, init_wfc, + onsite_radius, deepks_setorb, rpa)); + EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); + unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, + basis_type, orbital_dir, init_wfc, + onsite_radius, fixed_atoms, noncolin, + calculation, esolver_type, 0); + ofs_running.close(); + ofs_warning.close(); + ifa.close(); + remove("read_atom_positions.tmp"); + remove("read_atom_positions.warn"); +} + +TEST_F(ReadAtomsTest, ReadAtomPositionsS2) +{ + std::string fn = "./support/STRU_MgO"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + std::ofstream ofs_warning; + ofs_running.open("read_atom_positions.tmp"); + ofs_warning.open("read_atom_positions.warn"); + // mandatory preliminaries + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->set_atom_flag = true; + const std::string basis_type = "lcao"; + const std::string orbital_dir = ""; + const std::string init_wfc = ""; + const double onsite_radius = 0.0; + const bool deepks_setorb = true; + const bool rpa = false; + const int nspin = 2; + const bool fixed_atoms = false; + const bool noncolin = false; + const std::string calculation = "scf"; + const std::string esolver_type = "ksdft"; + EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, + basis_type, orbital_dir, init_wfc, + onsite_radius, deepks_setorb, rpa)); + EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); + unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, + basis_type, orbital_dir, init_wfc, + onsite_radius, fixed_atoms, noncolin, + calculation, esolver_type, 0); + ofs_running.close(); + ofs_warning.close(); + ifa.close(); + remove("read_atom_positions.tmp"); + remove("read_atom_positions.warn"); +} + +TEST_F(ReadAtomsTest, ReadAtomPositionsS4Noncolin) +{ + std::string fn = "./support/STRU_MgO"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + std::ofstream ofs_warning; + ofs_running.open("read_atom_positions.tmp"); + ofs_warning.open("read_atom_positions.warn"); + // mandatory preliminaries + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->set_atom_flag = true; + const std::string basis_type = "lcao"; + const std::string orbital_dir = ""; + const std::string init_wfc = ""; + const double onsite_radius = 0.0; + const bool deepks_setorb = true; + const bool rpa = false; + const int nspin = 4; + const bool fixed_atoms = false; + const bool noncolin = true; + const std::string calculation = "scf"; + const std::string esolver_type = "ksdft"; + EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, + basis_type, orbital_dir, init_wfc, + onsite_radius, deepks_setorb, rpa)); + EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); + unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, + basis_type, orbital_dir, init_wfc, + onsite_radius, fixed_atoms, noncolin, + calculation, esolver_type, 0); + ofs_running.close(); + ofs_warning.close(); + ifa.close(); + remove("read_atom_positions.tmp"); + remove("read_atom_positions.warn"); +} + +TEST_F(ReadAtomsTest, ReadAtomPositionsS4Colin) +{ + std::string fn = "./support/STRU_MgO"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + std::ofstream ofs_warning; + ofs_running.open("read_atom_positions.tmp"); + ofs_warning.open("read_atom_positions.warn"); + // mandatory preliminaries + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->set_atom_flag = true; + const std::string basis_type = "lcao"; + const std::string orbital_dir = ""; + const std::string init_wfc = ""; + const double onsite_radius = 0.0; + const bool deepks_setorb = true; + const bool rpa = false; + const int nspin = 4; + const bool fixed_atoms = false; + const bool noncolin = false; + const std::string calculation = "scf"; + const std::string esolver_type = "ksdft"; + EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, + basis_type, orbital_dir, init_wfc, + onsite_radius, deepks_setorb, rpa)); + EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); + unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, + basis_type, orbital_dir, init_wfc, + onsite_radius, fixed_atoms, noncolin, + calculation, esolver_type, 0); + ofs_running.close(); + ofs_warning.close(); + ifa.close(); + remove("read_atom_positions.tmp"); + remove("read_atom_positions.warn"); +} + +TEST_F(ReadAtomsTest, ReadAtomPositionsC) +{ + std::string fn = "./support/STRU_MgO_c"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + std::ofstream ofs_warning; + ofs_running.open("read_atom_positions.tmp"); + ofs_warning.open("read_atom_positions.warn"); + // mandatory preliminaries + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->set_atom_flag = true; + const std::string basis_type = "lcao"; + const std::string orbital_dir = ""; + const std::string init_wfc = ""; + const double onsite_radius = 0.0; + const bool deepks_setorb = true; + const bool rpa = false; + const int nspin = 1; + const bool fixed_atoms = false; + const bool noncolin = false; + const std::string calculation = "scf"; + const std::string esolver_type = "ksdft"; + EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, + basis_type, orbital_dir, init_wfc, + onsite_radius, deepks_setorb, rpa)); + EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); + unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, + basis_type, orbital_dir, init_wfc, + onsite_radius, fixed_atoms, noncolin, + calculation, esolver_type, 0); + ofs_running.close(); + ofs_warning.close(); + ifa.close(); + remove("read_atom_positions.tmp"); + remove("read_atom_positions.warn"); +} + +TEST_F(ReadAtomsTest, ReadAtomPositionsCA) +{ + std::string fn = "./support/STRU_MgO_ca"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + std::ofstream ofs_warning; + ofs_running.open("read_atom_positions.tmp"); + ofs_warning.open("read_atom_positions.warn"); + // mandatory preliminaries + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->set_atom_flag = true; + const std::string basis_type = "lcao"; + const std::string orbital_dir = ""; + const std::string init_wfc = ""; + const double onsite_radius = 0.0; + const bool deepks_setorb = true; + const bool rpa = false; + const int nspin = 1; + const bool fixed_atoms = false; + const bool noncolin = false; + const std::string calculation = "scf"; + const std::string esolver_type = "ksdft"; + EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, + basis_type, orbital_dir, init_wfc, + onsite_radius, deepks_setorb, rpa)); + EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); + unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, + basis_type, orbital_dir, init_wfc, + onsite_radius, fixed_atoms, noncolin, + calculation, esolver_type, 0); + ofs_running.close(); + ofs_warning.close(); + ifa.close(); + remove("read_atom_positions.tmp"); + remove("read_atom_positions.warn"); +} + +TEST_F(ReadAtomsTest, ReadAtomPositionsCACXY) +{ + std::string fn = "./support/STRU_MgO_cacxy"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + std::ofstream ofs_warning; + ofs_running.open("read_atom_positions.tmp"); + ofs_warning.open("read_atom_positions.warn"); + // mandatory preliminaries + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->set_atom_flag = true; + const std::string basis_type = "lcao"; + const std::string orbital_dir = ""; + const std::string init_wfc = ""; + const double onsite_radius = 0.0; + const bool deepks_setorb = true; + const bool rpa = false; + const int nspin = 1; + const bool fixed_atoms = false; + const bool noncolin = false; + const std::string calculation = "scf"; + const std::string esolver_type = "ksdft"; + EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, + basis_type, orbital_dir, init_wfc, + onsite_radius, deepks_setorb, rpa)); + EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); + unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, + basis_type, orbital_dir, init_wfc, + onsite_radius, fixed_atoms, noncolin, + calculation, esolver_type, 0); + ofs_running.close(); + ofs_warning.close(); + ifa.close(); + remove("read_atom_positions.tmp"); + remove("read_atom_positions.warn"); +} + +TEST_F(ReadAtomsTest, ReadAtomPositionsCACXZ) +{ + std::string fn = "./support/STRU_MgO_cacxz"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + std::ofstream ofs_warning; + ofs_running.open("read_atom_positions.tmp"); + ofs_warning.open("read_atom_positions.warn"); + // mandatory preliminaries + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->set_atom_flag = true; + const std::string basis_type = "lcao"; + const std::string orbital_dir = ""; + const std::string init_wfc = ""; + const double onsite_radius = 0.0; + const bool deepks_setorb = true; + const bool rpa = false; + const int nspin = 1; + const bool fixed_atoms = false; + const bool noncolin = false; + const std::string calculation = "scf"; + const std::string esolver_type = "ksdft"; + EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, + basis_type, orbital_dir, init_wfc, + onsite_radius, deepks_setorb, rpa)); + EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); + unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, + basis_type, orbital_dir, init_wfc, + onsite_radius, fixed_atoms, noncolin, + calculation, esolver_type, 0); + ofs_running.close(); + ofs_warning.close(); + ifa.close(); + remove("read_atom_positions.tmp"); + remove("read_atom_positions.warn"); +} + +TEST_F(ReadAtomsTest, ReadAtomPositionsCACYZ) +{ + std::string fn = "./support/STRU_MgO_cacyz"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + std::ofstream ofs_warning; + ofs_running.open("read_atom_positions.tmp"); + ofs_warning.open("read_atom_positions.warn"); + // mandatory preliminaries + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->set_atom_flag = true; + const std::string basis_type = "lcao"; + const std::string orbital_dir = ""; + const std::string init_wfc = ""; + const double onsite_radius = 0.0; + const bool deepks_setorb = true; + const bool rpa = false; + const int nspin = 1; + const bool fixed_atoms = false; + const bool noncolin = false; + const std::string calculation = "scf"; + const std::string esolver_type = "ksdft"; + EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, + basis_type, orbital_dir, init_wfc, + onsite_radius, deepks_setorb, rpa)); + EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); + unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, + basis_type, orbital_dir, init_wfc, + onsite_radius, fixed_atoms, noncolin, + calculation, esolver_type, 0); + ofs_running.close(); + ofs_warning.close(); + ifa.close(); + remove("read_atom_positions.tmp"); + remove("read_atom_positions.warn"); +} + +TEST_F(ReadAtomsTest, ReadAtomPositionsCACXYZ) +{ + std::string fn = "./support/STRU_MgO_cacxyz"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + std::ofstream ofs_warning; + ofs_running.open("read_atom_positions.tmp"); + ofs_warning.open("read_atom_positions.warn"); + // mandatory preliminaries + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->set_atom_flag = true; + const std::string basis_type = "lcao"; + const std::string orbital_dir = ""; + const std::string init_wfc = ""; + const double onsite_radius = 0.0; + const bool deepks_setorb = true; + const bool rpa = false; + const int nspin = 1; + const bool fixed_atoms = false; + const bool noncolin = false; + const std::string calculation = "scf"; + const std::string esolver_type = "ksdft"; + EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, + basis_type, orbital_dir, init_wfc, + onsite_radius, deepks_setorb, rpa)); + EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); + unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, + basis_type, orbital_dir, init_wfc, + onsite_radius, fixed_atoms, noncolin, + calculation, esolver_type, 0); + ofs_running.close(); + ofs_warning.close(); + ifa.close(); + remove("read_atom_positions.tmp"); + remove("read_atom_positions.warn"); +} + +TEST_F(ReadAtomsTest, ReadAtomPositionsCAU) +{ + std::string fn = "./support/STRU_MgO_cau"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + std::ofstream ofs_warning; + ofs_running.open("read_atom_positions.tmp"); + ofs_warning.open("read_atom_positions.warn"); + // mandatory preliminaries + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->set_atom_flag = true; + const std::string basis_type = "lcao"; + const std::string orbital_dir = ""; + const std::string init_wfc = ""; + const double onsite_radius = 0.0; + const bool deepks_setorb = true; + const bool rpa = false; + const int nspin = 1; + const bool fixed_atoms = true; + const bool noncolin = false; + const std::string calculation = "scf"; + const std::string esolver_type = "ksdft"; + EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, + basis_type, orbital_dir, init_wfc, + onsite_radius, deepks_setorb, rpa)); + EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); + unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, + basis_type, orbital_dir, init_wfc, + onsite_radius, fixed_atoms, noncolin, + calculation, esolver_type, 0); + ofs_running.close(); + ofs_warning.close(); + ifa.close(); + remove("read_atom_positions.tmp"); + remove("read_atom_positions.warn"); +} + +TEST_F(ReadAtomsTest, ReadAtomPositionsAutosetMag) +{ + std::string fn = "./support/STRU_MgO"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + std::ofstream ofs_warning; + ofs_running.open("read_atom_positions.tmp"); + ofs_warning.open("read_atom_positions.warn"); + // mandatory preliminaries + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->set_atom_flag = true; + const std::string basis_type = "lcao"; + const std::string orbital_dir = ""; + const std::string init_wfc = ""; + const double onsite_radius = 0.0; + const bool deepks_setorb = true; + const bool rpa = false; + const bool fixed_atoms = false; + const bool noncolin = false; + const std::string calculation = "scf"; + const std::string esolver_type = "ksdft"; + int nspin = 2; + EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, + basis_type, orbital_dir, init_wfc, + onsite_radius, deepks_setorb, rpa)); + EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); + unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, + basis_type, orbital_dir, init_wfc, + onsite_radius, fixed_atoms, noncolin, + calculation, esolver_type, 0); + for (int it = 0; it < ucell->ntype; it++) + { + for (int ia = 0; ia < ucell->atoms[it].na; ia++) + { + EXPECT_DOUBLE_EQ(ucell->atoms[it].mag[ia], 1.0); + EXPECT_DOUBLE_EQ(ucell->atoms[it].m_loc_[ia].z, 1.0); + } + } + // for nspin == 4 + // Issue #5939: nspin=4 with no mag in STRU no longer autosets (1,1,1); + // all moments stay zero and a warning is emitted instead. + nspin = 4; + testing::internal::CaptureStdout(); + unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, + basis_type, orbital_dir, init_wfc, + onsite_radius, fixed_atoms, noncolin, + calculation, esolver_type, 0); + const std::string stdout_output = testing::internal::GetCapturedStdout(); + for (int it = 0; it < ucell->ntype; it++) + { + for (int ia = 0; ia < ucell->atoms[it].na; ia++) + { + EXPECT_DOUBLE_EQ(ucell->atoms[it].mag[ia], 0.0); + EXPECT_DOUBLE_EQ(ucell->atoms[it].m_loc_[ia].x, 0.0); + EXPECT_DOUBLE_EQ(ucell->atoms[it].m_loc_[ia].y, 0.0); + EXPECT_DOUBLE_EQ(ucell->atoms[it].m_loc_[ia].z, 0.0); + } + } + // The zero-moment warning must reach both stdout and the running log. + EXPECT_NE(stdout_output.find("no initial magnetization is set in STRU"), + std::string::npos); + ofs_running.flush(); + std::ifstream ifs_log("read_atom_positions.tmp"); + std::string log_content; + std::string log_line; + while (std::getline(ifs_log, log_line)) + { + log_content += log_line; + } + ifs_log.close(); + EXPECT_NE(log_content.find("no initial magnetization is set in STRU"), + std::string::npos); + ofs_running.close(); + ofs_warning.close(); + ifa.close(); + remove("read_atom_positions.tmp"); + remove("read_atom_positions.warn"); +} + +TEST_F(ReadAtomsTest, ReadAtomPositionsWarning1) +{ + std::string fn = "./support/STRU_MgO_WarningC1"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + std::ofstream ofs_warning; + ofs_running.open("read_atom_positions.tmp"); + ofs_warning.open("read_atom_positions.warn"); + // mandatory preliminaries + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->set_atom_flag = true; + const std::string basis_type = "lcao"; + const std::string orbital_dir = ""; + const std::string init_wfc = ""; + const double onsite_radius = 0.0; + const bool deepks_setorb = true; + const bool rpa = false; + const int nspin = 1; + const bool fixed_atoms = false; + const bool noncolin = false; + const std::string calculation = "scf"; + const std::string esolver_type = "ksdft"; + EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, + basis_type, orbital_dir, init_wfc, + onsite_radius, deepks_setorb, rpa)); + EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); + EXPECT_NO_THROW(unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, + basis_type, orbital_dir, init_wfc, + onsite_radius, fixed_atoms, noncolin, + calculation, esolver_type, 0)); + ofs_running.close(); + ofs_warning.close(); + ifa.close(); + // check warning file + std::ifstream ifs_tmp; + ifs_tmp.open("read_atom_positions.warn"); + std::string str((std::istreambuf_iterator(ifs_tmp)), std::istreambuf_iterator()); + EXPECT_THAT(str, testing::HasSubstr("There are several options for you:")); + EXPECT_THAT(str, testing::HasSubstr("Direct")); + EXPECT_THAT(str, testing::HasSubstr("Cartesian_angstrom")); + EXPECT_THAT(str, testing::HasSubstr("Cartesian_au")); + EXPECT_THAT(str, testing::HasSubstr("Cartesian_angstrom_center_xy")); + EXPECT_THAT(str, testing::HasSubstr("Cartesian_angstrom_center_xz")); + EXPECT_THAT(str, testing::HasSubstr("Cartesian_angstrom_center_yz")); + EXPECT_THAT(str, testing::HasSubstr("Cartesian_angstrom_center_xyz")); + ifs_tmp.close(); + remove("read_atom_positions.tmp"); + remove("read_atom_positions.warn"); +} + +TEST_F(ReadAtomsTest, ReadAtomPositionsWarning2) +{ + std::string fn = "./support/STRU_MgO_WarningC2"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + std::ofstream ofs_warning; + ofs_running.open("read_atom_positions.tmp"); + ofs_warning.open("read_atom_positions.warn"); + // mandatory preliminaries + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->set_atom_flag = true; + const std::string basis_type = "lcao"; + const std::string orbital_dir = ""; + const std::string init_wfc = ""; + const double onsite_radius = 0.0; + const bool deepks_setorb = true; + const bool rpa = false; + const int nspin = 1; + const bool fixed_atoms = false; + const bool noncolin = false; + const std::string calculation = "scf"; + const std::string esolver_type = "ksdft"; + EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, + basis_type, orbital_dir, init_wfc, + onsite_radius, deepks_setorb, rpa)); + EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); + EXPECT_NO_THROW(unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, + basis_type, orbital_dir, init_wfc, + onsite_radius, fixed_atoms, noncolin, + calculation, esolver_type, 0)); + ofs_running.close(); + ofs_warning.close(); + ifa.close(); + // check warning file + std::ifstream ifs_tmp; + ifs_tmp.open("read_atom_positions.warn"); + std::string str((std::istreambuf_iterator(ifs_tmp)), std::istreambuf_iterator()); + EXPECT_THAT(str, testing::HasSubstr("Label read from ATOMIC_POSITIONS is Mo")); + EXPECT_THAT(str, testing::HasSubstr("Label from ATOMIC_SPECIES is Mg")); + ifs_tmp.close(); + remove("read_atom_positions.tmp"); + remove("read_atom_positions.warn"); +} + +TEST_F(ReadAtomsTest, ReadAtomPositionsWarning3) +{ + std::string fn = "./support/STRU_MgO_WarningC3"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + ofs_running.open("read_atom_positions.tmp"); + GlobalV::ofs_warning.open("read_atom_positions.warn"); + // mandatory preliminaries + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->set_atom_flag = true; + const std::string basis_type = "lcao"; + const std::string orbital_dir = ""; + const std::string init_wfc = ""; + const double onsite_radius = 0.0; + const bool deepks_setorb = true; + const bool rpa = false; + const int nspin = 1; + const bool fixed_atoms = false; + const bool noncolin = false; + const std::string calculation = "scf"; + const std::string esolver_type = "ksdft"; + EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, + basis_type, orbital_dir, init_wfc, + onsite_radius, deepks_setorb, rpa)); + EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); + EXPECT_NO_THROW(unitcell::read_atom_positions(*ucell, ifa, ofs_running, GlobalV::ofs_warning, nspin, + basis_type, orbital_dir, init_wfc, + onsite_radius, fixed_atoms, noncolin, + calculation, esolver_type, 0)); + ofs_running.close(); + GlobalV::ofs_warning.close(); + ifa.close(); + // check warning file + std::ifstream ifs_tmp; + ifs_tmp.open("read_atom_positions.warn"); + std::string str((std::istreambuf_iterator(ifs_tmp)), std::istreambuf_iterator()); + EXPECT_THAT(str, testing::HasSubstr("read_atom_positions warning : atom number < 0.")); + ifs_tmp.close(); + remove("read_atom_positions.tmp"); + remove("read_atom_positions.warn"); +} + +TEST_F(ReadAtomsTest, ReadAtomPositionsWarning4) +{ + std::string fn = "./support/STRU_MgO_WarningC4"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + std::ofstream ofs_warning; + ofs_running.open("read_atom_positions.tmp"); + ofs_warning.open("read_atom_positions.warn"); + // mandatory preliminaries + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->orbital_fn.resize(ucell->ntype); + ucell->set_atom_flag = true; + const std::string basis_type = "lcao"; + const std::string orbital_dir = ""; + const std::string init_wfc = ""; + const double onsite_radius = 0.0; + const bool deepks_setorb = true; + const bool rpa = false; + const int nspin = 1; + const bool fixed_atoms = false; + const bool noncolin = false; + const std::string calculation = "scf"; + const std::string esolver_type = "ksdft"; + EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, + basis_type, orbital_dir, init_wfc, + onsite_radius, deepks_setorb, rpa)); + EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); + testing::internal::CaptureStdout(); + EXPECT_EXIT(unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, + basis_type, orbital_dir, init_wfc, + onsite_radius, fixed_atoms, noncolin, + calculation, esolver_type, 0), ::testing::ExitedWithCode(1), ""); + output = testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, testing::HasSubstr("read_atom_positions, mismatch in atom number for atom type: Mg")); + ofs_running.close(); + ofs_warning.close(); + ifa.close(); + remove("read_atom_positions.tmp"); + remove("read_atom_positions.warn"); +} + +TEST_F(ReadAtomsTest, ReadAtomPositionsWarning5) +{ + std::string fn = "./support/STRU_MgO"; + std::ifstream ifa(fn.c_str()); + std::ofstream ofs_running; + ofs_running.open("read_atom_positions.tmp"); + GlobalV::ofs_warning.open("read_atom_positions.warn"); + // mandatory preliminaries + ucell->ntype = 2; + ucell->atoms = new Atom[ucell->ntype]; + ucell->set_atom_flag = true; + const std::string basis_type = "lcao"; + const std::string orbital_dir = ""; + const std::string init_wfc = ""; + const double onsite_radius = 0.0; + const bool deepks_setorb = true; + const bool rpa = false; + const int nspin = 1; + const bool fixed_atoms = true; + const bool noncolin = false; + const std::string calculation = "md"; + const std::string esolver_type = "ksdft"; + EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, + basis_type, orbital_dir, init_wfc, + onsite_radius, deepks_setorb, rpa)); + EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); + EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); + EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); + EXPECT_NO_THROW(unitcell::read_atom_positions(*ucell, ifa, ofs_running, GlobalV::ofs_warning, nspin, + basis_type, orbital_dir, init_wfc, + onsite_radius, fixed_atoms, noncolin, + calculation, esolver_type, 0)); + ofs_running.close(); + GlobalV::ofs_warning.close(); + ifa.close(); + // check warning file + std::ifstream ifs_tmp; + ifs_tmp.open("read_atom_positions.warn"); + std::string str((std::istreambuf_iterator(ifs_tmp)), std::istreambuf_iterator()); + EXPECT_THAT(str, testing::HasSubstr("read_atoms warning : no atoms can move in MD simulations!")); + ifs_tmp.close(); + remove("read_atom_positions.tmp"); + remove("read_atom_positions.warn"); +} + +#endif // __LCAO diff --git a/source/source_cell/test/unitcell_test.cpp b/source/source_cell/test/unitcell_test.cpp index f78cf0239fc..630390c5b7d 100644 --- a/source/source_cell/test/unitcell_test.cpp +++ b/source/source_cell/test/unitcell_test.cpp @@ -3,11 +3,9 @@ #include "source_cell/read_stru.h" #include "memory" -#include "source_cell/read_stru.h" #include "source_base/global_variable.h" #include "source_base/mathzone.h" #include "prepare_unitcell.h" -#include "source_cell/read_stru.h" #include #include #include @@ -45,37 +43,6 @@ Magnetism::~Magnetism() * - check_dtau(): move all atomic coordinates into the first unitcell, i.e. in between [0,1) * - CheckTau * - check_tau(): check if any "two atoms are too close" - * - ReadAtomPositionsS1 - * - read_atom_positions(): spin 1 case - * - ReadAtomPositionsS2 - * - read_atom_positions(): spin 2 case - * - ReadAtomPositionsS4Noncolin - * - read_atom_positions(): spin 4 noncolinear case - * - ReadAtomPositionsS4Colin - * - read_atom_positions(): spin 4 colinear case - * - ReadAtomPositionsC - * - read_atom_positions(): Cartesian coordinates - * - ReadAtomPositionsCA - * - read_atom_positions(): Cartesian_angstrom coordinates - * - ReadAtomPositionsCACXY - * - read_atom_positions(): Cartesian_angstrom_center_xy coordinates - * - ReadAtomPositionsCACXZ - * - read_atom_positions(): Cartesian_angstrom_center_xz coordinates - * - ReadAtomPositionsCACXYZ - * - read_atom_positions(): Cartesian_angstrom_center_xyz coordinates - * - ReadAtomPositionsCAU - * - read_atom_positions(): Cartesian_au coordinates - * - ReadAtomPositionsWarning1 - * - read_atom_positions(): unknown type of coordinates - * - ReadAtomPositionsWarning2 - * - read_atom_positions(): atomic label inconsistency between ATOM_POSITIONS - * and ATOM_SPECIES - * - ReadAtomPositionsWarning3 - * - read_atom_positions(): warning : atom number < 0 - * - ReadAtomPositionsWarning4 - * - read_atom_positions(): mismatch in atom number for atom type - * - ReadAtomPositionsWarning5 - * - read_atom_positions(): no atoms can move in MD simulations! */ class UcellTest : public ::testing::Test @@ -320,796 +287,3 @@ TEST_F(UcellTest, CheckTauTrue) EXPECT_EQ(unitcell::check_tau(ucell->atoms ,ucell->ntype, ucell->lat0),true); GlobalV::ofs_warning.close(); } - -#ifdef __LCAO -class UcellTestReadStru : public ::testing::Test -{ - protected: - std::unique_ptr ucell{new UnitCell}; - std::string output; - void SetUp() override - { - ucell->ntype = 2; - ucell->pseudo_fn.resize(ucell->ntype); - ucell->pseudo_type.resize(ucell->ntype); - ucell->orbital_fn.resize(ucell->ntype); - } - void TearDown() override - { - ucell->orbital_fn.shrink_to_fit(); - } -}; - -TEST_F(UcellTestReadStru, ReadAtomPositionsS1) -{ - std::string fn = "./support/STRU_MgO"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - std::ofstream ofs_warning; - ofs_running.open("read_atom_positions.tmp"); - ofs_warning.open("read_atom_positions.warn"); - // mandatory preliminaries - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->set_atom_flag = true; - const std::string basis_type = "lcao"; - const std::string orbital_dir = ""; - const std::string init_wfc = ""; - const double onsite_radius = 0.0; - const bool deepks_setorb = true; - const bool rpa = false; - const int nspin = 1; - const bool fixed_atoms = false; - const bool noncolin = false; - const std::string calculation = "scf"; - const std::string esolver_type = "ksdft"; - EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, - basis_type, orbital_dir, init_wfc, - onsite_radius, deepks_setorb, rpa)); - EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); - unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, - basis_type, orbital_dir, init_wfc, - onsite_radius, fixed_atoms, noncolin, - calculation, esolver_type, 0); - ofs_running.close(); - ofs_warning.close(); - ifa.close(); - remove("read_atom_positions.tmp"); - remove("read_atom_positions.warn"); -} - -TEST_F(UcellTestReadStru, ReadAtomPositionsS2) -{ - std::string fn = "./support/STRU_MgO"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - std::ofstream ofs_warning; - ofs_running.open("read_atom_positions.tmp"); - ofs_warning.open("read_atom_positions.warn"); - // mandatory preliminaries - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->set_atom_flag = true; - const std::string basis_type = "lcao"; - const std::string orbital_dir = ""; - const std::string init_wfc = ""; - const double onsite_radius = 0.0; - const bool deepks_setorb = true; - const bool rpa = false; - const int nspin = 2; - const bool fixed_atoms = false; - const bool noncolin = false; - const std::string calculation = "scf"; - const std::string esolver_type = "ksdft"; - EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, - basis_type, orbital_dir, init_wfc, - onsite_radius, deepks_setorb, rpa)); - EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); - unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, - basis_type, orbital_dir, init_wfc, - onsite_radius, fixed_atoms, noncolin, - calculation, esolver_type, 0); - ofs_running.close(); - ofs_warning.close(); - ifa.close(); - remove("read_atom_positions.tmp"); - remove("read_atom_positions.warn"); -} - -TEST_F(UcellTestReadStru, ReadAtomPositionsS4Noncolin) -{ - std::string fn = "./support/STRU_MgO"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - std::ofstream ofs_warning; - ofs_running.open("read_atom_positions.tmp"); - ofs_warning.open("read_atom_positions.warn"); - // mandatory preliminaries - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->set_atom_flag = true; - const std::string basis_type = "lcao"; - const std::string orbital_dir = ""; - const std::string init_wfc = ""; - const double onsite_radius = 0.0; - const bool deepks_setorb = true; - const bool rpa = false; - const int nspin = 4; - const bool fixed_atoms = false; - const bool noncolin = true; - const std::string calculation = "scf"; - const std::string esolver_type = "ksdft"; - EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, - basis_type, orbital_dir, init_wfc, - onsite_radius, deepks_setorb, rpa)); - EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); - unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, - basis_type, orbital_dir, init_wfc, - onsite_radius, fixed_atoms, noncolin, - calculation, esolver_type, 0); - ofs_running.close(); - ofs_warning.close(); - ifa.close(); - remove("read_atom_positions.tmp"); - remove("read_atom_positions.warn"); -} - -TEST_F(UcellTestReadStru, ReadAtomPositionsS4Colin) -{ - std::string fn = "./support/STRU_MgO"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - std::ofstream ofs_warning; - ofs_running.open("read_atom_positions.tmp"); - ofs_warning.open("read_atom_positions.warn"); - // mandatory preliminaries - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->set_atom_flag = true; - const std::string basis_type = "lcao"; - const std::string orbital_dir = ""; - const std::string init_wfc = ""; - const double onsite_radius = 0.0; - const bool deepks_setorb = true; - const bool rpa = false; - const int nspin = 4; - const bool fixed_atoms = false; - const bool noncolin = false; - const std::string calculation = "scf"; - const std::string esolver_type = "ksdft"; - EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, - basis_type, orbital_dir, init_wfc, - onsite_radius, deepks_setorb, rpa)); - EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); - unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, - basis_type, orbital_dir, init_wfc, - onsite_radius, fixed_atoms, noncolin, - calculation, esolver_type, 0); - ofs_running.close(); - ofs_warning.close(); - ifa.close(); - remove("read_atom_positions.tmp"); - remove("read_atom_positions.warn"); -} - -TEST_F(UcellTestReadStru, ReadAtomPositionsC) -{ - std::string fn = "./support/STRU_MgO_c"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - std::ofstream ofs_warning; - ofs_running.open("read_atom_positions.tmp"); - ofs_warning.open("read_atom_positions.warn"); - // mandatory preliminaries - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->set_atom_flag = true; - const std::string basis_type = "lcao"; - const std::string orbital_dir = ""; - const std::string init_wfc = ""; - const double onsite_radius = 0.0; - const bool deepks_setorb = true; - const bool rpa = false; - const int nspin = 1; - const bool fixed_atoms = false; - const bool noncolin = false; - const std::string calculation = "scf"; - const std::string esolver_type = "ksdft"; - EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, - basis_type, orbital_dir, init_wfc, - onsite_radius, deepks_setorb, rpa)); - EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); - unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, - basis_type, orbital_dir, init_wfc, - onsite_radius, fixed_atoms, noncolin, - calculation, esolver_type, 0); - ofs_running.close(); - ofs_warning.close(); - ifa.close(); - remove("read_atom_positions.tmp"); - remove("read_atom_positions.warn"); -} - -TEST_F(UcellTestReadStru, ReadAtomPositionsCA) -{ - std::string fn = "./support/STRU_MgO_ca"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - std::ofstream ofs_warning; - ofs_running.open("read_atom_positions.tmp"); - ofs_warning.open("read_atom_positions.warn"); - // mandatory preliminaries - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->set_atom_flag = true; - const std::string basis_type = "lcao"; - const std::string orbital_dir = ""; - const std::string init_wfc = ""; - const double onsite_radius = 0.0; - const bool deepks_setorb = true; - const bool rpa = false; - const int nspin = 1; - const bool fixed_atoms = false; - const bool noncolin = false; - const std::string calculation = "scf"; - const std::string esolver_type = "ksdft"; - EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, - basis_type, orbital_dir, init_wfc, - onsite_radius, deepks_setorb, rpa)); - EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); - unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, - basis_type, orbital_dir, init_wfc, - onsite_radius, fixed_atoms, noncolin, - calculation, esolver_type, 0); - ofs_running.close(); - ofs_warning.close(); - ifa.close(); - remove("read_atom_positions.tmp"); - remove("read_atom_positions.warn"); -} - -TEST_F(UcellTestReadStru, ReadAtomPositionsCACXY) -{ - std::string fn = "./support/STRU_MgO_cacxy"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - std::ofstream ofs_warning; - ofs_running.open("read_atom_positions.tmp"); - ofs_warning.open("read_atom_positions.warn"); - // mandatory preliminaries - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->set_atom_flag = true; - const std::string basis_type = "lcao"; - const std::string orbital_dir = ""; - const std::string init_wfc = ""; - const double onsite_radius = 0.0; - const bool deepks_setorb = true; - const bool rpa = false; - const int nspin = 1; - const bool fixed_atoms = false; - const bool noncolin = false; - const std::string calculation = "scf"; - const std::string esolver_type = "ksdft"; - EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, - basis_type, orbital_dir, init_wfc, - onsite_radius, deepks_setorb, rpa)); - EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); - unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, - basis_type, orbital_dir, init_wfc, - onsite_radius, fixed_atoms, noncolin, - calculation, esolver_type, 0); - ofs_running.close(); - ofs_warning.close(); - ifa.close(); - remove("read_atom_positions.tmp"); - remove("read_atom_positions.warn"); -} - -TEST_F(UcellTestReadStru, ReadAtomPositionsCACXZ) -{ - std::string fn = "./support/STRU_MgO_cacxz"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - std::ofstream ofs_warning; - ofs_running.open("read_atom_positions.tmp"); - ofs_warning.open("read_atom_positions.warn"); - // mandatory preliminaries - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->set_atom_flag = true; - const std::string basis_type = "lcao"; - const std::string orbital_dir = ""; - const std::string init_wfc = ""; - const double onsite_radius = 0.0; - const bool deepks_setorb = true; - const bool rpa = false; - const int nspin = 1; - const bool fixed_atoms = false; - const bool noncolin = false; - const std::string calculation = "scf"; - const std::string esolver_type = "ksdft"; - EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, - basis_type, orbital_dir, init_wfc, - onsite_radius, deepks_setorb, rpa)); - EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); - unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, - basis_type, orbital_dir, init_wfc, - onsite_radius, fixed_atoms, noncolin, - calculation, esolver_type, 0); - ofs_running.close(); - ofs_warning.close(); - ifa.close(); - remove("read_atom_positions.tmp"); - remove("read_atom_positions.warn"); -} - -TEST_F(UcellTestReadStru, ReadAtomPositionsCACYZ) -{ - std::string fn = "./support/STRU_MgO_cacyz"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - std::ofstream ofs_warning; - ofs_running.open("read_atom_positions.tmp"); - ofs_warning.open("read_atom_positions.warn"); - // mandatory preliminaries - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->set_atom_flag = true; - const std::string basis_type = "lcao"; - const std::string orbital_dir = ""; - const std::string init_wfc = ""; - const double onsite_radius = 0.0; - const bool deepks_setorb = true; - const bool rpa = false; - const int nspin = 1; - const bool fixed_atoms = false; - const bool noncolin = false; - const std::string calculation = "scf"; - const std::string esolver_type = "ksdft"; - EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, - basis_type, orbital_dir, init_wfc, - onsite_radius, deepks_setorb, rpa)); - EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); - unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, - basis_type, orbital_dir, init_wfc, - onsite_radius, fixed_atoms, noncolin, - calculation, esolver_type, 0); - ofs_running.close(); - ofs_warning.close(); - ifa.close(); - remove("read_atom_positions.tmp"); - remove("read_atom_positions.warn"); -} - -TEST_F(UcellTestReadStru, ReadAtomPositionsCACXYZ) -{ - std::string fn = "./support/STRU_MgO_cacxyz"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - std::ofstream ofs_warning; - ofs_running.open("read_atom_positions.tmp"); - ofs_warning.open("read_atom_positions.warn"); - // mandatory preliminaries - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->set_atom_flag = true; - const std::string basis_type = "lcao"; - const std::string orbital_dir = ""; - const std::string init_wfc = ""; - const double onsite_radius = 0.0; - const bool deepks_setorb = true; - const bool rpa = false; - const int nspin = 1; - const bool fixed_atoms = false; - const bool noncolin = false; - const std::string calculation = "scf"; - const std::string esolver_type = "ksdft"; - EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, - basis_type, orbital_dir, init_wfc, - onsite_radius, deepks_setorb, rpa)); - EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); - unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, - basis_type, orbital_dir, init_wfc, - onsite_radius, fixed_atoms, noncolin, - calculation, esolver_type, 0); - ofs_running.close(); - ofs_warning.close(); - ifa.close(); - remove("read_atom_positions.tmp"); - remove("read_atom_positions.warn"); -} - -TEST_F(UcellTestReadStru, ReadAtomPositionsCAU) -{ - std::string fn = "./support/STRU_MgO_cau"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - std::ofstream ofs_warning; - ofs_running.open("read_atom_positions.tmp"); - ofs_warning.open("read_atom_positions.warn"); - // mandatory preliminaries - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->set_atom_flag = true; - const std::string basis_type = "lcao"; - const std::string orbital_dir = ""; - const std::string init_wfc = ""; - const double onsite_radius = 0.0; - const bool deepks_setorb = true; - const bool rpa = false; - const int nspin = 1; - const bool fixed_atoms = true; - const bool noncolin = false; - const std::string calculation = "scf"; - const std::string esolver_type = "ksdft"; - EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, - basis_type, orbital_dir, init_wfc, - onsite_radius, deepks_setorb, rpa)); - EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); - unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, - basis_type, orbital_dir, init_wfc, - onsite_radius, fixed_atoms, noncolin, - calculation, esolver_type, 0); - ofs_running.close(); - ofs_warning.close(); - ifa.close(); - remove("read_atom_positions.tmp"); - remove("read_atom_positions.warn"); -} - -TEST_F(UcellTestReadStru, ReadAtomPositionsAutosetMag) -{ - std::string fn = "./support/STRU_MgO"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - std::ofstream ofs_warning; - ofs_running.open("read_atom_positions.tmp"); - ofs_warning.open("read_atom_positions.warn"); - // mandatory preliminaries - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->set_atom_flag = true; - const std::string basis_type = "lcao"; - const std::string orbital_dir = ""; - const std::string init_wfc = ""; - const double onsite_radius = 0.0; - const bool deepks_setorb = true; - const bool rpa = false; - const bool fixed_atoms = false; - const bool noncolin = false; - const std::string calculation = "scf"; - const std::string esolver_type = "ksdft"; - int nspin = 2; - EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, - basis_type, orbital_dir, init_wfc, - onsite_radius, deepks_setorb, rpa)); - EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); - unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, - basis_type, orbital_dir, init_wfc, - onsite_radius, fixed_atoms, noncolin, - calculation, esolver_type, 0); - for (int it = 0; it < ucell->ntype; it++) - { - for (int ia = 0; ia < ucell->atoms[it].na; ia++) - { - EXPECT_DOUBLE_EQ(ucell->atoms[it].mag[ia], 1.0); - EXPECT_DOUBLE_EQ(ucell->atoms[it].m_loc_[ia].z, 1.0); - } - } - // for nspin == 4 - // Issue #5939: nspin=4 with no mag in STRU no longer autosets (1,1,1); - // all moments stay zero and a warning is emitted instead. - nspin = 4; - testing::internal::CaptureStdout(); - unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, - basis_type, orbital_dir, init_wfc, - onsite_radius, fixed_atoms, noncolin, - calculation, esolver_type, 0); - const std::string stdout_output = testing::internal::GetCapturedStdout(); - for (int it = 0; it < ucell->ntype; it++) - { - for (int ia = 0; ia < ucell->atoms[it].na; ia++) - { - EXPECT_DOUBLE_EQ(ucell->atoms[it].mag[ia], 0.0); - EXPECT_DOUBLE_EQ(ucell->atoms[it].m_loc_[ia].x, 0.0); - EXPECT_DOUBLE_EQ(ucell->atoms[it].m_loc_[ia].y, 0.0); - EXPECT_DOUBLE_EQ(ucell->atoms[it].m_loc_[ia].z, 0.0); - } - } - // The zero-moment warning must reach both stdout and the running log. - EXPECT_NE(stdout_output.find("no initial magnetization is set in STRU"), - std::string::npos); - ofs_running.flush(); - std::ifstream ifs_log("read_atom_positions.tmp"); - std::string log_content; - std::string log_line; - while (std::getline(ifs_log, log_line)) - { - log_content += log_line; - } - ifs_log.close(); - EXPECT_NE(log_content.find("no initial magnetization is set in STRU"), - std::string::npos); - ofs_running.close(); - ofs_warning.close(); - ifa.close(); - remove("read_atom_positions.tmp"); - remove("read_atom_positions.warn"); -} - -TEST_F(UcellTestReadStru, ReadAtomPositionsWarning1) -{ - std::string fn = "./support/STRU_MgO_WarningC1"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - std::ofstream ofs_warning; - ofs_running.open("read_atom_positions.tmp"); - ofs_warning.open("read_atom_positions.warn"); - // mandatory preliminaries - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->set_atom_flag = true; - const std::string basis_type = "lcao"; - const std::string orbital_dir = ""; - const std::string init_wfc = ""; - const double onsite_radius = 0.0; - const bool deepks_setorb = true; - const bool rpa = false; - const int nspin = 1; - const bool fixed_atoms = false; - const bool noncolin = false; - const std::string calculation = "scf"; - const std::string esolver_type = "ksdft"; - EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, - basis_type, orbital_dir, init_wfc, - onsite_radius, deepks_setorb, rpa)); - EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); - EXPECT_NO_THROW(unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, - basis_type, orbital_dir, init_wfc, - onsite_radius, fixed_atoms, noncolin, - calculation, esolver_type, 0)); - ofs_running.close(); - ofs_warning.close(); - ifa.close(); - // check warning file - std::ifstream ifs_tmp; - ifs_tmp.open("read_atom_positions.warn"); - std::string str((std::istreambuf_iterator(ifs_tmp)), std::istreambuf_iterator()); - EXPECT_THAT(str, testing::HasSubstr("There are several options for you:")); - EXPECT_THAT(str, testing::HasSubstr("Direct")); - EXPECT_THAT(str, testing::HasSubstr("Cartesian_angstrom")); - EXPECT_THAT(str, testing::HasSubstr("Cartesian_au")); - EXPECT_THAT(str, testing::HasSubstr("Cartesian_angstrom_center_xy")); - EXPECT_THAT(str, testing::HasSubstr("Cartesian_angstrom_center_xz")); - EXPECT_THAT(str, testing::HasSubstr("Cartesian_angstrom_center_yz")); - EXPECT_THAT(str, testing::HasSubstr("Cartesian_angstrom_center_xyz")); - ifs_tmp.close(); - remove("read_atom_positions.tmp"); - remove("read_atom_positions.warn"); -} - -TEST_F(UcellTestReadStru, ReadAtomPositionsWarning2) -{ - std::string fn = "./support/STRU_MgO_WarningC2"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - std::ofstream ofs_warning; - ofs_running.open("read_atom_positions.tmp"); - ofs_warning.open("read_atom_positions.warn"); - // mandatory preliminaries - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->set_atom_flag = true; - const std::string basis_type = "lcao"; - const std::string orbital_dir = ""; - const std::string init_wfc = ""; - const double onsite_radius = 0.0; - const bool deepks_setorb = true; - const bool rpa = false; - const int nspin = 1; - const bool fixed_atoms = false; - const bool noncolin = false; - const std::string calculation = "scf"; - const std::string esolver_type = "ksdft"; - EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, - basis_type, orbital_dir, init_wfc, - onsite_radius, deepks_setorb, rpa)); - EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); - EXPECT_NO_THROW(unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, - basis_type, orbital_dir, init_wfc, - onsite_radius, fixed_atoms, noncolin, - calculation, esolver_type, 0)); - ofs_running.close(); - ofs_warning.close(); - ifa.close(); - // check warning file - std::ifstream ifs_tmp; - ifs_tmp.open("read_atom_positions.warn"); - std::string str((std::istreambuf_iterator(ifs_tmp)), std::istreambuf_iterator()); - EXPECT_THAT(str, testing::HasSubstr("Label read from ATOMIC_POSITIONS is Mo")); - EXPECT_THAT(str, testing::HasSubstr("Label from ATOMIC_SPECIES is Mg")); - ifs_tmp.close(); - remove("read_atom_positions.tmp"); - remove("read_atom_positions.warn"); -} - -TEST_F(UcellTestReadStru, ReadAtomPositionsWarning3) -{ - std::string fn = "./support/STRU_MgO_WarningC3"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - ofs_running.open("read_atom_positions.tmp"); - GlobalV::ofs_warning.open("read_atom_positions.warn"); - // mandatory preliminaries - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->set_atom_flag = true; - const std::string basis_type = "lcao"; - const std::string orbital_dir = ""; - const std::string init_wfc = ""; - const double onsite_radius = 0.0; - const bool deepks_setorb = true; - const bool rpa = false; - const int nspin = 1; - const bool fixed_atoms = false; - const bool noncolin = false; - const std::string calculation = "scf"; - const std::string esolver_type = "ksdft"; - EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, - basis_type, orbital_dir, init_wfc, - onsite_radius, deepks_setorb, rpa)); - EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); - EXPECT_NO_THROW(unitcell::read_atom_positions(*ucell, ifa, ofs_running, GlobalV::ofs_warning, nspin, - basis_type, orbital_dir, init_wfc, - onsite_radius, fixed_atoms, noncolin, - calculation, esolver_type, 0)); - ofs_running.close(); - GlobalV::ofs_warning.close(); - ifa.close(); - // check warning file - std::ifstream ifs_tmp; - ifs_tmp.open("read_atom_positions.warn"); - std::string str((std::istreambuf_iterator(ifs_tmp)), std::istreambuf_iterator()); - EXPECT_THAT(str, testing::HasSubstr("read_atom_positions warning : atom number < 0.")); - ifs_tmp.close(); - remove("read_atom_positions.tmp"); - remove("read_atom_positions.warn"); -} - -TEST_F(UcellTestReadStru, ReadAtomPositionsWarning4) -{ - std::string fn = "./support/STRU_MgO_WarningC4"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - std::ofstream ofs_warning; - ofs_running.open("read_atom_positions.tmp"); - ofs_warning.open("read_atom_positions.warn"); - // mandatory preliminaries - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->orbital_fn.resize(ucell->ntype); - ucell->set_atom_flag = true; - const std::string basis_type = "lcao"; - const std::string orbital_dir = ""; - const std::string init_wfc = ""; - const double onsite_radius = 0.0; - const bool deepks_setorb = true; - const bool rpa = false; - const int nspin = 1; - const bool fixed_atoms = false; - const bool noncolin = false; - const std::string calculation = "scf"; - const std::string esolver_type = "ksdft"; - EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, - basis_type, orbital_dir, init_wfc, - onsite_radius, deepks_setorb, rpa)); - EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); - testing::internal::CaptureStdout(); - EXPECT_EXIT(unitcell::read_atom_positions(*ucell, ifa, ofs_running, ofs_warning, nspin, - basis_type, orbital_dir, init_wfc, - onsite_radius, fixed_atoms, noncolin, - calculation, esolver_type, 0), ::testing::ExitedWithCode(1), ""); - output = testing::internal::GetCapturedStdout(); - EXPECT_THAT(output, testing::HasSubstr("read_atom_positions, mismatch in atom number for atom type: Mg")); - ofs_running.close(); - ofs_warning.close(); - ifa.close(); - remove("read_atom_positions.tmp"); - remove("read_atom_positions.warn"); -} - -TEST_F(UcellTestReadStru, ReadAtomPositionsWarning5) -{ - std::string fn = "./support/STRU_MgO"; - std::ifstream ifa(fn.c_str()); - std::ofstream ofs_running; - ofs_running.open("read_atom_positions.tmp"); - GlobalV::ofs_warning.open("read_atom_positions.warn"); - // mandatory preliminaries - ucell->ntype = 2; - ucell->atoms = new Atom[ucell->ntype]; - ucell->set_atom_flag = true; - const std::string basis_type = "lcao"; - const std::string orbital_dir = ""; - const std::string init_wfc = ""; - const double onsite_radius = 0.0; - const bool deepks_setorb = true; - const bool rpa = false; - const int nspin = 1; - const bool fixed_atoms = true; - const bool noncolin = false; - const std::string calculation = "md"; - const std::string esolver_type = "ksdft"; - EXPECT_NO_THROW(unitcell::read_atom_species(ifa, ofs_running, *ucell, - basis_type, orbital_dir, init_wfc, - onsite_radius, deepks_setorb, rpa)); - EXPECT_NO_THROW(unitcell::read_lattice_constant(ifa, ofs_running,ucell->lat)); - EXPECT_DOUBLE_EQ(ucell->latvec.e11, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e22, 4.27957); - EXPECT_DOUBLE_EQ(ucell->latvec.e33, 4.27957); - EXPECT_NO_THROW(unitcell::read_atom_positions(*ucell, ifa, ofs_running, GlobalV::ofs_warning, nspin, - basis_type, orbital_dir, init_wfc, - onsite_radius, fixed_atoms, noncolin, - calculation, esolver_type, 0)); - ofs_running.close(); - GlobalV::ofs_warning.close(); - ifa.close(); - // check warning file - std::ifstream ifs_tmp; - ifs_tmp.open("read_atom_positions.warn"); - std::string str((std::istreambuf_iterator(ifs_tmp)), std::istreambuf_iterator()); - EXPECT_THAT(str, testing::HasSubstr("read_atoms warning : no atoms can move in MD simulations!")); - ifs_tmp.close(); - remove("read_atom_positions.tmp"); - remove("read_atom_positions.warn"); -} -#endif From 8c314ef4b6e396a1f0750e992898e9b4fdb1e607 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Tue, 6 Oct 2026 19:38:17 +0800 Subject: [PATCH 12/18] update initialized mag --- tests/01_PW/035_PW_15_SO/STRU | 8 ++++---- tests/01_PW/057_PW_SO_IW/STRU | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/01_PW/035_PW_15_SO/STRU b/tests/01_PW/035_PW_15_SO/STRU index 901aa2771d4..71a2da3c729 100644 --- a/tests/01_PW/035_PW_15_SO/STRU +++ b/tests/01_PW/035_PW_15_SO/STRU @@ -15,9 +15,9 @@ Direct //Cartesian or Direct coordinate. As 0 1 -0.2500000 0.2500000 0.25000000 0 0 0 +0.2500000 0.2500000 0.25000000 0 0 0 mag 1.7320508 -Ga //Element Label +Ga //Element Label 0 -1 //number of atom -0.00000 0.00000 0.000000 0 0 0 +1 //number of atom +0.00000 0.00000 0.000000 0 0 0 mag 1.7320508 diff --git a/tests/01_PW/057_PW_SO_IW/STRU b/tests/01_PW/057_PW_SO_IW/STRU index 901aa2771d4..71a2da3c729 100644 --- a/tests/01_PW/057_PW_SO_IW/STRU +++ b/tests/01_PW/057_PW_SO_IW/STRU @@ -15,9 +15,9 @@ Direct //Cartesian or Direct coordinate. As 0 1 -0.2500000 0.2500000 0.25000000 0 0 0 +0.2500000 0.2500000 0.25000000 0 0 0 mag 1.7320508 -Ga //Element Label +Ga //Element Label 0 -1 //number of atom -0.00000 0.00000 0.000000 0 0 0 +1 //number of atom +0.00000 0.00000 0.000000 0 0 0 mag 1.7320508 From 7e79a8acbe270d7506f92c90d142abc07341987f Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Wed, 7 Oct 2026 07:24:54 +0800 Subject: [PATCH 13/18] move 057_PW_SO_IW test to scf_in_wf_spin4 --- tests/01_PW/CASES_CPU.txt | 2 +- tests/01_PW/CASES_GPU.txt | 2 +- tests/01_PW/{057_PW_SO_IW => scf_in_wf_spin4}/INPUT | 0 tests/01_PW/{057_PW_SO_IW => scf_in_wf_spin4}/KPT | 0 .../01_PW/{057_PW_SO_IW => scf_in_wf_spin4}/README | 0 tests/01_PW/{057_PW_SO_IW => scf_in_wf_spin4}/STRU | 0 .../01_PW/{057_PW_SO_IW => scf_in_wf_spin4}/eig.txt | 0 .../{057_PW_SO_IW => scf_in_wf_spin4}/result.ref | 0 .../{057_PW_SO_IW => scf_in_wf_spin4}/wfk1s4_pw.dat | Bin 9 files changed, 2 insertions(+), 2 deletions(-) rename tests/01_PW/{057_PW_SO_IW => scf_in_wf_spin4}/INPUT (100%) rename tests/01_PW/{057_PW_SO_IW => scf_in_wf_spin4}/KPT (100%) rename tests/01_PW/{057_PW_SO_IW => scf_in_wf_spin4}/README (100%) rename tests/01_PW/{057_PW_SO_IW => scf_in_wf_spin4}/STRU (100%) rename tests/01_PW/{057_PW_SO_IW => scf_in_wf_spin4}/eig.txt (100%) rename tests/01_PW/{057_PW_SO_IW => scf_in_wf_spin4}/result.ref (100%) rename tests/01_PW/{057_PW_SO_IW => scf_in_wf_spin4}/wfk1s4_pw.dat (100%) diff --git a/tests/01_PW/CASES_CPU.txt b/tests/01_PW/CASES_CPU.txt index 6f2f88dedda..7b1217bc732 100644 --- a/tests/01_PW/CASES_CPU.txt +++ b/tests/01_PW/CASES_CPU.txt @@ -46,7 +46,7 @@ scf_Al100_kspace3 051_PW_OBOD_MemSaver scf_out_band_dos_wf 056_PW_IW -057_PW_SO_IW +scf_in_wf_spin4 058_PW_RE_MB 059_PW_RE_MB_traj 060_PW_RE_MG diff --git a/tests/01_PW/CASES_GPU.txt b/tests/01_PW/CASES_GPU.txt index ae8dd3be56f..e1c8970f9b4 100644 --- a/tests/01_PW/CASES_GPU.txt +++ b/tests/01_PW/CASES_GPU.txt @@ -45,7 +45,7 @@ scf_Al100_kspace3 051_PW_OBOD_MemSaver scf_out_band_dos_wf 056_PW_IW -057_PW_SO_IW +scf_in_wf_spin4 058_PW_RE_MB 059_PW_RE_MB_traj 060_PW_RE_MG diff --git a/tests/01_PW/057_PW_SO_IW/INPUT b/tests/01_PW/scf_in_wf_spin4/INPUT similarity index 100% rename from tests/01_PW/057_PW_SO_IW/INPUT rename to tests/01_PW/scf_in_wf_spin4/INPUT diff --git a/tests/01_PW/057_PW_SO_IW/KPT b/tests/01_PW/scf_in_wf_spin4/KPT similarity index 100% rename from tests/01_PW/057_PW_SO_IW/KPT rename to tests/01_PW/scf_in_wf_spin4/KPT diff --git a/tests/01_PW/057_PW_SO_IW/README b/tests/01_PW/scf_in_wf_spin4/README similarity index 100% rename from tests/01_PW/057_PW_SO_IW/README rename to tests/01_PW/scf_in_wf_spin4/README diff --git a/tests/01_PW/057_PW_SO_IW/STRU b/tests/01_PW/scf_in_wf_spin4/STRU similarity index 100% rename from tests/01_PW/057_PW_SO_IW/STRU rename to tests/01_PW/scf_in_wf_spin4/STRU diff --git a/tests/01_PW/057_PW_SO_IW/eig.txt b/tests/01_PW/scf_in_wf_spin4/eig.txt similarity index 100% rename from tests/01_PW/057_PW_SO_IW/eig.txt rename to tests/01_PW/scf_in_wf_spin4/eig.txt diff --git a/tests/01_PW/057_PW_SO_IW/result.ref b/tests/01_PW/scf_in_wf_spin4/result.ref similarity index 100% rename from tests/01_PW/057_PW_SO_IW/result.ref rename to tests/01_PW/scf_in_wf_spin4/result.ref diff --git a/tests/01_PW/057_PW_SO_IW/wfk1s4_pw.dat b/tests/01_PW/scf_in_wf_spin4/wfk1s4_pw.dat similarity index 100% rename from tests/01_PW/057_PW_SO_IW/wfk1s4_pw.dat rename to tests/01_PW/scf_in_wf_spin4/wfk1s4_pw.dat From f42d24ec562f8c85a3cfa587c841c313ea162252 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Wed, 7 Oct 2026 07:27:34 +0800 Subject: [PATCH 14/18] move 035_PW_15_SO to scf_spin4 --- tests/01_PW/CASES_CPU.txt | 2 +- tests/01_PW/CASES_GPU.txt | 2 +- tests/01_PW/{035_PW_15_SO => scf_spin4}/INPUT | 0 tests/01_PW/{035_PW_15_SO => scf_spin4}/KPT | 0 tests/01_PW/{035_PW_15_SO => scf_spin4}/README | 0 tests/01_PW/{035_PW_15_SO => scf_spin4}/STRU | 0 tests/01_PW/{035_PW_15_SO => scf_spin4}/result.ref | 0 7 files changed, 2 insertions(+), 2 deletions(-) rename tests/01_PW/{035_PW_15_SO => scf_spin4}/INPUT (100%) rename tests/01_PW/{035_PW_15_SO => scf_spin4}/KPT (100%) rename tests/01_PW/{035_PW_15_SO => scf_spin4}/README (100%) rename tests/01_PW/{035_PW_15_SO => scf_spin4}/STRU (100%) rename tests/01_PW/{035_PW_15_SO => scf_spin4}/result.ref (100%) diff --git a/tests/01_PW/CASES_CPU.txt b/tests/01_PW/CASES_CPU.txt index 7b1217bc732..e145798111b 100644 --- a/tests/01_PW/CASES_CPU.txt +++ b/tests/01_PW/CASES_CPU.txt @@ -32,7 +32,7 @@ scf_out_chg_tau 029_PW_15_CF_CS_S1_smallg 030_PW_15_CF_CS_S2_smallg 032_PW_15_CF_CS_bspline -035_PW_15_SO +scf_spin4 036_PW_AF 038_PW_NC 038_PW_NC_GGA_GRAD2 diff --git a/tests/01_PW/CASES_GPU.txt b/tests/01_PW/CASES_GPU.txt index e1c8970f9b4..f4dc0654527 100644 --- a/tests/01_PW/CASES_GPU.txt +++ b/tests/01_PW/CASES_GPU.txt @@ -32,7 +32,7 @@ scf_out_elf 029_PW_15_CF_CS_S1_smallg 030_PW_15_CF_CS_S2_smallg 032_PW_15_CF_CS_bspline -035_PW_15_SO +scf_spin4 036_PW_AF #038_PW_NC scf_Al100_kspace3 diff --git a/tests/01_PW/035_PW_15_SO/INPUT b/tests/01_PW/scf_spin4/INPUT similarity index 100% rename from tests/01_PW/035_PW_15_SO/INPUT rename to tests/01_PW/scf_spin4/INPUT diff --git a/tests/01_PW/035_PW_15_SO/KPT b/tests/01_PW/scf_spin4/KPT similarity index 100% rename from tests/01_PW/035_PW_15_SO/KPT rename to tests/01_PW/scf_spin4/KPT diff --git a/tests/01_PW/035_PW_15_SO/README b/tests/01_PW/scf_spin4/README similarity index 100% rename from tests/01_PW/035_PW_15_SO/README rename to tests/01_PW/scf_spin4/README diff --git a/tests/01_PW/035_PW_15_SO/STRU b/tests/01_PW/scf_spin4/STRU similarity index 100% rename from tests/01_PW/035_PW_15_SO/STRU rename to tests/01_PW/scf_spin4/STRU diff --git a/tests/01_PW/035_PW_15_SO/result.ref b/tests/01_PW/scf_spin4/result.ref similarity index 100% rename from tests/01_PW/035_PW_15_SO/result.ref rename to tests/01_PW/scf_spin4/result.ref From b8ce15c9430b3266ced49e839b94703f97144fb3 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Wed, 7 Oct 2026 07:40:22 +0800 Subject: [PATCH 15/18] add comments about mag for nspin=4 calculations --- source/source_cell/cal_ux.cpp | 13 +++++++++++++ source/source_cell/read_atoms_helper.cpp | 7 +++++++ source/source_hamilt/module_xc/xc_grad_prepare.cpp | 7 +++++++ source/source_hamilt/module_xc/xc_grad_utils.cpp | 10 ++++++++++ 4 files changed, 37 insertions(+) diff --git a/source/source_cell/cal_ux.cpp b/source/source_cell/cal_ux.cpp index 80201310323..38638c31afc 100644 --- a/source/source_cell/cal_ux.cpp +++ b/source/source_cell/cal_ux.cpp @@ -2,6 +2,19 @@ namespace unitcell { +// Compute the global spin quantization axis ux_ for non-collinear (nspin=4) +// calculations. ux_ is a single axis shared by the whole system (NOT one axis +// per atom); it is consumed by XC_Functional::noncolin_rho to split the spin +// density matrix into spin-up/down scalars for the LSDA/GGA kernel. +// +// The axis is derived from the *initial* moments m_loc_ read from STRU +// (direction of the first atom with |m| > threshold), not from the converged +// density. Consequently the STRU initial moments silently select the XC +// projection axis: with all-zero initial moments lsign_ stays false and the +// XC projection becomes direction-blind (neg = +1 everywhere in +// noncolin_rho), which can follow a different SCF path than a run started +// with an explicit non-zero moment even when the starting density (e.g. from +// init_chg = wfc/file) is identical. void cal_ux(UnitCell& ucell, const int nspin) { if (nspin != 4) diff --git a/source/source_cell/read_atoms_helper.cpp b/source/source_cell/read_atoms_helper.cpp index c440d7ef8af..3f1e13adeb1 100644 --- a/source/source_cell/read_atoms_helper.cpp +++ b/source/source_cell/read_atoms_helper.cpp @@ -302,6 +302,13 @@ void process_magnetization(Atom& atom, int it, int ia, if(!noncolin) { // collinear case with nspin = 4, only z component is used + // Note: a scalar "mag " in STRU is stored purely in + // m_loc_.z (x/y stay zero), so it passes the check below without + // triggering the warning and still defines a non-zero z moment. + // cal_ux() then turns that into the global XC quantization axis + // ux_ = (0,0,1) with lsign_ = true. Any positive scalar suffices; + // only the *direction* enters ux_, the magnitude (e.g. 1.7320508 + // vs 1.0) is irrelevant. if(std::abs(atom.m_loc_[ia].x) > 1e-5 || std::abs(atom.m_loc_[ia].y) > 1e-5) { std::stringstream ss; diff --git a/source/source_hamilt/module_xc/xc_grad_prepare.cpp b/source/source_hamilt/module_xc/xc_grad_prepare.cpp index b60d0d45207..fe9187f18c9 100644 --- a/source/source_hamilt/module_xc/xc_grad_prepare.cpp +++ b/source/source_hamilt/module_xc/xc_grad_prepare.cpp @@ -152,6 +152,13 @@ void gradcorr_prepare_rho( } // Mode 1 ignores the global quantization axis to remain continuous // when the magnetic moments tilt away from a collinear state. + // use_global_axis selects the up/down projection inside noncolin_rho: + // - true (lsign_ set, i.e. STRU initial moments defined a non-zero + // axis via cal_ux): sign follows m(r).ux_ point by point; + // - false (lsign_ unset / Mode 1): neg = +1 everywhere, a + // direction-blind |m| projection. + // This is why two otherwise identical runs can follow different SCF + // paths depending solely on whether STRU carries an initial moment. const bool use_global_axis = ucell->magnet.lsign_ && params.gga_grad != 1; XC_Functional::noncolin_rho(buf.rhotmp1.data(), buf.rhotmp2.data(), buf.neg.data(), chr->rho, rhopw->nrxx, ucell->magnet.ux_, use_global_axis); rhopw->real2recip(buf.rhotmp1.data(), buf.rhogsum1.data()); diff --git a/source/source_hamilt/module_xc/xc_grad_utils.cpp b/source/source_hamilt/module_xc/xc_grad_utils.cpp index 2f14e600886..cfbc0fa3d9d 100644 --- a/source/source_hamilt/module_xc/xc_grad_utils.cpp +++ b/source/source_hamilt/module_xc/xc_grad_utils.cpp @@ -167,6 +167,16 @@ void XC_Functional::noncolin_rho( #ifdef _OPENMP #pragma omp parallel for #endif + // Note: with lsign_ = true the up/down channels are defined w.r.t. the + // global axis ux_ through sign(m . ux_), evaluated point by point above; + // with lsign_ = false, "up" is always the local |m| (neg stays +1 + // everywhere). amag = |m(r)| is non-negative; neg[ir] carries that sign. + // The global axis ux_ itself is derived from the STRU initial moments in + // cal_ux(). Because GGA also consumes the *gradients* of rhoout1/rhoout2, + // a flipping sign field changes the gradient terms too, so the two + // branches can give noticeably different v_xc even for predominantly + // single-sign mz. (Locked by GgaGradTools.NoncolinRhoGlobalAxis in + // module_xc/test/test_xc5.cpp.) for(int ir = 0;ir Date: Wed, 7 Oct 2026 07:40:39 +0800 Subject: [PATCH 16/18] try to fix bug for nspin=4 --- tests/03_NAO_multik/scf_out_dos_spin4/STRU | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/03_NAO_multik/scf_out_dos_spin4/STRU b/tests/03_NAO_multik/scf_out_dos_spin4/STRU index 79211e7719f..04e65cbc54f 100644 --- a/tests/03_NAO_multik/scf_out_dos_spin4/STRU +++ b/tests/03_NAO_multik/scf_out_dos_spin4/STRU @@ -19,9 +19,9 @@ Direct //Cartesian or Direct coordinate. As 0 1 -0.2600000 0.2400000 0.245000000 0 0 0 +0.2600000 0.2400000 0.245000000 0 0 0 m 1.7 Ga //Element Label 0 1 //number of atom -0.00000 0.00000 0.000000 0 0 0 +0.00000 0.00000 0.000000 0 0 0 m 1.7 From d8f6322b0afbdf79d5da7a5253f0797f6775124c Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Thu, 8 Oct 2026 17:21:21 +0800 Subject: [PATCH 17/18] update mag --- tests/03_NAO_multik/scf_out_dos_spin4/STRU | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/03_NAO_multik/scf_out_dos_spin4/STRU b/tests/03_NAO_multik/scf_out_dos_spin4/STRU index 04e65cbc54f..3e2f64acfb1 100644 --- a/tests/03_NAO_multik/scf_out_dos_spin4/STRU +++ b/tests/03_NAO_multik/scf_out_dos_spin4/STRU @@ -19,9 +19,9 @@ Direct //Cartesian or Direct coordinate. As 0 1 -0.2600000 0.2400000 0.245000000 0 0 0 m 1.7 +0.2600000 0.2400000 0.245000000 0 0 0 mag 1.7 Ga //Element Label 0 1 //number of atom -0.00000 0.00000 0.000000 0 0 0 m 1.7 +0.00000 0.00000 0.000000 0 0 0 mag 1.7 From 45afdb8f39f3329e1b37d40a0afd39658f04c894 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Fri, 9 Oct 2026 12:49:36 +0800 Subject: [PATCH 18/18] fix bug by change slightly the reference forces of the example 03_NAO_multik/scf_out_dos_spin4 --- tests/03_NAO_multik/scf_out_dos_spin4/INPUT | 4 ++-- tests/03_NAO_multik/scf_out_dos_spin4/STRU | 8 ++++---- tests/03_NAO_multik/scf_out_dos_spin4/result.ref | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/03_NAO_multik/scf_out_dos_spin4/INPUT b/tests/03_NAO_multik/scf_out_dos_spin4/INPUT index b57f2e84774..12ceec9e763 100644 --- a/tests/03_NAO_multik/scf_out_dos_spin4/INPUT +++ b/tests/03_NAO_multik/scf_out_dos_spin4/INPUT @@ -12,7 +12,7 @@ smearing_method gaussian smearing_sigma 0.001 #Parameters (3.PW) ecutwfc 10 -scf_thr 1e-6 +scf_thr 1e-8 scf_nmax 100 #noncolin 1 @@ -24,7 +24,7 @@ cal_stress 1 #Parameters (LCAO) basis_type lcao ks_solver scalapack_gvx -pw_diag_thr 0.00001 +pw_diag_thr 1e-5 mixing_type pulay mixing_beta 0.7 diff --git a/tests/03_NAO_multik/scf_out_dos_spin4/STRU b/tests/03_NAO_multik/scf_out_dos_spin4/STRU index 3e2f64acfb1..d5e6bfc9d72 100644 --- a/tests/03_NAO_multik/scf_out_dos_spin4/STRU +++ b/tests/03_NAO_multik/scf_out_dos_spin4/STRU @@ -19,9 +19,9 @@ Direct //Cartesian or Direct coordinate. As 0 1 -0.2600000 0.2400000 0.245000000 0 0 0 mag 1.7 +0.2600000 0.2400000 0.245000000 0 0 0 mag 1.7320508 -Ga //Element Label +Ga //Element Label 0 -1 //number of atom -0.00000 0.00000 0.000000 0 0 0 mag 1.7 +1 //number of atom +0.00000 0.00000 0.000000 0 0 0 mag 1.7320508 diff --git a/tests/03_NAO_multik/scf_out_dos_spin4/result.ref b/tests/03_NAO_multik/scf_out_dos_spin4/result.ref index e54b51d3064..8f9915deded 100644 --- a/tests/03_NAO_multik/scf_out_dos_spin4/result.ref +++ b/tests/03_NAO_multik/scf_out_dos_spin4/result.ref @@ -1,6 +1,6 @@ -etotref -1964.0663947982770878 -etotperatomref -982.0331973991 -totalforceref 0.162158 -totalstressref 1877.059089 -totaldosref 38 -totaltimeref 16.23 +etotref -1964.0663947983236994 +etotperatomref -982.0331973992 +totalforceref 0.162676 +totalstressref 1877.059085 +totaldosref 38.000000 +totaltimeref 5.26