diff --git a/.ci/slurm/config.ini b/.ci/slurm/config.ini index 3aeb77cba5f..89432701553 100644 --- a/.ci/slurm/config.ini +++ b/.ci/slurm/config.ini @@ -491,7 +491,7 @@ runner = autotest_gpu [case.080] suite = 01_PW -name = 035_PW_15_SO +name = scf_spin4 resource = pw_gpu1 runner = autotest_gpu diff --git a/docs/advanced/input_files/input-main.md b/docs/advanced/input_files/input-main.md index 417a517daa1..c268d1c4e6d 100644 --- a/docs/advanced/input_files/input-main.md +++ b/docs/advanced/input_files/input-main.md @@ -1365,6 +1365,8 @@ - 1: Spin degeneracy - 2: Collinear spin polarized. - 4: Noncollinear or spin-orbit calculations. Set nspin to 4 explicitly when noncolin or lspinorb is enabled. + - Note: With nspin=2 and no initial magnetization in STRU, a moment of 1.0 is autoset for every atom, unless symmetry is 1. + - Note: With nspin=4 no moment is ever autoset. The calculation starts from zero magnetic moment and a warning is printed; set 'mag' explicitly in STRU for the magnetic atoms if a magnetic ground state is expected. - **Default**: 1 ### gga_grad @@ -1606,6 +1608,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/advanced/input_files/stru.md b/docs/advanced/input_files/stru.md index a50cfb6022e..885a1e833fc 100644 --- a/docs/advanced/input_files/stru.md +++ b/docs/advanced/input_files/stru.md @@ -281,7 +281,7 @@ For general usage requirements, the APNSv1.0 pseudopotential and orbital set is 0.0 0.0 0.0 m 0 0 0 0.5 0.5 0.5 m 1 1 1 ``` - For `nspin==2`, we will autoset atomic magmon is `1.0`: + For `nspin==2`, the atomic magnetic moment is autoset to `1.0`: ``` Fe 1.0 @@ -295,21 +295,32 @@ For general usage requirements, the APNSv1.0 pseudopotential and orbital set is 0.0 0.0 0.0 m 0 0 0 0.5 0.5 0.5 m 1 1 1 ``` - For `nspin==4`, we will autoset atomic magmon as follow: + This autoset is skipped as soon as `STRU` specifies a finite moment for + any single atom, and also when [`symmetry`](input-main.md#symmetry) is + `1`, because an all-zero moment is a legitimate nonmagnetic choice under + the full point group. + + For `nspin==4`, **no** moment is autoset: the calculation starts from a + zero magnetic moment and a warning is printed. Zero magnetization is a + stationary point, so such a run stays nonmagnetic. Set `mag` explicitly + on the magnetic atoms if a magnetic ground state is expected, e.g.: ``` Fe 0.0 2 - 0.0 0.0 0.0 m 0 0 0 mag 1 1 1 - 0.5 0.5 0.5 m 1 1 1 mag 1 1 1 + 0.0 0.0 0.0 m 0 0 0 mag 0.0 0.0 2.0 + 0.5 0.5 0.5 m 1 1 1 mag 0.0 0.0 2.0 O 0.0 2 - 0.0 0.0 0.0 m 0 0 0 mag 1 1 1 - 0.5 0.5 0.5 m 1 1 1 mag 1 1 1 + 0.0 0.0 0.0 m 0 0 0 + 0.5 0.5 0.5 m 1 1 1 ``` - However, this autoset will not be vaild once `STRU` specalize a finite magnetic for any single atom. + With [`noncolin`](input-main.md#noncolin) `0`, only the z component of + `mag` is used; the x/y components are discarded and the number of + affected atoms is reported per atom type. A moment given purely along + x/y therefore also leaves a zero starting moment. - `lambda`: Lagrange multiplier vector for spin constraint method. Can specify one value (z-component) or three values for x, y, z components (e.g., `lambda 0.5` or `lambda 0.1 0.2 0.3`). Values are in eV and will be converted to Rydberg internally. Used with spin-constrained DFT (enable with `sc_mag_switch` in INPUT file). diff --git a/docs/parameters.yaml b/docs/parameters.yaml index a1bdb7c0766..9cf9dd62dee 100644 --- a/docs/parameters.yaml +++ b/docs/parameters.yaml @@ -709,6 +709,8 @@ parameters: * 1: Spin degeneracy * 2: Collinear spin polarized. * 4: Noncollinear or spin-orbit calculations. Set nspin to 4 explicitly when noncolin or lspinorb is enabled. + * Note: With nspin=2 and no initial magnetization in STRU, a moment of 1.0 is autoset for every atom, unless symmetry is 1. + * Note: With nspin=4 no moment is ever autoset. The calculation starts from zero magnetic moment and a warning is printed; set 'mag' explicitly in STRU for the magnetic atoms if a magnetic ground state is expected. default_value: "1" unit: "" availability: "" @@ -996,6 +998,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/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.cpp b/source/source_cell/read_atoms.cpp index d3991d662eb..f5223a7a162 100644 --- a/source/source_cell/read_atoms.cpp +++ b/source/source_cell/read_atoms.cpp @@ -70,6 +70,11 @@ bool unitcell::read_atom_positions(UnitCell& ucell, int na = ucell.atoms[it].na; ucell.nat += na; + // Number of atoms of this type whose x/y moment was discarded by + // the collinear projection (nspin=4 with noncolin=0). Reported + // once per type after the atom loop instead of once per atom. + int n_xy_discarded = 0; + if (na > 0) { unitcell::allocate_atom_properties(ucell.atoms[it], na); @@ -103,9 +108,14 @@ bool unitcell::read_atom_positions(UnitCell& ucell, } // Process magnetization - unitcell::process_magnetization(ucell.atoms[it], it, ia, nspin, - input_vec_mag, input_angle_mag, ofs_running, - noncolin); + const bool xy_discarded + = unitcell::process_magnetization(ucell.atoms[it], it, ia, nspin, + input_vec_mag, input_angle_mag, ofs_running, + noncolin); + if (xy_discarded) + { + ++n_xy_discarded; + } // Transform coordinates unitcell::transform_atom_coordinates(ucell.atoms[it], ia, Coordinate, @@ -117,6 +127,9 @@ bool unitcell::read_atom_positions(UnitCell& ucell, ucell.atoms[it].dis[ia].set(0, 0, 0); }//endj } // end na + + unitcell::warn_xy_magnetization_ignored(ucell.atoms[it].label, + n_xy_discarded, na, ofs_running); // reset some useless parameters if (set_element_mag_zero) { @@ -130,15 +143,29 @@ bool unitcell::read_atom_positions(UnitCell& ucell, // so do not override it with an autoset seed. Warn instead. if (symmetry == 1) { - ofs_running << "\n WARNING: initial magmom is all zero and symmetry=1; " - << "autoset magnetism is SKIPPED to preserve the symmetry of the initial (nonmagnetic) structure.\n" - << " If spontaneous magnetism is expected, set magmom explicitly " - << "in STRU, or use symmetry = 0 or -1." << std::endl; + // Only report the skipped autoset when there is in fact + // nothing set: this message used to be printed even for an + // explicitly magnetized STRU. + if (unitcell::is_magnetization_all_zero(ucell)) + { + ofs_running << "\n WARNING: initial magmom is all zero and symmetry=1; " + << "autoset magnetism is SKIPPED to preserve the symmetry of the initial (nonmagnetic) structure.\n" + << " If spontaneous magnetism is expected, set magmom explicitly " + << "in STRU, or use symmetry = 0 or -1." << std::endl; + } } else { unitcell::autoset_magnetization(ucell, nspin, ofs_running); } + + // nspin=4 never autosets a moment, so the zero-moment start has to + // be reported for every symmetry setting, not only on the autoset + // path that symmetry=1 skips. + if (nspin == 4) + { + unitcell::warn_zero_magnetization_nspin4(ucell, ofs_running); + } } // end scan_begin // Final validation and output diff --git a/source/source_cell/read_atoms_helper.cpp b/source/source_cell/read_atoms_helper.cpp index b1896bfaae9..58ce696db68 100644 --- a/source/source_cell/read_atoms_helper.cpp +++ b/source/source_cell/read_atoms_helper.cpp @@ -17,6 +17,9 @@ namespace { constexpr char LOWER_A = 'a'; constexpr char LOWER_Z = 'z'; constexpr char MINUS_SIGN = '-'; + + // Below this value a magnetic moment component is treated as zero. + constexpr double mag_threshold = 1e-5; } namespace unitcell { @@ -79,56 +82,97 @@ void set_atom_movement_flags(Atom& atom, int ia, } } -void autoset_magnetization(UnitCell& ucell, int nspin, - std::ofstream& ofs_running) +bool is_magnetization_all_zero(const UnitCell& ucell) { - const int ntype = ucell.ntype; - - // Check if any atom has non-zero magnetization - int autoset_mag = 1; - for (int it = 0; it < ntype; it++) + for (int it = 0; it < ucell.ntype; it++) { for (int ia = 0; ia < ucell.atoms[it].na; ia++) { - if(std::abs(ucell.atoms[it].mag[ia]) > 1e-5) + if (std::abs(ucell.atoms[it].mag[ia]) > mag_threshold) { - autoset_mag = 0; - break; + return false; } } } + return true; +} + +void autoset_magnetization(UnitCell& ucell, int nspin, + std::ofstream& ofs_running) +{ + // nspin=4 never autosets a moment. An all-zero moment in STRU is a + // legitimate nonmagnetic start; warn_zero_magnetization_nspin4() reports + // it instead, independently of the symmetry switch that gates this call. + if (nspin != 2) + { + return; + } - if (autoset_mag) + if (!is_magnetization_all_zero(ucell)) + { + return; + } + + const int ntype = ucell.ntype; + for (int it = 0; it < ntype; it++) { - if(nspin==4) + for (int ia = 0; ia < ucell.atoms[it].na; ia++) { - 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); - } - } + ucell.atoms[it].mag[ia] = 1.0; + ucell.atoms[it].m_loc_[ia].z = ucell.atoms[it].mag[ia]; + ModuleBase::GlobalFunc::OUT(ofs_running,"Autoset magnetism for this atom", 1.0); } - else if(nspin==2) + } +} + +void warn_zero_magnetization_nspin4(const UnitCell& ucell, + std::ofstream& ofs_running) +{ + const double threshold_sq = mag_threshold * mag_threshold; + for (int it = 0; it < ucell.ntype; it++) + { + for (int ia = 0; ia < ucell.atoms[it].na; ia++) { - for (int it = 0; it < ntype; it++) + const ModuleBase::Vector3& m = ucell.atoms[it].m_loc_[ia]; + const double norm_sq = m.x * m.x + m.y * m.y + m.z * m.z; + if (norm_sq > threshold_sq) { - for (int ia = 0; ia < ucell.atoms[it].na; ia++) - { - ucell.atoms[it].mag[ia] = 1.0; - ucell.atoms[it].m_loc_[ia].z = ucell.atoms[it].mag[ia]; - ModuleBase::GlobalFunc::OUT(ofs_running,"Autoset magnetism for this atom", 1.0); - } + return; } } } + + const std::string summary = "nspin=4 but no initial magnetization is set in STRU; " + "all atoms start from zero magnetic moment."; + std::cout << " Warning: " << summary << std::endl; + ModuleBase::WARNING("read_atom_positions", summary); + ofs_running << "\n WARNING: " << summary << std::endl; + ofs_running << " If a magnetic ground state is expected, set 'mag' explicitly " + << "in STRU for the magnetic atoms." << std::endl; + ofs_running << " With noncolin=0 the x/y components of 'mag' are discarded, so a " + << "moment given purely along x/y also leaves a zero starting moment." + << std::endl; +} + +void warn_xy_magnetization_ignored(const std::string& label, + int n_discarded, + int na, + std::ofstream& ofs_running) +{ + if (n_discarded <= 0) + { + return; + } + + std::stringstream ss; + ss << "atom type " << label << ": " << n_discarded << " of " << na + << " atoms give non-zero x/y magnetization in STRU, but nspin=4 with noncolin=0 " + << "is a collinear calculation; only the z component is used. " + << "x/y components are IGNORED. Set 'noncolin 1' to use the full vector."; + const std::string summary = ss.str(); + std::cout << " Warning: " << summary << std::endl; + ModuleBase::WARNING("read_atom_positions", summary); + ofs_running << "\n WARNING: " << summary << std::endl; } bool finalize_atom_positions(UnitCell& ucell, @@ -265,12 +309,14 @@ void transform_atom_coordinates(Atom& atom, int ia, } } -void process_magnetization(Atom& atom, int it, int ia, +bool process_magnetization(Atom& atom, int it, int ia, int nspin, bool input_vec_mag, bool input_angle_mag, std::ofstream& ofs_running, const bool noncolin) { + bool xy_discarded = false; + // Recalculate mag and m_loc_ from read in angle1, angle2 and mag or mx, my, mz if(input_angle_mag) { @@ -307,6 +353,23 @@ 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 + // flagging a discard 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. + // + // The discard is only reported back to the caller, which + // aggregates it per atom type: emitting a message here would + // print one warning per atom for a cell where every atom tilts + // the moment. + if(std::abs(atom.m_loc_[ia].x) > mag_threshold + || std::abs(atom.m_loc_[ia].y) > mag_threshold) + { + xy_discarded = true; + } atom.m_loc_[ia].x = 0; atom.m_loc_[ia].y = 0; } @@ -347,6 +410,8 @@ void process_magnetization(Atom& atom, int it, int ia, ModuleBase::GlobalFunc::OUT(ofs_running, ss.str(),atom.mag[ia]); } } + + return xy_discarded; } bool parse_atom_properties(std::ifstream& ifpos, diff --git a/source/source_cell/read_atoms_helper.h b/source/source_cell/read_atoms_helper.h index 05d6091cd81..7cb39af3e30 100644 --- a/source/source_cell/read_atoms_helper.h +++ b/source/source_cell/read_atoms_helper.h @@ -45,6 +45,39 @@ void set_atom_movement_flags(Atom& atom, int ia, void autoset_magnetization(UnitCell& ucell, int nspin, std::ofstream& ofs_running); +/** + * @brief Check whether every atom carries a zero collinear magnetic moment + * @param ucell Unit cell object + * @return true if |mag| of every atom is below the magnetization threshold + */ +bool is_magnetization_all_zero(const UnitCell& ucell); + +/** + * @brief Warn when a nspin=4 run starts from an all-zero magnetization vector + * + * The check uses m_loc_, the vector actually consumed by cal_ux(), and not + * mag: the collinear projection applied when noncolin=0 can leave mag + * non-zero while m_loc_ is already zero, so keying the check on mag would + * miss exactly the silent zero-moment start this warning reports. + * + * @param ucell Unit cell object + * @param ofs_running Output stream for running information + */ +void warn_zero_magnetization_nspin4(const UnitCell& ucell, + std::ofstream& ofs_running); + +/** + * @brief Report, once per atom type, that x/y magnetization was discarded + * @param label Element label of the atom type + * @param n_discarded Number of atoms of this type whose x/y moment was dropped + * @param na Number of atoms of this type + * @param ofs_running Output stream for running information + */ +void warn_xy_magnetization_ignored(const std::string& label, + int n_discarded, + int na, + std::ofstream& ofs_running); + /** * @brief Perform final validation and output * @param ucell Unit cell object @@ -94,8 +127,10 @@ void transform_atom_coordinates(Atom& atom, int ia, * @param input_vec_mag Whether vector magnetization was input * @param input_angle_mag Whether angle magnetization was input * @param ofs_running Output stream for running information + * @return true if the x/y components were discarded by the collinear + * projection applied when nspin=4 and noncolin=0 */ -void process_magnetization(Atom& atom, int it, int ia, +bool process_magnetization(Atom& atom, int it, int ia, int nspin, bool input_vec_mag, bool input_angle_mag, std::ofstream& ofs_running, diff --git a/source/source_cell/test/CMakeLists.txt b/source/source_cell/test/CMakeLists.txt index e0db610c5bf..d681868cc7b 100644 --- a/source/source_cell/test/CMakeLists.txt +++ b/source/source_cell/test/CMakeLists.txt @@ -173,7 +173,43 @@ 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( + TARGET MODULE_CELL_read_orb_test + LIBS base device cell_info + 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_cell_tools_test + LIBS base device cell_info + 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_read_atoms_test + LIBS base device cell_info + SOURCES test_read_atoms.cpp ) AddTest( diff --git a/source/source_cell/test/read_atoms_hlp_test.cpp b/source/source_cell/test/read_atoms_hlp_test.cpp index c4c8d7c0b6c..c536fa4eabf 100644 --- a/source/source_cell/test/read_atoms_hlp_test.cpp +++ b/source/source_cell/test/read_atoms_hlp_test.cpp @@ -769,6 +769,296 @@ TEST_F(ReadAtomsHelperTest, RoundTripMultiAtomMixedFields) delete[] ucell.atoms; } +// ============================================================ +// Tests for issue #5021: nspin=4 with noncolin=0 discards x/y +// ============================================================ + +TEST_F(ReadAtomsHelperTest, ProcessMagnetizationNspin4CollinearReportsXYDiscard) +{ + 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; + + // The discard is reported to the caller, not printed once per atom. + testing::internal::CaptureStdout(); + const bool xy_discarded = unitcell::process_magnetization( + atom, 0, 0, nspin, input_vec_mag, input_angle_mag, ofs_running, noncolin); + const std::string stdout_output = testing::internal::GetCapturedStdout(); + + EXPECT_TRUE(xy_discarded); + 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); + EXPECT_EQ(stdout_output.find("Warning"), std::string::npos); +} + +TEST_F(ReadAtomsHelperTest, ProcessMagnetizationNspin4CollinearNoDiscardOnZeroXY) +{ + 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; + + const bool xy_discarded = unitcell::process_magnetization( + atom, 0, 0, nspin, input_vec_mag, input_angle_mag, ofs_running, noncolin); + + EXPECT_FALSE(xy_discarded); + 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); +} + +TEST_F(ReadAtomsHelperTest, ProcessMagnetizationNspin4NoncolinKeepsXY) +{ + 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; + + const bool xy_discarded = unitcell::process_magnetization( + atom, 0, 0, nspin, input_vec_mag, input_angle_mag, ofs_running, noncolin); + + EXPECT_FALSE(xy_discarded); + 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); +} + +TEST_F(ReadAtomsHelperTest, WarnXYMagnetizationIgnoredAggregatesPerType) +{ + testing::internal::CaptureStdout(); + unitcell::warn_xy_magnetization_ignored("Fe", 3, 4, ofs_running); + const std::string stdout_output = testing::internal::GetCapturedStdout(); + + // A single message for the whole type, carrying the affected-atom count. + const std::string::size_type first = stdout_output.find("Warning"); + EXPECT_NE(first, std::string::npos); + EXPECT_NE(stdout_output.find("atom type Fe: 3 of 4 atoms"), std::string::npos); + EXPECT_NE(stdout_output.find("x/y components are IGNORED"), std::string::npos); + EXPECT_EQ(stdout_output.find("Warning", first + 1), std::string::npos); + + ofs_running.flush(); + std::ifstream ifs("test_running.log"); + std::stringstream buffer; + buffer << ifs.rdbuf(); + const std::string log_content = buffer.str(); + ifs.close(); + EXPECT_NE(log_content.find("x/y components are IGNORED"), std::string::npos); +} + +TEST_F(ReadAtomsHelperTest, WarnXYMagnetizationIgnoredSilentWhenNoneDiscarded) +{ + testing::internal::CaptureStdout(); + unitcell::warn_xy_magnetization_ignored("Fe", 0, 4, ofs_running); + const std::string stdout_output = testing::internal::GetCapturedStdout(); + + EXPECT_EQ(stdout_output.find("Warning"), std::string::npos); +} + +// ============================================================ +// Tests for issue #5939: nspin=4 no longer autosets (1,1,1) +// ============================================================ + +TEST_F(ReadAtomsHelperTest, IsMagnetizationAllZero) +{ + UnitCell ucell; + ucell.ntype = 1; + ucell.atoms = new Atom[1]; + ucell.atoms[0].label = "Fe"; + ucell.atoms[0].na = 2; + ucell.atoms[0].mag.resize(2, 0.0); + ucell.atoms[0].m_loc_.resize(2); + + EXPECT_TRUE(unitcell::is_magnetization_all_zero(ucell)); + + ucell.atoms[0].mag[1] = 1.5; + EXPECT_FALSE(unitcell::is_magnetization_all_zero(ucell)); + + delete[] ucell.atoms; +} + +TEST_F(ReadAtomsHelperTest, AutosetMagnetizationNspin4NoAutosetAndSilent) +{ + 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); + const std::string stdout_output = testing::internal::GetCapturedStdout(); + + // Magnetization stays zero (NOT autoset to (1,1,1)), and this function + // stays silent: reporting belongs to warn_zero_magnetization_nspin4(), + // which read_atom_positions() calls for every symmetry setting. + 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); + EXPECT_EQ(stdout_output.find("Warning"), std::string::npos); + + delete[] ucell.atoms; +} + +TEST_F(ReadAtomsHelperTest, WarnZeroMagnetizationNspin4) +{ + 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); + + testing::internal::CaptureStdout(); + unitcell::warn_zero_magnetization_nspin4(ucell, ofs_running); + const std::string stdout_output = testing::internal::GetCapturedStdout(); + + EXPECT_NE(stdout_output.find("Warning"), std::string::npos); + EXPECT_NE(stdout_output.find("no initial magnetization is set in STRU"), + std::string::npos); + + ofs_running.flush(); + std::ifstream ifs("test_running.log"); + std::stringstream buffer; + buffer << ifs.rdbuf(); + const std::string log_content = buffer.str(); + ifs.close(); + EXPECT_NE(log_content.find("no initial magnetization is set in STRU"), + std::string::npos); + + delete[] ucell.atoms; +} + +TEST_F(ReadAtomsHelperTest, WarnZeroMagnetizationNspin4KeysOnMLoc) +{ + // Regression guard: a three-component magmom lying purely in x/y leaves + // mag at the full norm (2.0) while m_loc_ has already been projected to + // zero by the noncolin=0 branch. Keying this check on mag would silence + // the warning in exactly that case. + 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, 2.0); + ucell.atoms[0].m_loc_.resize(1); + ucell.atoms[0].m_loc_[0].set(0.0, 0.0, 0.0); + + EXPECT_FALSE(unitcell::is_magnetization_all_zero(ucell)); + + testing::internal::CaptureStdout(); + unitcell::warn_zero_magnetization_nspin4(ucell, ofs_running); + const std::string stdout_output = testing::internal::GetCapturedStdout(); + + EXPECT_NE(stdout_output.find("no initial magnetization is set in STRU"), + std::string::npos); + + delete[] ucell.atoms; +} + +TEST_F(ReadAtomsHelperTest, WarnZeroMagnetizationNspin4SilentWhenMagSet) +{ + 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); + + testing::internal::CaptureStdout(); + unitcell::warn_zero_magnetization_nspin4(ucell, ofs_running); + const std::string stdout_output = testing::internal::GetCapturedStdout(); + + 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); + const std::string stdout_output = testing::internal::GetCapturedStdout(); + + // nspin=2 still autosets 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); + EXPECT_EQ(stdout_output.find("Warning"), std::string::npos); + + delete[] ucell.atoms; +} + +TEST_F(ReadAtomsHelperTest, AutosetMagnetizationNspin2SkippedWhenMagSet) +{ + 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); + + unitcell::autoset_magnetization(ucell, 2, ofs_running); + + EXPECT_DOUBLE_EQ(ucell.atoms[0].mag[0], 1.5); + EXPECT_DOUBLE_EQ(ucell.atoms[0].m_loc_[0].z, 1.5); + + delete[] ucell.atoms; +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); 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/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/test_print_cell.cpp b/source/source_cell/test/test_print_cell.cpp index 6a3e6fdab11..b1d131ffcb4 100644 --- a/source/source_cell/test/test_print_cell.cpp +++ b/source/source_cell/test/test_print_cell.cpp @@ -325,3 +325,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("print_cell_test.log"); + unitcell::print_cell(*ucell, ofs); + ofs.close(); + std::ifstream ifs; + ifs.open("print_cell_test.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("print_cell_test.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/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/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/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/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 22ed1fd421c..630390c5b7d 100644 --- a/source/source_cell/test/unitcell_test.cpp +++ b/source/source_cell/test/unitcell_test.cpp @@ -1,19 +1,11 @@ #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" -#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" #include "source_base/mathzone.h" #include "prepare_unitcell.h" -#include "source_cell/update_cell.h" -#include "source_cell/read_stru.h" #include #include #include @@ -38,92 +30,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 - * - RemakeCell - * - 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 * - 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 - * - PeriodicBoundaryAdjustment - * - periodic_boundary_adjustment(): move atoms inside the unitcell after relaxation - * - 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 - * - PrintUnitcellPseudo - * - 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 - * - read_orb_file(): ABACUS Cannot find the ORBITAL file - * - 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 - * - 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 @@ -174,384 +93,52 @@ 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)); } } } -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", - "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, 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"]; @@ -613,10 +200,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) @@ -643,14 +226,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) @@ -712,1151 +287,3 @@ TEST_F(UcellTest, CheckTauTrue) EXPECT_EQ(unitcell::check_tau(ucell->atoms ,ucell->ntype, ucell->lat0),true); 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)); -} - - -// 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"]; - 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(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 - -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"); -} - -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; -} - -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) -{ - 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: - 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, 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"; - 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 - nspin = 4; - 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], 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); - } - } - 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 -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"); -} 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) { 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..6fe1dac62ca 100644 --- a/source/source_hamilt/module_xc/xc_grad_utils.cpp +++ b/source/source_hamilt/module_xc/xc_grad_utils.cpp @@ -164,6 +164,16 @@ void XC_Functional::noncolin_rho( } } } + // 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.) #ifdef _OPENMP #pragma omp parallel for #endif diff --git a/source/source_io/module_parameter/read_inp_estruc.cpp b/source/source_io/module_parameter/read_inp_estruc.cpp index 49c5fec46b3..5da535085ca 100644 --- a/source/source_io/module_parameter/read_inp_estruc.cpp +++ b/source/source_io/module_parameter/read_inp_estruc.cpp @@ -472,7 +472,9 @@ The other way is only available when compiling with LIBXC, and it allows for sup item.description = R"(The number of spin components of wave functions. * 1: Spin degeneracy * 2: Collinear spin polarized. -* 4: Noncollinear or spin-orbit calculations. Set nspin to 4 explicitly when noncolin or lspinorb is enabled.)"; +* 4: Noncollinear or spin-orbit calculations. Set nspin to 4 explicitly when noncolin or lspinorb is enabled. +* Note: With nspin=2 and no initial magnetization in STRU, a moment of 1.0 is autoset for every atom, unless symmetry is 1. +* Note: With nspin=4 no moment is ever autoset. The calculation starts from zero magnetic moment and a warning is printed; set 'mag' explicitly in STRU for the magnetic atoms if a magnetic ground state is expected.)"; item.default_value = "1"; item.unit = ""; read_sync_int(input.nspin); @@ -1006,7 +1008,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); diff --git a/tests/01_PW/CASES_CPU.txt b/tests/01_PW/CASES_CPU.txt index 6f2f88dedda..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 @@ -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..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 @@ -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/035_PW_15_SO/STRU b/tests/01_PW/scf_in_wf_spin4/STRU similarity index 63% rename from tests/01_PW/035_PW_15_SO/STRU rename to tests/01_PW/scf_in_wf_spin4/STRU index 901aa2771d4..71a2da3c729 100644 --- a/tests/01_PW/035_PW_15_SO/STRU +++ b/tests/01_PW/scf_in_wf_spin4/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/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 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/057_PW_SO_IW/STRU b/tests/01_PW/scf_spin4/STRU similarity index 63% rename from tests/01_PW/057_PW_SO_IW/STRU rename to tests/01_PW/scf_spin4/STRU index 901aa2771d4..71a2da3c729 100644 --- a/tests/01_PW/057_PW_SO_IW/STRU +++ b/tests/01_PW/scf_spin4/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/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 diff --git a/tests/03_NAO_multik/scf_out_dos_spin4/INPUT b/tests/03_NAO_multik/scf_out_dos_spin4/INPUT index b57f2e84774..11b9c7932ef 100644 --- a/tests/03_NAO_multik/scf_out_dos_spin4/INPUT +++ b/tests/03_NAO_multik/scf_out_dos_spin4/INPUT @@ -1,4 +1,4 @@ -INPUT_PARAMETERS +INPUT_PARAMETERS #Parameters (General) suffix autotest pseudo_dir ../../PP_ORB @@ -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 79211e7719f..887de781273 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 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/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