diff --git a/docs/advanced/input_files/input-main.md b/docs/advanced/input_files/input-main.md index ffd6574946a..8c2db0e7290 100644 --- a/docs/advanced/input_files/input-main.md +++ b/docs/advanced/input_files/input-main.md @@ -8,6 +8,7 @@ - [System variables](#system-variables) - [suffix](#suffix) - [ntype](#ntype) + - [cell\_replica](#cell_replica) - [calculation](#calculation) - [esolver\_type](#esolver_type) - [symmetry](#symmetry) @@ -354,6 +355,7 @@ - [md\_restart](#md_restart) - [md\_restartfreq](#md_restartfreq) - [md\_dumpfreq](#md_dumpfreq) + - [md\_out\_force](#md_out_force) - [dump\_force](#dump_force) - [dump\_vel](#dump_vel) - [dump\_virial](#dump_virial) @@ -580,6 +582,12 @@ - **Description**: Number of different atom species in the calculation. - **Default**: 0 +### cell_replica + +- **Type**: Three Integers +- **Description**: Replicate the input STRU by Na, Nb, and Nc along its lattice vectors for distributed MDCell workflows. The default is 1 1 1, which preserves the input structure. +- **Default**: 1 1 1 + ### calculation - **Type**: String @@ -3447,15 +3455,21 @@ ### md_restartfreq - **Type**: Integer -- **Description**: The output frequency of OUT.{suffix}/STRIU/, which are used to restart molecular dynamics calculations, see md_restart in detail. +- **Description**: The output frequency of OUT.{suffix}/STRU_MD_*, which are used to restart molecular dynamics calculations, see md_restart in detail. Set to 0 to disable MD restart output. - **Default**: 5 ### md_dumpfreq - **Type**: Integer -- **Description**: The output frequency of OUT.${suffix}/MD_dump in molecular dynamics calculations, which including the information of lattices and atoms. +- **Description**: The output frequency of OUT.${suffix}/MD_dump in molecular dynamics calculations, which includes lattice and atomic information. Set to 0 to disable MD_dump output; scalar MD progress remains printed to the terminal and running_md.log every step. - **Default**: 1 +### md_out_force + +- **Type**: Boolean +- **Description**: Whether to output the TOTAL-FORCE table in OUT.${suffix}/running_md.log for MDCell molecular dynamics. This does not affect force calculation or molecular dynamics integration. +- **Default**: True + ### dump_force - **Type**: Boolean @@ -3478,8 +3492,8 @@ - **Type**: Integer - **Description**: The random seed to initialize random numbers used in molecular dynamics calculations. - - < 0: No srand() function is called. - - >= 0: The function srand(md_seed) is called. +- < 0: Each MPI rank uses the default seed 1 plus its rank. +- >= 0: Each MPI rank uses md_seed plus its rank. - **Default**: -1 ### md_tfreq diff --git a/docs/parameters.yaml b/docs/parameters.yaml index b321efef96e..f350c324e29 100644 --- a/docs/parameters.yaml +++ b/docs/parameters.yaml @@ -17,6 +17,14 @@ parameters: default_value: "0" unit: "" availability: "" + - name: cell_replica + category: System variables + type: Three Integers + description: | + Replicate the input STRU by Na, Nb, and Nc along its lattice vectors for distributed MDCell workflows. The default is 1 1 1, which preserves the input structure. + default_value: "1 1 1" + unit: "" + availability: "" - name: calculation category: System variables type: String @@ -1435,7 +1443,7 @@ parameters: category: Molecular dynamics type: Integer description: | - The output frequency of OUT.{suffix}/STRIU/, which are used to restart molecular dynamics calculations, see md_restart in detail. + The output frequency of OUT.{suffix}/STRU_MD_*, which are used to restart molecular dynamics calculations, see md_restart in detail. Set to 0 to disable MD restart output. default_value: "5" unit: "" availability: "" @@ -1443,10 +1451,18 @@ parameters: category: Molecular dynamics type: Integer description: | - The output frequency of OUT.${suffix}/MD_dump in molecular dynamics calculations, which including the information of lattices and atoms. + The output frequency of OUT.${suffix}/MD_dump in molecular dynamics calculations, which includes lattice and atomic information. Set to 0 to disable MD_dump output; scalar MD progress remains printed to the terminal and running_md.log every step. default_value: "1" unit: "" availability: "" + - name: md_out_force + category: Molecular dynamics + type: Boolean + description: | + Whether to output the TOTAL-FORCE table in OUT.${suffix}/running_md.log for MDCell molecular dynamics. This does not affect force calculation or molecular dynamics integration. + default_value: "True" + unit: "" + availability: "" - name: dump_force category: Molecular dynamics type: Boolean @@ -1476,8 +1492,8 @@ parameters: type: Integer description: | The random seed to initialize random numbers used in molecular dynamics calculations. - * < 0: No srand() function is called. - * >= 0: The function srand(md_seed) is called. + * < 0: Each MPI rank uses the default seed 1 plus its rank. + * >= 0: Each MPI rank uses md_seed plus its rank. default_value: "-1" unit: "" availability: "" diff --git a/source/source_base/CMakeLists.txt b/source/source_base/CMakeLists.txt index 13f7a761798..cfdd25bd7ec 100644 --- a/source/source_base/CMakeLists.txt +++ b/source/source_base/CMakeLists.txt @@ -51,7 +51,7 @@ add_library( tool_title.cpp ylm.cpp parallel_common.cpp - communication_domain.cpp + parallel_cell.cpp parallel_global.cpp parallel_comm.cpp parallel_reduce.cpp diff --git a/source/source_base/communication_domain.cpp b/source/source_base/parallel_cell.cpp similarity index 80% rename from source/source_base/communication_domain.cpp rename to source/source_base/parallel_cell.cpp index 946222bc3eb..a1c4ca5a9ac 100644 --- a/source/source_base/communication_domain.cpp +++ b/source/source_base/parallel_cell.cpp @@ -1,4 +1,4 @@ -#include "source_base/communication_domain.h" +#include "source_base/parallel_cell.h" namespace ModuleBase { @@ -12,7 +12,6 @@ CommunicationDomain::CommunicationDomain(MPI_Comm communicator) : communicator_( if (communicator_ != MPI_COMM_NULL) { MPI_Comm_rank(communicator_, &rank_); - MPI_Comm_size(communicator_, &size_); } } @@ -27,11 +26,6 @@ int CommunicationDomain::rank() const return rank_; } -int CommunicationDomain::size() const -{ - return size_; -} - CommunicationDomain world_communication_domain() { #ifdef __MPI diff --git a/source/source_base/communication_domain.h b/source/source_base/parallel_cell.h similarity index 81% rename from source/source_base/communication_domain.h rename to source/source_base/parallel_cell.h index b91817db27e..34d00a50ecc 100644 --- a/source/source_base/communication_domain.h +++ b/source/source_base/parallel_cell.h @@ -1,5 +1,5 @@ -#ifndef COMMUNICATION_DOMAIN_H -#define COMMUNICATION_DOMAIN_H +#ifndef PARALLEL_CELL_H +#define PARALLEL_CELL_H #ifdef __MPI #include @@ -16,14 +16,12 @@ class CommunicationDomain MPI_Comm communicator() const; #endif int rank() const; - int size() const; private: #ifdef __MPI MPI_Comm communicator_ = MPI_COMM_NULL; #endif int rank_ = 0; - int size_ = 1; }; CommunicationDomain world_communication_domain(); diff --git a/source/source_cell/base_cell.h b/source/source_cell/base_cell.h index ee81db83450..220fcd4a572 100644 --- a/source/source_cell/base_cell.h +++ b/source/source_cell/base_cell.h @@ -3,6 +3,8 @@ #include "source_base/matrix3.h" +#include + class BaseCell { public: @@ -19,7 +21,7 @@ class BaseCell return get_kind(); } - int nat() const + std::int64_t nat() const { return get_nat(); } @@ -48,7 +50,7 @@ class BaseCell private: virtual Kind get_kind() const = 0; - virtual int get_nat() const = 0; + virtual std::int64_t get_nat() const = 0; virtual double get_lat0() const = 0; virtual double get_omega() const = 0; virtual const ModuleBase::Matrix3& get_latvec() const = 0; diff --git a/source/source_cell/distributed_mdcell_reader.cpp b/source/source_cell/distributed_mdcell_reader.cpp index 5640c54038c..efbfb770841 100644 --- a/source/source_cell/distributed_mdcell_reader.cpp +++ b/source/source_cell/distributed_mdcell_reader.cpp @@ -1,7 +1,7 @@ #include "source_cell/distributed_mdcell_reader.h" #include "source_base/constants.h" -#include "source_base/communication_domain.h" +#include "source_base/parallel_cell.h" #include "source_base/vector3.h" #include "source_cell/md_cell.h" @@ -10,6 +10,7 @@ #endif #include +#include #include #include #include @@ -28,6 +29,8 @@ struct StruMetadata ModuleBase::Matrix3 gt; std::vector labels; std::vector masses; + std::vector type_atom_counts; + MdStruFileMetadata stru_file_metadata; }; std::string trim_copy(const std::string& value) @@ -96,6 +99,17 @@ int parse_int(const std::string& token, const char* context) return static_cast(value); } +std::int64_t parse_int64(const std::string& token, const char* context) +{ + char* end = NULL; + const long long value = std::strtoll(token.c_str(), &end, 10); + if (end == token.c_str() || *end != '\0') + { + throw std::runtime_error(std::string("Failed to parse int64 for ") + context + ": " + token); + } + return static_cast(value); +} + ModuleBase::Vector3 wrap_fractional(const ModuleBase::Vector3& frac) { ModuleBase::Vector3 wrapped = frac; @@ -126,15 +140,15 @@ StruMetadata parse_stru_metadata(std::ifstream& ifs) } if (line == "NUMERICAL_ORBITAL") { - for (std::size_t it = 0; it < metadata.labels.size(); ++it) + for (std::size_t it = 0; it < metadata.stru_file_metadata.species.size(); ++it) { - next_data_line(ifs, "NUMERICAL_ORBITAL body"); + metadata.stru_file_metadata.species[it].orbital_file = next_data_line(ifs, "NUMERICAL_ORBITAL body"); } continue; } if (line == "NUMERICAL_DESCRIPTOR") { - next_data_line(ifs, "NUMERICAL_DESCRIPTOR body"); + metadata.stru_file_metadata.descriptor_file = next_data_line(ifs, "NUMERICAL_DESCRIPTOR body"); continue; } @@ -149,6 +163,9 @@ StruMetadata parse_stru_metadata(std::ifstream& ifs) metadata.labels.push_back(label); metadata.masses.push_back(parse_double(mass_token, "atomic mass")); + MdStruFileSpecies species; + iss >> species.pseudo_file >> species.pseudo_type; + metadata.stru_file_metadata.species.push_back(species); } expect_keyword(ifs, "LATTICE_CONSTANT"); @@ -179,10 +196,10 @@ std::vector read_owned_atoms(std::ifstream& ifs, StruMetadata& metadata, const ModuleBase::Matrix3& primitive_latvec, const ModuleBase::Matrix3& primitive_gt, - const std::vector& replicate, + const std::vector& cell_replica, double cutoff, double skin, - int& nat, + std::int64_t& nat, const ModuleBase::CommunicationDomain& communication_domain) { int rank = 0; @@ -193,16 +210,16 @@ std::vector read_owned_atoms(std::ifstream& ifs, #endif int begin[3] = {0, 0, 0}; - int end[3] = {replicate[0], replicate[1], replicate[2]}; + int end[3] = {cell_replica[0], cell_replica[1], cell_replica[2]}; #ifdef __MPI const std::array& dims = decomposition.dims(); const std::array& coords = decomposition.coords(); for (int idim = 0; idim < 3; ++idim) { begin[idim] = std::max(0, static_cast(std::floor( - static_cast(coords[idim]) * replicate[idim] / dims[idim])) - 1); - end[idim] = std::min(replicate[idim], static_cast(std::ceil( - static_cast(coords[idim] + 1) * replicate[idim] / dims[idim])) + 1); + static_cast(coords[idim]) * cell_replica[idim] / dims[idim])) - 1); + end[idim] = std::min(cell_replica[idim], static_cast(std::ceil( + static_cast(coords[idim] + 1) * cell_replica[idim] / dims[idim])) + 1); } #endif @@ -224,10 +241,11 @@ std::vector read_owned_atoms(std::ifstream& ifs, { throw std::runtime_error("ATOMIC_POSITIONS label order does not match ATOMIC_SPECIES."); } - next_data_line(ifs, "magnetism"); - const int nat_type = parse_int(next_data_line(ifs, "atom count"), "atom count"); + std::istringstream magnetism(next_data_line(ifs, "magnetism")); + magnetism >> metadata.stru_file_metadata.species[it].start_mag; + const std::int64_t nat_type = parse_int64(next_data_line(ifs, "atom count"), "atom count"); - for (int ia = 0; ia < nat_type; ++ia) + for (std::int64_t ia = 0; ia < nat_type; ++ia) { std::istringstream iss(next_data_line(ifs, "atom line")); double c1 = 0.0; @@ -287,9 +305,9 @@ std::vector read_owned_atoms(std::ifstream& ifs, for (int iz = begin[2]; iz < end[2]; ++iz) { ModuleBase::Vector3 final_frac( - (ix + frac.x) / replicate[0], - (iy + frac.y) / replicate[1], - (iz + frac.z) / replicate[2]); + (ix + frac.x) / cell_replica[0], + (iy + frac.y) / cell_replica[1], + (iz + frac.z) / cell_replica[2]); int owner = 0; #ifdef __MPI owner = decomposition.owner_rank_from_frac(final_frac); @@ -303,24 +321,27 @@ std::vector read_owned_atoms(std::ifstream& ifs, mbl, metadata.masses[it] / ModuleBase::AU_to_MASS, static_cast(it), - ((ix * replicate[1] + iy) * replicate[2] + iz) * nat_type + ia, - owner, - false)); + ((static_cast(ix) * cell_replica[1] + iy) + * cell_replica[2] + iz) * nat_type + ia, + owner)); } } } } } - nat += nat_type * replicate[0] * replicate[1] * replicate[2]; + const std::int64_t replicated_atom_count = nat_type * cell_replica[0] * cell_replica[1] * cell_replica[2]; + metadata.type_atom_counts.push_back(replicated_atom_count); + nat += replicated_atom_count; } return owned_atoms; } } // namespace MDCell DistributedMDCellReader::read_stru(const std::string& stru_file, - const std::vector& replicate, + const std::vector& cell_replica, double cutoff, double skin, + MdStruFileMetadata& stru_metadata, const ModuleBase::CommunicationDomain& communication_domain) { if (cutoff <= 0.0) @@ -334,21 +355,21 @@ MDCell DistributedMDCellReader::read_stru(const std::string& stru_file, throw std::runtime_error("Failed to open STRU file: " + stru_file); } - if (replicate.size() != 3 || replicate[0] <= 0 || replicate[1] <= 0 || replicate[2] <= 0) + if (cell_replica.size() != 3 || cell_replica[0] <= 0 || cell_replica[1] <= 0 || cell_replica[2] <= 0) { - throw std::runtime_error("replicate requires three positive integers."); + throw std::runtime_error("cell_replica requires three positive integers."); } StruMetadata metadata = parse_stru_metadata(ifs); const ModuleBase::Matrix3 primitive_latvec = metadata.latvec; const ModuleBase::Matrix3 primitive_gt = metadata.gt; - metadata.latvec.e11 *= replicate[0]; metadata.latvec.e12 *= replicate[0]; metadata.latvec.e13 *= replicate[0]; - metadata.latvec.e21 *= replicate[1]; metadata.latvec.e22 *= replicate[1]; metadata.latvec.e23 *= replicate[1]; - metadata.latvec.e31 *= replicate[2]; metadata.latvec.e32 *= replicate[2]; metadata.latvec.e33 *= replicate[2]; + metadata.latvec.e11 *= cell_replica[0]; metadata.latvec.e12 *= cell_replica[0]; metadata.latvec.e13 *= cell_replica[0]; + metadata.latvec.e21 *= cell_replica[1]; metadata.latvec.e22 *= cell_replica[1]; metadata.latvec.e23 *= cell_replica[1]; + metadata.latvec.e31 *= cell_replica[2]; metadata.latvec.e32 *= cell_replica[2]; metadata.latvec.e33 *= cell_replica[2]; metadata.gt = metadata.latvec.Inverse(); metadata.omega = std::abs(metadata.latvec.Det()) * metadata.lat0 * metadata.lat0 * metadata.lat0; - int nat = 0; + std::int64_t nat = 0; const std::vector owned_atoms = read_owned_atoms(ifs, metadata, primitive_latvec, primitive_gt, - replicate, cutoff, skin, nat, communication_domain); + cell_replica, cutoff, skin, nat, communication_domain); MDCell mdcell(metadata.latvec, metadata.gt, metadata.lat0, @@ -357,8 +378,10 @@ MDCell DistributedMDCellReader::read_stru(const std::string& stru_file, owned_atoms, metadata.labels, metadata.masses, + metadata.type_atom_counts, cutoff, skin, communication_domain); + stru_metadata = metadata.stru_file_metadata; return mdcell; } diff --git a/source/source_cell/distributed_mdcell_reader.h b/source/source_cell/distributed_mdcell_reader.h index 1d74c71ca88..e4c04ed42d7 100644 --- a/source/source_cell/distributed_mdcell_reader.h +++ b/source/source_cell/distributed_mdcell_reader.h @@ -1,6 +1,8 @@ #ifndef DISTRIBUTED_MDCELL_READER_H #define DISTRIBUTED_MDCELL_READER_H +#include "source_cell/md_stru_file_metadata.h" + #include #include @@ -14,9 +16,10 @@ class DistributedMDCellReader { public: static MDCell read_stru(const std::string& stru_file, - const std::vector& replicate, + const std::vector& cell_replica, double cutoff, double skin, + MdStruFileMetadata& stru_metadata, const ModuleBase::CommunicationDomain& communication_domain); }; diff --git a/source/source_cell/md_cell.cpp b/source/source_cell/md_cell.cpp index 496e87d9b01..b4cff6a45a4 100644 --- a/source/source_cell/md_cell.cpp +++ b/source/source_cell/md_cell.cpp @@ -1,6 +1,6 @@ #include "source_cell/md_cell.h" -#include "source_base/communication_domain.h" +#include "source_base/parallel_cell.h" #include "source_cell/unitcell.h" #include @@ -43,7 +43,6 @@ void MDCell::sync_backing_unitcell_geometry_() backing_unitcell_->a1.set(latvec_.e11, latvec_.e12, latvec_.e13); backing_unitcell_->a2.set(latvec_.e21, latvec_.e22, latvec_.e23); backing_unitcell_->a3.set(latvec_.e31, latvec_.e32, latvec_.e33); - backing_unitcell_->cell_parameter_updated = true; } void MDCell::sync_backing_unitcell_owned_atoms_() @@ -56,55 +55,26 @@ void MDCell::sync_backing_unitcell_owned_atoms_() for (std::size_t i = 0; i < owned_atoms_.size(); ++i) { const LocalAtom& atom = owned_atoms_[i]; + ModuleBase::Vector3 displacement = atom.frac - backing_unitcell_->atoms[atom.type].taud[atom.type_index]; + for (int k = 0; k < 3; ++k) + { + if (displacement[k] > 0.5) + { + displacement[k] -= 1.0; + } + else if (displacement[k] < -0.5) + { + displacement[k] += 1.0; + } + } backing_unitcell_->atoms[atom.type].tau[atom.type_index] = atom.cart; backing_unitcell_->atoms[atom.type].taud[atom.type_index] = atom.frac; + backing_unitcell_->atoms[atom.type].dis[atom.type_index] = displacement; backing_unitcell_->atoms[atom.type].vel[atom.type_index] = atom.vel; backing_unitcell_->atoms[atom.type].mbl[atom.type_index] = atom.mbl; } } -void MDCell::initialize_from_ucell_serial_(UnitCell& ucell, double cutoff, double skin) -{ - backing_unitcell_ = &ucell; - nat_ = ucell.nat; - lat0_ = ucell.lat0; - omega_ = ucell.omega; - latvec_ = ucell.latvec; - gt_ = ucell.GT; - type_labels_.clear(); - type_masses_.clear(); - type_labels_.reserve(static_cast(ucell.ntype)); - type_masses_.reserve(static_cast(ucell.ntype)); - for (int it = 0; it < ucell.ntype; ++it) - { - type_labels_.push_back(ucell.atoms[it].label); - type_masses_.push_back(ucell.atoms[it].mass); - } - init_vel_ = ucell.init_vel; - cutoff_ = cutoff; - skin_ = skin; - owned_atoms_.clear(); - ghost_atoms_.clear(); - - for (int it = 0; it < ucell.ntype; ++it) - { - for (int ia = 0; ia < ucell.atoms[it].na; ++ia) - { - owned_atoms_.push_back(LocalAtom(ucell.atoms[it].tau[ia], - ucell.atoms[it].taud[ia], - ucell.atoms[it].vel[ia], - ModuleBase::Vector3(0.0, 0.0, 0.0), - ucell.atoms[it].mbl[ia], - ucell.atoms[it].mass / ModuleBase::AU_to_MASS, - it, - ia, - 0, - false)); - } - } - exchange_ghost_atoms(); -} - #ifdef __MPI void MDCell::initialize_from_ucell_(UnitCell& ucell, MPI_Comm comm, double cutoff, double skin) { @@ -114,16 +84,15 @@ void MDCell::initialize_from_ucell_(UnitCell& ucell, MPI_Comm comm, double cutof omega_ = ucell.omega; latvec_ = ucell.latvec; gt_ = ucell.GT; - type_labels_.clear(); - type_masses_.clear(); - type_labels_.reserve(static_cast(ucell.ntype)); - type_masses_.reserve(static_cast(ucell.ntype)); + type_labels_.resize(static_cast(ucell.ntype)); + type_masses_.resize(static_cast(ucell.ntype)); + type_atom_counts_.resize(static_cast(ucell.ntype)); for (int it = 0; it < ucell.ntype; ++it) { - type_labels_.push_back(ucell.atoms[it].label); - type_masses_.push_back(ucell.atoms[it].mass); + type_labels_[static_cast(it)] = ucell.atoms[it].label; + type_masses_[static_cast(it)] = ucell.atoms[it].mass; + type_atom_counts_[static_cast(it)] = ucell.atoms[it].na; } - init_vel_ = ucell.init_vel; comm_ = comm; cutoff_ = cutoff; skin_ = skin; @@ -150,10 +119,47 @@ void MDCell::initialize_from_owned_atoms_(MPI_Comm comm, double cutoff, double s clear_forces_(owned_atoms_); exchange_ghost_atoms(); } +#else +void MDCell::initialize_from_ucell_(UnitCell& ucell, double cutoff, double skin) +{ + backing_unitcell_ = &ucell; + nat_ = ucell.nat; + lat0_ = ucell.lat0; + omega_ = ucell.omega; + latvec_ = ucell.latvec; + gt_ = ucell.GT; + type_labels_.resize(static_cast(ucell.ntype)); + type_masses_.resize(static_cast(ucell.ntype)); + type_atom_counts_.resize(static_cast(ucell.ntype)); + for (int it = 0; it < ucell.ntype; ++it) + { + type_labels_[static_cast(it)] = ucell.atoms[it].label; + type_masses_[static_cast(it)] = ucell.atoms[it].mass; + type_atom_counts_[static_cast(it)] = ucell.atoms[it].na; + } + cutoff_ = cutoff; + skin_ = skin; + owned_atoms_.clear(); + ghost_atoms_.clear(); -#endif + for (int it = 0; it < ucell.ntype; ++it) + { + for (int ia = 0; ia < ucell.atoms[it].na; ++ia) + { + owned_atoms_.push_back(LocalAtom(ucell.atoms[it].tau[ia], + ucell.atoms[it].taud[ia], + ucell.atoms[it].vel[ia], + ModuleBase::Vector3(0.0, 0.0, 0.0), + ucell.atoms[it].mbl[ia], + ucell.atoms[it].mass / ModuleBase::AU_to_MASS, + it, + ia, + 0)); + } + } + exchange_ghost_atoms(); +} -#ifndef __MPI void MDCell::initialize_from_owned_atoms_(double cutoff, double skin) { cutoff_ = cutoff; @@ -163,6 +169,7 @@ void MDCell::initialize_from_owned_atoms_(double cutoff, double skin) } #endif + MDCell::MDCell(UnitCell& ucell, double cutoff, double skin, @@ -172,7 +179,7 @@ MDCell::MDCell(UnitCell& ucell, initialize_from_ucell_(ucell, communication_domain.communicator(), cutoff, skin); #else static_cast(communication_domain); - initialize_from_ucell_serial_(ucell, cutoff, skin); + initialize_from_ucell_(ucell, cutoff, skin); #endif } @@ -180,10 +187,11 @@ MDCell::MDCell(const ModuleBase::Matrix3& latvec, const ModuleBase::Matrix3& gt, double lat0, double omega, - int nat, + std::int64_t nat, const std::vector& owned_atoms, const std::vector& type_labels, const std::vector& type_masses, + const std::vector& type_atom_counts, double cutoff, double skin, const ModuleBase::CommunicationDomain& communication_domain) @@ -196,7 +204,7 @@ MDCell::MDCell(const ModuleBase::Matrix3& latvec, owned_atoms_ = owned_atoms; type_labels_ = type_labels; type_masses_ = type_masses; - init_vel_ = true; + type_atom_counts_ = type_atom_counts; #ifdef __MPI initialize_from_owned_atoms_(communication_domain.communicator(), cutoff, skin); #else @@ -216,15 +224,6 @@ int MDCell::mpi_size() const return size_; } -MPI_Comm MDCell::communicator() const -{ - return comm_; -} - -const DomainDecomposition& MDCell::decomposition() const -{ - return decomp_; -} #endif void MDCell::exchange_ghost_atoms() @@ -284,7 +283,6 @@ void MDCell::exchange_ghost_atoms() image.frac.z + iz); image.cart = shifted_frac * latvec_; image.force.set(0.0, 0.0, 0.0); - image.is_ghost = true; ghost_atoms_.push_back(image); } } @@ -329,7 +327,6 @@ void MDCell::migrate_owned_atoms() atom.frac.z = wrap_fractional_(atom.frac.z); atom.cart = atom.frac * latvec_; } - sync_backing_unitcell_owned_atoms_(); exchange_ghost_atoms(); } @@ -345,6 +342,10 @@ void MDCell::set_lattice_vectors(const ModuleBase::Matrix3& latvec) } #endif sync_backing_unitcell_geometry_(); + if (backing_unitcell_ != nullptr) + { + backing_unitcell_->cell_parameter_updated = true; + } } void MDCell::refresh_cart_from_frac() @@ -356,30 +357,14 @@ void MDCell::refresh_cart_from_frac() owned_atoms_[i].frac.z = wrap_fractional_(owned_atoms_[i].frac.z); owned_atoms_[i].cart = owned_atoms_[i].frac * latvec_; } - sync_backing_unitcell_owned_atoms_(); exchange_ghost_atoms(); } -const std::vector& MDCell::owned_atoms() const -{ - return owned_atoms_; -} - const std::vector& MDCell::ghost_atoms() const { return ghost_atoms_; } -const std::vector& MDCell::type_labels() const -{ - return type_labels_; -} - -const std::vector& MDCell::type_masses() const -{ - return type_masses_; -} - std::vector& MDCell::mutable_owned_atoms() { return owned_atoms_; @@ -390,36 +375,11 @@ std::vector& MDCell::mutable_ghost_atoms() return ghost_atoms_; } -int MDCell::nlocal() const -{ - return static_cast(owned_atoms_.size()); -} - -int MDCell::nghost() const -{ - return static_cast(ghost_atoms_.size()); -} - -bool MDCell::init_vel() const -{ - return init_vel_; -} - -void MDCell::set_init_vel(bool init_vel) -{ - init_vel_ = init_vel; -} - double MDCell::cutoff() const { return cutoff_; } -double MDCell::skin() const -{ - return skin_; -} - bool MDCell::has_backing_unitcell() const { return backing_unitcell_ != nullptr; @@ -496,7 +456,22 @@ void MDCell::sync_backing_unitcell() throw std::runtime_error("MDCell backing UnitCell atom ownership is invalid."); } backing_unitcell_->atoms[it].tau[ia].set(cart[3 * iat], cart[3 * iat + 1], cart[3 * iat + 2]); + ModuleBase::Vector3 displacement(frac[3 * iat] - backing_unitcell_->atoms[it].taud[ia].x, + frac[3 * iat + 1] - backing_unitcell_->atoms[it].taud[ia].y, + frac[3 * iat + 2] - backing_unitcell_->atoms[it].taud[ia].z); + for (int k = 0; k < 3; ++k) + { + if (displacement[k] > 0.5) + { + displacement[k] -= 1.0; + } + else if (displacement[k] < -0.5) + { + displacement[k] += 1.0; + } + } backing_unitcell_->atoms[it].taud[ia].set(frac[3 * iat], frac[3 * iat + 1], frac[3 * iat + 2]); + backing_unitcell_->atoms[it].dis[ia] = displacement; backing_unitcell_->atoms[it].vel[ia].set(vel[3 * iat], vel[3 * iat + 1], vel[3 * iat + 2]); backing_unitcell_->atoms[it].mbl[ia].set(mbl[3 * iat], mbl[3 * iat + 1], mbl[3 * iat + 2]); } @@ -513,7 +488,7 @@ BaseCell::Kind MDCell::get_kind() const return Kind::md_cell; } -int MDCell::get_nat() const +std::int64_t MDCell::get_nat() const { return nat_; } diff --git a/source/source_cell/md_cell.h b/source/source_cell/md_cell.h index 0224ce6ccc9..9f7d2db9b6b 100644 --- a/source/source_cell/md_cell.h +++ b/source/source_cell/md_cell.h @@ -9,6 +9,7 @@ #endif #include +#include #include class UnitCell; @@ -16,26 +17,28 @@ namespace ModuleBase { class CommunicationDomain; } + class MDCell : public BaseCell { public: - MDCell(UnitCell& ucell, - double cutoff, - double skin, - const ModuleBase::CommunicationDomain& communication_domain); MDCell(const MDCell&) = delete; MDCell& operator=(const MDCell&) = delete; MDCell(MDCell&&) = default; MDCell& operator=(MDCell&&) = default; + MDCell(UnitCell& ucell, + double cutoff, + double skin, + const ModuleBase::CommunicationDomain& communication_domain); MDCell(const ModuleBase::Matrix3& latvec, const ModuleBase::Matrix3& gt, double lat0, double omega, - int nat, + std::int64_t nat, const std::vector& owned_atoms, const std::vector& type_labels, const std::vector& type_masses, + const std::vector& type_atom_counts, double cutoff, double skin, const ModuleBase::CommunicationDomain& communication_domain); @@ -43,9 +46,8 @@ class MDCell : public BaseCell #ifdef __MPI int mpi_rank() const; int mpi_size() const; - MPI_Comm communicator() const; + MPI_Comm communicator() const { return comm_; } - const DomainDecomposition& decomposition() const; #endif void exchange_ghost_atoms(); @@ -54,19 +56,17 @@ class MDCell : public BaseCell void set_lattice_vectors(const ModuleBase::Matrix3& latvec); void refresh_cart_from_frac(); - const std::vector& owned_atoms() const; + const std::vector& owned_atoms() const { return owned_atoms_; } const std::vector& ghost_atoms() const; - const std::vector& type_labels() const; - const std::vector& type_masses() const; + const std::vector& type_labels() const { return type_labels_; } + const std::vector& type_masses() const { return type_masses_; } + const std::vector& type_atom_counts() const { return type_atom_counts_; } std::vector& mutable_owned_atoms(); std::vector& mutable_ghost_atoms(); - int nlocal() const; - int nghost() const; - bool init_vel() const; - void set_init_vel(bool init_vel); + int nlocal() const { return static_cast(owned_atoms_.size()); } + int nghost() const { return static_cast(ghost_atoms_.size()); } double cutoff() const; - double skin() const; bool has_backing_unitcell() const; UnitCell& backing_unitcell(); const UnitCell& backing_unitcell() const; @@ -74,7 +74,7 @@ class MDCell : public BaseCell private: Kind get_kind() const override; - int get_nat() const override; + std::int64_t get_nat() const override; double get_lat0() const override; double get_omega() const override; const ModuleBase::Matrix3& get_latvec() const override; @@ -82,19 +82,18 @@ class MDCell : public BaseCell #ifdef __MPI void initialize_from_ucell_(UnitCell& ucell, MPI_Comm comm, double cutoff, double skin); + void initialize_from_owned_atoms_(MPI_Comm comm, double cutoff, double skin); +#else + void initialize_from_ucell_(UnitCell& ucell, double cutoff, double skin); + void initialize_from_owned_atoms_(double cutoff, double skin); #endif - void initialize_from_ucell_serial_(UnitCell& ucell, double cutoff, double skin); + void sync_backing_unitcell_geometry_(); void sync_backing_unitcell_owned_atoms_(); void clear_forces_(std::vector& atoms); static double wrap_fractional_(double value); -#ifdef __MPI - void initialize_from_owned_atoms_(MPI_Comm comm, double cutoff, double skin); -#else - void initialize_from_owned_atoms_(double cutoff, double skin); -#endif - int nat_ = 0; + std::int64_t nat_ = 0; double lat0_ = 0.0; double omega_ = 0.0; ModuleBase::Matrix3 latvec_; @@ -103,7 +102,7 @@ class MDCell : public BaseCell std::vector ghost_atoms_; std::vector type_labels_; std::vector type_masses_; - bool init_vel_ = false; + std::vector type_atom_counts_; double cutoff_ = 0.0; double skin_ = 0.0; UnitCell* backing_unitcell_ = nullptr; diff --git a/source/source_cell/md_stru_file_metadata.h b/source/source_cell/md_stru_file_metadata.h new file mode 100644 index 00000000000..ffed7ce6c73 --- /dev/null +++ b/source/source_cell/md_stru_file_metadata.h @@ -0,0 +1,28 @@ +#ifndef MD_STRU_FILE_METADATA_H +#define MD_STRU_FILE_METADATA_H + +#include +#include + +/** + * @brief STRU fields retained only to reproduce an MD restart STRU file. + * + * Atom labels, masses, and atom counts belong to MDCell because they are + * physical topology data. This type deliberately contains only input/output + * information that is not used by MD integration or force evaluation. + */ +struct MdStruFileSpecies +{ + std::string pseudo_file; + std::string pseudo_type; + std::string orbital_file; + double start_mag = 0.0; +}; + +struct MdStruFileMetadata +{ + std::vector species; + std::string descriptor_file; +}; + +#endif diff --git a/source/source_cell/module_neighlist/domain_decomposition.cpp b/source/source_cell/module_neighlist/domain_decomposition.cpp index 8472d7d0565..e23f9d0e781 100644 --- a/source/source_cell/module_neighlist/domain_decomposition.cpp +++ b/source/source_cell/module_neighlist/domain_decomposition.cpp @@ -11,6 +11,7 @@ #include #include #include +#include DomainDecomposition::DomainDecomposition() : comm_(MPI_COMM_NULL), @@ -81,7 +82,6 @@ DomainDecomposition& DomainDecomposition::operator=(DomainDecomposition&& other) lat0_ = other.lat0_; cutoff_ = other.cutoff_; skin_ = other.skin_; - other.comm_ = MPI_COMM_NULL; other.cart_comm_ = MPI_COMM_NULL; other.owns_cart_comm_ = false; @@ -280,8 +280,7 @@ void DomainDecomposition::split_owned_atoms_from_ucell(const UnitCell& ucell, ucell.atoms[it].mass / ModuleBase::AU_to_MASS, it, ia, - owner, - false)); + owner)); } } } @@ -410,8 +409,7 @@ LocalAtom DomainDecomposition::unpack_ghost_atom(const PackedAtom& packed) const packed.mass, packed.type, packed.type_index, - packed.owner_rank, - true); + packed.owner_rank); } LocalAtom DomainDecomposition::unpack_owned_atom(const PackedAtom& packed) const @@ -429,8 +427,7 @@ LocalAtom DomainDecomposition::unpack_owned_atom(const PackedAtom& packed) const packed.mass, packed.type, packed.type_index, - packed.owner_rank, - false); + packed.owner_rank); } void DomainDecomposition::exchange_ghost_atoms(const std::vector& owned_atoms, @@ -589,7 +586,7 @@ void DomainDecomposition::exchange_ghost_atoms(const std::vector& own void DomainDecomposition::accumulate_ghost_forces(std::vector& owned_atoms, std::vector& ghost_atoms) const { - std::map, std::size_t> owned_lookup; + std::map, std::size_t> owned_lookup; for (std::size_t iat = 0; iat < owned_atoms.size(); ++iat) { const LocalAtom& atom = owned_atoms[iat]; @@ -602,7 +599,7 @@ void DomainDecomposition::accumulate_ghost_forces(std::vector& owned_ LocalAtom& atom = ghost_atoms[iat]; if (atom.owner_rank == rank_) { - const std::map, std::size_t>::const_iterator found + const std::map, std::size_t>::const_iterator found = owned_lookup.find(std::make_pair(atom.type, atom.type_index)); if (found == owned_lookup.end()) { @@ -664,7 +661,7 @@ void DomainDecomposition::accumulate_ghost_forces(std::vector& owned_ for (std::size_t irecord = 0; irecord < recv_records.size(); ++irecord) { const ForceRecord& record = recv_records[irecord]; - const std::map, std::size_t>::const_iterator found + const std::map, std::size_t>::const_iterator found = owned_lookup.find(std::make_pair(record.type, record.type_index)); if (found == owned_lookup.end()) { @@ -679,67 +676,114 @@ void DomainDecomposition::accumulate_ghost_forces(std::vector& owned_ void DomainDecomposition::migrate_owned_atoms(std::vector& owned_atoms) const { - std::vector > send_atoms(static_cast(size_)); - for (std::size_t i = 0; i < owned_atoms.size(); ++i) + const int direction_count = 6; + const int axis[direction_count] = {0, 0, 1, 1, 2, 2}; + const int step[direction_count] = {-1, 1, -1, 1, -1, 1}; + std::array neighbors; + for (int idir = 0; idir < direction_count; ++idir) { - LocalAtom atom = owned_atoms[i]; - atom.frac = wrapped_frac_from_cart(atom.cart); - atom.cart = atom.frac * latvec_; - atom.owner_rank = owner_rank_from_frac(atom.frac); - atom.is_ghost = false; - const std::array no_shift = {{0, 0, 0}}; - send_atoms[static_cast(atom.owner_rank)].push_back(pack_atom(atom, no_shift)); + std::array neighbor_coords = coords_; + neighbor_coords[axis[idir]] = positive_mod(neighbor_coords[axis[idir]] + step[idir], dims_[axis[idir]]); + neighbors[idir] = rank_from_coords(neighbor_coords); } - std::vector send_counts(static_cast(size_), 0); - std::vector recv_counts(static_cast(size_), 0); - for (int irank = 0; irank < size_; ++irank) - { - send_counts[static_cast(irank)] - = static_cast(send_atoms[static_cast(irank)].size() * sizeof(PackedAtom)); - } - MPI_Alltoall(&send_counts[0], 1, MPI_INT, &recv_counts[0], 1, MPI_INT, comm_); + std::vector pending_atoms; + pending_atoms.swap(owned_atoms); + std::vector retained_atoms; + retained_atoms.reserve(pending_atoms.size()); + const std::array no_shift = {{0, 0, 0}}; - std::vector send_displs(static_cast(size_), 0); - std::vector recv_displs(static_cast(size_), 0); - int total_send_bytes = 0; - int total_recv_bytes = 0; - for (int irank = 0; irank < size_; ++irank) + long long global_outgoing = 0; + do { - send_displs[static_cast(irank)] = total_send_bytes; - recv_displs[static_cast(irank)] = total_recv_bytes; - total_send_bytes += send_counts[static_cast(irank)]; - total_recv_bytes += recv_counts[static_cast(irank)]; - } + std::array, direction_count> send_atoms; + for (std::size_t i = 0; i < pending_atoms.size(); ++i) + { + LocalAtom atom = std::move(pending_atoms[i]); + atom.frac = wrapped_frac_from_cart(atom.cart); + atom.cart = atom.frac * latvec_; - std::vector send_buffer(static_cast(total_send_bytes / static_cast(sizeof(PackedAtom)))); - int send_index = 0; - for (int irank = 0; irank < size_; ++irank) - { - const std::vector& atoms = send_atoms[static_cast(irank)]; - for (std::size_t i = 0; i < atoms.size(); ++i) + std::array owner_coords; + const double frac[3] = {atom.frac.x, atom.frac.y, atom.frac.z}; + for (int idim = 0; idim < 3; ++idim) + { + owner_coords[idim] = std::min(static_cast(std::floor(frac[idim] * dims_[idim])), dims_[idim] - 1); + } + atom.owner_rank = rank_from_coords(owner_coords); + if (atom.owner_rank == rank_) + { + retained_atoms.push_back(std::move(atom)); + continue; + } + + int direction = -1; + for (int idim = 0; idim < 3 && direction < 0; ++idim) + { + int delta = owner_coords[idim] - coords_[idim]; + if (delta > dims_[idim] / 2) delta -= dims_[idim]; + if (delta < -dims_[idim] / 2) delta += dims_[idim]; + if (delta != 0) direction = 2 * idim + (delta > 0 ? 1 : 0); + } + assert(direction >= 0); + send_atoms[direction].push_back(pack_atom(atom, no_shift)); + } + pending_atoms.clear(); + + std::array send_counts; + std::array recv_counts; + long long local_outgoing = 0; + for (int idir = 0; idir < direction_count; ++idir) { - send_buffer[static_cast(send_index++)] = atoms[i]; + const std::size_t bytes = send_atoms[idir].size() * sizeof(PackedAtom); + if (bytes > static_cast(std::numeric_limits::max())) + { + throw std::overflow_error("DomainDecomposition migration send count exceeds int range."); + } + send_counts[idir] = static_cast(bytes); + local_outgoing += static_cast(send_atoms[idir].size()); } - } + MPI_Allreduce(&local_outgoing, &global_outgoing, 1, MPI_LONG_LONG, MPI_SUM, comm_); + if (global_outgoing == 0) break; - std::vector recv_buffer(static_cast(total_recv_bytes / static_cast(sizeof(PackedAtom)))); - MPI_Alltoallv(total_send_bytes > 0 ? reinterpret_cast(&send_buffer[0]) : 0, - &send_counts[0], - &send_displs[0], - MPI_BYTE, - total_recv_bytes > 0 ? reinterpret_cast(&recv_buffer[0]) : 0, - &recv_counts[0], - &recv_displs[0], - MPI_BYTE, - comm_); + std::array requests; + for (int idir = 0; idir < direction_count; ++idir) + { + const int opposite = idir ^ 1; + MPI_Irecv(&recv_counts[idir], 1, MPI_INT, neighbors[idir], 100 + opposite, comm_, &requests[idir]); + MPI_Isend(&send_counts[idir], 1, MPI_INT, neighbors[idir], 100 + idir, comm_, &requests[direction_count + idir]); + } + MPI_Waitall(2 * direction_count, &requests[0], MPI_STATUSES_IGNORE); - owned_atoms.clear(); - owned_atoms.reserve(recv_buffer.size()); - for (std::size_t i = 0; i < recv_buffer.size(); ++i) - { - owned_atoms.push_back(unpack_owned_atom(recv_buffer[i])); - } + std::array, direction_count> recv_atoms; + for (int idir = 0; idir < direction_count; ++idir) + { + if (recv_counts[idir] < 0 || recv_counts[idir] % static_cast(sizeof(PackedAtom)) != 0) + { + throw std::runtime_error("Invalid DomainDecomposition migration receive count."); + } + recv_atoms[idir].resize(static_cast(recv_counts[idir] / static_cast(sizeof(PackedAtom)))); + } + + for (int idir = 0; idir < direction_count; ++idir) + { + const int opposite = idir ^ 1; + MPI_Irecv(recv_atoms[idir].empty() ? NULL : reinterpret_cast(&recv_atoms[idir][0]), + recv_counts[idir], MPI_BYTE, neighbors[idir], 200 + opposite, comm_, &requests[idir]); + MPI_Isend(send_atoms[idir].empty() ? NULL : reinterpret_cast(&send_atoms[idir][0]), + send_counts[idir], MPI_BYTE, neighbors[idir], 200 + idir, comm_, &requests[direction_count + idir]); + } + MPI_Waitall(2 * direction_count, &requests[0], MPI_STATUSES_IGNORE); + + for (int idir = 0; idir < direction_count; ++idir) + { + for (std::size_t i = 0; i < recv_atoms[idir].size(); ++i) + { + pending_atoms.push_back(unpack_owned_atom(recv_atoms[idir][i])); + } + } + } while (global_outgoing > 0); + + owned_atoms.swap(retained_atoms); } #endif // __MPI diff --git a/source/source_cell/module_neighlist/domain_decomposition.h b/source/source_cell/module_neighlist/domain_decomposition.h index cd6d010881b..33d532f04a0 100644 --- a/source/source_cell/module_neighlist/domain_decomposition.h +++ b/source/source_cell/module_neighlist/domain_decomposition.h @@ -8,6 +8,7 @@ #include "source_cell/module_neighlist/local_atom.h" #include +#include #include #include @@ -63,7 +64,7 @@ class DomainDecomposition double mass; int image_shift[3]; int type; - int type_index; + std::int64_t type_index; int owner_rank; }; @@ -80,7 +81,7 @@ class DomainDecomposition struct ForceRecord { int type; - int type_index; + std::int64_t type_index; double force[3]; }; diff --git a/source/source_cell/module_neighlist/local_atom.h b/source/source_cell/module_neighlist/local_atom.h index 5969a8508e1..a311081c2b1 100644 --- a/source/source_cell/module_neighlist/local_atom.h +++ b/source/source_cell/module_neighlist/local_atom.h @@ -4,6 +4,8 @@ #include "source_cell/module_neighlist/neighbor_types.h" #include "source_base/vector3.h" +#include + /** * @brief Atom record owned by a distributed neighbor-search rank. * @@ -21,9 +23,8 @@ struct LocalAtom ModuleBase::Vector3 mbl; double mass; int type; - int type_index; + std::int64_t type_index; int owner_rank; - bool is_ghost; LocalAtom() : cart(0.0, 0.0, 0.0), @@ -34,8 +35,7 @@ struct LocalAtom mass(1.0), type(0), type_index(0), - owner_rank(0), - is_ghost(false) + owner_rank(0) { } @@ -46,9 +46,8 @@ struct LocalAtom const ModuleBase::Vector3& mbl_in, double mass_in, int type_in, - int type_index_in, - int owner_rank_in, - bool is_ghost_in) + std::int64_t type_index_in, + int owner_rank_in) : cart(cart_in), frac(frac_in), vel(vel_in), @@ -57,8 +56,7 @@ struct LocalAtom mass(mass_in), type(type_in), type_index(type_index_in), - owner_rank(owner_rank_in), - is_ghost(is_ghost_in) + owner_rank(owner_rank_in) { } }; diff --git a/source/source_cell/module_neighlist/test/CMakeLists.txt b/source/source_cell/module_neighlist/test/CMakeLists.txt index 08d5b030ced..5653e54bd29 100644 --- a/source/source_cell/module_neighlist/test/CMakeLists.txt +++ b/source/source_cell/module_neighlist/test/CMakeLists.txt @@ -55,18 +55,14 @@ if(ENABLE_MPI) distributed_mdcell_reader_test.cpp ../../distributed_mdcell_reader.cpp ../../md_cell.cpp + ../../print_cell.cpp ../domain_decomposition.cpp - ../../../source_base/global_variable.cpp - ../../../source_base/communication_domain.cpp - ../../../source_base/matrix.cpp - ../../../source_base/matrix3.cpp - ../../../source_base/tool_quit.cpp ) target_include_directories(MODULE_CELL_NEIGHBOR_distributed_mdcell_reader PRIVATE ${ABACUS_SOURCE_DIR}) target_compile_definitions(MODULE_CELL_NEIGHBOR_distributed_mdcell_reader PRIVATE __NORMAL) target_link_libraries(MODULE_CELL_NEIGHBOR_distributed_mdcell_reader PRIVATE - Threads::Threads MPI::MPI_CXX GTest::gtest GTest::gmock + parameter base device Threads::Threads MPI::MPI_CXX GTest::gtest GTest::gmock abacus::linalg_libs ) install(TARGETS MODULE_CELL_NEIGHBOR_distributed_mdcell_reader DESTINATION ${CMAKE_BINARY_DIR}/tests) add_test(NAME MODULE_CELL_NEIGHBOR_distributed_mdcell_reader_np4 diff --git a/source/source_cell/module_neighlist/test/distributed_mdcell_reader_test.cpp b/source/source_cell/module_neighlist/test/distributed_mdcell_reader_test.cpp index 6a4b9be6cab..283b94b649f 100644 --- a/source/source_cell/module_neighlist/test/distributed_mdcell_reader_test.cpp +++ b/source/source_cell/module_neighlist/test/distributed_mdcell_reader_test.cpp @@ -2,18 +2,24 @@ #include "source_cell/distributed_mdcell_reader.h" #include "source_cell/md_cell.h" +#include "source_cell/print_cell.h" #include "source_base/constants.h" -#include "source_base/communication_domain.h" +#include "source_base/parallel_cell.h" +#include "source_base/global_variable.h" #include "source_cell/module_neighlist/domain_decomposition.h" +#include +#include #include #include #include +#include #include #include -static_assert(!std::is_copy_constructible::value, - "MDCell must not copy MPI communicator ownership."); +static_assert(!std::is_copy_constructible::value, "MDCell must not be copy constructible."); +static_assert(!std::is_copy_assignable::value, "MDCell must not be copy assignable."); +static_assert(std::is_move_constructible::value, "MDCell must be move constructible."); namespace { @@ -71,16 +77,23 @@ TEST(DistributedMDCellReaderTest, ReadOwnedAtomsFromSTRUWithoutUnitCell) MPI_Comm_split(MPI_COMM_WORLD, world_rank % 2, world_rank, &md_comm); const ModuleBase::CommunicationDomain communication_domain(md_comm); + MdStruFileMetadata stru_metadata; MDCell mdcell = DistributedMDCellReader::read_stru(stru_file, std::vector{1, 1, 1}, 1.0 * ModuleBase::ANGSTROM_AU, 0.0, + stru_metadata, communication_domain); EXPECT_EQ(mdcell.type_labels().size(), 1U); EXPECT_EQ(mdcell.type_labels()[0], "He"); ASSERT_EQ(mdcell.type_masses().size(), 1U); EXPECT_DOUBLE_EQ(mdcell.type_masses()[0], 4.0026); + ASSERT_EQ(mdcell.type_atom_counts().size(), 1U); + EXPECT_EQ(mdcell.type_atom_counts()[0], 4); + ASSERT_EQ(stru_metadata.species.size(), 1U); + EXPECT_EQ(stru_metadata.species[0].pseudo_file, "auto"); + EXPECT_EQ(stru_metadata.species[0].pseudo_type, "auto"); EXPECT_EQ(mdcell.nat(), 4); DomainDecomposition decomp; @@ -137,9 +150,182 @@ TEST(DistributedMDCellReaderTest, ReadOwnedAtomsFromSTRUWithoutUnitCell) MPI_Comm_free(&md_comm); } +TEST(DistributedMDCellReaderTest, RestartStruPreservesAtomRecordsAcrossRanks) +{ + int rank = 0; + int size = 1; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + ASSERT_GE(size, 4); + + std::vector owned_atoms; + if (rank == 0) + { + owned_atoms.push_back(LocalAtom(ModuleBase::Vector3(11.0, 0.0, 0.0), + ModuleBase::Vector3(0.0, 0.0, 0.0), + ModuleBase::Vector3(0.11, 0.0, 0.0), + ModuleBase::Vector3(0.0, 0.0, 0.0), + ModuleBase::Vector3(1, 0, 1), + 1.0, + 1, + 1, + rank)); + } + if (rank == 1) + { + owned_atoms.push_back(LocalAtom(ModuleBase::Vector3(1.0, 0.0, 0.0), + ModuleBase::Vector3(0.0, 0.0, 0.0), + ModuleBase::Vector3(0.01, 0.0, 0.0), + ModuleBase::Vector3(0.0, 0.0, 0.0), + ModuleBase::Vector3(0, 1, 1), + 1.0, + 0, + 1, + rank)); + } + if (rank == 2) + { + owned_atoms.push_back(LocalAtom(ModuleBase::Vector3(10.0, 0.0, 0.0), + ModuleBase::Vector3(0.0, 0.0, 0.0), + ModuleBase::Vector3(0.10, 0.0, 0.0), + ModuleBase::Vector3(0.0, 0.0, 0.0), + ModuleBase::Vector3(1, 1, 0), + 1.0, + 1, + 0, + rank)); + } + if (rank == 3) + { + owned_atoms.push_back(LocalAtom(ModuleBase::Vector3(0.0, 0.0, 0.0), + ModuleBase::Vector3(0.0, 0.0, 0.0), + ModuleBase::Vector3(0.0, 0.0, 0.0), + ModuleBase::Vector3(0.0, 0.0, 0.0), + ModuleBase::Vector3(0, 0, 1), + 1.0, + 0, + 0, + rank)); + } + + ModuleBase::Matrix3 lattice = make_lattice(); + lattice.e11 = 20.0; + lattice.e22 = 20.0; + lattice.e33 = 20.0; + MDCell mdcell(lattice, + lattice.Inverse(), + 1.0, + 1.0, + 4, + owned_atoms, + std::vector{"A", "B"}, + std::vector{1.0, 1.0}, + std::vector{2, 2}, + 0.0, + 0.0, + ModuleBase::world_communication_domain()); + MdStruFileMetadata metadata; + metadata.species.resize(2); + const std::string output_file = "distributed_mdcell_restart.STRU"; + mdcell::print_stru_file(mdcell, metadata, output_file); + + MdStruFileMetadata round_trip_metadata; + MDCell round_trip = DistributedMDCellReader::read_stru(output_file, + std::vector{1, 1, 1}, + 0.1, + 0.0, + round_trip_metadata, + ModuleBase::world_communication_domain()); + double local_positions[4] = {0.0, 0.0, 0.0, 0.0}; + double local_velocities[4] = {0.0, 0.0, 0.0, 0.0}; + int local_mbl_x[4] = {0, 0, 0, 0}; + int local_owners[4] = {0, 0, 0, 0}; + for (std::size_t iat = 0; iat < round_trip.owned_atoms().size(); ++iat) + { + const LocalAtom& atom = round_trip.owned_atoms()[iat]; + const int index = atom.type == 0 ? static_cast(atom.cart.x) + : 2 + static_cast(atom.cart.x) - 10; + local_positions[index] = atom.cart.x; + local_velocities[index] = atom.vel.x; + local_mbl_x[index] = atom.mbl.x; + local_owners[index] = 1; + } + double global_positions[4] = {0.0, 0.0, 0.0, 0.0}; + double global_velocities[4] = {0.0, 0.0, 0.0, 0.0}; + int global_mbl_x[4] = {0, 0, 0, 0}; + int global_owners[4] = {0, 0, 0, 0}; + MPI_Allreduce(local_positions, global_positions, 4, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(local_velocities, global_velocities, 4, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(local_mbl_x, global_mbl_x, 4, MPI_INT, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(local_owners, global_owners, 4, MPI_INT, MPI_SUM, MPI_COMM_WORLD); + for (int iat = 0; iat < 4; ++iat) EXPECT_EQ(global_owners[iat], 1); + EXPECT_DOUBLE_EQ(global_positions[0], 0.0); + EXPECT_DOUBLE_EQ(global_positions[1], 1.0); + EXPECT_DOUBLE_EQ(global_positions[2], 10.0); + EXPECT_DOUBLE_EQ(global_positions[3], 11.0); + EXPECT_DOUBLE_EQ(global_velocities[0], 0.0); + EXPECT_DOUBLE_EQ(global_velocities[1], 0.01); + EXPECT_DOUBLE_EQ(global_velocities[2], 0.10); + EXPECT_DOUBLE_EQ(global_velocities[3], 0.11); + EXPECT_EQ(global_mbl_x[0], 0); + EXPECT_EQ(global_mbl_x[1], 0); + EXPECT_EQ(global_mbl_x[2], 1); + EXPECT_EQ(global_mbl_x[3], 1); + + if (rank == 0) + { + std::ifstream input(output_file.c_str()); + ASSERT_TRUE(input.good()); + std::vector coordinates_a; + std::vector coordinates_b; + std::string line; + int current_type = -1; + int atoms_remaining = 0; + while (std::getline(input, line)) + { + if (line == "A #label") + { + current_type = 0; + continue; + } + if (line == "B #label") + { + current_type = 1; + continue; + } + if (current_type >= 0 && line.find("#number of atoms") != std::string::npos) + { + std::istringstream count_stream(line); + count_stream >> atoms_remaining; + continue; + } + if (current_type < 0 || atoms_remaining == 0) continue; + std::istringstream values(line); + double x = 0.0; + values >> x; + --atoms_remaining; + if (values) + { + if (current_type == 0) coordinates_a.push_back(x); + else coordinates_b.push_back(x); + } + } + ASSERT_EQ(coordinates_a.size(), 2U); + ASSERT_EQ(coordinates_b.size(), 2U); + std::set expected_a = {0.0, 1.0}; + std::set expected_b = {10.0, 11.0}; + EXPECT_EQ(std::set(coordinates_a.begin(), coordinates_a.end()), expected_a); + EXPECT_EQ(std::set(coordinates_b.begin(), coordinates_b.end()), expected_b); + } + MPI_Barrier(MPI_COMM_WORLD); + if (rank == 0) std::remove(output_file.c_str()); +} + int main(int argc, char** argv) { MPI_Init(&argc, &argv); + MPI_Comm_rank(MPI_COMM_WORLD, &GlobalV::MY_RANK); + MPI_Comm_size(MPI_COMM_WORLD, &GlobalV::NPROC); ::testing::InitGoogleTest(&argc, argv); const int result = RUN_ALL_TESTS(); MPI_Finalize(); diff --git a/source/source_cell/module_neighlist/test/md_cell_migrate_mpi_test.cpp b/source/source_cell/module_neighlist/test/md_cell_migrate_mpi_test.cpp index 7c418ad73e9..e166a04e665 100644 --- a/source/source_cell/module_neighlist/test/md_cell_migrate_mpi_test.cpp +++ b/source/source_cell/module_neighlist/test/md_cell_migrate_mpi_test.cpp @@ -1,10 +1,12 @@ #include #include "source_cell/md_cell.h" -#include "source_base/communication_domain.h" +#include "source_base/parallel_cell.h" #include +#include +#include #include #include @@ -52,8 +54,7 @@ TEST(MdCellMigrateMpiTest, AtomCrossingDomainMigratesToNewOwner) 1.0, 0, rank, - rank, - false)); + rank)); } MDCell mdcell(latvec, latvec.Inverse(), @@ -63,6 +64,7 @@ TEST(MdCellMigrateMpiTest, AtomCrossingDomainMigratesToNewOwner) owned_atoms, std::vector(1, "X"), std::vector(1, 1.0), + std::vector(1, 2), 0.1, 0.0, ModuleBase::world_communication_domain()); @@ -70,6 +72,15 @@ TEST(MdCellMigrateMpiTest, AtomCrossingDomainMigratesToNewOwner) ASSERT_EQ(mdcell.mpi_size(), size); if (size == 2) { + ASSERT_EQ(mdcell.nlocal(), 1); + mdcell.mutable_owned_atoms()[0].vel.x = static_cast(rank + 1); + mdcell.mutable_owned_atoms()[0].force.y = static_cast(rank + 3); + mdcell.migrate_owned_atoms(); + ASSERT_EQ(mdcell.nlocal(), 1); + EXPECT_EQ(mdcell.owned_atoms()[0].owner_rank, rank); + EXPECT_EQ(mdcell.owned_atoms()[0].vel.x, static_cast(rank + 1)); + EXPECT_EQ(mdcell.owned_atoms()[0].force.y, static_cast(rank + 3)); + if (rank == 0 && mdcell.nlocal() == 1) { mdcell.mutable_owned_atoms()[0].cart.x = 0.8; diff --git a/source/source_cell/print_cell.cpp b/source/source_cell/print_cell.cpp index fe269e53683..c8e3bd22bf9 100644 --- a/source/source_cell/print_cell.cpp +++ b/source/source_cell/print_cell.cpp @@ -1,12 +1,23 @@ #include #include +#include +#include +#include +#include +#include +#include #include "print_cell.h" +#include "source_cell/md_cell.h" #include "source_base/formatter.h" #include "source_base/tool_title.h" #include "source_base/global_variable.h" #include "source_base/output.h" +#ifdef __MPI +#include +#endif + namespace unitcell { void print_tau(Atom* atoms, @@ -196,3 +207,203 @@ namespace unitcell return; } } + +namespace +{ +std::string mdcell_stru_header(const MDCell& cell, const MdStruFileMetadata& metadata) +{ + std::ostringstream output; + output << std::fixed << std::setprecision(10); + output << "ATOMIC_SPECIES\n"; + for (std::size_t it = 0; it < metadata.species.size(); ++it) + { + const MdStruFileSpecies& species = metadata.species[it]; + output << cell.type_labels()[it] << " " << std::setprecision(4) << cell.type_masses()[it] << std::setprecision(10); + if (!species.pseudo_file.empty()) output << " " << species.pseudo_file; + if (!species.pseudo_type.empty()) output << " " << species.pseudo_type; + output << "\n"; + } + bool has_orbitals = false; + for (std::size_t it = 0; it < metadata.species.size(); ++it) + has_orbitals = has_orbitals || !metadata.species[it].orbital_file.empty(); + if (has_orbitals) + { + output << "\nNUMERICAL_ORBITAL\n"; + for (std::size_t it = 0; it < metadata.species.size(); ++it) + output << metadata.species[it].orbital_file << "\n"; + } + if (!metadata.descriptor_file.empty()) output << "\nNUMERICAL_DESCRIPTOR\n" << metadata.descriptor_file << "\n"; + output << "\nLATTICE_CONSTANT\n" << cell.lat0() << "\n\nLATTICE_VECTORS\n"; + const ModuleBase::Matrix3& lattice = cell.latvec(); + output << lattice.e11 << " " << lattice.e12 << " " << lattice.e13 << "\n"; + output << lattice.e21 << " " << lattice.e22 << " " << lattice.e23 << "\n"; + output << lattice.e31 << " " << lattice.e32 << " " << lattice.e33 << "\n"; + output << "\nATOMIC_POSITIONS\nCartesian\n"; + return output.str(); +} + +std::string mdcell_type_header(const MDCell& cell, const MdStruFileMetadata& metadata, const std::size_t it) +{ + const MdStruFileSpecies& species = metadata.species[it]; + std::ostringstream output; + output << "\n" << cell.type_labels()[it] << " #label\n"; + output << std::fixed << std::setprecision(4) << species.start_mag << " #magnetism\n"; + output << cell.type_atom_counts()[it] << " #number of atoms\n"; + return output.str(); +} + +std::string mdcell_atom_line(const LocalAtom& atom) +{ + std::ostringstream output; + output << std::fixed << std::setprecision(10) + << atom.cart.x << " " << atom.cart.y << " " << atom.cart.z + << " m " << atom.mbl.x << " " << atom.mbl.y << " " << atom.mbl.z + << " v " << atom.vel.x << " " << atom.vel.y << " " << atom.vel.z << "\n"; + return output.str(); +} + +std::string local_mdcell_atoms(const MDCell& cell, const std::size_t type) +{ + std::string output; + for (std::size_t iat = 0; iat < cell.owned_atoms().size(); ++iat) + { + const LocalAtom& atom = cell.owned_atoms()[iat]; + if (atom.type == static_cast(type)) output += mdcell_atom_line(atom); + } + return output; +} + +#ifdef __MPI +bool write_at(const int file, const std::string& data, MPI_Offset offset) +{ + std::size_t written = 0; + while (written < data.size()) + { + const ssize_t count = pwrite(file, + data.data() + written, + data.size() - written, + static_cast(offset + written)); + if (count <= 0) + { + return false; + } + written += static_cast(count); + } + return true; +} +#endif +} + +namespace unitcell +{ +MdStruFileMetadata make_md_stru_file_metadata(const UnitCell& ucell) +{ + MdStruFileMetadata metadata; + metadata.species.resize(static_cast(ucell.ntype)); + for (int it = 0; it < ucell.ntype; ++it) + { + MdStruFileSpecies& species = metadata.species[static_cast(it)]; + if (static_cast(it) < ucell.pseudo_fn.size()) species.pseudo_file = ucell.pseudo_fn[it]; + if (static_cast(it) < ucell.pseudo_type.size()) species.pseudo_type = ucell.pseudo_type[it]; + if (static_cast(it) < ucell.orbital_fn.size()) species.orbital_file = ucell.orbital_fn[it]; + if (static_cast(it) < ucell.magnet.start_mag.size()) species.start_mag = ucell.magnet.start_mag[it]; + } + metadata.descriptor_file = ucell.descriptor_file; + return metadata; +} +} + +namespace mdcell +{ +void print_stru_file(const MDCell& cell, const MdStruFileMetadata& metadata, const std::string& fn) +{ + if (metadata.species.size() != cell.type_labels().size() + || metadata.species.size() != cell.type_masses().size() + || metadata.species.size() != cell.type_atom_counts().size()) + { + throw std::runtime_error("MDCell STRU metadata does not match the MDCell type data."); + } + const std::string header = mdcell_stru_header(cell, metadata); +#ifdef __MPI + int rank = 0; + const MPI_Comm comm = cell.communicator(); + MPI_Comm_rank(comm, &rank); + int header_ok = 1; + if (rank == 0) + { + const int header_file = open(fn.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0666); + if (header_file < 0) + { + header_ok = 0; + } + else + { + const bool header_written = write_at(header_file, header, 0); + const bool header_closed = close(header_file) == 0; + header_ok = header_written && header_closed; + } + } + MPI_Bcast(&header_ok, 1, MPI_INT, 0, comm); + if (header_ok == 0) + { + throw std::runtime_error("Unable to create MDCell restart STRU file: " + fn + ": " + std::strerror(errno)); + } + MPI_Barrier(comm); + + const int file = open(fn.c_str(), O_WRONLY); + int file_ok = file >= 0 ? 1 : 0; + int all_files_ok = 0; + MPI_Allreduce(&file_ok, &all_files_ok, 1, MPI_INT, MPI_MIN, comm); + if (all_files_ok == 0) + { + if (file >= 0) close(file); + throw std::runtime_error("Unable to open MDCell restart STRU file: " + fn + ": " + std::strerror(errno)); + } + + MPI_Offset offset = static_cast(header.size()); + for (std::size_t it = 0; it < metadata.species.size(); ++it) + { + const std::string type_header = mdcell_type_header(cell, metadata, it); + int type_header_ok = 1; + if (rank == 0) type_header_ok = write_at(file, type_header, offset) ? 1 : 0; + MPI_Bcast(&type_header_ok, 1, MPI_INT, 0, comm); + if (type_header_ok == 0) + { + close(file); + throw std::runtime_error("Unable to write MDCell restart STRU type header: " + fn + ": " + std::strerror(errno)); + } + offset += static_cast(type_header.size()); + const std::string local_atoms = local_mdcell_atoms(cell, it); + const MPI_Offset local_size = static_cast(local_atoms.size()); + MPI_Offset type_size = 0; + MPI_Offset rank_offset = 0; + MPI_Allreduce(&local_size, &type_size, 1, MPI_OFFSET, MPI_SUM, comm); + MPI_Exscan(&local_size, &rank_offset, 1, MPI_OFFSET, MPI_SUM, comm); + if (rank == 0) rank_offset = 0; + int atom_data_ok = 1; + if (local_size > 0) + { + atom_data_ok = write_at(file, local_atoms, offset + rank_offset) ? 1 : 0; + } + int all_atom_data_ok = 0; + MPI_Allreduce(&atom_data_ok, &all_atom_data_ok, 1, MPI_INT, MPI_MIN, comm); + if (all_atom_data_ok == 0) + { + close(file); + throw std::runtime_error("Unable to write MDCell restart STRU atom data: " + fn + ": " + std::strerror(errno)); + } + MPI_Barrier(comm); + offset += type_size; + } + if (close(file) != 0) + { + throw std::runtime_error("Unable to close MDCell restart STRU file: " + fn + ": " + std::strerror(errno)); + } +#else + std::ofstream output(fn.c_str()); + output << header; + for (std::size_t it = 0; it < metadata.species.size(); ++it) + output << mdcell_type_header(cell, metadata, it) << local_mdcell_atoms(cell, it); +#endif +} +} diff --git a/source/source_cell/print_cell.h b/source/source_cell/print_cell.h index 08b255a786d..2fd1b98f18f 100644 --- a/source/source_cell/print_cell.h +++ b/source/source_cell/print_cell.h @@ -6,8 +6,11 @@ #define PRINT_CELL_H #include "atom_spec.h" +#include "source_cell/md_stru_file_metadata.h" #include "source_cell/unitcell.h" +class MDCell; + namespace unitcell { /** @@ -63,6 +66,15 @@ namespace unitcell * @param ofs output file stream [in] */ void print_cell(const UnitCell& ucell, std::ofstream& ofs); + + MdStruFileMetadata make_md_stru_file_metadata(const UnitCell& ucell); +} + +namespace mdcell +{ +void print_stru_file(const MDCell& mdcell, + const MdStruFileMetadata& stru_metadata, + const std::string& fn); } #endif diff --git a/source/source_cell/unitcell.h b/source/source_cell/unitcell.h index bc992f16280..1361af657e7 100644 --- a/source/source_cell/unitcell.h +++ b/source/source_cell/unitcell.h @@ -241,7 +241,7 @@ class UnitCell : public BaseCell { return Kind::unit_cell; } - int get_nat() const override + std::int64_t get_nat() const override { return nat; } diff --git a/source/source_esolver/esolver.h b/source/source_esolver/esolver.h index fcc30b0b359..5b5d4ab1325 100644 --- a/source/source_esolver/esolver.h +++ b/source/source_esolver/esolver.h @@ -46,6 +46,17 @@ class ESolver //! calcualte stress of given cell virtual void cal_stress(BaseCell& cell, ModuleBase::matrix& stress) = 0; + virtual bool supports_mdcell() const + { + return false; + } + + virtual double mdcell_cutoff(const Input_para& inp) const + { + static_cast(inp); + return 0.0; + } + bool conv_esolver = true; // whether esolver is converged std::string classname; diff --git a/source/source_esolver/esolver_dp.cpp b/source/source_esolver/esolver_dp.cpp index 84359cde992..b540520afcf 100644 --- a/source/source_esolver/esolver_dp.cpp +++ b/source/source_esolver/esolver_dp.cpp @@ -20,10 +20,15 @@ #include "esolver_dp.h" #include "source_base/parallel_common.h" #include "source_base/timer.h" +#include "source_cell/md_cell.h" +#include "source_cell/module_neighlist/neighbor_search.h" +#include "source_cell/cif_io.h" #include "source_io/module_output/output_log.h" #include "source_io/module_parameter/parameter.h" +#include #include +#include #include #include @@ -31,81 +36,199 @@ using namespace ModuleESolver; void ESolver_DP::before_all_runners(BaseCell& basecell, const Input_para& inp) { - basecell.require_kind(BaseCell::Kind::unit_cell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); - dp_potential = 0; - dp_force.create(ucell.nat, 3); dp_virial.create(3, 3); - dp_cell.resize(9); - dp_coord.resize(3 * ucell.nat); - dp_model_force.clear(); - dp_model_virial.clear(); - - atype.resize(ucell.nat); - - // Build flat atom index for OpenMP coordinate fill in runner() - atom_type_index.resize(ucell.nat); - atom_local_index.resize(ucell.nat); - int iat = 0; - for (int it = 0; it < ucell.ntype; ++it) - { - for (int ia = 0; ia < ucell.atoms[it].na; ++ia) - { - atom_type_index[iat] = it; - atom_local_index[iat] = ia; - iat++; - } - } - rescaling = inp.mdp.dp_rescaling; fparam = inp.mdp.dp_fparam; aparam = inp.mdp.dp_aparam; + if (basecell.kind() == BaseCell::Kind::md_cell) + { + MDCell& mdcell = static_cast(basecell); +#ifdef __DPMD + initialize_type_map_(mdcell.type_labels()); +#endif + return; + } + + UnitCell& ucell = static_cast(basecell); + dp_force.create(ucell.nat, 3); + ModuleIO::CifParser::write(PARAM.globalv.global_out_dir + "STRU.cif", + ucell, + "# Generated by ABACUS ModuleIO::CifParser", + "data_?"); + atype.resize(ucell.nat); #ifdef __DPMD - /// determine the type map from STRU to DP model type_map(ucell); #endif } void ESolver_DP::runner(BaseCell& basecell, const int istep) { - basecell.require_kind(BaseCell::Kind::unit_cell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); - ModuleBase::TITLE("ESolver_DP", "runner"); ModuleBase::timer::start("ESolver_DP", "runner"); - dp_cell[0] = ucell.latvec.e11 * ucell.lat0_angstrom; - dp_cell[1] = ucell.latvec.e12 * ucell.lat0_angstrom; - dp_cell[2] = ucell.latvec.e13 * ucell.lat0_angstrom; - dp_cell[3] = ucell.latvec.e21 * ucell.lat0_angstrom; - dp_cell[4] = ucell.latvec.e22 * ucell.lat0_angstrom; - dp_cell[5] = ucell.latvec.e23 * ucell.lat0_angstrom; - dp_cell[6] = ucell.latvec.e31 * ucell.lat0_angstrom; - dp_cell[7] = ucell.latvec.e32 * ucell.lat0_angstrom; - dp_cell[8] = ucell.latvec.e33 * ucell.lat0_angstrom; - - dp_coord.resize(3 * ucell.nat); - const int nat = ucell.nat; -#pragma omp parallel for schedule(static) if (nat >= 256) - for (int iat = 0; iat < nat; ++iat) + if (basecell.kind() == BaseCell::Kind::md_cell) { - const int it = atom_type_index[iat]; - const int ia = atom_local_index[iat]; - dp_coord[3 * iat] = ucell.atoms[it].tau[ia].x * ucell.lat0_angstrom; - dp_coord[3 * iat + 1] = ucell.atoms[it].tau[ia].y * ucell.lat0_angstrom; - dp_coord[3 * iat + 2] = ucell.atoms[it].tau[ia].z * ucell.lat0_angstrom; +#ifndef __DPMD + ModuleBase::WARNING_QUIT("ESolver_DP", "Please recompile with -D__DPMD"); +#else + static_cast(istep); + MDCell& mdcell = static_cast(basecell); + const int nlocal = mdcell.nlocal(); + const int nghost = mdcell.nghost(); + const int natom = nlocal + nghost; + if (natom == 0) + { + ModuleBase::WARNING_QUIT("ESolver_DP", "MDCell contains no atoms."); + } + + std::vector cell(9, 0.0); + cell[0] = mdcell.latvec().e11 * mdcell.lat0() * ModuleBase::BOHR_TO_A; + cell[1] = mdcell.latvec().e12 * mdcell.lat0() * ModuleBase::BOHR_TO_A; + cell[2] = mdcell.latvec().e13 * mdcell.lat0() * ModuleBase::BOHR_TO_A; + cell[3] = mdcell.latvec().e21 * mdcell.lat0() * ModuleBase::BOHR_TO_A; + cell[4] = mdcell.latvec().e22 * mdcell.lat0() * ModuleBase::BOHR_TO_A; + cell[5] = mdcell.latvec().e23 * mdcell.lat0() * ModuleBase::BOHR_TO_A; + cell[6] = mdcell.latvec().e31 * mdcell.lat0() * ModuleBase::BOHR_TO_A; + cell[7] = mdcell.latvec().e32 * mdcell.lat0() * ModuleBase::BOHR_TO_A; + cell[8] = mdcell.latvec().e33 * mdcell.lat0() * ModuleBase::BOHR_TO_A; + + const std::vector& owned_atoms = mdcell.owned_atoms(); + const std::vector& ghost_atoms = mdcell.ghost_atoms(); + std::vector coord(static_cast(3 * natom), 0.0); + std::vector local_atype(static_cast(natom), 0); + for (int iat = 0; iat < natom; ++iat) + { + const LocalAtom& atom = iat < nlocal ? owned_atoms[static_cast(iat)] + : ghost_atoms[static_cast(iat - nlocal)]; + coord[3 * iat] = atom.cart.x * mdcell.lat0() * ModuleBase::BOHR_TO_A; + coord[3 * iat + 1] = atom.cart.y * mdcell.lat0() * ModuleBase::BOHR_TO_A; + coord[3 * iat + 2] = atom.cart.z * mdcell.lat0() * ModuleBase::BOHR_TO_A; + if (atom.type < 0 || static_cast(atom.type) >= md_type_to_dp_type_.size()) + { + ModuleBase::WARNING_QUIT("ESolver_DP", "MDCell atom type is outside the DeePMD type map."); + } + local_atype[static_cast(iat)] = md_type_to_dp_type_[static_cast(atom.type)]; + } + + const int dim_aparam = dp.dim_aparam(); + if (dim_aparam > 0) + { + ModuleBase::WARNING_QUIT("ESolver_DP", + "MDCell support does not yet support DeePMD atomic parameters (dim_aparam > 0)."); + } + + NeighborSearch neighbor_search; + neighbor_search.init(mdcell, mdcell.cutoff()); + neighbor_search.build_neighbors(); + const NeighborList& neighbor_list = neighbor_search.get_neighbor_list(); + std::vector ilist(static_cast(nlocal), 0); + std::vector numneigh(static_cast(nlocal), 0); + std::vector firstneigh(static_cast(nlocal), NULL); + for (int iat = 0; iat < nlocal; ++iat) + { + ilist[static_cast(iat)] = iat; + numneigh[static_cast(iat)] = neighbor_list.get_numneigh(iat); + firstneigh[static_cast(iat)] = const_cast(neighbor_list.get_firstneigh(iat)); + } +#ifdef __DPMDC + deepmd::hpp::InputNlist nlist(nlocal, + nlocal > 0 ? &ilist[0] : NULL, + nlocal > 0 ? &numneigh[0] : NULL, + nlocal > 0 ? &firstneigh[0] : NULL); +#else + deepmd::InputNlist nlist(nlocal, + nlocal > 0 ? &ilist[0] : NULL, + nlocal > 0 ? &numneigh[0] : NULL, + nlocal > 0 ? &firstneigh[0] : NULL); +#endif + double local_energy = 0.0; + std::vector force, virial; + ModuleBase::timer::start("ESolver_DP", "compute"); + dp.compute(local_energy, force, virial, coord, local_atype, cell, nghost, nlist, 0, fparam); + ModuleBase::timer::end("ESolver_DP", "compute"); + if (force.size() != static_cast(3 * natom)) + { + ModuleBase::WARNING_QUIT("ESolver_DP", "DeePMD returned an invalid force array for MDCell."); + } + + std::vector& mutable_owned_atoms = mdcell.mutable_owned_atoms(); + std::vector& mutable_ghost_atoms = mdcell.mutable_ghost_atoms(); + for (int iat = 0; iat < nlocal; ++iat) + { + mutable_owned_atoms[static_cast(iat)].force.set(force[3 * iat], force[3 * iat + 1], force[3 * iat + 2]); + } + for (int iat = 0; iat < nghost; ++iat) + { + mutable_ghost_atoms[static_cast(iat)].force.set(force[3 * (nlocal + iat)], + force[3 * (nlocal + iat) + 1], + force[3 * (nlocal + iat) + 2]); + } + mdcell.accumulate_ghost_forces(); + + if (virial.size() != 9) + { + ModuleBase::WARNING_QUIT("ESolver_DP", "DeePMD returned an invalid virial tensor for MDCell."); + } + + std::array local_virial; + std::copy(virial.begin(), virial.end(), local_virial.begin()); +#ifdef __MPI + MPI_Allreduce(MPI_IN_PLACE, &local_energy, 1, MPI_DOUBLE, MPI_SUM, mdcell.communicator()); + MPI_Allreduce(MPI_IN_PLACE, local_virial.data(), 9, MPI_DOUBLE, MPI_SUM, mdcell.communicator()); +#endif + const double fact_e = rescaling / ModuleBase::Ry_to_eV; + const double fact_f = rescaling / (ModuleBase::Ry_to_eV * ModuleBase::ANGSTROM_AU); + const double fact_v = rescaling / (mdcell.omega() * ModuleBase::Ry_to_eV); + dp_potential = local_energy * fact_e; + for (int iat = 0; iat < nlocal; ++iat) + { + LocalAtom& atom = mutable_owned_atoms[static_cast(iat)]; + atom.force *= fact_f; + } + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 3; ++j) + dp_virial(i, j) = local_virial[static_cast(3 * i + j)] * fact_v; +#endif + ModuleBase::timer::end("ESolver_DP", "runner"); + return; } + UnitCell& ucell = static_cast(basecell); + + std::vector cell(9, 0.0); + cell[0] = ucell.latvec.e11 * ucell.lat0_angstrom; + cell[1] = ucell.latvec.e12 * ucell.lat0_angstrom; + cell[2] = ucell.latvec.e13 * ucell.lat0_angstrom; + cell[3] = ucell.latvec.e21 * ucell.lat0_angstrom; + cell[4] = ucell.latvec.e22 * ucell.lat0_angstrom; + cell[5] = ucell.latvec.e23 * ucell.lat0_angstrom; + cell[6] = ucell.latvec.e31 * ucell.lat0_angstrom; + cell[7] = ucell.latvec.e32 * ucell.lat0_angstrom; + cell[8] = ucell.latvec.e33 * ucell.lat0_angstrom; + + std::vector coord(3 * ucell.nat, 0.0); + int iat = 0; + for (int it = 0; it < ucell.ntype; ++it) + { + for (int ia = 0; ia < ucell.atoms[it].na; ++ia) + { + coord[3 * iat] = ucell.atoms[it].tau[ia].x * ucell.lat0_angstrom; + coord[3 * iat + 1] = ucell.atoms[it].tau[ia].y * ucell.lat0_angstrom; + coord[3 * iat + 2] = ucell.atoms[it].tau[ia].z * ucell.lat0_angstrom; + iat++; + } + } + assert(ucell.nat == iat); + #ifdef __DPMD + std::vector f, v; dp_potential = 0; dp_force.zero_out(); dp_virial.zero_out(); - dp_model_force.clear(); - dp_model_virial.clear(); - dp.compute(dp_potential, dp_model_force, dp_model_virial, dp_coord, atype, dp_cell, fparam, aparam); + dp.compute(dp_potential, f, v, coord, atype, cell, fparam, aparam); // rescale the energy, force, and stress const double fact_e = rescaling / ModuleBase::Ry_to_eV; @@ -116,20 +239,18 @@ void ESolver_DP::runner(BaseCell& basecell, const int istep) GlobalV::ofs_running << " #TOTAL ENERGY# " << std::setprecision(11) << dp_potential * ModuleBase::Ry_to_eV << " eV" << std::endl; - const int nat_f = ucell.nat; -#pragma omp parallel for schedule(static) if (nat_f >= 256) - for (int i = 0; i < nat_f; ++i) + for (int i = 0; i < ucell.nat; ++i) { - dp_force(i, 0) = dp_model_force[3 * i] * fact_f; - dp_force(i, 1) = dp_model_force[3 * i + 1] * fact_f; - dp_force(i, 2) = dp_model_force[3 * i + 2] * fact_f; + dp_force(i, 0) = f[3 * i] * fact_f; + dp_force(i, 1) = f[3 * i + 1] * fact_f; + dp_force(i, 2) = f[3 * i + 2] * fact_f; } for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { - dp_virial(i, j) = dp_model_virial[3 * i + j] * fact_v; + dp_virial(i, j) = v[3 * i + j] * fact_v; } } #else @@ -143,23 +264,60 @@ double ESolver_DP::cal_energy() return dp_potential; } -void ESolver_DP::cal_force(BaseCell& basecell, ModuleBase::matrix& force) +bool ESolver_DP::supports_mdcell() const { - basecell.require_kind(BaseCell::Kind::unit_cell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + return true; +} +double ESolver_DP::mdcell_cutoff(const Input_para& inp) const +{ + static_cast(inp); +#ifdef __DPMD + return dp.cutoff() * ModuleBase::ANGSTROM_AU; +#else + ModuleBase::WARNING_QUIT("ESolver_DP::mdcell_cutoff", "Please recompile with -D__DPMD"); + return 0.0; +#endif +} + +void ESolver_DP::cal_force(BaseCell& basecell, ModuleBase::matrix& force) +{ + if (basecell.kind() == BaseCell::Kind::md_cell) + { + const MDCell& mdcell = static_cast(basecell); + force.create(mdcell.nlocal(), 3); + for (int iat = 0; iat < mdcell.nlocal(); ++iat) + { + const LocalAtom& atom = mdcell.owned_atoms()[static_cast(iat)]; + force(iat, 0) = atom.force.x; + force(iat, 1) = atom.force.y; + force(iat, 2) = atom.force.z; + } + return; + } force = dp_force; - ModuleIO::print_force(GlobalV::ofs_running, ucell, "TOTAL-FORCE (eV/Angstrom)", force, false); + ModuleIO::print_force(GlobalV::ofs_running, + static_cast(basecell), + "TOTAL-FORCE (eV/Angstrom)", force, false); } void ESolver_DP::cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) { - basecell.require_kind(BaseCell::Kind::unit_cell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); - stress = dp_virial; - ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, GlobalV::ofs_running); + if (basecell.kind() == BaseCell::Kind::unit_cell) + { + ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, GlobalV::ofs_running); + } + else + { +#ifdef __MPI + if (static_cast(basecell).mpi_rank() == 0) +#endif + { + ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, GlobalV::ofs_running); + } + } // external stress double unit_transform = ModuleBase::RYDBERG_SI / pow(ModuleBase::BOHR_RADIUS_SI, 3) * 1.0e-8; @@ -172,8 +330,7 @@ void ESolver_DP::cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) void ESolver_DP::after_all_runners(BaseCell& basecell) { - basecell.require_kind(BaseCell::Kind::unit_cell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + static_cast(basecell); GlobalV::ofs_running << "\n --------------------------------------------" << std::endl; GlobalV::ofs_running << std::setprecision(16); @@ -183,6 +340,26 @@ void ESolver_DP::after_all_runners(BaseCell& basecell) #ifdef __DPMD void ESolver_DP::type_map(const UnitCell& ucell) +{ + std::vector type_labels(static_cast(ucell.ntype)); + for (int it = 0; it < ucell.ntype; ++it) + { + type_labels[static_cast(it)] = ucell.atoms[it].label; + } + initialize_type_map_(type_labels); + + int iat = 0; + for (int it = 0; it < ucell.ntype; ++it) + { + for (int ia = 0; ia < ucell.atoms[it].na; ++ia) + { + atype[static_cast(iat++)] = md_type_to_dp_type_[static_cast(it)]; + } + } + assert(ucell.nat == iat); +} + +void ESolver_DP::initialize_type_map_(const std::vector& type_labels) { std::string type = ""; dp.get_type_map(type); @@ -212,20 +389,16 @@ void ESolver_DP::type_map(const UnitCell& ucell) } std::cout << "\n -----------------------------------------------------------------" << std::endl; - int iat = 0; - for (int it = 0; it < ucell.ntype; ++it) + md_type_to_dp_type_.resize(type_labels.size()); + for (std::size_t it = 0; it < type_labels.size(); ++it) { - for (int ia = 0; ia < ucell.atoms[it].na; ++ia) + const std::unordered_map::const_iterator found = label.find(type_labels[it]); + if (found == label.end()) { - if (label.find(ucell.atoms[it].label) == label.end()) - { - ModuleBase::WARNING_QUIT("ESolver_DP", - "The label " + ucell.atoms[it].label + " is not found in the type map."); - } - atype[iat] = label[ucell.atoms[it].label]; - iat++; + ModuleBase::WARNING_QUIT("ESolver_DP", + "The label " + type_labels[it] + " is not found in the type map."); } + md_type_to_dp_type_[it] = found->second; } - assert(ucell.nat == iat); } #endif diff --git a/source/source_esolver/esolver_dp.h b/source/source_esolver/esolver_dp.h index 7e9ee770d03..0695711a3bb 100644 --- a/source/source_esolver/esolver_dp.h +++ b/source/source_esolver/esolver_dp.h @@ -68,6 +68,9 @@ class ESolver_DP : public ESolver */ void cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) override; + bool supports_mdcell() const override; + double mdcell_cutoff(const Input_para& inp) const override; + /** * @brief Prints the final total energy of the DP model to the output file * @@ -82,6 +85,7 @@ class ESolver_DP : public ESolver * @param ucell unitcell information */ void type_map(const UnitCell& ucell); + void initialize_type_map_(const std::vector& type_labels); /** * @brief DeePMD related variables for ESolver_DP class @@ -109,18 +113,13 @@ class ESolver_DP : public ESolver std::string dp_file; ///< directory of DP model file std::vector atype = {}; ///< atom type corresponding to DP model - std::vector atom_type_index; ///< type index (it) for each global atom iat - std::vector atom_local_index; ///< local index (ia) within type for each global atom iat + std::vector md_type_to_dp_type_; std::vector fparam = {}; ///< frame parameter for dp potential: dim_fparam std::vector aparam = {}; ///< atomic parameter for dp potential: natoms x dim_aparam double rescaling = 1.0; ///< rescaling factor for DP model double dp_potential = 0.0; ///< computed potential energy ModuleBase::matrix dp_force; ///< computed atomic forces ModuleBase::matrix dp_virial; ///< computed lattice virials - std::vector dp_cell; ///< DP cell buffer in Angstrom - std::vector dp_coord; ///< DP coordinate buffer in Angstrom - std::vector dp_model_force; ///< raw force buffer returned by DP - std::vector dp_model_virial; ///< raw virial buffer returned by DP }; } // namespace ModuleESolver diff --git a/source/source_esolver/esolver_lj.cpp b/source/source_esolver/esolver_lj.cpp index 3ddd664e9b2..b214e30975b 100644 --- a/source/source_esolver/esolver_lj.cpp +++ b/source/source_esolver/esolver_lj.cpp @@ -1,16 +1,14 @@ #include "esolver_lj.h" + +#include "source_base/global_variable.h" +#include "source_cell/md_cell.h" +#include "source_cell/module_neighlist/neighbor_search.h" +#include "source_cell/module_neighlist/neighbor_types.h" #include "source_io/module_parameter/parameter.h" -#include "source_cell/module_neighbor/sltk_atom_arrange.h" -#include "source_cell/module_neighbor/sltk_grid_driver.h" +#include "source_cell/cif_io.h" #include "source_io/module_output/output_log.h" -#include "source_cell/module_neighlist/neighbor_types.h" -#include "source_cell/module_neighlist/neighbor_search.h" -#include "source_cell/md_cell.h" -#include "source_base/communication_domain.h" -#include "source_base/global_variable.h" -#include "source_base/timer.h" #ifdef __MPI -#include "source_base/parallel_reduce.h" +#include #endif #include @@ -18,398 +16,391 @@ #include #include - namespace ModuleESolver { +double ESolver_LJ::mdcell_cutoff(const Input_para& inp) const +{ + double cutoff = 0.0; + for (std::size_t i = 0; i < inp.mdp.lj_rcut.size(); ++i) + { + cutoff = std::max(cutoff, inp.mdp.lj_rcut[i] * ModuleBase::ANGSTROM_AU); + } + return cutoff; +} void ESolver_LJ::before_all_runners(BaseCell& cell, const Input_para& inp) { - cell.require_kind(BaseCell::Kind::unit_cell, __FUNCTION__); - UnitCell& ucell = static_cast(cell); - lj_potential = 0; - lj_force.create(ucell.nat, 3); + lj_potential = 0.0; lj_virial.create(3, 3); - // determine the maximum rcut and lj_rcut - rcut_search_radius(ucell.ntype, inp.mdp.lj_rcut); + if (cell.kind() == BaseCell::Kind::md_cell) + { + MDCell& mdcell = static_cast(cell); + rcut_search_radius(static_cast(mdcell.type_labels().size()), inp.mdp.lj_rcut); + set_c6_c12(static_cast(mdcell.type_labels().size()), inp.mdp.lj_rule, inp.mdp.lj_epsilon, inp.mdp.lj_sigma); + cal_en_shift(static_cast(mdcell.type_labels().size()), inp.mdp.lj_eshift); + return; + } - // determine the LJ parameters + UnitCell& ucell = static_cast(cell); + lj_force.create(ucell.nat, 3); + ModuleIO::CifParser::write(PARAM.globalv.global_out_dir + "STRU.cif", + ucell, + "# Generated by ABACUS ModuleIO::CifParser", + "data_?"); + rcut_search_radius(ucell.ntype, inp.mdp.lj_rcut); set_c6_c12(ucell.ntype, inp.mdp.lj_rule, inp.mdp.lj_epsilon, inp.mdp.lj_sigma); - - // calculate the energy shift so that LJ energy is zero at rcut cal_en_shift(ucell.ntype, inp.mdp.lj_eshift); } void ESolver_LJ::runner(BaseCell& cell, const int istep) { static_cast(istep); - cell.require_kind(BaseCell::Kind::unit_cell, __FUNCTION__); - UnitCell& ucell = static_cast(cell); - NeighborSearch neighbor_search; - // Important! potential, force, virial must be zero per step - lj_potential = 0; - lj_force.zero_out(); + NeighborSearch neighbor_search; + lj_potential = 0.0; lj_virial.zero_out(); - double distance = 0.0; - ModuleBase::Vector3 tau1, tau2, dtau; - - #ifdef __MPI + if (cell.kind() == BaseCell::Kind::unit_cell) { - ModuleBase::timer::start("ESolverLJ", "mpi_total"); - ModuleBase::timer::start("ESolverLJ", "neigh_init"); - const ModuleBase::CommunicationDomain communication_domain = ModuleBase::world_communication_domain(); - MDCell mdcell(ucell, search_radius, 0.0, communication_domain); - neighbor_search.init(mdcell, search_radius); - ModuleBase::timer::end("ESolverLJ", "neigh_init"); - ModuleBase::timer::start("ESolverLJ", "neigh_bld"); + UnitCell& ucell = static_cast(cell); + lj_force.zero_out(); + neighbor_search.init(ucell, search_radius); neighbor_search.build_neighbors(); - ModuleBase::timer::end("ESolverLJ", "neigh_bld"); const NeighborList& neighbor_list = neighbor_search.get_neighbor_list(); const std::vector& inside_atoms = neighbor_search.get_inside_atoms(); const std::vector& all_atoms = neighbor_search.get_all_atoms(); - - std::vector atom_start(ucell.ntype + 1, 0); + std::array virial{}; + std::vector atom_offsets(ucell.ntype + 1, 0); for (int it = 0; it < ucell.ntype; ++it) { - atom_start[it + 1] = atom_start[it] + ucell.atoms[it].na; + atom_offsets[it + 1] = atom_offsets[it] + ucell.atoms[it].na; } - const std::size_t local_virial_size - = ModuleNeighList::checked_size_product(inside_atoms.size(), 9, "ESolver_LJ local virial size"); - std::vector potential_by_local_atom(inside_atoms.size(), 0.0); - std::vector virial_by_local_atom(local_virial_size, 0.0); - - ModuleBase::timer::start("ESolverLJ", "force_loc"); for (int local_i = 0; local_i < neighbor_list.get_nlocal(); ++local_i) { - const NeighborAtom& center_atom = inside_atoms[local_i]; + const NeighborAtom& center_atom = inside_atoms[static_cast(local_i)]; const int it = center_atom.atom_type; const int ia = center_atom.atom_index; - const int global_i = atom_start[it] + ia; - - tau1.x = center_atom.position_x; - tau1.y = center_atom.position_y; - tau1.z = center_atom.position_z; - + const int iat = atom_offsets[it] + ia; + const ModuleBase::Vector3 tau1(center_atom.position_x, + center_atom.position_y, + center_atom.position_z); for (int ad = 0; ad < neighbor_list.get_numneigh(local_i); ++ad) { const NeighborAtom& neighbor_atom = all_atoms[neighbor_list.get_firstneigh(local_i)[ad]]; - tau2.x = neighbor_atom.position_x; - tau2.y = neighbor_atom.position_y; - tau2.z = neighbor_atom.position_z; - int it2 = neighbor_atom.atom_type; - dtau = (tau1 - tau2) * ucell.lat0; - distance = dtau.norm(); - if (distance < lj_rcut(it, it2)) + const ModuleBase::Vector3 tau2(neighbor_atom.position_x, + neighbor_atom.position_y, + neighbor_atom.position_z); + const ModuleBase::Vector3 dtau = (tau1 - tau2) * ucell.lat0; + const double distance = dtau.norm(); + if (distance < lj_rcut(it, neighbor_atom.atom_type)) { - potential_by_local_atom[local_i] += LJ_energy(distance, it, it2) - en_shift(it, it2); - ModuleBase::Vector3 f_ij = LJ_force(dtau, it, it2); - lj_force(global_i, 0) += f_ij.x; - lj_force(global_i, 1) += f_ij.y; - lj_force(global_i, 2) += f_ij.z; + lj_potential += LJ_energy(distance, it, neighbor_atom.atom_type) + - en_shift(it, neighbor_atom.atom_type); + const ModuleBase::Vector3 f_ij = LJ_force(dtau, it, neighbor_atom.atom_type); + lj_force(iat, 0) += f_ij.x; + lj_force(iat, 1) += f_ij.y; + lj_force(iat, 2) += f_ij.z; for (int i = 0; i < 3; ++i) - { - for (int j = 0; j < 3; ++j) - { - virial_by_local_atom[local_i * 9 + i * 3 + j] += dtau[i] * f_ij[j]; - } - } + for (int j = 0; j < 3; ++j) virial[i * 3 + j] += dtau[i] * f_ij[j]; } } } - ModuleBase::timer::end("ESolverLJ", "force_loc"); - double local_potential = 0.0; - std::array local_virial{}; - for (std::size_t local_i = 0; local_i < potential_by_local_atom.size(); ++local_i) - { - local_potential += potential_by_local_atom[local_i]; - for (int component = 0; component < 9; ++component) - { - local_virial[component] += virial_by_local_atom[local_i * 9 + component]; - } - } - - ModuleBase::timer::start("ESolverLJ", "reduce"); - Parallel_Reduce::reduce_all(&local_potential, 1); - Parallel_Reduce::reduce_all(local_virial.data(), static_cast(local_virial.size())); - // Existing MD code expects a full global force matrix on each rank. - // Keeping this reduction preserves current behavior; removing the global - // force layout requires a distributed MD data model. - Parallel_Reduce::reduce_all(lj_force.c, lj_force.nr * lj_force.nc); - ModuleBase::timer::end("ESolverLJ", "reduce"); - - lj_potential += local_potential; + lj_potential *= 0.5; for (int i = 0; i < 3; ++i) - { - for (int j = 0; j < 3; ++j) - { - lj_virial(i, j) += local_virial[i * 3 + j]; - } - } - ModuleBase::timer::end("ESolverLJ", "mpi_total"); + for (int j = 0; j < 3; ++j) lj_virial(i, j) = virial[i * 3 + j] / (2.0 * ucell.omega); + GlobalV::ofs_running << " #TOTAL ENERGY# " << std::setprecision(11) + << lj_potential * ModuleBase::Ry_to_eV << " eV" << std::endl; + return; } - #else + + MDCell& mdcell = static_cast(cell); + + std::vector& owned_atoms = mdcell.mutable_owned_atoms(); + for (std::size_t i = 0; i < owned_atoms.size(); ++i) { - ModuleBase::timer::start("ESolverLJ", "serial_tot"); - ModuleBase::timer::start("ESolverLJ", "ser_neigh"); - neighbor_search.init(ucell, search_radius); - neighbor_search.build_neighbors(); - ModuleBase::timer::end("ESolverLJ", "ser_neigh"); + owned_atoms[i].force.set(0.0, 0.0, 0.0); + } - int index = 0; - const NeighborList& neighbor_list = neighbor_search.get_neighbor_list(); - const std::vector& all_atoms = neighbor_search.get_all_atoms(); - ModuleBase::timer::start("ESolverLJ", "ser_force"); - for (int it = 0; it < ucell.ntype; ++it) + neighbor_search.init(mdcell, search_radius); + neighbor_search.build_neighbors(); + + const NeighborList& neighbor_list = neighbor_search.get_neighbor_list(); + const std::vector& inside_atoms = neighbor_search.get_inside_atoms(); + const std::vector& all_atoms = neighbor_search.get_all_atoms(); + + double local_potential = 0.0; + std::array local_virial{}; + + for (int local_i = 0; local_i < neighbor_list.get_nlocal(); ++local_i) + { + LocalAtom& center_atom = owned_atoms[static_cast(local_i)]; + ModuleBase::Vector3 tau1(center_atom.cart.x, center_atom.cart.y, center_atom.cart.z); + for (int ad = 0; ad < neighbor_list.get_numneigh(local_i); ++ad) { - Atom* atom1 = &ucell.atoms[it]; - for (int ia = 0; ia < atom1->na; ++ia) + const NeighborAtom& neighbor_atom = all_atoms[neighbor_list.get_firstneigh(local_i)[ad]]; + ModuleBase::Vector3 tau2(neighbor_atom.position_x, + neighbor_atom.position_y, + neighbor_atom.position_z); + ModuleBase::Vector3 dtau = (tau1 - tau2) * mdcell.lat0(); + const double distance = dtau.norm(); + if (distance < lj_rcut(center_atom.type, neighbor_atom.atom_type)) { - tau1 = atom1->tau[ia]; - for (int ad = 0; ad < neighbor_list.get_numneigh(index); ++ad) + local_potential += LJ_energy(distance, center_atom.type, neighbor_atom.atom_type) + - en_shift(center_atom.type, neighbor_atom.atom_type); + ModuleBase::Vector3 f_ij = LJ_force(dtau, center_atom.type, neighbor_atom.atom_type); + center_atom.force += f_ij; + for (int i = 0; i < 3; ++i) { - const NeighborAtom& neighbor_atom = all_atoms[neighbor_list.get_firstneigh(index)[ad]]; - tau2.x = neighbor_atom.position_x; - tau2.y = neighbor_atom.position_y; - tau2.z = neighbor_atom.position_z; - int it2 = neighbor_atom.atom_type; - dtau = (tau1 - tau2) * ucell.lat0; - distance = dtau.norm(); - if (distance < lj_rcut(it, it2)) + for (int j = 0; j < 3; ++j) { - lj_potential += LJ_energy(distance, it, it2) - en_shift(it, it2); - ModuleBase::Vector3 f_ij = LJ_force(dtau, it, it2); - lj_force(index, 0) += f_ij.x; - lj_force(index, 1) += f_ij.y; - lj_force(index, 2) += f_ij.z; - LJ_virial(f_ij, dtau); + local_virial[i * 3 + j] += dtau[i] * f_ij[j]; } } - index++; } } - ModuleBase::timer::end("ESolverLJ", "ser_force"); - ModuleBase::timer::end("ESolverLJ", "serial_tot"); } - #endif - lj_potential /= 2.0; - GlobalV::ofs_running << " #TOTAL ENERGY# " << std::setprecision(11) << lj_potential * ModuleBase::Ry_to_eV << " eV" - << std::endl; +#ifdef __MPI + MPI_Allreduce(MPI_IN_PLACE, &local_potential, 1, MPI_DOUBLE, MPI_SUM, mdcell.communicator()); + MPI_Allreduce(MPI_IN_PLACE, + local_virial.data(), + static_cast(local_virial.size()), + MPI_DOUBLE, + MPI_SUM, + mdcell.communicator()); +#endif - // Post treatment for virial + lj_potential = local_potential / 2.0; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { - lj_virial(i, j) /= (2.0 * ucell.omega); + lj_virial(i, j) = local_virial[i * 3 + j] / (2.0 * mdcell.omega()); } } } - double ESolver_LJ::cal_energy() - { - return lj_potential; - } +double ESolver_LJ::cal_energy() +{ + return lj_potential; +} - void ESolver_LJ::cal_force(BaseCell& cell, ModuleBase::matrix& force) +void ESolver_LJ::cal_force(BaseCell& cell, ModuleBase::matrix& force) +{ + if (cell.kind() == BaseCell::Kind::unit_cell) { - cell.require_kind(BaseCell::Kind::unit_cell, __FUNCTION__); UnitCell& ucell = static_cast(cell); force = lj_force; ModuleIO::print_force(GlobalV::ofs_running, ucell, "TOTAL-FORCE (eV/Angstrom)", force, false); + return; } - void ESolver_LJ::cal_stress(BaseCell& cell, ModuleBase::matrix& stress) + MDCell& mdcell = static_cast(cell); + force.create(mdcell.nlocal(), 3); + for (int i = 0; i < mdcell.nlocal(); ++i) { - cell.require_kind(BaseCell::Kind::unit_cell, __FUNCTION__); - stress = lj_virial; + force(i, 0) = mdcell.owned_atoms()[static_cast(i)].force.x; + force(i, 1) = mdcell.owned_atoms()[static_cast(i)].force.y; + force(i, 2) = mdcell.owned_atoms()[static_cast(i)].force.z; + } +} - const bool screen = true; - const bool ry = false; - ModuleIO::print_stress("TOTAL-STRESS", stress, screen, ry, GlobalV::ofs_running); +void ESolver_LJ::cal_stress(BaseCell& cell, ModuleBase::matrix& stress) +{ + stress = lj_virial; - // external stress - double unit_transform = ModuleBase::RYDBERG_SI / pow(ModuleBase::BOHR_RADIUS_SI, 3) * 1.0e-8; - double external_stress[3] = {PARAM.inp.press1, PARAM.inp.press2, PARAM.inp.press3}; - for (int i = 0; i < 3; i++) + if (cell.kind() == BaseCell::Kind::unit_cell) + { + ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, GlobalV::ofs_running); + } + else + { +#ifdef __MPI + if (static_cast(cell).mpi_rank() == 0) +#endif { - stress(i, i) -= external_stress[i] / unit_transform; + ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, GlobalV::ofs_running); } } - void ESolver_LJ::after_all_runners(BaseCell& cell) + const double unit_transform = ModuleBase::RYDBERG_SI / pow(ModuleBase::BOHR_RADIUS_SI, 3) * 1.0e-8; + const double external_stress[3] = {PARAM.inp.press1, PARAM.inp.press2, PARAM.inp.press3}; + for (int i = 0; i < 3; ++i) { - cell.require_kind(BaseCell::Kind::unit_cell, __FUNCTION__); - GlobalV::ofs_running << "\n --------------------------------------------" << std::endl; - GlobalV::ofs_running << std::setprecision(16); - GlobalV::ofs_running << " !FINAL_ETOT_IS " << lj_potential * ModuleBase::Ry_to_eV << " eV" << std::endl; - GlobalV::ofs_running << " --------------------------------------------\n\n" << std::endl; + stress(i, i) -= external_stress[i] / unit_transform; } +} - double ESolver_LJ::LJ_energy(const double& d, const int& i, const int& j) const - { - assert(d > 1e-6); // avoid atom overlap - const double r2 = d * d; - const double r4 = r2 * r2; - const double r6 = r2 * r4; - return lj_c12(i, j) / (r6 * r6) - lj_c6(i, j) / r6; - } +void ESolver_LJ::after_all_runners(BaseCell& cell) +{ + static_cast(cell); - ModuleBase::Vector3 ESolver_LJ::LJ_force(const ModuleBase::Vector3& dr, const int& i, const int& j) const - { - const double d = dr.norm(); - assert(d > 1e-6); // avoid atom overlap - const double r2 = d * d; - const double r4 = r2 * r2; - const double r8 = r4 * r4; - const double r14 = r8 * r4 * r2; - double coff = 12.0 * lj_c12(i, j) / r14 - 6.0 * lj_c6(i, j) / r8; - return dr * coff; - } + GlobalV::ofs_running << "\n --------------------------------------------" << std::endl; + GlobalV::ofs_running << std::setprecision(16); + GlobalV::ofs_running << " !FINAL_ETOT_IS " << lj_potential * ModuleBase::Ry_to_eV << " eV" << std::endl; + GlobalV::ofs_running << " --------------------------------------------\n\n" << std::endl; +} - void ESolver_LJ::LJ_virial(const ModuleBase::Vector3& force, const ModuleBase::Vector3& dtau) +void ESolver_LJ::others(BaseCell& cell, const int istep) +{ + static_cast(istep); + static_cast(cell); +} + +double ESolver_LJ::LJ_energy(const double& d, const int& i, const int& j) const +{ + assert(d > 1e-6); // avoid atom overlap + const double r2 = d * d; + const double r4 = r2 * r2; + const double r6 = r2 * r4; + return lj_c12(i, j) / (r6 * r6) - lj_c6(i, j) / r6; +} + +ModuleBase::Vector3 ESolver_LJ::LJ_force(const ModuleBase::Vector3& dr, + const int& i, + const int& j) const +{ + const double d = dr.norm(); + assert(d > 1e-6); // avoid atom overlap + const double r2 = d * d; + const double r4 = r2 * r2; + const double r8 = r4 * r4; + const double r14 = r8 * r4 * r2; + double coff = 12.0 * lj_c12(i, j) / r14 - 6.0 * lj_c6(i, j) / r8; + return dr * coff; +} + +void ESolver_LJ::rcut_search_radius(const int& ntype, const std::vector& rcut) +{ + lj_rcut.create(ntype, ntype); + double rcut_max = 0.0; + + if (rcut.size() == 1) { - for (int i = 0; i < 3; ++i) + rcut_max = rcut[0] * ModuleBase::ANGSTROM_AU; + for (int i = 0; i < ntype; i++) { - for (int j = 0; j < 3; ++j) + for (int j = 0; j <= i; j++) { - lj_virial(i, j) += dtau[i] * force[j]; + lj_rcut(i, j) = rcut_max; + lj_rcut(j, i) = rcut_max; } } } - - void ESolver_LJ::rcut_search_radius(const int& ntype, const std::vector& rcut) + else if (rcut.size() == ntype * (ntype + 1) / 2) { - lj_rcut.create(ntype, ntype); - double rcut_max = 0.0; - - if (rcut.size() == 1) + for (int i = 0; i < ntype; i++) { - rcut_max = rcut[0] * ModuleBase::ANGSTROM_AU; - for (int i = 0; i < ntype; i++) + for (int j = 0; j <= i; j++) { - for (int j = 0; j <= i; j++) - { - lj_rcut(i, j) = rcut_max; - lj_rcut(j, i) = rcut_max; - } + int k = i * (i + 1) / 2 + j; + lj_rcut(i, j) = rcut[k] * ModuleBase::ANGSTROM_AU; + lj_rcut(j, i) = lj_rcut(i, j); + rcut_max = std::max(rcut_max, lj_rcut(i, j)); } } - else if (rcut.size() == ntype * (ntype + 1) / 2) - { - for (int i = 0; i < ntype; i++) - { - for (int j = 0; j <= i; j++) - { - int k = i * (i + 1) / 2 + j; - lj_rcut(i, j) = rcut[k] * ModuleBase::ANGSTROM_AU; - lj_rcut(j, i) = lj_rcut(i, j); - rcut_max = std::max(rcut_max, lj_rcut(i, j)); - } - } - } - - // set the search radius - search_radius = rcut_max + 0.01; } - void ESolver_LJ::set_c6_c12(const int& ntype, - const int& rule, - const std::vector& epsilon, - const std::vector& sigma) - { - lj_c6.create(ntype, ntype); - lj_c12.create(ntype, ntype); + // set the search radius + search_radius = rcut_max + 0.01; +} + +void ESolver_LJ::set_c6_c12(const int& ntype, + const int& rule, + const std::vector& epsilon, + const std::vector& sigma) +{ + lj_c6.create(ntype, ntype); + lj_c12.create(ntype, ntype); - std::vector lj_epsilon = epsilon; - std::vector lj_sigma = sigma; + std::vector lj_epsilon = epsilon; + std::vector lj_sigma = sigma; - std::transform(begin(lj_epsilon), end(lj_epsilon), begin(lj_epsilon), [](double x) { - return x / ModuleBase::Ry_to_eV; - }); - std::transform(begin(lj_sigma), end(lj_sigma), begin(lj_sigma), [](double x) { - return x * ModuleBase::ANGSTROM_AU; - }); + std::transform(begin(lj_epsilon), end(lj_epsilon), begin(lj_epsilon), [](double x) { + return x / ModuleBase::Ry_to_eV; + }); + std::transform(begin(lj_sigma), end(lj_sigma), begin(lj_sigma), [](double x) { + return x * ModuleBase::ANGSTROM_AU; + }); - if (lj_epsilon.size() != lj_sigma.size()) - { - ModuleBase::WARNING_QUIT("ESolver_LJ", " the number of lj_epsilon should be equal to lj_sigma "); - } - // do not need any combination rules - else if (lj_sigma.size() == ntype * (ntype + 1) / 2) + if (lj_epsilon.size() != lj_sigma.size()) + { + ModuleBase::WARNING_QUIT("ESolver_LJ", " the number of lj_epsilon should be equal to lj_sigma "); + } + // do not need any combination rules + else if (lj_sigma.size() == ntype * (ntype + 1) / 2) + { + for (int i = 0; i < ntype; i++) { - for (int i = 0; i < ntype; i++) + for (int j = 0; j <= i; j++) { - for (int j = 0; j <= i; j++) - { - int k = i * (i + 1) / 2 + j; - double temp = pow(lj_sigma[k], 6); - lj_c6(i, j) = 4.0 * lj_epsilon[k] * temp; - lj_c12(i, j) = lj_c6(i, j) * temp; - lj_c6(j, i) = lj_c6(i, j); - lj_c12(j, i) = lj_c12(i, j); - } + int k = i * (i + 1) / 2 + j; + double temp = pow(lj_sigma[k], 6); + lj_c6(i, j) = 4.0 * lj_epsilon[k] * temp; + lj_c12(i, j) = lj_c6(i, j) * temp; + lj_c6(j, i) = lj_c6(i, j); + lj_c12(j, i) = lj_c12(i, j); } } - // combination rule 1 - else if (lj_sigma.size() == ntype && rule == 1) + } + // combination rule 1 + else if (lj_sigma.size() == ntype && rule == 1) + { + for (int i = 0; i < ntype; i++) { - for (int i = 0; i < ntype; i++) - { - // first determine the diagonal elements - double temp = pow(lj_sigma[i], 6); - lj_c6(i, i) = 4.0 * lj_epsilon[i] * temp; - lj_c12(i, i) = lj_c6(i, i) * temp; + // first determine the diagonal elements + double temp = pow(lj_sigma[i], 6); + lj_c6(i, i) = 4.0 * lj_epsilon[i] * temp; + lj_c12(i, i) = lj_c6(i, i) * temp; - // then determine the non-diagonal elements - for (int j = 0; j < i; j++) - { - lj_c6(i, j) = std::sqrt(lj_c6(i, i) * lj_c6(j, j)); - lj_c12(i, j) = std::sqrt(lj_c12(i, i) * lj_c12(j, j)); - lj_c6(j, i) = lj_c6(i, j); - lj_c12(j, i) = lj_c12(i, j); - } + // then determine the non-diagonal elements + for (int j = 0; j < i; j++) + { + lj_c6(i, j) = std::sqrt(lj_c6(i, i) * lj_c6(j, j)); + lj_c12(i, j) = std::sqrt(lj_c12(i, i) * lj_c12(j, j)); + lj_c6(j, i) = lj_c6(i, j); + lj_c12(j, i) = lj_c12(i, j); } } - // combination rule 2 - else if (lj_sigma.size() == ntype && rule == 2) + } + // combination rule 2 + else if (lj_sigma.size() == ntype && rule == 2) + { + for (int i = 0; i < ntype; i++) { - for (int i = 0; i < ntype; i++) + for (int j = 0; j <= i; j++) { - for (int j = 0; j <= i; j++) - { - double sigma_ij = (lj_sigma[i] + lj_sigma[j]) / 2.0; - double epsilon_ij = std::sqrt(lj_epsilon[i] * lj_epsilon[j]); - - double temp = pow(sigma_ij, 6); - lj_c6(i, j) = 4.0 * epsilon_ij * temp; - lj_c12(i, j) = lj_c6(i, j) * temp; - lj_c6(j, i) = lj_c6(i, j); - lj_c12(j, i) = lj_c12(i, j); - } + double sigma_ij = (lj_sigma[i] + lj_sigma[j]) / 2.0; + double epsilon_ij = std::sqrt(lj_epsilon[i] * lj_epsilon[j]); + + double temp = pow(sigma_ij, 6); + lj_c6(i, j) = 4.0 * epsilon_ij * temp; + lj_c12(i, j) = lj_c6(i, j) * temp; + lj_c6(j, i) = lj_c6(i, j); + lj_c12(j, i) = lj_c12(i, j); } } } +} - void ESolver_LJ::cal_en_shift(const int& ntype, const bool& is_shift) - { - en_shift.create(ntype, ntype); +void ESolver_LJ::cal_en_shift(const int& ntype, const bool& is_shift) +{ + en_shift.create(ntype, ntype); - if (is_shift) + if (is_shift) + { + for (int i = 0; i < ntype; i++) { - for (int i = 0; i < ntype; i++) + for (int j = 0; j <= i; j++) { - for (int j = 0; j <= i; j++) - { - en_shift(i, j) = LJ_energy(lj_rcut(i, j), i, j); - en_shift(j, i) = en_shift(i, j); - } + en_shift(i, j) = LJ_energy(lj_rcut(i, j), i, j); + en_shift(j, i) = en_shift(i, j); } } } } +} // namespace ModuleESolver diff --git a/source/source_esolver/esolver_lj.h b/source/source_esolver/esolver_lj.h index fd0b390e1ed..8321c52aa5e 100644 --- a/source/source_esolver/esolver_lj.h +++ b/source/source_esolver/esolver_lj.h @@ -5,54 +5,68 @@ namespace ModuleESolver { +class ESolver_LJ; +} + +class MDCell; - class ESolver_LJ : public ESolver +namespace ModuleESolver +{ + +class ESolver_LJ : public ESolver +{ + public: + ESolver_LJ() { - public: - ESolver_LJ() - { - classname = "ESolver_LJ"; - } + classname = "ESolver_LJ"; + } - void before_all_runners(BaseCell& cell, const Input_para& inp) override; + void before_all_runners(BaseCell& cell, const Input_para& inp) override; - void runner(BaseCell& cell, const int istep) override; + void runner(BaseCell& cell, const int istep) override; - double cal_energy() override; + double cal_energy() override; - void cal_force(BaseCell& cell, ModuleBase::matrix& force) override; + void cal_force(BaseCell& cell, ModuleBase::matrix& force) override; - void cal_stress(BaseCell& cell, ModuleBase::matrix& stress) override; + void cal_stress(BaseCell& cell, ModuleBase::matrix& stress) override; void after_all_runners(BaseCell& cell) override; - private: - double LJ_energy(const double& d, const int& i, const int& j) const; + void others(BaseCell& cell, const int istep) override; + + bool supports_mdcell() const override + { + return true; + } + + double mdcell_cutoff(const Input_para& inp) const override; - ModuleBase::Vector3 LJ_force(const ModuleBase::Vector3& dr, const int& i, const int& j) const; + private: + double LJ_energy(const double& d, const int& i, const int& j) const; - void LJ_virial(const ModuleBase::Vector3& force, const ModuleBase::Vector3& dtau); + ModuleBase::Vector3 LJ_force(const ModuleBase::Vector3& dr, const int& i, const int& j) const; - void rcut_search_radius(const int& ntype, const std::vector& rcut); + void rcut_search_radius(const int& ntype, const std::vector& rcut); - void set_c6_c12(const int& ntype, - const int& rule, - const std::vector& epsilon, - const std::vector& sigma); + void set_c6_c12(const int& ntype, + const int& rule, + const std::vector& epsilon, + const std::vector& sigma); - void cal_en_shift(const int& ntype, const bool& is_shift); + void cal_en_shift(const int& ntype, const bool& is_shift); - //--------------temporary---------------------------- - double search_radius=-1.0; - ModuleBase::matrix lj_rcut; - ModuleBase::matrix lj_c12; - ModuleBase::matrix lj_c6; - ModuleBase::matrix en_shift; + //--------------temporary---------------------------- + double search_radius = -1.0; + ModuleBase::matrix lj_rcut; + ModuleBase::matrix lj_c12; + ModuleBase::matrix lj_c6; + ModuleBase::matrix en_shift; - double lj_potential=0.0; - ModuleBase::matrix lj_force; - ModuleBase::matrix lj_virial; - //--------------------------------------------------- - }; -} + double lj_potential = 0.0; + ModuleBase::matrix lj_force; + ModuleBase::matrix lj_virial; + //--------------------------------------------------- +}; +} // namespace ModuleESolver #endif diff --git a/source/source_esolver/esolver_nep.cpp b/source/source_esolver/esolver_nep.cpp index c130a34ad89..024f1302440 100644 --- a/source/source_esolver/esolver_nep.cpp +++ b/source/source_esolver/esolver_nep.cpp @@ -18,30 +18,45 @@ #include "esolver_nep.h" #include "source_base/parallel_common.h" #include "source_base/timer.h" +#include "source_cell/md_cell.h" +#include "source_cell/module_neighlist/neighbor_search.h" +#include "source_cell/cif_io.h" #include "source_io/module_output/output_log.h" #include "source_io/module_parameter/parameter.h" #include +#include +#include #include using namespace ModuleESolver; void ESolver_NEP::before_all_runners(BaseCell& basecell, const Input_para& inp) { - basecell.require_kind(BaseCell::Kind::unit_cell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); - nep_potential = 0.0; - nep_force.create(ucell.nat, 3); nep_virial.create(3, 3); + + if (basecell.kind() == BaseCell::Kind::md_cell) + { + MDCell& mdcell = static_cast(basecell); +#ifdef __NEP + initialize_type_map_(mdcell.type_labels()); +#endif + return; + } + + UnitCell& ucell = static_cast(basecell); + nep_force.create(ucell.nat, 3); atype.resize(ucell.nat); - nep_cell.resize(9); - nep_coord.resize(3 * ucell.nat); - nep_virial_sum.resize(9); _e.resize(ucell.nat); _f.resize(3 * ucell.nat); _v.resize(9 * ucell.nat); + ModuleIO::CifParser::write(PARAM.globalv.global_out_dir + "STRU.cif", + ucell, + "# Generated by ABACUS ModuleIO::CifParser", + "data_?"); + #ifdef __NEP /// determine the type map from STRU to NEP model type_map(ucell); @@ -50,43 +65,157 @@ void ESolver_NEP::before_all_runners(BaseCell& basecell, const Input_para& inp) void ESolver_NEP::runner(BaseCell& basecell, const int istep) { - basecell.require_kind(BaseCell::Kind::unit_cell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); - ModuleBase::TITLE("ESolver_NEP", "runner"); ModuleBase::timer::start("ESolver_NEP", "runner"); + if (basecell.kind() == BaseCell::Kind::md_cell) + { +#ifndef __NEP + ModuleBase::WARNING_QUIT("ESolver_NEP", "Please recompile with -D__NEP"); +#else + static_cast(istep); + MDCell& mdcell = static_cast(basecell); + const int nlocal = mdcell.nlocal(); + const int nghost = mdcell.nghost(); + const int natom = nlocal + nghost; + if (natom == 0) + { + ModuleBase::WARNING_QUIT("ESolver_NEP", "MDCell contains no atoms."); + } + + const std::vector& owned_atoms = mdcell.owned_atoms(); + const std::vector& ghost_atoms = mdcell.ghost_atoms(); + std::vector local_type(static_cast(natom), 0); + std::vector > position(static_cast(natom)); + std::vector > force(static_cast(natom)); + std::vector position_ptrs(static_cast(natom), NULL); + std::vector force_ptrs(static_cast(natom), NULL); + for (int iat = 0; iat < natom; ++iat) + { + const LocalAtom& atom = iat < nlocal ? owned_atoms[static_cast(iat)] + : ghost_atoms[static_cast(iat - nlocal)]; + if (atom.type < 0 || static_cast(atom.type) >= md_type_to_nep_type_.size()) + { + ModuleBase::WARNING_QUIT("ESolver_NEP", "MDCell atom type is outside the NEP type map."); + } + local_type[static_cast(iat)] = atom.type; + position[static_cast(iat)][0] = atom.cart.x * mdcell.lat0() * ModuleBase::BOHR_TO_A; + position[static_cast(iat)][1] = atom.cart.y * mdcell.lat0() * ModuleBase::BOHR_TO_A; + position[static_cast(iat)][2] = atom.cart.z * mdcell.lat0() * ModuleBase::BOHR_TO_A; + force[static_cast(iat)].fill(0.0); + position_ptrs[static_cast(iat)] = position[static_cast(iat)].data(); + force_ptrs[static_cast(iat)] = force[static_cast(iat)].data(); + } + + NeighborSearch neighbor_search; + neighbor_search.init(mdcell, mdcell.cutoff()); + neighbor_search.build_neighbors(); + const NeighborList& neighbor_list = neighbor_search.get_neighbor_list(); + std::vector ilist(static_cast(nlocal), 0); + std::vector numneigh(static_cast(natom), 0); + std::vector firstneigh(static_cast(natom), NULL); + for (int iat = 0; iat < nlocal; ++iat) + { + ilist[static_cast(iat)] = iat; + numneigh[static_cast(iat)] = neighbor_list.get_numneigh(iat); + firstneigh[static_cast(iat)] = const_cast(neighbor_list.get_firstneigh(iat)); + } + + double local_energy = 0.0; + double local_virial[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + ModuleBase::timer::start("ESolver_NEP", "compute"); + nep.compute_for_lammps(nlocal, + nlocal, + nlocal > 0 ? ilist.data() : NULL, + numneigh.data(), + firstneigh.data(), + local_type.data(), + md_type_to_nep_type_.data(), + position_ptrs.data(), + local_energy, + local_virial, + NULL, + force_ptrs.data(), + NULL); + ModuleBase::timer::end("ESolver_NEP", "compute"); + + std::vector& mutable_owned_atoms = mdcell.mutable_owned_atoms(); + std::vector& mutable_ghost_atoms = mdcell.mutable_ghost_atoms(); + for (int iat = 0; iat < nlocal; ++iat) + { + mutable_owned_atoms[static_cast(iat)].force.set(force[static_cast(iat)][0], + force[static_cast(iat)][1], + force[static_cast(iat)][2]); + } + for (int iat = 0; iat < nghost; ++iat) + { + mutable_ghost_atoms[static_cast(iat)].force.set(force[static_cast(nlocal + iat)][0], + force[static_cast(nlocal + iat)][1], + force[static_cast(nlocal + iat)][2]); + } + mdcell.accumulate_ghost_forces(); + +#ifdef __MPI + MPI_Allreduce(MPI_IN_PLACE, &local_energy, 1, MPI_DOUBLE, MPI_SUM, mdcell.communicator()); + MPI_Allreduce(MPI_IN_PLACE, local_virial, 6, MPI_DOUBLE, MPI_SUM, mdcell.communicator()); +#endif + const double fact_e = 1.0 / ModuleBase::Ry_to_eV; + const double fact_f = 1.0 / (ModuleBase::Ry_to_eV * ModuleBase::ANGSTROM_AU); + const double fact_v = 1.0 / (mdcell.omega() * ModuleBase::Ry_to_eV); + nep_potential = local_energy * fact_e; + for (int iat = 0; iat < nlocal; ++iat) + { + LocalAtom& atom = mutable_owned_atoms[static_cast(iat)]; + atom.force *= fact_f; + } + nep_virial(0, 0) = local_virial[0] * fact_v; + nep_virial(1, 1) = local_virial[1] * fact_v; + nep_virial(2, 2) = local_virial[2] * fact_v; + nep_virial(0, 1) = nep_virial(1, 0) = local_virial[3] * fact_v; + nep_virial(0, 2) = nep_virial(2, 0) = local_virial[4] * fact_v; + nep_virial(1, 2) = nep_virial(2, 1) = local_virial[5] * fact_v; +#endif + ModuleBase::timer::end("ESolver_NEP", "runner"); + return; + } + + UnitCell& ucell = static_cast(basecell); + // note that NEP are column major, thus a transpose is needed // cell - nep_cell[0] = ucell.latvec.e11 * ucell.lat0_angstrom; - nep_cell[1] = ucell.latvec.e21 * ucell.lat0_angstrom; - nep_cell[2] = ucell.latvec.e31 * ucell.lat0_angstrom; - nep_cell[3] = ucell.latvec.e12 * ucell.lat0_angstrom; - nep_cell[4] = ucell.latvec.e22 * ucell.lat0_angstrom; - nep_cell[5] = ucell.latvec.e32 * ucell.lat0_angstrom; - nep_cell[6] = ucell.latvec.e13 * ucell.lat0_angstrom; - nep_cell[7] = ucell.latvec.e23 * ucell.lat0_angstrom; - nep_cell[8] = ucell.latvec.e33 * ucell.lat0_angstrom; + std::vector cell(9, 0.0); + cell[0] = ucell.latvec.e11 * ucell.lat0_angstrom; + cell[1] = ucell.latvec.e21 * ucell.lat0_angstrom; + cell[2] = ucell.latvec.e31 * ucell.lat0_angstrom; + cell[3] = ucell.latvec.e12 * ucell.lat0_angstrom; + cell[4] = ucell.latvec.e22 * ucell.lat0_angstrom; + cell[5] = ucell.latvec.e32 * ucell.lat0_angstrom; + cell[6] = ucell.latvec.e13 * ucell.lat0_angstrom; + cell[7] = ucell.latvec.e23 * ucell.lat0_angstrom; + cell[8] = ucell.latvec.e33 * ucell.lat0_angstrom; // coord - nep_coord.resize(3 * ucell.nat); + std::vector coord(3 * ucell.nat, 0.0); + int iat = 0; const int nat = ucell.nat; -#pragma omp parallel for schedule(static) if (nat >= 256) - for (int iat = 0; iat < nat; ++iat) + for (int it = 0; it < ucell.ntype; ++it) { - const int it = atom_type_index[iat]; - const int ia = atom_local_index[iat]; - nep_coord[iat] = ucell.atoms[it].tau[ia].x * ucell.lat0_angstrom; - nep_coord[iat + nat] = ucell.atoms[it].tau[ia].y * ucell.lat0_angstrom; - nep_coord[iat + 2 * nat] = ucell.atoms[it].tau[ia].z * ucell.lat0_angstrom; + for (int ia = 0; ia < ucell.atoms[it].na; ++ia) + { + coord[iat] = ucell.atoms[it].tau[ia].x * ucell.lat0_angstrom; + coord[iat + nat] = ucell.atoms[it].tau[ia].y * ucell.lat0_angstrom; + coord[iat + 2 * nat] = ucell.atoms[it].tau[ia].z * ucell.lat0_angstrom; + iat++; + } } + assert(ucell.nat == iat); #ifdef __NEP nep_potential = 0.0; nep_force.zero_out(); nep_virial.zero_out(); - nep.compute(atype, nep_cell, nep_coord, _e, _f, _v); + nep.compute(atype, cell, coord, _e, _f, _v); // unit conversion const double fact_e = 1.0 / ModuleBase::Ry_to_eV; @@ -94,18 +223,11 @@ void ESolver_NEP::runner(BaseCell& basecell, const int istep) const double fact_v = 1.0 / (ucell.omega * ModuleBase::Ry_to_eV); // potential energy - double energy_sum = 0.0; -#pragma omp parallel for reduction(+:energy_sum) schedule(static) if (nat >= 256) - for (int i = 0; i < nat; ++i) - { - energy_sum += _e[i]; - } - nep_potential = fact_e * energy_sum; + nep_potential = fact_e * std::accumulate(_e.begin(), _e.end(), 0.0); GlobalV::ofs_running << " #TOTAL ENERGY# " << std::setprecision(11) << nep_potential * ModuleBase::Ry_to_eV << " eV" << std::endl; // forces -#pragma omp parallel for schedule(static) if (nat >= 256) for (int i = 0; i < nat; ++i) { nep_force(i, 0) = _f[i] * fact_f; @@ -114,44 +236,22 @@ void ESolver_NEP::runner(BaseCell& basecell, const int istep) } // virial - double v0 = 0.0; - double v1 = 0.0; - double v2 = 0.0; - double v3 = 0.0; - double v4 = 0.0; - double v5 = 0.0; - double v6 = 0.0; - double v7 = 0.0; - double v8 = 0.0; -#pragma omp parallel for reduction(+:v0, v1, v2, v3, v4, v5, v6, v7, v8) schedule(static) if (nat >= 256) - for (int i = 0; i < nat; ++i) + std::vector v_sum(9, 0.0); + for (int j = 0; j < 9; ++j) { - v0 += _v[i]; - v1 += _v[nat + i]; - v2 += _v[2 * nat + i]; - v3 += _v[3 * nat + i]; - v4 += _v[4 * nat + i]; - v5 += _v[5 * nat + i]; - v6 += _v[6 * nat + i]; - v7 += _v[7 * nat + i]; - v8 += _v[8 * nat + i]; + for (int i = 0; i < nat; ++i) + { + int index = j * nat + i; + v_sum[j] += _v[index]; + } } - nep_virial_sum[0] = v0; - nep_virial_sum[1] = v1; - nep_virial_sum[2] = v2; - nep_virial_sum[3] = v3; - nep_virial_sum[4] = v4; - nep_virial_sum[5] = v5; - nep_virial_sum[6] = v6; - nep_virial_sum[7] = v7; - nep_virial_sum[8] = v8; // virial -> stress for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { - nep_virial(i, j) = nep_virial_sum[3 * i + j] * fact_v; + nep_virial(i, j) = v_sum[3 * i + j] * fact_v; } } #else @@ -165,22 +265,62 @@ double ESolver_NEP::cal_energy() return nep_potential; } -void ESolver_NEP::cal_force(BaseCell& basecell, ModuleBase::matrix& force) +bool ESolver_NEP::supports_mdcell() const { - basecell.require_kind(BaseCell::Kind::unit_cell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); +#ifdef __NEP + return true; +#else + return false; +#endif +} + +double ESolver_NEP::mdcell_cutoff(const Input_para& inp) const +{ + static_cast(inp); +#ifdef __NEP + return std::max(nep.paramb.rc_radial_max, nep.paramb.rc_angular_max) * ModuleBase::ANGSTROM_AU; +#else + ModuleBase::WARNING_QUIT("ESolver_NEP::mdcell_cutoff", "Please recompile with -D__NEP"); + return 0.0; +#endif +} +void ESolver_NEP::cal_force(BaseCell& basecell, ModuleBase::matrix& force) +{ + if (basecell.kind() == BaseCell::Kind::md_cell) + { + const MDCell& mdcell = static_cast(basecell); + force.create(mdcell.nlocal(), 3); + for (int iat = 0; iat < mdcell.nlocal(); ++iat) + { + const LocalAtom& atom = mdcell.owned_atoms()[static_cast(iat)]; + force(iat, 0) = atom.force.x; + force(iat, 1) = atom.force.y; + force(iat, 2) = atom.force.z; + } + return; + } force = nep_force; + UnitCell& ucell = static_cast(basecell); ModuleIO::print_force(GlobalV::ofs_running, ucell, "TOTAL-FORCE (eV/Angstrom)", force, false); } void ESolver_NEP::cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) { - basecell.require_kind(BaseCell::Kind::unit_cell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); - stress = nep_virial; - ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, GlobalV::ofs_running); + if (basecell.kind() == BaseCell::Kind::unit_cell) + { + ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, GlobalV::ofs_running); + } + else + { +#ifdef __MPI + if (static_cast(basecell).mpi_rank() == 0) +#endif + { + ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, GlobalV::ofs_running); + } + } // external stress double unit_transform = ModuleBase::RYDBERG_SI / pow(ModuleBase::BOHR_RADIUS_SI, 3) * 1.0e-8; @@ -193,8 +333,7 @@ void ESolver_NEP::cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) void ESolver_NEP::after_all_runners(BaseCell& basecell) { - basecell.require_kind(BaseCell::Kind::unit_cell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + static_cast(basecell); GlobalV::ofs_running << "\n --------------------------------------------" << std::endl; GlobalV::ofs_running << std::setprecision(16); @@ -204,6 +343,26 @@ void ESolver_NEP::after_all_runners(BaseCell& basecell) #ifdef __NEP void ESolver_NEP::type_map(const UnitCell& ucell) +{ + std::vector type_labels(static_cast(ucell.ntype)); + for (int it = 0; it < ucell.ntype; ++it) + { + type_labels[static_cast(it)] = ucell.atoms[it].label; + } + initialize_type_map_(type_labels); + + int iat = 0; + for (int it = 0; it < ucell.ntype; ++it) + { + for (int ia = 0; ia < ucell.atoms[it].na; ++ia) + { + atype[static_cast(iat++)] = md_type_to_nep_type_[static_cast(it)]; + } + } + assert(ucell.nat == iat); +} + +void ESolver_NEP::initialize_type_map_(const std::vector& type_labels) { // parse the element list from NEP model file std::unordered_map label; @@ -230,20 +389,16 @@ void ESolver_NEP::type_map(const UnitCell& ucell) std::cout << "\n -----------------------------------------------------------------" << std::endl; // parse the atype based on the element list - int iat = 0; - for (int it = 0; it < ucell.ntype; ++it) + md_type_to_nep_type_.resize(type_labels.size()); + for (std::size_t it = 0; it < type_labels.size(); ++it) { - for (int ia = 0; ia < ucell.atoms[it].na; ++ia) + const std::unordered_map::const_iterator found = label.find(type_labels[it]); + if (found == label.end()) { - if (label.find(ucell.atoms[it].label) == label.end()) - { - ModuleBase::WARNING_QUIT("ESolver_NEP", - "The label " + ucell.atoms[it].label + " is not found in the type map."); - } - atype[iat] = label[ucell.atoms[it].label]; - iat++; + ModuleBase::WARNING_QUIT("ESolver_NEP", + "The label " + type_labels[it] + " is not found in the type map."); } + md_type_to_nep_type_[it] = found->second; } - assert(ucell.nat == iat); } #endif diff --git a/source/source_esolver/esolver_nep.h b/source/source_esolver/esolver_nep.h index 49862f80cb0..16a5e08effa 100644 --- a/source/source_esolver/esolver_nep.h +++ b/source/source_esolver/esolver_nep.h @@ -66,6 +66,9 @@ class ESolver_NEP : public ESolver */ void cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) override; + bool supports_mdcell() const override; + double mdcell_cutoff(const Input_para& inp) const override; + /** * @brief Prints the final total energy of the NEP model to the output file * @@ -80,6 +83,7 @@ class ESolver_NEP : public ESolver * @param ucell unitcell information */ void type_map(const UnitCell& ucell); + void initialize_type_map_(const std::vector& type_labels); /** * @brief NEP related variables for ESolver_NEP class @@ -93,19 +97,15 @@ class ESolver_NEP : public ESolver NEP nep; ///< NEP object for NEP calculations #endif - std::string nep_file; ///< directory of NEP model file - std::vector atype = {}; ///< atom type mapping for NEP model - std::vector atom_type_index; ///< global atom index to UnitCell atom type - std::vector atom_local_index; ///< global atom index to local index inside atom type - double nep_potential; ///< computed potential energy - ModuleBase::matrix nep_force; ///< computed atomic forces - ModuleBase::matrix nep_virial; ///< computed lattice virials - std::vector nep_cell; ///< NEP cell buffer in Angstrom, column-major - std::vector nep_coord; ///< NEP coordinate buffer in Angstrom, column-major - std::vector nep_virial_sum; ///< summed per-atom virial components - std::vector _e; ///< temporary storage for energy computation - std::vector _f; ///< temporary storage for force computation - std::vector _v; ///< temporary storage for virial computation + std::string nep_file; ///< directory of NEP model file + std::vector atype = {}; ///< atom type mapping for NEP model + std::vector md_type_to_nep_type_; + double nep_potential; ///< computed potential energy + ModuleBase::matrix nep_force; ///< computed atomic forces + ModuleBase::matrix nep_virial; ///< computed lattice virials + std::vector _e; ///< temporary storage for energy computation + std::vector _f; ///< temporary storage for force computation + std::vector _v; ///< temporary storage for virial computation }; } // namespace ModuleESolver diff --git a/source/source_io/module_output/output_log.cpp b/source/source_io/module_output/output_log.cpp index 8c3ba0d1146..7d920fb8d2a 100644 --- a/source/source_io/module_output/output_log.cpp +++ b/source/source_io/module_output/output_log.cpp @@ -6,6 +6,10 @@ #include "source_base/global_variable.h" #include "source_base/parallel_reduce.h" #include "source_base/parallel_comm.h" +#include "source_cell/md_cell.h" + +#include +#include #ifdef __MPI #include @@ -271,6 +275,64 @@ void print_force(std::ofstream& ofs_running, } } +void print_force(std::ofstream& ofs, const MDCell& cell, const std::string& name) +{ + const double output_acc = 1.0e-8; + const double force_unit = ModuleBase::Hartree_to_eV / ModuleBase::BOHR_TO_A; + const std::vector& owned_atoms = cell.owned_atoms(); + const std::vector& type_labels = cell.type_labels(); + + const auto print_atom = [&ofs, &type_labels, output_acc, force_unit](const LocalAtom& atom) { + const std::string& label = type_labels[static_cast(atom.type)]; + const double fx = std::abs(atom.force.x) > output_acc ? atom.force.x * force_unit : 0.0; + const double fy = std::abs(atom.force.y) > output_acc ? atom.force.y * force_unit : 0.0; + const double fz = std::abs(atom.force.z) > output_acc ? atom.force.z * force_unit : 0.0; + ofs << std::setw(9) << label + std::to_string(atom.type_index + 1) + << std::setw(20) << std::fixed << std::setprecision(10) << fx + << std::setw(20) << fy << std::setw(20) << fz << std::endl; + }; + +#ifdef __MPI + int rank = 0; + int size = 1; + MPI_Comm_rank(cell.communicator(), &rank); + MPI_Comm_size(cell.communicator(), &size); + if (rank != 0) + { + const int nlocal = cell.nlocal(); + MPI_Send(&nlocal, 1, MPI_INT, 0, 0, cell.communicator()); + for (const LocalAtom& atom : owned_atoms) + { + MPI_Send(&atom.type, 1, MPI_INT, 0, 1, cell.communicator()); + MPI_Send(&atom.type_index, 1, MPI_INT64_T, 0, 2, cell.communicator()); + MPI_Send(&atom.force.x, 3, MPI_DOUBLE, 0, 3, cell.communicator()); + } + return; + } +#endif + + ofs << "\n #" << name << "#" << std::endl; + ofs << std::setw(9) << "Atoms" << std::setw(20) << "Force_x" << std::setw(20) + << "Force_y" << std::setw(20) << "Force_z" << std::endl; + for (const LocalAtom& atom : owned_atoms) print_atom(atom); + +#ifdef __MPI + for (int source = 1; source < size; ++source) + { + int nlocal = 0; + MPI_Recv(&nlocal, 1, MPI_INT, source, 0, cell.communicator(), MPI_STATUS_IGNORE); + for (int iat = 0; iat < nlocal; ++iat) + { + LocalAtom atom; + MPI_Recv(&atom.type, 1, MPI_INT, source, 1, cell.communicator(), MPI_STATUS_IGNORE); + MPI_Recv(&atom.type_index, 1, MPI_INT64_T, source, 2, cell.communicator(), MPI_STATUS_IGNORE); + MPI_Recv(&atom.force.x, 3, MPI_DOUBLE, source, 3, cell.communicator(), MPI_STATUS_IGNORE); + print_atom(atom); + } + } +#endif +} + void print_stress(const std::string& name, const ModuleBase::matrix& scs, const bool screen, const bool ry, std::ofstream &ofs) { diff --git a/source/source_io/module_output/output_log.h b/source/source_io/module_output/output_log.h index a6b6c8b90c3..0a12869a449 100644 --- a/source/source_io/module_output/output_log.h +++ b/source/source_io/module_output/output_log.h @@ -7,6 +7,8 @@ #include "source_base/matrix.h" #include "source_cell/unitcell.h" +class MDCell; + namespace ModuleIO { @@ -60,6 +62,12 @@ void print_force(std::ofstream& ofs, const ModuleBase::matrix& force, bool ry = true); +/// @brief output forces stored on locally owned atoms of an MDCell +/// @param ofs the output stream on rank zero +/// @param cell the MD cell +/// @param name force term name +void print_force(std::ofstream& ofs, const MDCell& cell, const std::string& name); + /// @brief output stress components /// @param name stress term name /// @param f stress components diff --git a/source/source_io/module_parameter/input_parameter.h b/source/source_io/module_parameter/input_parameter.h index f984a4609d7..bef68b35cd2 100644 --- a/source/source_io/module_parameter/input_parameter.h +++ b/source/source_io/module_parameter/input_parameter.h @@ -54,6 +54,7 @@ struct Input_para std::string input_file = "INPUT"; ///< input file name std::string stru_file = "STRU"; ///< file contains atomic positions -- + std::vector cell_replica = {1, 1, 1}; ///< replicate the input STRU along its lattice vectors ///< xiaohui modify 2015-02-01 std::string kpoint_file = "KPT"; ///< file contains k-points -- xiaohui modify 2015-02-01 std::string pseudo_dir = ""; ///< directory of pseudopotential diff --git a/source/source_io/module_parameter/md_parameter.h b/source/source_io/module_parameter/md_parameter.h index 6488759132f..96aa8cfbfd2 100644 --- a/source/source_io/module_parameter/md_parameter.h +++ b/source/source_io/module_parameter/md_parameter.h @@ -20,6 +20,7 @@ struct MD_para double md_tlast = -1.0; ///< Target temperature int md_dumpfreq = 1; ///< The period to dump MD information int md_restartfreq = 5; ///< The period to output MD restart information + bool md_out_force = true; ///< output all atomic forces into running_md.log int md_seed = -1; ///< random seed for MD int md_prec_level = 0; ///< precision level for vc-md @@ -71,4 +72,4 @@ struct MD_para ///< not. liuyu 2023-03-01 }; -#endif // MD_PARA_H \ No newline at end of file +#endif // MD_PARA_H diff --git a/source/source_io/module_parameter/read_inp_sys.cpp b/source/source_io/module_parameter/read_inp_sys.cpp index 74b21ae33d3..357b9188fac 100644 --- a/source/source_io/module_parameter/read_inp_sys.cpp +++ b/source/source_io/module_parameter/read_inp_sys.cpp @@ -73,6 +73,36 @@ void ReadInput::item_system() read_sync_int(input.ntype); this->add_item(item); } + { + Input_Item item("cell_replica"); + item.annotation = "replicate the input structure along the three lattice vectors"; + item.category = "System variables"; + item.type = "Three Integers"; + item.description = "Replicate the input STRU by Na, Nb, and Nc along its lattice vectors for " + "distributed MDCell workflows. The default is 1 1 1, which preserves the input structure."; + item.default_value = "1 1 1"; + item.read_value = [](const Input_Item& item, Parameter& para) { + if (item.str_values.size() != 3) + { + ModuleBase::WARNING_QUIT("ReadInput", "cell_replica requires exactly three integers."); + } + for (int i = 0; i < 3; ++i) + { + para.input.cell_replica[static_cast(i)] = std::stoi(item.str_values[static_cast(i)]); + } + }; + item.check_value = [](const Input_Item&, const Parameter& para) { + for (int i = 0; i < 3; ++i) + { + if (para.input.cell_replica[static_cast(i)] <= 0) + { + ModuleBase::WARNING_QUIT("ReadInput", "cell_replica values must all be positive."); + } + } + }; + sync_intvec(input.cell_replica, 3, 1); + this->add_item(item); + } { Input_Item item("calculation"); item.annotation = "scf; relax; md; cell-relax; nscf; get_s; get_wf; get_pchg; gen_bessel; gen_opt_abfs; test_memory; test_neighbour"; diff --git a/source/source_io/module_parameter/read_input_item_md.cpp b/source/source_io/module_parameter/read_input_item_md.cpp index ac9054cc119..0adf282adb8 100644 --- a/source/source_io/module_parameter/read_input_item_md.cpp +++ b/source/source_io/module_parameter/read_input_item_md.cpp @@ -177,7 +177,7 @@ Note that md_tlast is only used in NVT/NPT simulations. If md_tlast is unset or item.annotation = "The period to output MD restart information"; item.category = "Molecular dynamics"; item.type = "Integer"; - item.description = "The output frequency of OUT.{suffix}/STRIU/, which are used to restart molecular dynamics calculations, see md_restart in detail."; + item.description = "The output frequency of OUT.{suffix}/STRU_MD_*, which are used to restart molecular dynamics calculations, see md_restart in detail. Set to 0 to disable MD restart output."; item.default_value = "5"; item.unit = ""; item.availability = ""; @@ -189,13 +189,25 @@ Note that md_tlast is only used in NVT/NPT simulations. If md_tlast is unset or item.annotation = "The period to dump MD information"; item.category = "Molecular dynamics"; item.type = "Integer"; - item.description = "The output frequency of OUT.${suffix}/MD_dump in molecular dynamics calculations, which including the information of lattices and atoms."; + item.description = "The output frequency of OUT.${suffix}/MD_dump in molecular dynamics calculations, which includes lattice and atomic information. Set to 0 to disable MD_dump output."; item.default_value = "1"; item.unit = ""; item.availability = ""; read_sync_int(input.mdp.md_dumpfreq); this->add_item(item); } + { + Input_Item item("md_out_force"); + item.annotation = "output all atomic forces into running_md.log or not"; + item.category = "Molecular dynamics"; + item.type = "Boolean"; + item.description = "Whether to output the TOTAL-FORCE table in OUT.${suffix}/running_md.log for MDCell molecular dynamics. This does not affect force calculation or molecular dynamics integration."; + item.default_value = "True"; + item.unit = ""; + item.availability = ""; + read_sync_bool(input.mdp.md_out_force); + this->add_item(item); + } { Input_Item item("dump_force"); item.annotation = "output atomic forces into the file MD_dump or not"; @@ -238,8 +250,8 @@ Note that md_tlast is only used in NVT/NPT simulations. If md_tlast is unset or item.category = "Molecular dynamics"; item.type = "Integer"; item.description = R"(The random seed to initialize random numbers used in molecular dynamics calculations. -* < 0: No srand() function is called. -* >= 0: The function srand(md_seed) is called.)"; +* < 0: Each MPI rank uses the default seed 1 plus its rank. +* >= 0: Each MPI rank uses md_seed plus its rank.)"; item.default_value = "-1"; item.unit = ""; item.availability = ""; diff --git a/source/source_io/test/read_input_ptest.cpp b/source/source_io/test/read_input_ptest.cpp index f278035afd7..d6e36eadace 100644 --- a/source/source_io/test/read_input_ptest.cpp +++ b/source/source_io/test/read_input_ptest.cpp @@ -407,6 +407,7 @@ TEST_F(InputParaTest, ParaRead) EXPECT_EQ(param.inp.mdp.md_pmode, "iso"); EXPECT_EQ(param.inp.mdp.md_restart, 0); EXPECT_EQ(param.inp.mdp.md_restartfreq, 5); + EXPECT_FALSE(param.inp.mdp.md_out_force); EXPECT_EQ(param.inp.mdp.md_seed, -1); EXPECT_EQ(param.inp.mdp.md_prec_level, 0); EXPECT_DOUBLE_EQ(param.inp.ref_cell_factor, 1.2); diff --git a/source/source_io/test/support/INPUT b/source/source_io/test/support/INPUT index a32923d8c36..df78fb591ee 100644 --- a/source/source_io/test/support/INPUT +++ b/source/source_io/test/support/INPUT @@ -187,6 +187,7 @@ md_tfirst -1 #temperature first md_tlast -1 #temperature last md_dumpfreq 1 #The period to dump MD information md_restartfreq 5 #The period to output MD restart information +md_out_force 0 #output all atomic forces into running_md.log or not md_seed -1 #random seed for MD md_prec_level 2 #precision level for vc-md ref_cell_factor 1.2 #construct a reference cell bigger than the initial cell diff --git a/source/source_main/driver_run.cpp b/source/source_main/driver_run.cpp index de1356c56ca..2b5a798ac0d 100644 --- a/source/source_main/driver_run.cpp +++ b/source/source_main/driver_run.cpp @@ -1,16 +1,22 @@ -#include "source_main/driver.h" +#include "source_base/constants.h" +#include "source_base/global_function.h" +#include "source_base/global_variable.h" +#include "source_base/kernels/math_kernel_op.h" +#include "source_base/module_device/device.h" +#include "source_base/module_device/memory_op.h" +#include "source_base/parallel_cell.h" #include "source_cell/check_atomic_stru.h" +#include "source_cell/distributed_mdcell_reader.h" +#include "source_cell/md_cell.h" #include "source_cell/module_neighbor/sltk_atom_arrange.h" -#include "source_relax/relax_driver.h" -#include "source_io/module_parameter/parameter.h" +#include "source_cell/print_cell.h" +#include "source_hsolver/kernels/hegvd_op.h" #include "source_io/module_json/para_json.h" #include "source_io/module_output/print_info.h" +#include "source_io/module_parameter/parameter.h" +#include "source_main/driver.h" #include "source_md/run_md.h" -#include "source_base/global_variable.h" -#include "source_base/module_device/device.h" -#include "source_base/module_device/memory_op.h" -#include "source_base/kernels/math_kernel_op.h" -#include "source_hsolver/kernels/hegvd_op.h" +#include "source_relax/relax_driver.h" #include #include @@ -41,76 +47,130 @@ void Driver::driver_run() //! 1: setup cell and atom information // this warning should not be here, mohan 2024-05-22 #ifndef __LCAO - if (PARAM.inp.basis_type == "lcao_in_pw" || PARAM.inp.basis_type == "lcao") { - ModuleBase::WARNING_QUIT("driver", - "to use LCAO basis, compile with __LCAO"); + if (PARAM.inp.basis_type == "lcao_in_pw" || PARAM.inp.basis_type == "lcao") + { + ModuleBase::WARNING_QUIT("driver", "to use LCAO basis, compile with __LCAO"); } #endif - // the life of ucell should begin here, mohan 2024-05-12 - UnitCell ucell; - ucell.setup_from_input(PARAM.inp.latname, - PARAM.inp.ntype, - PARAM.inp.lmaxmax, - PARAM.inp.init_vel, - PARAM.inp.fixed_axes); - - ucell.setup_cell(PARAM.globalv.global_in_stru, GlobalV::ofs_running, PARAM.inp.symmetry_prec, PARAM.inp.dfthalf_type, PARAM.inp.pseudo_dir, PARAM.inp.nspin, - PARAM.inp.basis_type, PARAM.inp.orbital_dir, PARAM.inp.init_wfc, - PARAM.inp.onsite_radius, PARAM.globalv.deepks_setorb, PARAM.inp.rpa, - PARAM.inp.fixed_atoms, PARAM.inp.noncolin, PARAM.inp.calculation, PARAM.inp.esolver_type, - std::stoi(PARAM.inp.symmetry)); - unitcell::check_atomic_stru(ucell, PARAM.inp.min_dist_coef); - - //! 2: initialize the ESolver (depends on a set-up ucell after `setup_cell`) - this->init_hardware(); + const std::string cal = PARAM.inp.calculation; + const Input_para& input = PARAM.inp; + this->init_hardware(); ModuleESolver::ESolver* p_esolver = ModuleESolver::init_esolver(PARAM.inp); - //! 3: initialize Esolver and fill json-structure - p_esolver->before_all_runners(ucell, PARAM.inp); + // UnitCell is initialized only for workflows that require its full DFT state. + UnitCell ucell; + bool ucell_initialized = false; + const auto initialize_ucell = [&ucell, &ucell_initialized, &input]() + { + if (ucell_initialized) + { + return; + } + + ucell.setup_from_input(input.latname, + input.ntype, + input.lmaxmax, + input.init_vel, + input.fixed_axes); + ucell.setup_cell(PARAM.globalv.global_in_stru, + GlobalV::ofs_running, + input.symmetry_prec, + input.dfthalf_type, + input.pseudo_dir, + input.nspin, + input.basis_type, + input.orbital_dir, + input.init_wfc, + input.onsite_radius, + PARAM.globalv.deepks_setorb, + input.rpa, + input.fixed_atoms, + input.noncolin, + input.calculation, + input.esolver_type, + std::stoi(input.symmetry)); + unitcell::check_atomic_stru(ucell, input.min_dist_coef); + ucell_initialized = true; - // this Json part should be moved to before_all_runners, mohan 2024-05-12 #ifdef __RAPIDJSON - Json::gen_stru_wrapper(&ucell, PARAM.inp); + Json::gen_stru_wrapper(&ucell, input); #endif + }; - const std::string cal = PARAM.inp.calculation; - - //! 4: different types of calculations if (cal == "md") { - Run_MD::md_line(ucell, p_esolver, PARAM); - } - else if (cal == "scf" || cal == "relax" || cal == "cell-relax" || cal == "nscf") - { - Relax_Driver rl_driver; - rl_driver.relax_driver(p_esolver, ucell, PARAM.inp, GlobalV::ofs_running); - } - else if (cal == "get_s") - { - p_esolver->runner(ucell, 0); - } - else if (cal == "get_pchg" || cal == "get_wf" || cal == "gen_bessel" || cal == "gen_opt_abfs" || - cal == "test_memory" || cal == "test_neighbour") - { - const int istep = 0; - p_esolver->others(ucell, istep); + const ModuleBase::CommunicationDomain communication_domain = ModuleBase::world_communication_domain(); + if (p_esolver->supports_mdcell()) + { + const double cutoff = p_esolver->mdcell_cutoff(PARAM.inp); + if (cutoff <= 0.0) + { + ModuleBase::WARNING_QUIT("Driver::driver_run", + "An ESolver supporting MDCell must provide a positive cutoff."); + } + const std::vector effective_replicate = PARAM.inp.mdp.md_restart + ? std::vector{1, 1, 1} + : PARAM.inp.cell_replica; + MdStruFileMetadata stru_metadata; + MDCell mdcell = DistributedMDCellReader::read_stru(PARAM.globalv.global_in_stru, + effective_replicate, + cutoff, + 0.0, + stru_metadata, + communication_domain); + GlobalV::ofs_running << std::endl; + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "TOTAL ATOM NUMBER", mdcell.nat()); + GlobalV::ofs_running << std::endl; + p_esolver->before_all_runners(mdcell, PARAM.inp); + Run_MD::md_line(mdcell, p_esolver, PARAM, stru_metadata); + p_esolver->after_all_runners(mdcell); + } + else + { + initialize_ucell(); + MDCell mdcell(ucell, 0.0, 0.0, communication_domain); + const MdStruFileMetadata stru_metadata = unitcell::make_md_stru_file_metadata(ucell); + p_esolver->before_all_runners(ucell, PARAM.inp); + Run_MD::md_line(mdcell, p_esolver, PARAM, stru_metadata); + p_esolver->after_all_runners(ucell); + } } else { - ModuleBase::WARNING_QUIT("Driver::driver_run","cannot recognize the 'calculation' command"); + initialize_ucell(); + p_esolver->before_all_runners(ucell, PARAM.inp); + if (cal == "scf" || cal == "relax" || cal == "cell-relax" || cal == "nscf") + { + Relax_Driver rl_driver; + rl_driver.relax_driver(p_esolver, ucell, PARAM.inp, GlobalV::ofs_running); + } + else if (cal == "get_s") + { + p_esolver->runner(ucell, 0); + } + else if (cal == "get_pchg" || cal == "get_wf" || cal == "gen_bessel" || cal == "gen_opt_abfs" + || cal == "test_memory" || cal == "test_neighbour") + { + p_esolver->others(ucell, 0); + } + else + { + ModuleBase::WARNING_QUIT("Driver::driver_run", "cannot recognize the 'calculation' command"); + } + p_esolver->after_all_runners(ucell); } - //! 5: clean up esolver - p_esolver->after_all_runners(ucell); - delete p_esolver; this->finalize_hardware(); //! 6: output the json file - Json::create_Json(&ucell, PARAM); + if (ucell_initialized) + { + Json::create_Json(&ucell, PARAM); + } return; } diff --git a/source/source_md/fire.cpp b/source/source_md/fire.cpp index faf47a3e453..767d87281c8 100644 --- a/source/source_md/fire.cpp +++ b/source/source_md/fire.cpp @@ -6,7 +6,7 @@ #endif #include "source_base/timer.h" -FIRE::FIRE(const Parameter& param_in, UnitCell& unit_in) : MD_base(param_in, unit_in) +FIRE::FIRE(const Parameter& param_in, MDCell& mdcell_in) : MD_base(param_in, mdcell_in) { force_thr = param_in.inp.force_thr; dt_max = -1.0; @@ -19,7 +19,11 @@ FIRE::FIRE(const Parameter& param_in, UnitCell& unit_in) : MD_base(param_in, uni n_min = 4; negative_count = 0; max = 0.0; - force_thr = 1e-3; + + // BUGFIX: + // Do not override the force convergence threshold read from INPUT. + // force_thr is stored in internal force unit, Hartree/Bohr. + // force_thr = 1e-3; } FIRE::~FIRE() @@ -45,7 +49,7 @@ void FIRE::first_half(std::ofstream& ofs) ModuleBase::TITLE("FIRE", "first_half"); ModuleBase::timer::start("FIRE", "first_half"); - MD_base::update_vel(force); + MD_base::update_vel(); check_fire(); @@ -62,7 +66,7 @@ void FIRE::second_half(void) ModuleBase::TITLE("FIRE", "second_half"); ModuleBase::timer::start("FIRE", "second_half"); - MD_base::update_vel(force); + MD_base::update_vel(); check_force(); @@ -102,7 +106,7 @@ void FIRE::write_restart(const std::string& global_out_dir) file.close(); } #ifdef __MPI - MPI_Barrier(MPI_COMM_WORLD); + MPI_Barrier(mdcell.communicator()); #endif return; @@ -136,7 +140,7 @@ void FIRE::restart(const std::string& global_readin_dir) } #ifdef __MPI - MPI_Bcast(&ok, 1, MPI_C_BOOL, 0, MPI_COMM_WORLD); + MPI_Bcast(&ok, 1, MPI_C_BOOL, 0, mdcell.communicator()); #endif if (!ok) @@ -145,33 +149,67 @@ void FIRE::restart(const std::string& global_readin_dir) } #ifdef __MPI - MPI_Bcast(&step_rst_, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&md_tfirst, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&alpha, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&negative_count, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&dt_max, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&md_dt, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&step_rst_, 1, MPI_INT, 0, mdcell.communicator()); + MPI_Bcast(&md_tfirst, 1, MPI_DOUBLE, 0, mdcell.communicator()); + MPI_Bcast(&alpha, 1, MPI_DOUBLE, 0, mdcell.communicator()); + MPI_Bcast(&negative_count, 1, MPI_INT, 0, mdcell.communicator()); + MPI_Bcast(&dt_max, 1, MPI_DOUBLE, 0, mdcell.communicator()); + MPI_Bcast(&md_dt, 1, MPI_DOUBLE, 0, mdcell.communicator()); #endif return; } - void FIRE::check_force(void) { - max = 0; + max = 0.0; - for (int i = 0; i < ucell.nat; ++i) + std::int64_t movable_dof = 0; + + for (const LocalAtom& atom : mdcell.owned_atoms()) { for (int j = 0; j < 3; ++j) { - if (max < std::abs(force[i][j])) + // Only movable degrees of freedom should be used + // in the FIRE convergence criterion. + // + // For example: + // m 1 1 1 -> x/y/z are included. + // m 1 0 1 -> y is excluded. + // m 0 0 0 -> this atom contributes no DOF to convergence. + if (!atom.mbl[j]) { - max = std::abs(force[i][j]); + continue; + } + + ++movable_dof; + + if (max < std::abs(atom.force[j])) + { + max = std::abs(atom.force[j]); } } } + #ifdef __MPI + if (mdcell.mpi_size() > 1) + { + double global_max = 0.0; + std::int64_t global_movable_dof = 0; + MPI_Allreduce(&max, &global_max, 1, MPI_DOUBLE, MPI_MAX, mdcell.communicator()); + MPI_Allreduce(&movable_dof, &global_movable_dof, 1, MPI_INT64_T, MPI_SUM, mdcell.communicator()); + max = global_max; + movable_dof = global_movable_dof; + } +#endif + + // If there are no movable degrees of freedom, there is nothing to optimize. + if (movable_dof == 0) + { + stop = true; + return; + } + if (2.0 * max < force_thr) { stop = true; @@ -193,25 +231,71 @@ void FIRE::check_fire(void) dt_max = 2.5 * md_dt; } - const int nat = ucell.nat; + std::int64_t movable_dof = 0; -#pragma omp parallel for reduction(+:P, sumforce, normvel) schedule(static) if (nat >= 256) - for (int i = 0; i < nat; ++i) + // Compute P, |F| and |v| only on movable degrees of freedom. + // Fixed atoms/directions may have non-zero raw forces, but they should not + // affect the FIRE velocity projection or adaptive time-step control. + for (LocalAtom& atom : mdcell.mutable_owned_atoms()) { - P += vel[i].x * force[i].x + vel[i].y * force[i].y + vel[i].z * force[i].z; - sumforce += force[i].norm2(); - normvel += vel[i].norm2(); + for (int j = 0; j < 3; ++j) + { + if (!atom.mbl[j]) + { + // Keep frozen components clean. + atom.vel[j] = 0.0; + continue; + } + + ++movable_dof; + + P += atom.vel[j] * atom.force[j]; + sumforce += atom.force[j] * atom.force[j]; + normvel += atom.vel[j] * atom.vel[j]; + } } - sumforce = sqrt(sumforce); - normvel = sqrt(normvel); + #ifdef __MPI + if (mdcell.mpi_size() > 1) + { + double local_values[3] = {P, sumforce, normvel}; + double global_values[3] = {0.0, 0.0, 0.0}; + std::int64_t global_movable_dof = 0; + MPI_Allreduce(local_values, global_values, 3, MPI_DOUBLE, MPI_SUM, mdcell.communicator()); + MPI_Allreduce(&movable_dof, &global_movable_dof, 1, MPI_INT64_T, MPI_SUM, mdcell.communicator()); + P = global_values[0]; + sumforce = global_values[1]; + normvel = global_values[2]; + movable_dof = global_movable_dof; + } +#endif -#pragma omp parallel for schedule(static) if (nat >= 256) - for (int i = 0; i < nat; ++i) + // No movable degrees of freedom: nothing to update. + if (movable_dof == 0) { - for (int j = 0; j < 3; ++j) + return; + } + + sumforce = std::sqrt(sumforce); + normvel = std::sqrt(normvel); + + // If force or velocity norm is zero, the velocity projection is undefined. + // Avoid 0/0. In a truly converged case check_force() should stop the run. + if (sumforce > 0.0 && normvel > 0.0) + { + for (LocalAtom& atom : mdcell.mutable_owned_atoms()) { - vel[i][j] = (1.0 - alpha) * vel[i][j] + alpha * force[i][j] / sumforce * normvel; + for (int j = 0; j < 3; ++j) + { + if (!atom.mbl[j]) + { + atom.vel[j] = 0.0; + continue; + } + + atom.vel[j] = (1.0 - alpha) * atom.vel[j] + + alpha * atom.force[j] / sumforce * normvel; + } } } @@ -229,17 +313,16 @@ void FIRE::check_fire(void) md_dt *= fdec; negative_count = 0; -#pragma omp parallel for schedule(static) if (nat >= 256) - for (int i = 0; i < nat; ++i) + for (LocalAtom& atom : mdcell.mutable_owned_atoms()) { for (int j = 0; j < 3; ++j) { - vel[i][j] = 0; + atom.vel[j] = 0; } } alpha = alpha_start; } - + return; } diff --git a/source/source_md/fire.h b/source/source_md/fire.h index d586f6399fc..1cb065c44e0 100644 --- a/source/source_md/fire.h +++ b/source/source_md/fire.h @@ -13,7 +13,7 @@ class FIRE : public MD_base { public: - FIRE(const Parameter& param_in, UnitCell& unit_in); + FIRE(const Parameter& param_in, MDCell& mdcell_in); ~FIRE(); diff --git a/source/source_md/langevin.cpp b/source/source_md/langevin.cpp index 31996810aa0..a0af2ccc6fd 100644 --- a/source/source_md/langevin.cpp +++ b/source/source_md/langevin.cpp @@ -1,24 +1,17 @@ #include "langevin.h" #include "md_func.h" -#include "source_base/parallel_common.h" +#include "source_cell/unitcell.h" #include "source_base/timer.h" -Langevin::Langevin(const Parameter& param_in, UnitCell& unit_in) : MD_base(param_in, unit_in) +Langevin::Langevin(const Parameter& param_in, MDCell& mdcell_in) : MD_base(param_in, mdcell_in) { /// convert to a.u. unit assert(ModuleBase::AU_to_FS!=0.0); md_damp = mdp.md_damp / ModuleBase::AU_to_FS; - assert(ucell.nat>0); - - total_force = new ModuleBase::Vector3[ucell.nat]; -} - -Langevin::~Langevin() -{ - delete[] total_force; + total_force.resize(static_cast(mdcell.nlocal())); } @@ -41,7 +34,14 @@ void Langevin::first_half(std::ofstream& ofs) ModuleBase::TITLE("Langevin", "first_half"); ModuleBase::timer::start("Langevin", "first_half"); - MD_base::update_vel(total_force); + for (int i = 0; i < mdcell.nlocal(); ++i) + { + LocalAtom& atom = mdcell.mutable_owned_atoms()[static_cast(i)]; + for (int k = 0; k < 3; ++k) + { + if (atom.mbl[k]) atom.vel[k] += 0.5 * total_force[i][k] * md_dt / atom.mass; + } + } MD_base::update_pos(); ModuleBase::timer::end("Langevin", "first_half"); @@ -55,7 +55,14 @@ void Langevin::second_half() ModuleBase::timer::start("Langevin", "second_half"); post_force(); - MD_base::update_vel(total_force); + for (int i = 0; i < mdcell.nlocal(); ++i) + { + LocalAtom& atom = mdcell.mutable_owned_atoms()[static_cast(i)]; + for (int k = 0; k < 3; ++k) + { + if (atom.mbl[k]) atom.vel[k] += 0.5 * total_force[i][k] * md_dt / atom.mass; + } + } ModuleBase::timer::end("Langevin", "second_half"); return; @@ -85,23 +92,23 @@ void Langevin::restart(const std::string& global_readin_dir) void Langevin::post_force() { - if (my_rank == 0) + double t_target = MD_func::target_temp(step_ + step_rst_, mdp.md_nstep, md_tfirst, md_tlast); + total_force.resize(static_cast(mdcell.nlocal())); + + for (int i = 0; i < mdcell.nlocal(); ++i) { - double t_target = MD_func::target_temp(step_ + step_rst_, mdp.md_nstep, md_tfirst, md_tlast); - ModuleBase::Vector3 fictitious_force; - for (int i = 0; i < ucell.nat; ++i) + ModuleBase::Vector3 random_value; + for (int k = 0; k < 3; ++k) + { + random_value[k] = static_cast(std::rand()) / RAND_MAX - 0.5; + } + const LocalAtom& atom = mdcell.owned_atoms()[static_cast(i)]; + ModuleBase::Vector3 fictitious_force = -atom.mass * atom.vel / md_damp; + for (int j = 0; j < 3; ++j) { - fictitious_force = -allmass[i] * vel[i] / md_damp; - for (int j = 0; j < 3; ++j) - { - fictitious_force[j] += sqrt(24.0 * t_target * allmass[i] / md_damp / md_dt) - * (static_cast(std::rand()) / RAND_MAX - 0.5); - } - total_force[i] = force[i] + fictitious_force; + fictitious_force[j] += sqrt(24.0 * t_target * atom.mass / md_damp / md_dt) + * random_value[j]; } + total_force[i] = atom.force + fictitious_force; } - -#ifdef __MPI - MPI_Bcast(total_force, ucell.nat * 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); -#endif } diff --git a/source/source_md/langevin.h b/source/source_md/langevin.h index e89122d9f14..d227fd68502 100644 --- a/source/source_md/langevin.h +++ b/source/source_md/langevin.h @@ -3,6 +3,8 @@ #include "md_base.h" +#include + /** * @brief Langevin method * @@ -14,9 +16,7 @@ class Langevin : public MD_base { public: - Langevin(const Parameter& param_in, UnitCell& unit_in); - - ~Langevin(); + Langevin(const Parameter& param_in, MDCell& mdcell_in); private: void setup(ModuleESolver::ESolver* p_esolver, const std::string& global_readin_dir); @@ -37,7 +37,7 @@ class Langevin : public MD_base */ void post_force(); - ModuleBase::Vector3* total_force; ///< total force = true force + Langevin fictitious_force + std::vector > total_force; ///< total force = true force + Langevin fictitious_force double md_damp; ///< damping factor }; diff --git a/source/source_md/md_base.cpp b/source/source_md/md_base.cpp index 577d796b204..246013bcb02 100644 --- a/source/source_md/md_base.cpp +++ b/source/source_md/md_base.cpp @@ -1,29 +1,26 @@ #include "md_base.h" #include "md_func.h" +#include "source_cell/unitcell.h" #ifdef __MPI #include "mpi.h" #endif #include "source_io/module_output/print_info.h" -#include "source_cell/update_cell.h" -MD_base::MD_base(const Parameter& param_in, UnitCell& unit_in) -: mdp(param_in.mdp), ucell(unit_in) +#include +#include + +MD_base::MD_base(const Parameter& param_in, MDCell& mdcell_in) +: mdp(param_in.mdp), mdcell(mdcell_in) { +#ifdef __MPI + my_rank = mdcell.mpi_rank(); +#else my_rank = param_in.globalv.myrank; +#endif cal_stress = param_in.inp.cal_stress; - if (mdp.md_seed >= 0) - { - srand(mdp.md_seed); - } + srand((mdp.md_seed >= 0 ? mdp.md_seed : 1) + my_rank); stop = false; - assert(ucell.nat>0); - - allmass = new double[ucell.nat]; - pos = new ModuleBase::Vector3[ucell.nat]; - vel = new ModuleBase::Vector3[ucell.nat]; - ionmbl = new ModuleBase::Vector3[ucell.nat]; - force = new ModuleBase::Vector3[ucell.nat]; virial.create(3, 3); stress.create(3, 3); @@ -38,19 +35,12 @@ MD_base::MD_base(const Parameter& param_in, UnitCell& unit_in) step_ = 0; step_rst_ = 0; - MD_func::init_vel(ucell, my_rank, mdp.md_restart, md_tfirst, allmass, frozen_freedom_, ionmbl, vel); - t_current = MD_func::current_temp(kinetic, ucell.nat, frozen_freedom_, allmass, vel); + MD_func::init_vel(mdcell, param_in.inp.init_vel, mdp.md_restart, md_tfirst, frozen_freedom_); + t_current = MD_func::current_temp(kinetic, mdcell, frozen_freedom_); } -MD_base::~MD_base() -{ - delete[] allmass; - delete[] pos; - delete[] vel; - delete[] ionmbl; - delete[] force; -} +MD_base::~MD_base() {} void MD_base::setup(ModuleESolver::ESolver* p_esolver, const std::string& global_readin_dir) @@ -67,9 +57,12 @@ void MD_base::setup(ModuleESolver::ESolver* p_esolver, const std::string& global ModuleIO::print_screen(stress_step, force_step, istep_print); - MD_func::force_virial(p_esolver, step_, ucell, potential, force, cal_stress, virial); - MD_func::compute_stress(ucell, vel, allmass, cal_stress, virial, stress); - ucell.ionic_position_updated = true; + MD_func::force_virial(p_esolver, step_, mdcell, potential, cal_stress, virial, mdp.md_out_force); + MD_func::compute_stress(mdcell, cal_stress, virial, stress); + if (mdcell.has_backing_unitcell()) + { + mdcell.backing_unitcell().ionic_position_updated = true; + } return; } @@ -77,7 +70,7 @@ void MD_base::setup(ModuleESolver::ESolver* p_esolver, const std::string& global void MD_base::first_half(std::ofstream& ofs) { - update_vel(force); + update_vel(); update_pos(); return; @@ -86,7 +79,7 @@ void MD_base::first_half(std::ofstream& ofs) void MD_base::second_half() { - update_vel(force); + update_vel(); return; } @@ -94,71 +87,63 @@ void MD_base::second_half() void MD_base::update_pos() { - if (my_rank == 0) + std::vector& atoms = mdcell.mutable_owned_atoms(); + for (std::size_t i = 0; i < atoms.size(); ++i) { - const int natom = ucell.nat; -#pragma omp parallel for schedule(static) if (natom >= 256) - for (int i = 0; i < natom; ++i) + LocalAtom& atom = atoms[i]; + ModuleBase::Vector3 pos; + for (int k = 0; k < 3; ++k) { - for (int k = 0; k < 3; ++k) + if (atom.mbl[k]) { - if (ionmbl[i][k]) - { - pos[i][k] = vel[i][k] * md_dt / ucell.lat0; - } - else - { - pos[i][k] = 0; - } + pos[k] = atom.vel[k] * md_dt / mdcell.lat0(); + } + else + { + pos[k] = 0; } - pos[i] = pos[i] * ucell.GT; } + pos = pos * mdcell.GT(); + atom.frac += pos; + atom.frac.x -= std::floor(atom.frac.x); + atom.frac.y -= std::floor(atom.frac.y); + atom.frac.z -= std::floor(atom.frac.z); + atom.cart = atom.frac * mdcell.latvec(); } -#ifdef __MPI - MPI_Bcast(pos, ucell.nat * 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); -#endif - - unitcell::update_pos_taud(ucell.lat,pos,ucell.ntype,ucell.nat,ucell.atoms); + mdcell.migrate_owned_atoms(); return; } -void MD_base::update_vel(const ModuleBase::Vector3* force) +void MD_base::update_vel() { - if (my_rank == 0) + std::vector& atoms = mdcell.mutable_owned_atoms(); + for (std::size_t i = 0; i < atoms.size(); ++i) { - const int natom = ucell.nat; -#pragma omp parallel for schedule(static) if (natom >= 256) - for (int i = 0; i < natom; ++i) + LocalAtom& atom = atoms[i]; + for (int k = 0; k < 3; ++k) { - for (int k = 0; k < 3; ++k) + if (atom.mbl[k]) { - if (ionmbl[i][k]) - { - vel[i][k] += 0.5 * force[i][k] * md_dt / allmass[i]; - } + atom.vel[k] += 0.5 * atom.force[k] * md_dt / atom.mass; } } } - -#ifdef __MPI - MPI_Bcast(vel, ucell.nat * 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); -#endif return; } void MD_base::print_md(std::ofstream& ofs, const bool& cal_stress) { + t_current = MD_func::current_temp(kinetic, mdcell, frozen_freedom_); + if (my_rank!=0) { return; } - t_current = MD_func::current_temp(kinetic, ucell.nat, frozen_freedom_, allmass, vel); - assert(ModuleBase::BOHR_RADIUS_SI>0.0); const double unit_transform = ModuleBase::HARTREE_SI / pow(ModuleBase::BOHR_RADIUS_SI, 3) * 1.0e-8; @@ -169,36 +154,34 @@ void MD_base::print_md(std::ofstream& ofs, const bool& cal_stress) } // screen output - std::cout << " -------------------------------------------------------------------------" + std::cout << std::setprecision(8); + std::cout << " ------------------------------------------------------------------------------------------------" << std::endl; - std::cout << " " << std::left << std::setw(24) << "Energy (Ry)" << std::left << std::setw(24) << "Potential (Ry)" - << std::left << std::setw(24) << "Kinetic (Ry)" << std::endl; - std::cout << std::setprecision(12); - std::cout << " " << std::left << std::setw(24) << 2 * (potential + kinetic) << std::left << std::setw(24) - << 2 * potential << std::left << std::setw(24) << 2 * kinetic << std::endl; - std::cout << " " << std::left << std::setw(24) << "Temperature (K)"; + std::cout << " " << std::left << std::setw(20) << "Energy (Ry)" << std::left << std::setw(20) << "Potential (Ry)" + << std::left << std::setw(20) << "Kinetic (Ry)" << std::left << std::setw(20) << "Temperature (K)"; if (cal_stress) { - std::cout << std::left << std::setw(24) << "Pressure (kbar)"; + std::cout << std::left << std::setw(20) << "Pressure (kbar)"; } std::cout << std::endl; - std::cout << std::setprecision(6); - std::cout << " " << std::left << std::setw(24) << t_current * ModuleBase::Hartree_to_K; + std::cout << " " << std::left << std::setw(20) << 2 * (potential + kinetic) << std::left << std::setw(20) + << 2 * potential << std::left << std::setw(20) << 2 * kinetic << std::left << std::setw(20) + << t_current * ModuleBase::Hartree_to_K; if (cal_stress) { - std::cout << std::left << std::setw(24) << press * unit_transform; + std::cout << std::left << std::setw(20) << press * unit_transform; } std::cout << std::endl; - std::cout << " -------------------------------------------------------------------------" + std::cout << " ------------------------------------------------------------------------------------------------" << std::endl; // running_log output ofs.unsetf(std::ios::fixed); - ofs << std::setprecision(12); + ofs << std::setprecision(8); if (cal_stress) { @@ -206,30 +189,28 @@ void MD_base::print_md(std::ofstream& ofs, const bool& cal_stress) ofs << std::endl; } - ofs << " -------------------------------------------------------------------------" + ofs << " ------------------------------------------------------------------------------------------------" << std::endl; - ofs << " " << std::left << std::setw(24) << "Energy (Ry)" << std::left << std::setw(24) << "Potential (Ry)" - << std::left << std::setw(24) << "Kinetic (Ry)" << std::endl; - ofs << " " << std::left << std::setw(24) << 2 * (potential + kinetic) << std::left << std::setw(24) << 2 * potential - << std::left << std::setw(24) << 2 * kinetic << std::endl; - ofs << " " << std::left << std::setw(24) << "Temperature (K)"; + ofs << " " << std::left << std::setw(20) << "Energy (Ry)" << std::left << std::setw(20) << "Potential (Ry)" + << std::left << std::setw(20) << "Kinetic (Ry)" << std::left << std::setw(20) << "Temperature (K)"; if (cal_stress) { - ofs << std::left << std::setw(24) << "Pressure (kbar)"; + ofs << std::left << std::setw(20) << "Pressure (kbar)"; } ofs << std::endl; - ofs << std::setprecision(6); - ofs << " " << std::left << std::setw(24) << t_current * ModuleBase::Hartree_to_K; + ofs << " " << std::left << std::setw(20) << 2 * (potential + kinetic) << std::left << std::setw(20) << 2 * potential + << std::left << std::setw(20) << 2 * kinetic << std::left << std::setw(20) + << t_current * ModuleBase::Hartree_to_K; if (cal_stress) { - ofs << std::left << std::setw(24) << press * unit_transform; + ofs << std::left << std::setw(20) << press * unit_transform; } ofs << std::endl; - ofs << " -------------------------------------------------------------------------" + ofs << " ------------------------------------------------------------------------------------------------" << std::endl; ofs << std::endl; return; @@ -249,7 +230,7 @@ void MD_base::write_restart(const std::string& global_out_dir) file.close(); } #ifdef __MPI - MPI_Barrier(MPI_COMM_WORLD); + MPI_Barrier(mdcell.communicator()); #endif return; @@ -258,7 +239,7 @@ void MD_base::write_restart(const std::string& global_out_dir) void MD_base::restart(const std::string& global_readin_dir) { - MD_func::current_md_info(my_rank, global_readin_dir, step_rst_, md_tfirst); + MD_func::current_md_info(mdcell, global_readin_dir, step_rst_, md_tfirst); return; } diff --git a/source/source_md/md_base.h b/source/source_md/md_base.h index ccc919ba89c..d0b1b8e9543 100644 --- a/source/source_md/md_base.h +++ b/source/source_md/md_base.h @@ -1,9 +1,12 @@ #ifndef MD_BASE_H #define MD_BASE_H +#include "source_cell/md_cell.h" #include "source_esolver/esolver.h" #include "source_io/module_parameter/parameter.h" +#include + /** * @brief base class of md * @@ -15,7 +18,7 @@ class MD_base { public: - MD_base(const Parameter& param_in, UnitCell& unit_in); + MD_base(const Parameter& param_in, MDCell& mdcell_in); virtual ~MD_base(); /** @@ -67,19 +70,14 @@ class MD_base * @brief perform half-step update of vel due to atomic force * @param force atomic forces */ - virtual void update_vel(const ModuleBase::Vector3* force); + virtual void update_vel(); public: bool stop; ///< MD stop or not double t_current; ///< current temperature int step_; ///< the MD step finished in current calculation int step_rst_; ///< the MD step finished in previous calculations - int frozen_freedom_; ///< the fixed freedom of the system - double* allmass = nullptr; ///< atom mass - ModuleBase::Vector3* pos; ///< atom displacements liuyu modify 2023-03-22 - ModuleBase::Vector3* vel; ///< atom velocity - ModuleBase::Vector3* ionmbl; ///< atom is frozen or not - ModuleBase::Vector3* force; ///< force of each atom + std::int64_t frozen_freedom_; ///< the fixed freedom of the system ModuleBase::matrix virial; ///< virial for this lattice ModuleBase::matrix stress; ///< stress for this lattice double potential=0.0; ///< potential energy @@ -87,7 +85,7 @@ class MD_base protected: const MD_para& mdp; ///< input parameters used in md - UnitCell& ucell; ///< unitcell information + MDCell& mdcell; ///< mdcell information double energy_=0.0; ///< total energy of the system bool cal_stress; ///< whether calculate stress @@ -97,4 +95,4 @@ class MD_base double md_tlast; ///< Target temperature }; -#endif // MD_BASE_H \ No newline at end of file +#endif // MD_BASE_H diff --git a/source/source_md/md_func.cpp b/source/source_md/md_func.cpp index c0f17f1f4d8..ac3c6ff66ed 100644 --- a/source/source_md/md_func.cpp +++ b/source/source_md/md_func.cpp @@ -2,11 +2,34 @@ #include "source_base/global_variable.h" #include "source_base/timer.h" +#include "source_io/module_output/output_log.h" #include "source_io/module_parameter/parameter.h" +#include +#include +#include +#include + namespace MD_func { +#ifdef __MPI +namespace +{ +bool write_dump_at(const int file, const std::string& data, const MPI_Offset offset) +{ + std::size_t written = 0; + while (written < data.size()) + { + const ssize_t count = pwrite(file, data.data() + written, data.size() - written, + static_cast(offset + written)); + if (count <= 0) return false; + written += static_cast(count); + } + return true; +} +} +#endif double gaussrand() { @@ -53,56 +76,47 @@ double kinetic_energy(const int& natom, const ModuleBase::Vector3* vel, return ke; } -MDKineticState calc_kinetic_state(const int& natom, - const int& frozen_freedom, - const double* allmass, - const ModuleBase::Vector3* vel) -{ - MDKineticState state; - if (3 * natom == frozen_freedom) - { - return state; - } - - state.kinetic = kinetic_energy(natom, vel, allmass); - state.temperature = 2 * state.kinetic / (3 * natom - frozen_freedom); - return state; -} - -MDStressState calc_stress_state(const int& natom, - const double& omega, - const ModuleBase::Vector3* vel, - const double* allmass, - const ModuleBase::matrix& virial) +void compute_stress(const UnitCell& unit_in, + const ModuleBase::Vector3* vel, + const double* allmass, + const bool& cal_stress, + const ModuleBase::matrix& virial, + ModuleBase::matrix& stress) { - MDStressState state; - temp_vector(natom, vel, allmass, state.temperature_tensor); - state.stress.create(3, 3); - - for (int i = 0; i < 3; ++i) + if (cal_stress) { - for (int j = 0; j < 3; ++j) + ModuleBase::matrix temperature_tensor(3, 3); + temp_vector(unit_in.nat, vel, allmass, temperature_tensor); + for (int i = 0; i < 3; ++i) { - state.stress(i, j) = virial(i, j) + state.temperature_tensor(i, j) / omega; + for (int j = 0; j < 3; ++j) + { + stress(i, j) = virial(i, j) + temperature_tensor(i, j) / unit_in.omega; + } } } - return state; + return; } -void compute_stress(const UnitCell& unit_in, - const ModuleBase::Vector3* vel, - const double* allmass, +void compute_stress(const MDCell& mdcell, const bool& cal_stress, const ModuleBase::matrix& virial, ModuleBase::matrix& stress) { - if (cal_stress) + if (!cal_stress) return; + ModuleBase::matrix t_vector(3, 3); + for (std::size_t i = 0; i < mdcell.owned_atoms().size(); ++i) { - stress = calc_stress_state(unit_in.nat, unit_in.omega, vel, allmass, virial).stress; + const LocalAtom& atom = mdcell.owned_atoms()[i]; + for (int a = 0; a < 3; ++a) for (int b = 0; b < 3; ++b) + t_vector(a, b) += atom.mass * atom.vel[a] * atom.vel[b]; } - - return; +#ifdef __MPI + MPI_Allreduce(MPI_IN_PLACE, t_vector.c, 9, MPI_DOUBLE, MPI_SUM, mdcell.communicator()); +#endif + for (int i = 0; i < 3; ++i) for (int j = 0; j < 3; ++j) + stress(i, j) = virial(i, j) + t_vector(i, j) / mdcell.omega(); } void read_vel(const UnitCell& unit_in, ModuleBase::Vector3* vel) @@ -274,6 +288,70 @@ void init_vel(const UnitCell& unit_in, } } +void init_vel(MDCell& mdcell, + const bool& init_vel, + const bool& restart, + double& temperature, + std::int64_t& frozen_freedom) +{ + std::vector& atoms = mdcell.mutable_owned_atoms(); + ModuleBase::Vector3 frozen(0, 0, 0); + for (std::size_t i = 0; i < atoms.size(); ++i) + for (int k = 0; k < 3; ++k) if (!atoms[i].mbl[k]) ++frozen[k]; +#ifdef __MPI + if (mdcell.mpi_size() > 1) + { + MPI_Allreduce(MPI_IN_PLACE, &frozen.x, 3, MPI_INT64_T, MPI_SUM, mdcell.communicator()); + } +#endif + frozen_freedom = frozen.x + frozen.y + frozen.z; + if (!frozen.x) ++frozen_freedom; + if (!frozen.y) ++frozen_freedom; + if (!frozen.z) ++frozen_freedom; + if (init_vel) + { + double kinetic = 0.0; + const double current = current_temp(kinetic, mdcell, frozen_freedom); + if (!restart && current > 0.0 && temperature > 0.0) + { + const double factor = sqrt(temperature / current); + for (LocalAtom& atom : atoms) atom.vel *= factor; + } + return; + } + + double local_mass = 0.0; + ModuleBase::Vector3 momentum(0.0, 0.0, 0.0); + for (LocalAtom& atom : atoms) + { + local_mass += atom.mass; + for (int k = 0; k < 3; ++k) + { + atom.vel[k] = atom.mbl[k] ? gaussrand() * sqrt(temperature / atom.mass) : 0.0; + if (frozen[k] == 0) momentum[k] += atom.mass * atom.vel[k]; + } + } +#ifdef __MPI + MPI_Allreduce(MPI_IN_PLACE, &local_mass, 1, MPI_DOUBLE, MPI_SUM, mdcell.communicator()); + MPI_Allreduce(MPI_IN_PLACE, &momentum.x, 3, MPI_DOUBLE, MPI_SUM, mdcell.communicator()); +#endif + for (int k = 0; k < 3; ++k) + { + if (frozen[k] == 0 && local_mass > 0.0) + { + for (LocalAtom& atom : atoms) atom.vel[k] -= momentum[k] / local_mass; + } + } + double kinetic = 0.0; + const double current = current_temp(kinetic, mdcell, frozen_freedom); + if (current > 0.0 && temperature > 0.0) + { + const double factor = sqrt(temperature / current); + for (LocalAtom& atom : atoms) atom.vel *= factor; + } + static_cast(restart); +} + void force_virial(ModuleESolver::ESolver* p_esolver, const int& istep, UnitCell& unit_in, @@ -317,6 +395,53 @@ void force_virial(ModuleESolver::ESolver* p_esolver, return; } +void force_virial(ModuleESolver::ESolver* p_esolver, + const int& istep, + MDCell& mdcell, + double& potential, + const bool& cal_stress, + ModuleBase::matrix& virial, + const bool& md_out_force) +{ + ModuleBase::TITLE("MD_func", "force_virial"); + ModuleBase::timer::start("MD_func", "force_virial"); + if (p_esolver->supports_mdcell()) + { + p_esolver->runner(static_cast(mdcell), istep); + potential = 0.5 * p_esolver->cal_energy(); + for (LocalAtom& atom : mdcell.mutable_owned_atoms()) atom.force *= 0.5; + if (md_out_force) + { + ModuleIO::print_force(GlobalV::ofs_running, mdcell, "TOTAL-FORCE (eV/Angstrom)"); + } + if (cal_stress) { p_esolver->cal_stress(static_cast(mdcell), virial); virial *= 0.5; } + } + else + { + if (!mdcell.has_backing_unitcell()) ModuleBase::WARNING_QUIT("MD_func::force_virial", "This ESolver requires UnitCell, but MDCell has no backing UnitCell."); + UnitCell& ucell = mdcell.backing_unitcell(); + std::vector>> backing_velocities( + static_cast(ucell.ntype)); + for (int it = 0; it < ucell.ntype; ++it) + { + backing_velocities[static_cast(it)] = ucell.atoms[it].vel; + } + mdcell.sync_backing_unitcell(); + for (int it = 0; it < ucell.ntype; ++it) + { + std::copy(backing_velocities[static_cast(it)].begin(), + backing_velocities[static_cast(it)].end(), + ucell.atoms[it].vel.begin()); + } + p_esolver->runner(ucell, istep); potential = 0.5 * p_esolver->cal_energy(); + ModuleBase::matrix full_force(ucell.nat, 3); p_esolver->cal_force(ucell, full_force); full_force *= 0.5; + if (cal_stress) { p_esolver->cal_stress(ucell, virial); virial *= 0.5; } + std::vector offsets(ucell.ntype + 1, 0); for (int it=0; it type_offsets(mdcell.type_atom_counts().size() + 1, 0); + for (std::size_t it = 0; it < mdcell.type_atom_counts().size(); ++it) + { + type_offsets[it + 1] = type_offsets[it] + mdcell.type_atom_counts()[it]; + } + std::ostringstream local; + local << std::fixed << std::setprecision(12); + for (int i = 0; i < mdcell.nlocal(); ++i) + { + const LocalAtom& atom = mdcell.owned_atoms()[static_cast(i)]; + local << " " << type_offsets[static_cast(atom.type)] + atom.type_index + << " " << mdcell.type_labels()[static_cast(atom.type)] + << " " << atom.cart.x * unit_pos << " " << atom.cart.y * unit_pos << " " << atom.cart.z * unit_pos; + if (param_in.mdp.dump_force) + local << " " << atom.force.x * unit_force << " " << atom.force.y * unit_force << " " << atom.force.z * unit_force; + if (param_in.mdp.dump_vel) + local << " " << atom.vel.x * unit_vel << " " << atom.vel.y * unit_vel << " " << atom.vel.z * unit_vel; + local << "\n"; + } +#ifdef __MPI + const MPI_Comm comm = mdcell.communicator(); + int rank = 0; MPI_Comm_rank(comm, &rank); + MPI_Offset base = 0; + if (rank == 0) + { + const int file_descriptor = open(file.str().c_str(), O_CREAT | O_WRONLY | (step == 0 ? O_TRUNC : O_APPEND), 0666); + if (file_descriptor < 0) ModuleBase::WARNING_QUIT("MD_func::dump_info", "cannot open MD_dump."); + base = lseek(file_descriptor, 0, SEEK_END); + if (!write_dump_at(file_descriptor, header.str(), base) || close(file_descriptor) != 0) ModuleBase::WARNING_QUIT("MD_func::dump_info", "cannot write MD_dump header."); + } + MPI_Bcast(&base, 1, MPI_OFFSET, 0, comm); + const MPI_Offset atom_offset = base + static_cast(header.str().size()); + const MPI_Offset local_size = static_cast(local.str().size()); + MPI_Offset rank_offset = 0; + MPI_Exscan(&local_size, &rank_offset, 1, MPI_OFFSET, MPI_SUM, comm); + if (rank == 0) rank_offset = 0; + const int file_descriptor = open(file.str().c_str(), O_WRONLY); + if (file_descriptor < 0 || !write_dump_at(file_descriptor, local.str(), atom_offset + rank_offset) || close(file_descriptor) != 0) ModuleBase::WARNING_QUIT("MD_func::dump_info", "cannot write MD_dump atoms."); +#else + std::ofstream ofs(file.str().c_str(), step == 0 ? std::ios::trunc : std::ios::app); + ofs << header.str() << local.str(); +#endif +} + void get_mass_mbl(const UnitCell& unit_in, double* allmass, ModuleBase::Vector3& frozen, @@ -492,12 +689,47 @@ double current_temp(double& kinetic, kinetic = 0.0; return 0.0; } - else + kinetic = kinetic_energy(natom, vel, allmass); + return 2 * kinetic / (3 * natom - frozen_freedom); +} + +double current_temp(double& kinetic, + const MDCell& mdcell, + const std::int64_t& frozen_freedom) +{ + kinetic = 0.0; + for (std::size_t i = 0; i < mdcell.owned_atoms().size(); ++i) + { + const LocalAtom& atom = mdcell.owned_atoms()[i]; + kinetic += 0.5 * atom.mass * atom.vel.norm2(); + } +#ifdef __MPI + MPI_Allreduce(MPI_IN_PLACE, &kinetic, 1, MPI_DOUBLE, MPI_SUM, mdcell.communicator()); +#endif + const std::int64_t dof = 3 * mdcell.nat() - frozen_freedom; + if (dof == 0) return 0.0; + return 2.0 * kinetic / static_cast(dof); +} + +std::int64_t global_dof(const MDCell& mdcell) +{ + std::int64_t local_frozen[3] = {0, 0, 0}; + for (int i = 0; i < mdcell.nlocal(); ++i) { - const MDKineticState state = calc_kinetic_state(natom, frozen_freedom, allmass, vel); - kinetic = state.kinetic; - return state.temperature; + const ModuleBase::Vector3& mbl = mdcell.owned_atoms()[static_cast(i)].mbl; + if (mbl.x == 0) ++local_frozen[0]; + if (mbl.y == 0) ++local_frozen[1]; + if (mbl.z == 0) ++local_frozen[2]; } + std::int64_t global_frozen[3] = {local_frozen[0], local_frozen[1], local_frozen[2]}; +#ifdef __MPI + MPI_Allreduce(MPI_IN_PLACE, global_frozen, 3, MPI_INT64_T, MPI_SUM, mdcell.communicator()); +#endif + std::int64_t total_frozen = global_frozen[0] + global_frozen[1] + global_frozen[2]; + if (global_frozen[0] == 0) ++total_frozen; + if (global_frozen[1] == 0) ++total_frozen; + if (global_frozen[2] == 0) ++total_frozen; + return 3 * mdcell.nat() - total_frozen; } void temp_vector(const int& natom, @@ -589,4 +821,41 @@ void current_md_info(const int& my_rank, const std::string& file_dir, int& md_st return; } +void current_md_info(const MDCell& mdcell, const std::string& file_dir, int& md_step, double& temperature) +{ + bool ok = true; + +#ifdef __MPI + const int rank = mdcell.mpi_rank(); +#else + const int rank = 0; +#endif + if (rank == 0) + { + std::stringstream ssc; + ssc << file_dir << "Restart_md.txt"; + std::ifstream file(ssc.str().c_str()); + if (!file) + { + ok = false; + } + if (ok) + { + file >> md_step >> temperature; + } + } + +#ifdef __MPI + MPI_Bcast(&ok, 1, MPI_C_BOOL, 0, mdcell.communicator()); +#endif + if (!ok) + { + ModuleBase::WARNING_QUIT("current_md_info", "no Restart_md.txt!"); + } +#ifdef __MPI + MPI_Bcast(&md_step, 1, MPI_INT, 0, mdcell.communicator()); + MPI_Bcast(&temperature, 1, MPI_DOUBLE, 0, mdcell.communicator()); +#endif +} + } // namespace MD_func diff --git a/source/source_md/md_func.h b/source/source_md/md_func.h index 51c4eb47d83..55b288bd97c 100644 --- a/source/source_md/md_func.h +++ b/source/source_md/md_func.h @@ -1,9 +1,11 @@ #ifndef MD_FUNC_H #define MD_FUNC_H -#include "md_statistics.h" +#include "source_cell/md_cell.h" #include "source_esolver/esolver.h" +#include + class Parameter; #ifdef __MPI @@ -45,6 +47,11 @@ void init_vel(const UnitCell& unit_in, int& frozen_freedom, ModuleBase::Vector3* ionmbl, ModuleBase::Vector3* vel); +void init_vel(MDCell& mdcell, + const bool& init_vel, + const bool& restart, + double& temperature, + std::int64_t& frozen_freedom); /** * @brief read in atomic velocities from STRU @@ -108,6 +115,13 @@ void force_virial(ModuleESolver::ESolver* p_esolver, ModuleBase::Vector3* force, const bool& cal_stress, ModuleBase::matrix& virial); +void force_virial(ModuleESolver::ESolver* p_esolver, + const int& istep, + MDCell& mdcell, + double& potential, + const bool& cal_stress, + ModuleBase::matrix& virial, + const bool& md_out_force); /** * @brief calculate the ionic kinetic energy * @@ -118,14 +132,6 @@ void force_virial(ModuleESolver::ESolver* p_esolver, */ double kinetic_energy(const int& natom, const ModuleBase::Vector3* vel, const double* allmass); -/** - * @brief calculate kinetic energy and temperature without writing caller-owned state - */ -MDKineticState calc_kinetic_state(const int& natom, - const int& frozen_freedom, - const double* allmass, - const ModuleBase::Vector3* vel); - /** * @brief calculate the total stress tensor * @@ -142,15 +148,10 @@ void compute_stress(const UnitCell& unit_in, const bool& cal_stress, const ModuleBase::matrix& virial, ModuleBase::matrix& stress); - -/** - * @brief calculate stress and ionic temperature tensor without writing caller-owned state - */ -MDStressState calc_stress_state(const int& natom, - const double& omega, - const ModuleBase::Vector3* vel, - const double* allmass, - const ModuleBase::matrix& virial); +void compute_stress(const MDCell& mdcell, + const bool& cal_stress, + const ModuleBase::matrix& virial, + ModuleBase::matrix& stress); /** * @brief output the stress information @@ -182,6 +183,11 @@ void dump_info(const int& step, const ModuleBase::matrix& virial, const ModuleBase::Vector3* force, const ModuleBase::Vector3* vel); +void dump_info(const int& step, + const std::string& global_out_dir, + const MDCell& mdcell, + const Parameter& param_in, + const ModuleBase::matrix& virial); /** * @brief obtain the atomic mass and whether the freedom is fixed @@ -222,6 +228,10 @@ double current_temp(double& kinetic, const int& frozen_freedom, const double* allmass, const ModuleBase::Vector3* vel); +double current_temp(double& kinetic, + const MDCell& mdcell, + const std::int64_t& frozen_freedom); +std::int64_t global_dof(const MDCell& mdcell); /** * @brief get the temperature vectors @@ -247,6 +257,7 @@ void temp_vector(const int& natom, * @param temperature current temperature */ void current_md_info(const int& my_rank, const std::string& file_dir, int& md_step, double& temperature); +void current_md_info(const MDCell& mdcell, const std::string& file_dir, int& md_step, double& temperature); } // namespace MD_func diff --git a/source/source_md/msst.cpp b/source/source_md/msst.cpp index 2343a54ea90..b467b5b0b24 100644 --- a/source/source_md/msst.cpp +++ b/source/source_md/msst.cpp @@ -1,21 +1,20 @@ #include "msst.h" -#include "source_cell/update_cell.h" #include "md_func.h" +#include "source_cell/unitcell.h" #ifdef __MPI #include "mpi.h" #endif #include "source_base/timer.h" -MSST::MSST(const Parameter& param_in, UnitCell& unit_in) : MD_base(param_in, unit_in) +MSST::MSST(const Parameter& param_in, MDCell& mdcell_in) : MD_base(param_in, mdcell_in) { msst_qmass = mdp.msst_qmass / pow(ModuleBase::ANGSTROM_AU, 4) / pow(ModuleBase::AU_to_MASS, 2); msst_vel = mdp.msst_vel * ModuleBase::ANGSTROM_AU * ModuleBase::AU_to_FS; msst_vis = mdp.msst_vis / ModuleBase::AU_to_MASS / ModuleBase::ANGSTROM_AU * ModuleBase::AU_to_FS; - assert(ucell.nat>0); + assert(mdcell.nat() > 0); - old_v = new ModuleBase::Vector3[ucell.nat]; dilation.set(1, 1, 1); omega.set(0, 0, 0); p0 = 0; @@ -24,16 +23,15 @@ MSST::MSST(const Parameter& param_in, UnitCell& unit_in) : MD_base(param_in, uni totmass = 0; lag_pos = 0; vsum = 0; - - for (int i = 0; i < ucell.nat; ++i) - { - totmass += allmass[i]; - } + + for (const LocalAtom& atom : mdcell.owned_atoms()) totmass += atom.mass; +#ifdef __MPI + MPI_Allreduce(MPI_IN_PLACE, &totmass, 1, MPI_DOUBLE, MPI_SUM, mdcell.communicator()); +#endif } MSST::~MSST() { - delete[] old_v; } void MSST::setup(ModuleESolver::ESolver* p_esolver, const std::string& global_readin_dir) @@ -42,14 +40,17 @@ void MSST::setup(ModuleESolver::ESolver* p_esolver, const std::string& global_re ModuleBase::timer::start("MSST", "setup"); MD_base::setup(p_esolver, global_readin_dir); - ucell.cell_parameter_updated = true; + if (mdcell.has_backing_unitcell()) + { + mdcell.backing_unitcell().cell_parameter_updated = true; + } int sd = mdp.msst_direction; if (!mdp.md_restart) { lag_pos = 0; - v0 = ucell.omega; + v0 = mdcell.omega(); p0 = stress(sd, sd); e0 = potential + kinetic; @@ -61,14 +62,11 @@ void MSST::setup(ModuleESolver::ESolver* p_esolver, const std::string& global_re std::cout << "initial strain rate = " << fac2 << " msst_tscale = " << mdp.msst_tscale << std::endl; - for (int i = 0; i < ucell.nat; ++i) - { - vel[i] *= sqrt(1.0 - mdp.msst_tscale); - } + for (LocalAtom& atom : mdcell.mutable_owned_atoms()) atom.vel *= sqrt(1.0 - mdp.msst_tscale); } - MD_func::compute_stress(ucell, vel, allmass, cal_stress, virial, stress); - t_current = MD_func::current_temp(kinetic, ucell.nat, frozen_freedom_, allmass, vel); + MD_func::compute_stress(mdcell, cal_stress, virial, stress); + t_current = MD_func::current_temp(kinetic, mdcell, frozen_freedom_); } ModuleBase::timer::end("MSST", "setup"); @@ -92,9 +90,10 @@ void MSST::first_half(std::ofstream& ofs) vsum = vel_sum(); /// save the velocities - for (int i = 0; i < ucell.nat; ++i) + old_v.resize(mdcell.owned_atoms().size()); + for (int i = 0; i < mdcell.nlocal(); ++i) { - old_v[i] = vel[i]; + old_v[static_cast(i)] = mdcell.owned_atoms()[static_cast(i)].vel; } /// propagate velocity sum 1/2 step by temporarily propagating the velocities @@ -103,16 +102,16 @@ void MSST::first_half(std::ofstream& ofs) vsum = vel_sum(); /// reset the velocities - for (int i = 0; i < ucell.nat; ++i) + for (int i = 0; i < mdcell.nlocal(); ++i) { - vel[i] = old_v[i]; + mdcell.mutable_owned_atoms()[static_cast(i)].vel = old_v[static_cast(i)]; } /// propagate velocities 1/2 step using the new velocity sum propagate_vel(); /// propagate volume 1/2 step - vol = ucell.omega + omega[sd] * dthalf; + vol = mdcell.omega() + omega[sd] * dthalf; /// rescale positions and change box size rescale(ofs, vol); @@ -121,7 +120,7 @@ void MSST::first_half(std::ofstream& ofs) MD_base::update_pos(); /// propagate volume 1/2 step - vol = ucell.omega + omega[sd] * dthalf; + vol = mdcell.omega() + omega[sd] * dthalf; /// rescale positions and change box size rescale(ofs, vol); @@ -144,14 +143,14 @@ void MSST::second_half() propagate_vel(); vsum = vel_sum(); - MD_func::compute_stress(ucell, vel, allmass, cal_stress, virial, stress); - t_current = MD_func::current_temp(kinetic, ucell.nat, frozen_freedom_, allmass, vel); + MD_func::compute_stress(mdcell, cal_stress, virial, stress); + t_current = MD_func::current_temp(kinetic, mdcell, frozen_freedom_); /// propagate the time derivative of volume 1/2 step propagate_voldot(); /// calculate Lagrangian position - lag_pos -= msst_vel * ucell.omega / v0 * md_dt; + lag_pos -= msst_vel * mdcell.omega() / v0 * md_dt; ModuleBase::timer::end("MSST", "second_half"); @@ -185,7 +184,7 @@ void MSST::write_restart(const std::string& global_out_dir) file.close(); } #ifdef __MPI - MPI_Barrier(MPI_COMM_WORLD); + MPI_Barrier(mdcell.communicator()); #endif return; @@ -219,7 +218,7 @@ void MSST::restart(const std::string& global_readin_dir) } #ifdef __MPI - MPI_Bcast(&ok, 1, MPI_C_BOOL, 0, MPI_COMM_WORLD); + MPI_Bcast(&ok, 1, MPI_C_BOOL, 0, mdcell.communicator()); #endif if (!ok) @@ -228,13 +227,13 @@ void MSST::restart(const std::string& global_readin_dir) } #ifdef __MPI - MPI_Bcast(&step_rst_, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&md_tfirst, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&omega[mdp.msst_direction], 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&e0, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&v0, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&p0, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&lag_pos, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&step_rst_, 1, MPI_INT, 0, mdcell.communicator()); + MPI_Bcast(&md_tfirst, 1, MPI_DOUBLE, 0, mdcell.communicator()); + MPI_Bcast(&omega[mdp.msst_direction], 1, MPI_DOUBLE, 0, mdcell.communicator()); + MPI_Bcast(&e0, 1, MPI_DOUBLE, 0, mdcell.communicator()); + MPI_Bcast(&v0, 1, MPI_DOUBLE, 0, mdcell.communicator()); + MPI_Bcast(&p0, 1, MPI_DOUBLE, 0, mdcell.communicator()); + MPI_Bcast(&lag_pos, 1, MPI_DOUBLE, 0, mdcell.communicator()); #endif return; @@ -243,13 +242,11 @@ void MSST::restart(const std::string& global_readin_dir) double MSST::vel_sum() const { double vsum = 0; - const int nat = ucell.nat; -#pragma omp parallel for reduction(+:vsum) schedule(static) if (nat >= 256) - for (int i = 0; i < nat; ++i) - { - vsum += vel[i].norm2(); - } + for (const LocalAtom& atom : mdcell.owned_atoms()) vsum += atom.vel.norm2(); +#ifdef __MPI + MPI_Allreduce(MPI_IN_PLACE, &vsum, 1, MPI_DOUBLE, MPI_SUM, mdcell.communicator()); +#endif return vsum; } @@ -257,63 +254,50 @@ void MSST::rescale(std::ofstream& ofs, const double& volume) { int sd = mdp.msst_direction; - assert(ucell.omega>0.0); + assert(mdcell.omega() > 0.0); - dilation[sd] = volume / ucell.omega; - ucell.latvec.e11 *= dilation[0]; - ucell.latvec.e22 *= dilation[1]; - ucell.latvec.e33 *= dilation[2]; - - unitcell::setup_cell_after_vc(ucell,ofs, PARAM.inp.nspin); + dilation[sd] = volume / mdcell.omega(); + ModuleBase::Matrix3 latvec = mdcell.latvec(); + latvec.e11 *= dilation[0]; + latvec.e22 *= dilation[1]; + latvec.e33 *= dilation[2]; + mdcell.set_lattice_vectors(latvec); + mdcell.refresh_cart_from_frac(); /// rescale velocity - const int nat = ucell.nat; -#pragma omp parallel for schedule(static) if (nat >= 256) - for (int i = 0; i < nat; ++i) - { - vel[i][sd] *= dilation[sd]; - } + for (LocalAtom& atom : mdcell.mutable_owned_atoms()) atom.vel[sd] *= dilation[sd]; + static_cast(ofs); } void MSST::propagate_vel() { - if (my_rank == 0) + const int sd = mdp.msst_direction; + const double dthalf = 0.5 * md_dt; + const double fac = msst_vis * pow(omega[sd], 2) / (vsum * mdcell.omega()); + + for (LocalAtom& atom : mdcell.mutable_owned_atoms()) { - const int sd = mdp.msst_direction; - const double dthalf = 0.5 * md_dt; - const double fac = msst_vis * pow(omega[sd], 2) / (vsum * ucell.omega); - const int nat = ucell.nat; + ModuleBase::Vector3 const_C = atom.force / atom.mass; + ModuleBase::Vector3 const_D; + const_D.set(fac / atom.mass, fac / atom.mass, fac / atom.mass); + const_D[sd] -= 2 * omega[sd] / mdcell.omega(); -#pragma omp parallel for schedule(static) if (nat >= 256) - for (int i = 0; i < nat; ++i) + for (int k = 0; k < 3; ++k) { - ModuleBase::Vector3 const_C = force[i] / allmass[i]; - ModuleBase::Vector3 const_D; - const_D.set(fac / allmass[i], fac / allmass[i], fac / allmass[i]); - const_D[sd] -= 2 * omega[sd] / ucell.omega; - - for (int k = 0; k < 3; ++k) + if (fabs(dthalf * const_D[k]) > 1e-6) { - if (fabs(dthalf * const_D[k]) > 1e-6) - { - double expd = exp(dthalf * const_D[k]); - vel[i][k] = expd * (const_C[k] + const_D[k] * vel[i][k] - const_C[k] / expd) / const_D[k]; - } - else - { - vel[i][k] - += (const_C[k] + const_D[k] * vel[i][k]) * dthalf - + 0.5 * (const_D[k] * const_D[k] * vel[i][k] + const_C[k] * const_D[k]) * dthalf * dthalf; - } + double expd = exp(dthalf * const_D[k]); + atom.vel[k] = expd * (const_C[k] + const_D[k] * atom.vel[k] - const_C[k] / expd) / const_D[k]; + } + else + { + atom.vel[k] + += (const_C[k] + const_D[k] * atom.vel[k]) * dthalf + + 0.5 * (const_D[k] * const_D[k] * atom.vel[k] + const_C[k] * const_D[k]) * dthalf * dthalf; } } } - -#ifdef __MPI - MPI_Bcast(vel, ucell.nat * 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); -#endif - return; } @@ -323,12 +307,12 @@ void MSST::propagate_voldot() const int sd = mdp.msst_direction; const double dthalf = 0.5 * md_dt; double p_current = stress(sd, sd); - double p_msst = msst_vel * msst_vel * totmass * (v0 - ucell.omega) / (v0 * v0); + double p_msst = msst_vel * msst_vel * totmass * (v0 - mdcell.omega()) / (v0 * v0); double const_A = totmass * (p_current - p0 - p_msst) / msst_qmass; - double const_B = totmass * msst_vis / (msst_qmass * ucell.omega); + double const_B = totmass * msst_vis / (msst_qmass * mdcell.omega()); /// prevent the increase of volume - if (ucell.omega > v0 && const_A > 0) + if (mdcell.omega() > v0 && const_A > 0) { const_A = -const_A; } diff --git a/source/source_md/msst.h b/source/source_md/msst.h index ca87571c4d6..0f9d377252e 100644 --- a/source/source_md/msst.h +++ b/source/source_md/msst.h @@ -2,6 +2,7 @@ #define MSST_H #include "md_base.h" +#include /** * @brief MSST method @@ -14,7 +15,7 @@ class MSST : public MD_base { public: - MSST(const Parameter& param_in, UnitCell& unit_in); + MSST(const Parameter& param_in, MDCell& mdcell_in); ~MSST(); private: @@ -52,7 +53,7 @@ class MSST : public MD_base */ void propagate_voldot(void); - ModuleBase::Vector3* old_v; ///< old atomic velocities + std::vector > old_v; ///< old atomic velocities ModuleBase::Vector3 dilation; ///< dilation scale ModuleBase::Vector3 omega; ///< time derivative of volume double p0; ///< initial pressure diff --git a/source/source_md/nhchain.cpp b/source/source_md/nhchain.cpp index ad91aee8248..f78299813a9 100644 --- a/source/source_md/nhchain.cpp +++ b/source/source_md/nhchain.cpp @@ -5,8 +5,24 @@ #include "mpi.h" #endif #include "source_base/timer.h" -#include "source_cell/update_cell.h" -Nose_Hoover::Nose_Hoover(const Parameter& param_in, UnitCell& unit_in) : MD_base(param_in, unit_in) + +namespace +{ +ModuleBase::matrix global_temp_tensor(const MDCell& mdcell) +{ + ModuleBase::matrix t_vector(3, 3); + for (const LocalAtom& atom : mdcell.owned_atoms()) + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 3; ++j) + t_vector(i, j) += atom.mass * atom.vel[i] * atom.vel[j]; +#ifdef __MPI + MPI_Allreduce(MPI_IN_PLACE, t_vector.c, t_vector.nr * t_vector.nc, MPI_DOUBLE, MPI_SUM, mdcell.communicator()); +#endif + return t_vector; +} +} + +Nose_Hoover::Nose_Hoover(const Parameter& param_in, MDCell& mdcell_in) : MD_base(param_in, mdcell_in) { const double unit_transform = ModuleBase::HARTREE_SI / pow(ModuleBase::BOHR_RADIUS_SI, 3) * 1.0e-8; @@ -59,7 +75,8 @@ Nose_Hoover::Nose_Hoover(const Parameter& param_in, UnitCell& unit_in) : MD_base */ else if (mdp.md_pmode == "tri") { - if (ucell.latvec.e12 || ucell.latvec.e13 || ucell.latvec.e23) + const ModuleBase::Matrix3& latvec = mdcell.latvec(); + if (latvec.e12 || latvec.e13 || latvec.e23) { ModuleBase::WARNING_QUIT("Nose_Hoover", "the lattice must be lower-triangular when md_pmode == tri!"); } @@ -87,7 +104,7 @@ Nose_Hoover::Nose_Hoover(const Parameter& param_in, UnitCell& unit_in) : MD_base } pdim = pflag[0] + pflag[1] + pflag[2]; - tdof = 3 * ucell.nat - frozen_freedom_; + tdof = MD_func::global_dof(mdcell); assert(mdp.md_tchain>0); @@ -159,10 +176,6 @@ void Nose_Hoover::setup(ModuleESolver::ESolver* p_esolver, const std::string& gl ModuleBase::timer::start("Nose_Hoover", "setup"); MD_base::setup(p_esolver, global_readin_dir); - if (mdp.md_type == "npt") - { - ucell.cell_parameter_updated = true; - } /// determine target temperature t_target = MD_func::target_temp(step_ + step_rst_, mdp.md_nstep, md_tfirst, md_tlast); @@ -185,7 +198,7 @@ void Nose_Hoover::setup(ModuleESolver::ESolver* p_esolver, const std::string& gl couple_stress(); /// init barostat - double nkt = (ucell.nat + 1) * t_target; + double nkt = (static_cast(mdcell.nat()) + 1.0) * t_target; for (int i = 0; i < 6; ++i) { @@ -232,8 +245,8 @@ void Nose_Hoover::first_half(std::ofstream& ofs) if (npt_flag) { /// update temperature and stress due to velocity rescaling - t_current = MD_func::current_temp(kinetic, ucell.nat, frozen_freedom_, allmass, vel); - MD_func::compute_stress(ucell, vel, allmass, cal_stress, virial, stress); + t_current = MD_func::current_temp(kinetic, mdcell, frozen_freedom_); + MD_func::compute_stress(mdcell, cal_stress, virial, stress); /// couple stress component due to md_pcouple couple_stress(); @@ -249,7 +262,7 @@ void Nose_Hoover::first_half(std::ofstream& ofs) } /// perform half-step update of vel due to atomic force - MD_base::update_vel(force); + MD_base::update_vel(); if (npt_flag) { @@ -278,7 +291,7 @@ void Nose_Hoover::second_half() ModuleBase::timer::start("Nose_Hoover", "second_half"); /// perform half-step update of vel due to atomic force - MD_base::update_vel(force); + MD_base::update_vel(); if (npt_flag) { @@ -287,12 +300,12 @@ void Nose_Hoover::second_half() } /// update temperature and kinetic energy due to velocity rescaling - t_current = MD_func::current_temp(kinetic, ucell.nat, frozen_freedom_, allmass, vel); + t_current = MD_func::current_temp(kinetic, mdcell, frozen_freedom_); if (npt_flag) { /// update stress due to velocity rescaling - MD_func::compute_stress(ucell, vel, allmass, cal_stress, virial, stress); + MD_func::compute_stress(mdcell, cal_stress, virial, stress); /// couple stress component due to md_pcouple couple_stress(); @@ -367,7 +380,7 @@ void Nose_Hoover::write_restart(const std::string& global_out_dir) file.close(); } #ifdef __MPI - MPI_Barrier(MPI_COMM_WORLD); + MPI_Barrier(mdcell.communicator()); #endif } @@ -442,9 +455,9 @@ void Nose_Hoover::restart(const std::string& global_readin_dir) } #ifdef __MPI - MPI_Bcast(&ok, 1, MPI_C_BOOL, 0, MPI_COMM_WORLD); - MPI_Bcast(&ok2, 1, MPI_C_BOOL, 0, MPI_COMM_WORLD); - MPI_Bcast(&ok3, 1, MPI_C_BOOL, 0, MPI_COMM_WORLD); + MPI_Bcast(&ok, 1, MPI_C_BOOL, 0, mdcell.communicator()); + MPI_Bcast(&ok2, 1, MPI_C_BOOL, 0, mdcell.communicator()); + MPI_Bcast(&ok3, 1, MPI_C_BOOL, 0, mdcell.communicator()); #endif if (!ok) @@ -461,15 +474,15 @@ void Nose_Hoover::restart(const std::string& global_readin_dir) } #ifdef __MPI - MPI_Bcast(&step_rst_, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&md_tfirst, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(eta, mdp.md_tchain, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(v_eta, mdp.md_tchain, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&step_rst_, 1, MPI_INT, 0, mdcell.communicator()); + MPI_Bcast(&md_tfirst, 1, MPI_DOUBLE, 0, mdcell.communicator()); + MPI_Bcast(eta, mdp.md_tchain, MPI_DOUBLE, 0, mdcell.communicator()); + MPI_Bcast(v_eta, mdp.md_tchain, MPI_DOUBLE, 0, mdcell.communicator()); if (npt_flag) { - MPI_Bcast(v_omega, 6, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(peta, mdp.md_pchain, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(v_peta, mdp.md_pchain, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(v_omega, 6, MPI_DOUBLE, 0, mdcell.communicator()); + MPI_Bcast(peta, mdp.md_pchain, MPI_DOUBLE, 0, mdcell.communicator()); + MPI_Bcast(v_peta, mdp.md_pchain, MPI_DOUBLE, 0, mdcell.communicator()); } #endif } @@ -553,12 +566,7 @@ void Nose_Hoover::particle_thermo() } /// rescale velocity due to thermostats - const int nat = ucell.nat; -#pragma omp parallel for schedule(static) if (nat >= 256) - for (int i = 0; i < nat; ++i) - { - vel[i] *= scale; - } + for (LocalAtom& atom : mdcell.mutable_owned_atoms()) atom.vel *= scale; } void Nose_Hoover::baro_thermo() @@ -651,8 +659,7 @@ void Nose_Hoover::update_baro() } else { - ModuleBase::matrix t_vector; - MD_func::temp_vector(ucell.nat, vel, allmass, t_vector); + const ModuleBase::matrix t_vector = global_temp_tensor(mdcell); for (int i = 0; i < 3; ++i) { @@ -662,7 +669,7 @@ void Nose_Hoover::update_baro() } } } - term_one /= pdim * ucell.nat; + term_one /= static_cast(pdim) * mdcell.nat(); double g_omega = 0.0; double term_two = 0; @@ -670,18 +677,18 @@ void Nose_Hoover::update_baro() { if (pflag[i]) { - g_omega = (p_current[i] - p_hydro) * ucell.omega / mass_omega[i] + term_one / mass_omega[i]; + g_omega = (p_current[i] - p_hydro) * mdcell.omega() / mass_omega[i] + term_one / mass_omega[i]; v_omega[i] += g_omega * md_dt / 2.0; term_two += v_omega[i]; } } - term_two /= pdim * ucell.nat; + term_two /= static_cast(pdim) * mdcell.nat(); for (int i = 3; i < 6; ++i) { if (pflag[i]) { - g_omega = p_current[i] * ucell.omega / mass_omega[i]; + g_omega = p_current[i] * mdcell.omega() / mass_omega[i]; v_omega[i] += g_omega * md_dt / 2.0; } } @@ -697,28 +704,26 @@ void Nose_Hoover::vel_baro() factor[i] = exp(-(v_omega[i] + mtk_term) * md_dt / 4); } - const int nat = ucell.nat; -#pragma omp parallel for schedule(static) if (nat >= 256) - for (int i = 0; i < nat; ++i) + for (LocalAtom& atom : mdcell.mutable_owned_atoms()) { for (int j = 0; j < 3; ++j) { - vel[i][j] *= factor[j]; + atom.vel[j] *= factor[j]; } /// Note: I am not sure whether fixed atoms should update here - if (ionmbl[i][0]) + if (atom.mbl[0]) { - vel[i][0] -= (vel[i][1] * v_omega[5] + vel[i][2] * v_omega[4]) * md_dt / 2; + atom.vel[0] -= (atom.vel[1] * v_omega[5] + atom.vel[2] * v_omega[4]) * md_dt / 2; } - if (ionmbl[i][1]) + if (atom.mbl[1]) { - vel[i][1] -= vel[i][2] * v_omega[3] * md_dt / 2; + atom.vel[1] -= atom.vel[2] * v_omega[3] * md_dt / 2; } for (int j = 0; j < 3; ++j) { - vel[i][j] *= factor[j]; + atom.vel[j] *= factor[j]; } } } @@ -726,94 +731,96 @@ void Nose_Hoover::vel_baro() void Nose_Hoover::update_volume(std::ofstream& ofs) { double factor = 0.0; + ModuleBase::Matrix3 latvec = mdcell.latvec(); /// tri mode, off-diagonal components, first half if (pflag[4]) { factor = exp(v_omega[0] * md_dt / 16); - ucell.latvec.e31 *= factor; - ucell.latvec.e31 += (v_omega[5] * ucell.latvec.e32 + v_omega[4] * ucell.latvec.e33); - ucell.latvec.e31 *= factor; + latvec.e31 *= factor; + latvec.e31 += (v_omega[5] * latvec.e32 + v_omega[4] * latvec.e33); + latvec.e31 *= factor; } if (pflag[3]) { factor = exp(v_omega[1] * md_dt / 8); - ucell.latvec.e32 *= factor; - ucell.latvec.e32 += (v_omega[3] * ucell.latvec.e33); - ucell.latvec.e32 *= factor; + latvec.e32 *= factor; + latvec.e32 += (v_omega[3] * latvec.e33); + latvec.e32 *= factor; } if (pflag[5]) { factor = exp(v_omega[0] * md_dt / 8); - ucell.latvec.e21 *= factor; - ucell.latvec.e21 += (v_omega[5] * ucell.latvec.e22); - ucell.latvec.e21 *= factor; + latvec.e21 *= factor; + latvec.e21 += (v_omega[5] * latvec.e22); + latvec.e21 *= factor; } if (pflag[4]) { factor = exp(v_omega[0] * md_dt / 16); - ucell.latvec.e31 *= factor; - ucell.latvec.e31 += (v_omega[5] * ucell.latvec.e32 + v_omega[4] * ucell.latvec.e33); - ucell.latvec.e31 *= factor; + latvec.e31 *= factor; + latvec.e31 += (v_omega[5] * latvec.e32 + v_omega[4] * latvec.e33); + latvec.e31 *= factor; } /// Diagonal components if (pflag[0]) { factor = exp(v_omega[0] * md_dt / 2); - ucell.latvec.e11 *= factor; + latvec.e11 *= factor; } if (pflag[1]) { factor = exp(v_omega[1] * md_dt / 2); - ucell.latvec.e22 *= factor; + latvec.e22 *= factor; } if (pflag[2]) { factor = exp(v_omega[2] * md_dt / 2); - ucell.latvec.e33 *= factor; + latvec.e33 *= factor; } /// tri mode, off-diagonal components, second half if (pflag[4]) { factor = exp(v_omega[0] * md_dt / 16); - ucell.latvec.e31 *= factor; - ucell.latvec.e31 += (v_omega[5] * ucell.latvec.e32 + v_omega[4] * ucell.latvec.e33); - ucell.latvec.e31 *= factor; + latvec.e31 *= factor; + latvec.e31 += (v_omega[5] * latvec.e32 + v_omega[4] * latvec.e33); + latvec.e31 *= factor; } if (pflag[3]) { factor = exp(v_omega[1] * md_dt / 8); - ucell.latvec.e32 *= factor; - ucell.latvec.e32 += (v_omega[3] * ucell.latvec.e33); - ucell.latvec.e32 *= factor; + latvec.e32 *= factor; + latvec.e32 += (v_omega[3] * latvec.e33); + latvec.e32 *= factor; } if (pflag[5]) { factor = exp(v_omega[0] * md_dt / 8); - ucell.latvec.e21 *= factor; - ucell.latvec.e21 += (v_omega[5] * ucell.latvec.e22); - ucell.latvec.e21 *= factor; + latvec.e21 *= factor; + latvec.e21 += (v_omega[5] * latvec.e22); + latvec.e21 *= factor; } if (pflag[4]) { factor = exp(v_omega[0] * md_dt / 16); - ucell.latvec.e31 *= factor; - ucell.latvec.e31 += (v_omega[5] * ucell.latvec.e32 + v_omega[4] * ucell.latvec.e33); - ucell.latvec.e31 *= factor; + latvec.e31 *= factor; + latvec.e31 += (v_omega[5] * latvec.e32 + v_omega[4] * latvec.e33); + latvec.e31 *= factor; } - /// reset ucell and pos due to change of lattice - unitcell::setup_cell_after_vc(ucell,ofs, PARAM.inp.nspin); + mdcell.set_lattice_vectors(latvec); + mdcell.refresh_cart_from_frac(); + static_cast(ofs); } void Nose_Hoover::target_stress() diff --git a/source/source_md/nhchain.h b/source/source_md/nhchain.h index e338f2bb355..0bd02df5cc0 100644 --- a/source/source_md/nhchain.h +++ b/source/source_md/nhchain.h @@ -12,7 +12,7 @@ class Nose_Hoover : public MD_base { public: - Nose_Hoover(const Parameter& param_in, UnitCell& unit_in); + Nose_Hoover(const Parameter& param_in, MDCell& mdcell_in); ~Nose_Hoover(); private: @@ -71,7 +71,7 @@ class Nose_Hoover : public MD_base const static int nys = 7; ///< the number of scale evolution operator double w[nys]; ///< scale evolution operator - int tdof; ///< particle degree of freedom + std::int64_t tdof; ///< particle degree of freedom double t_target=0.0;///< target temperature double* mass_eta = nullptr; ///< mass of thermostats coupled with particles double* eta = nullptr; ///< position of thermostats coupled with particles @@ -100,4 +100,4 @@ class Nose_Hoover : public MD_base double md_pfreq; ///< Oscillation frequency, used to determine qmass of thermostats coupled with barostat }; -#endif \ No newline at end of file +#endif diff --git a/source/source_md/run_md.cpp b/source/source_md/run_md.cpp index fdc86718919..15d4c0c095f 100644 --- a/source/source_md/run_md.cpp +++ b/source/source_md/run_md.cpp @@ -1,5 +1,6 @@ #include "run_md.h" +#include "source_cell/md_cell.h" #include "source_io/module_parameter/parameter.h" #include "fire.h" #include "langevin.h" @@ -12,47 +13,42 @@ #include "verlet.h" #include "source_cell/update_cell.h" #include "source_cell/print_cell.h" -#include - -namespace +namespace Run_MD { -std::unique_ptr create_md_runner(const Parameter& param_in, UnitCell& unit_in) + +void md_line(MDCell& mdcell, + ModuleESolver::ESolver* p_esolver, + const Parameter& param_in, + const MdStruFileMetadata& stru_metadata) { + ModuleBase::TITLE("Run_MD", "md_line"); + ModuleBase::timer::start("Run_MD", "md_line"); + /// determine the md_type + MD_base* mdrun = nullptr; if (param_in.mdp.md_type == "fire") { - return std::unique_ptr(new FIRE(param_in, unit_in)); + mdrun = new FIRE(param_in, mdcell); } - if ((param_in.mdp.md_type == "nvt" && param_in.mdp.md_thermostat == "nhc") || param_in.mdp.md_type == "npt") + else if ((param_in.mdp.md_type == "nvt" && param_in.mdp.md_thermostat == "nhc") || param_in.mdp.md_type == "npt") { - return std::unique_ptr(new Nose_Hoover(param_in, unit_in)); + mdrun = new Nose_Hoover(param_in, mdcell); } - if (param_in.mdp.md_type == "nve" || param_in.mdp.md_type == "nvt") + else if (param_in.mdp.md_type == "nve" || param_in.mdp.md_type == "nvt") { - return std::unique_ptr(new Verlet(param_in, unit_in)); + mdrun = new Verlet(param_in, mdcell); } - if (param_in.mdp.md_type == "langevin") + else if (param_in.mdp.md_type == "langevin") { - return std::unique_ptr(new Langevin(param_in, unit_in)); + mdrun = new Langevin(param_in, mdcell); } - if (param_in.mdp.md_type == "msst") + else if (param_in.mdp.md_type == "msst") { - return std::unique_ptr(new MSST(param_in, unit_in)); + mdrun = new MSST(param_in, mdcell); + } + else + { + ModuleBase::WARNING_QUIT("md_line", "no such md_type!"); } - - ModuleBase::WARNING_QUIT("md_line", "no such md_type!"); - return nullptr; -} -} // namespace - -namespace Run_MD -{ - -void md_line(UnitCell& unit_in, ModuleESolver::ESolver* p_esolver, const Parameter& param_in) -{ - ModuleBase::TITLE("Run_MD", "md_line"); - ModuleBase::timer::start("Run_MD", "md_line"); - - std::unique_ptr mdrun = create_md_runner(param_in, unit_in); /// md cycle, mohan update 2026-01-04, change '<=' to '<' while ((mdrun->step_ + mdrun->step_rst_) < param_in.mdp.md_nstep && !mdrun->stop) @@ -73,70 +69,51 @@ void md_line(UnitCell& unit_in, ModuleESolver::ESolver* p_esolver, const Paramet /// update force and virial due to the update of atom positions MD_func::force_virial(p_esolver, mdrun->step_, - unit_in, + mdcell, mdrun->potential, - mdrun->force, param_in.inp.cal_stress, - mdrun->virial); + mdrun->virial, + param_in.mdp.md_out_force); mdrun->second_half(); - MD_func::compute_stress(unit_in, - mdrun->vel, - mdrun->allmass, + MD_func::compute_stress(mdcell, param_in.inp.cal_stress, mdrun->virial, mdrun->stress); mdrun->t_current = MD_func::current_temp(mdrun->kinetic, - unit_in.nat, - mdrun->frozen_freedom_, - mdrun->allmass, - mdrun->vel); + mdcell, + mdrun->frozen_freedom_); } - if ((mdrun->step_ + mdrun->step_rst_) % param_in.mdp.md_dumpfreq == 0) + mdrun->print_md(GlobalV::ofs_running, PARAM.inp.cal_stress); + if (param_in.mdp.md_dumpfreq > 0 + && (mdrun->step_ + mdrun->step_rst_) % param_in.mdp.md_dumpfreq == 0) { - mdrun->print_md(GlobalV::ofs_running, PARAM.inp.cal_stress); - MD_func::dump_info(mdrun->step_ + mdrun->step_rst_, PARAM.globalv.global_out_dir, - unit_in, + mdcell, param_in, - mdrun->virial, - mdrun->force, - mdrun->vel); + mdrun->virial); } - if ((mdrun->step_ + mdrun->step_rst_) % param_in.mdp.md_restartfreq == 0) + if (param_in.mdp.md_restartfreq > 0 + && (mdrun->step_ + mdrun->step_rst_) % param_in.mdp.md_restartfreq == 0) { - unitcell::update_vel(mdrun->vel,unit_in.ntype,unit_in.nat,unit_in.atoms); + if (mdcell.has_backing_unitcell()) + { + mdcell.sync_backing_unitcell(); + } std::stringstream file; file << PARAM.globalv.global_stru_dir << "STRU_MD_" << mdrun->step_ + mdrun->step_rst_; - // changelog 20240509 - // because I move out the dependence on GlobalV from UnitCell::print_stru_file - // so its parameter is calculated here - bool need_orb = PARAM.inp.basis_type=="pw"; - need_orb = need_orb && PARAM.inp.init_wfc.substr(0, 3)=="nao"; - need_orb = need_orb || PARAM.inp.basis_type=="lcao"; - need_orb = need_orb || PARAM.inp.basis_type=="lcao_in_pw"; - unitcell::print_stru_file(unit_in, - unit_in.atoms, - unit_in.latvec, - file.str(), - "", - PARAM.inp.nspin, - false, // Cartesian coordinates - PARAM.inp.calculation == "md", - PARAM.inp.out_mul, - need_orb, - PARAM.globalv.deepks_setorb, - GlobalV::MY_RANK); + mdcell::print_stru_file(mdcell, stru_metadata, file.str()); mdrun->write_restart(PARAM.globalv.global_out_dir); } mdrun->step_++; } + delete mdrun; ModuleBase::timer::end("Run_MD", "md_line"); return; } diff --git a/source/source_md/run_md.h b/source/source_md/run_md.h index 4de44d52885..574dc8e104c 100644 --- a/source/source_md/run_md.h +++ b/source/source_md/run_md.h @@ -1,6 +1,8 @@ #ifndef RUN_MD_H #define RUN_MD_H +#include "source_cell/md_cell.h" +#include "source_cell/md_stru_file_metadata.h" #include "source_esolver/esolver.h" #include "source_io/module_parameter/parameter.h" @@ -13,11 +15,14 @@ namespace Run_MD /** * @brief the md loop line * - * @param unit_in unitcell information + * @param cell cell information * @param p_esolver energy solver * @param md_para input parameters used in md */ -void md_line(UnitCell& unit_in, ModuleESolver::ESolver* p_esolver, const Parameter& param_in); +void md_line(MDCell& mdcell, + ModuleESolver::ESolver* p_esolver, + const Parameter& param_in, + const MdStruFileMetadata& stru_metadata); } // namespace Run_MD -#endif \ No newline at end of file +#endif diff --git a/source/source_md/test/CMakeLists.txt b/source/source_md/test/CMakeLists.txt index 2bc7d9668d3..c2e6f61f8fa 100644 --- a/source/source_md/test/CMakeLists.txt +++ b/source/source_md/test/CMakeLists.txt @@ -4,7 +4,6 @@ abacus_add_local_feature_definitions(__NORMAL) list(APPEND depend_files ../md_func.cpp ../../source_cell/base_cell.cpp - ../../source_cell/md_cell.cpp ../../source_cell/unitcell.cpp ../../source_cell/update_cell.cpp ../../source_cell/bcast_cell.cpp @@ -51,6 +50,8 @@ list(APPEND depend_files ../../source_cell/module_neighlist/neighbor_search.cpp ../../source_cell/module_neighlist/bin_manager.cpp ../../source_cell/module_neighlist/page_allocator.cpp + ../../source_cell/module_neighlist/domain_decomposition.cpp + ../../source_cell/md_cell.cpp ../../source_base/output.cpp ../../source_io/module_output/output_log.cpp ../../source_io/module_output/print_info.cpp @@ -58,6 +59,7 @@ list(APPEND depend_files ../../source_esolver/esolver_lj.cpp ../../source_base/parallel_reduce.cpp ../../source_base/parallel_global.cpp + ../../source_base/parallel_cell.cpp ../../source_base/parallel_comm.cpp ../../source_cell/read_pp_ucell.cpp ../../source_cell/cal_wfc.cpp diff --git a/source/source_md/test/fire_test.cpp b/source/source_md/test/fire_test.cpp index 626cc780b8c..b8ad969ba7b 100644 --- a/source/source_md/test/fire_test.cpp +++ b/source/source_md/test/fire_test.cpp @@ -5,8 +5,9 @@ #undef private #define private public #define protected public +#include "setcell.h" +#include "source_esolver/esolver_lj.h" #include "source_md/fire.h" -#include "md_test_fixture.h" #define doublethreshold 1e-12 /************************************************ @@ -34,8 +35,34 @@ * - output MD information such as energy, temperature, and pressure */ -class FIREtest : public MdIntegratorFixture +class FIREtest : public testing::Test { + protected: + MD_base* mdrun; + UnitCell ucell; + MDCell* mdcell; + Parameter param_in; + ModuleESolver::ESolver* p_esolver; + + void SetUp() + { + Setcell::setupcell(ucell); + Setcell::parameters(param_in.input); + + p_esolver = new ModuleESolver::ESolver_LJ(); + mdcell = new MDCell(ucell, 8.5 * ModuleBase::ANGSTROM_AU, 0.0, + ModuleBase::world_communication_domain()); + p_esolver->before_all_runners(*mdcell, param_in.inp); + mdrun = new FIRE(param_in, *mdcell); + mdrun->setup(p_esolver, PARAM.sys.global_readin_dir); + } + + void TearDown() + { + delete mdrun; + delete mdcell; + delete p_esolver; + } }; TEST_F(FIREtest, Setup) @@ -56,31 +83,31 @@ TEST_F(FIREtest, FirstHalf) { mdrun->first_half(GlobalV::ofs_running); - EXPECT_NEAR(mdrun->pos[0].x, -0.00045447059554315662, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].y, 0.00032646833232493271, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].z, -5.215709523063016e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].x, 0.0005213674681407162, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].y, -0.00059486888444406608, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].z, 0.00035886062145122004, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].x, -0.00052406920303529794, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].y, 4.8706739346586155e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].z, -0.00020129054406946794, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].x, 0.00045717233044145918, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].y, 0.00021969381277291936, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].z, -0.00010541298215149392, doublethreshold); - - EXPECT_NEAR(mdrun->vel[0].x, -0.00010993118004167345, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].y, 7.8968913216100539e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].z, -1.2616198016939999e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].x, 0.00012611275970351733, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].y, -0.00014389190209072655, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].z, 8.6804233262820007e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].x, -0.00012676627812260489, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].y, 1.1781596840062159e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].z, -4.8689854212330001e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].x, 0.00011058469846166102, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].y, 5.3141392034653857e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].z, -2.5498181033639999e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).x, -0.00045447059554315662, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).y, 0.00032646833232493271, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).z, -5.215709523063016e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).x, 0.0005213674681407162, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).y, -0.00059486888444406608, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).z, 0.00035886062145122004, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).x, -0.00052406920303529794, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).y, 4.8706739346586155e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).z, -0.00020129054406946794, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).x, 0.00045717233044145918, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).y, 0.00021969381277291936, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).z, -0.00010541298215149392, doublethreshold); + + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.x, -0.00010993118004167345, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.y, 7.8968913216100539e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.z, -1.2616198016939999e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.x, 0.00012611275970351733, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.y, -0.00014389190209072655, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.z, 8.6804233262820007e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.x, -0.00012676627812260489, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.y, 1.1781596840062159e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.z, -4.8689854212330001e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.x, 0.00011058469846166102, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.y, 5.3141392034653857e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.z, -2.5498181033639999e-05, doublethreshold); } TEST_F(FIREtest, SecondHalf) @@ -88,31 +115,31 @@ TEST_F(FIREtest, SecondHalf) mdrun->first_half(GlobalV::ofs_running); mdrun->second_half(); - EXPECT_NEAR(mdrun->pos[0].x, -0.00045447059554315662, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].y, 0.00032646833232493271, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].z, -5.215709523063016e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].x, 0.0005213674681407162, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].y, -0.00059486888444406608, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].z, 0.00035886062145122004, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].x, -0.00052406920303529794, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].y, 4.8706739346586155e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].z, -0.00020129054406946794, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].x, 0.00045717233044145918, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].y, 0.00021969381277291936, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].z, -0.00010541298215149392, doublethreshold); - - EXPECT_NEAR(mdrun->vel[0].x, -0.00010978976887416819, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].y, 7.9202349471957007e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].z, -1.2616198016939999e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].x, 0.00012592893778281191, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].y, -0.00014408187344675441, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].z, 8.6804233262820007e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].x, -0.00012686679539500493, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].y, 1.2011267908381344e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].z, -4.8689854212330001e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].x, 0.00011072762648726122, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].y, 5.2868256066506055e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].z, -2.5498181033639999e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).x, -0.00045447059554315662, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).y, 0.00032646833232493271, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).z, -5.215709523063016e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).x, 0.0005213674681407162, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).y, -0.00059486888444406608, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).z, 0.00035886062145122004, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).x, -0.00052406920303529794, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).y, 4.8706739346586155e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).z, -0.00020129054406946794, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).x, 0.00045717233044145918, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).y, 0.00021969381277291936, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).z, -0.00010541298215149392, doublethreshold); + + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.x, -0.00010978976887416819, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.y, 7.9202349471957007e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.z, -1.2616198016939999e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.x, 0.00012592893778281191, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.y, -0.00014408187344675441, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.z, 8.6804233262820007e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.x, -0.00012686679539500493, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.y, 1.2011267908381344e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.z, -4.8689854212330001e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.x, 0.00011072762648726122, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.y, 5.2868256066506055e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.z, -2.5498181033639999e-05, doublethreshold); } TEST_F(FIREtest, WriteRestart) @@ -143,7 +170,7 @@ TEST_F(FIREtest, Restart) mdrun->restart(PARAM.sys.global_readin_dir); remove("Restart_md.txt"); - FIRE* fire = dynamic_cast(mdrun.get()); + FIRE* fire = dynamic_cast(mdrun); EXPECT_EQ(mdrun->step_rst_, 3); EXPECT_EQ(fire->alpha, 0.1); EXPECT_EQ(fire->negative_count, 0); @@ -161,39 +188,36 @@ TEST_F(FIREtest, PrintMD) std::string output_str; getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr(" ELECTRONIC PART OF STRESS: 0.24609992")); + EXPECT_THAT(output_str, testing::HasSubstr(" ELECTRONIC PART OF STRESS: 0.24609992 kbar")); getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr(" IONIC (KINETIC) PART OF STRESS: 0.838539188441")); + EXPECT_THAT(output_str, testing::HasSubstr(" IONIC (KINETIC) PART OF STRESS: 0.83853919 kbar")); getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr(" MD PRESSURE (ELECTRONS+IONS) : 1.0846391")); + EXPECT_THAT(output_str, testing::HasSubstr(" MD PRESSURE (ELECTRONS+IONS) : 1.0846391 kbar")); getline(ifs, output_str); getline(ifs, output_str); - EXPECT_THAT(output_str, + EXPECT_THAT( + output_str, testing::HasSubstr( - " ----------------------------------------")); + " ------------------------------------------------------------------------------------------------")); getline(ifs, output_str); - EXPECT_THAT(output_str, + EXPECT_THAT( + output_str, testing::HasSubstr( - " Energy (Ry) Potential (Ry) Kinetic (Ry) ")); - getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr("-0.0153652356062")); - EXPECT_THAT(output_str, testing::HasSubstr("-0.0239156372471")); - EXPECT_THAT(output_str, testing::HasSubstr("0.00855040164087")); + " Energy (Ry) Potential (Ry) Kinetic (Ry) Temperature (K) Pressure (kbar) ")); getline(ifs, output_str); - EXPECT_THAT(output_str, + EXPECT_THAT( + output_str, testing::HasSubstr( - " Temperature (K) Pressure (kbar) ")); - getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr("1.08464")); + " -0.015365236 -0.023915637 0.0085504016 300 1.0846391 ")); getline(ifs, output_str); EXPECT_THAT( output_str, testing::HasSubstr( - " ----------------------------------------")); + " ------------------------------------------------------------------------------------------------")); + getline(ifs, output_str); getline(ifs, output_str); - getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr(" LARGEST FORCE (eV/A) : 0.0494799")); + EXPECT_THAT(output_str, testing::HasSubstr(" LARGEST FORCE (eV/A) : 0.049479926")); ifs.close(); - //remove("running_fire.log"); + // remove("running_fire.log"); } diff --git a/source/source_md/test/langevin_test.cpp b/source/source_md/test/langevin_test.cpp index 894e21feb64..1b3a65f260f 100644 --- a/source/source_md/test/langevin_test.cpp +++ b/source/source_md/test/langevin_test.cpp @@ -5,8 +5,9 @@ #undef private #define private public #define protected public +#include "setcell.h" +#include "source_esolver/esolver_lj.h" #include "source_md/langevin.h" -#include "md_test_fixture.h" #define doublethreshold 1e-12 /************************************************ @@ -34,8 +35,34 @@ * - output MD information such as energy, temperature, and pressure */ -class Langevin_test : public MdIntegratorFixture +class Langevin_test : public testing::Test { + protected: + MD_base* mdrun; + UnitCell ucell; + MDCell* mdcell; + Parameter param_in; + ModuleESolver::ESolver* p_esolver; + + void SetUp() + { + Setcell::setupcell(ucell); + Setcell::parameters(param_in.input); + + p_esolver = new ModuleESolver::ESolver_LJ(); + mdcell = new MDCell(ucell, 8.5 * ModuleBase::ANGSTROM_AU, 0.0, + ModuleBase::world_communication_domain()); + p_esolver->before_all_runners(*mdcell, param_in.inp); + mdrun = new Langevin(param_in, *mdcell); + mdrun->setup(p_esolver, PARAM.sys.global_readin_dir); + } + + void TearDown() + { + delete mdrun; + delete mdcell; + delete p_esolver; + } }; TEST_F(Langevin_test, setup) @@ -56,31 +83,31 @@ TEST_F(Langevin_test, first_half) { mdrun->first_half(GlobalV::ofs_running); - EXPECT_NEAR(mdrun->pos[0].x, -0.00042883345359910814, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].y, 0.00016393608896004904, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].z, 0.00049409894499896569, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].x, 0.00079697932877452634, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].y, -0.00014670764202547791, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].z, 0.0004507052338971732, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].x, -0.00069151085005912606, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].y, 0.00011838145470033956, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].z, -0.00067130287159685429, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].x, -6.3573121476911994e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].y, -0.00025901016337184232, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].z, 0.00029326569457701463, doublethreshold); - - EXPECT_NEAR(mdrun->vel[0].x, -0.00010372985195918919, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].y, 3.9654243613399205e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].z, 0.00011951681938006538, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].x, 0.00019278008069211768, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].y, -3.5486881587393478e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].z, 0.00010902038261476422, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].x, -0.00016726847568161691, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].y, 2.8635104532351301e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].z, -0.00016238039944434295, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].x, -1.5377602712750055e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].y, -6.2651562458564838e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].z, 7.093757921139429e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).x, 0.00012104549072633688, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).y, 2.6272991724490339e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).z, 0.0002984728051383459, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).x, 0.00066077703137157329, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).y, 0.00017245549939737259, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).z, -0.00015046260270490386, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).x, -0.00046755850510571406, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).y, 0.00030490494761200812, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).z, -0.00036886672854369307, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).x, 0.00029624371924650601, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).y, 0.00013444493932002199, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).z, 9.0496812405138627e-05, doublethreshold); + + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.x, 2.9279504031204254e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.y, 6.3551327892765255e-06, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.z, 7.2197119023712585e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.x, 0.00015983432044991118, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.y, 4.1714990451188365e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.z, -3.639516314080526e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.x, -0.0001130969939724264, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.y, 7.3752979885251439e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.z, -8.9224594824346108e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.x, 7.1657928931092104e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.y, 3.2520675649909766e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.z, 2.189013211254232e-05, doublethreshold); } TEST_F(Langevin_test, second_half) @@ -89,31 +116,31 @@ TEST_F(Langevin_test, second_half) mdrun->second_half(); ; - EXPECT_NEAR(mdrun->pos[0].x, -0.00066954020090275205, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].y, 3.3862365219131354e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].z, -0.00045718198868662484, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].x, -0.0001368904183573199, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].y, 0.00027340532086011393, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].z, -0.00012651337976204397, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].x, -0.00026200923787255071, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].y, 0.00038689191688656276, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].z, 1.8457678359430833e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].x, -2.1027113600492346e-06, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].y, 0.000319689743723507, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].z, -3.0470796271690045e-05, doublethreshold); - - EXPECT_NEAR(mdrun->vel[0].x, -8.2630969616448438e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].y, 0.0001366029202159129, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].z, -0.00011334362366793093, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].x, 5.9181121902101574e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].y, 4.0359589497484719e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].z, 6.0216019900454962e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].x, -5.9703272809828887e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].y, 0.00015656497429546092, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].z, -5.8392323248176516e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].x, -4.1390907965075468e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].y, 0.00012448732653877297, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].z, 0.00011355087370269158, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).x, 0.00012104549072633688, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).y, 2.6272991724490339e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).z, 0.0002984728051383459, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).x, 0.00066077703137157329, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).y, 0.00017245549939737259, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).z, -0.00015046260270490386, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).x, -0.00046755850510571406, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).y, 0.00030490494761200812, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).z, -0.00036886672854369307, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).x, 0.00029624371924650601, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).y, 0.00013444493932002199, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).z, 9.0496812405138627e-05, doublethreshold); + + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.x, -2.3049731761587064e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.y, 7.1603385162874621e-06, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.z, 0.00016262437779022168, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.x, 0.0001961773016510733, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.y, 5.8637246942200678e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.z, 4.259822700946159e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.x, -0.00015692223255483009, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.y, 6.7034146380577021e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.z, -0.00017994277784966602, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.x, -3.5963807276704002e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.y, -8.5508938351509974e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.z, 9.6048301397465443e-05, doublethreshold); } TEST_F(Langevin_test, write_restart) @@ -146,38 +173,32 @@ TEST_F(Langevin_test, print_md) std::ifstream ifs("running_langevin.log"); std::string output_str; getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr(" ELECTRONIC PART OF STRESS: 0.24609992")); + EXPECT_THAT(output_str, testing::HasSubstr(" ELECTRONIC PART OF STRESS: 0.24609992 kbar")); getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr(" IONIC (KINETIC) PART OF STRESS: 0.838539188441")); + EXPECT_THAT(output_str, testing::HasSubstr(" IONIC (KINETIC) PART OF STRESS: 0.83853919 kbar")); getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr(" MD PRESSURE (ELECTRONS+IONS) : 1.0846391")); + EXPECT_THAT(output_str, testing::HasSubstr(" MD PRESSURE (ELECTRONS+IONS) : 1.0846391 kbar")); getline(ifs, output_str); getline(ifs, output_str); EXPECT_THAT( output_str, testing::HasSubstr( - " ----------------------------------------")); + " ------------------------------------------------------------------------------------------------")); getline(ifs, output_str); EXPECT_THAT( output_str, testing::HasSubstr( - " Energy (Ry) Potential (Ry) Kinetic (Ry) ")); - getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr("-0.0153652356062")); - EXPECT_THAT(output_str, testing::HasSubstr("-0.0239156372471")); - EXPECT_THAT(output_str, testing::HasSubstr("0.00855040164087")); + " Energy (Ry) Potential (Ry) Kinetic (Ry) Temperature (K) Pressure (kbar) ")); getline(ifs, output_str); EXPECT_THAT( output_str, testing::HasSubstr( - " Temperature (K) Pressure (kbar) ")); - getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr("1.08464")); + " -0.015365236 -0.023915637 0.0085504016 300 1.0846391 ")); getline(ifs, output_str); EXPECT_THAT( output_str, testing::HasSubstr( - " ----------------------------------------")); + " ------------------------------------------------------------------------------------------------")); ifs.close(); remove("running_langevin.log"); } diff --git a/source/source_md/test/lj_pot_test.cpp b/source/source_md/test/lj_pot_test.cpp index 99cec432b56..f3e6ac88a3e 100644 --- a/source/source_md/test/lj_pot_test.cpp +++ b/source/source_md/test/lj_pot_test.cpp @@ -1,8 +1,8 @@ #include "gtest/gtest.h" #define private public -#include "source_io/module_parameter/parameter.h" -#include "md_test_fixture.h" +#include "setcell.h" #include "source_esolver/esolver_lj.h" +#include "source_io/module_parameter/parameter.h" #include "source_md/md_func.h" #undef private #define doublethreshold 1e-12 @@ -17,56 +17,138 @@ * - calculate energy, force, virial for lj pot */ -class LJ_pot_test : public LjPotTestFixture +class LJ_pot_test : public testing::Test { + protected: + ModuleBase::matrix stress; + double potential; + int natom; + UnitCell ucell; + Parameter param; + + void SetUp() + { + Setcell::setupcell(ucell); + + natom = ucell.nat; + stress.create(3, 3); + + Setcell::parameters(param.input); + } + + void TearDown() + { + } }; TEST_F(LJ_pot_test, potential) { - std::unique_ptr p_esolver(new ModuleESolver::ESolver_LJ()); - p_esolver->before_all_runners(ucell, input); - MD_func::force_virial(p_esolver.get(), 0, ucell, potential, force, true, stress); + ModuleESolver::ESolver* p_esolver = new ModuleESolver::ESolver_LJ(); + MDCell mdcell = Setcell::setup_mdcell(ucell, param); + p_esolver->before_all_runners(mdcell, param.inp); + MD_func::force_virial(p_esolver, 0, mdcell, potential, true, stress, false); EXPECT_NEAR(potential, -0.011957818623534381, doublethreshold); } +TEST_F(LJ_pot_test, unitcell_compatibility) +{ + ModuleESolver::ESolver* p_esolver = new ModuleESolver::ESolver_LJ(); + p_esolver->before_all_runners(ucell, param.inp); + p_esolver->runner(ucell, 0); + p_esolver->cal_force(ucell, stress); + + EXPECT_NEAR(p_esolver->cal_energy(), -0.023915637247068761, doublethreshold); + EXPECT_NEAR(stress(0, 0), 0.00099635466178755387, doublethreshold); + + delete p_esolver; +} + TEST_F(LJ_pot_test, force) { - std::unique_ptr p_esolver(new ModuleESolver::ESolver_LJ()); - p_esolver->before_all_runners(ucell, input); - MD_func::force_virial(p_esolver.get(), 0, ucell, potential, force, true, stress); - EXPECT_NEAR(force[0].x, 0.00049817733089377704, doublethreshold); - EXPECT_NEAR(force[0].y, 0.00082237246837022328, doublethreshold); - EXPECT_NEAR(force[0].z, -3.0493186101154812e-20, doublethreshold); - EXPECT_NEAR(force[1].x, -0.00064758615201580339, doublethreshold); - EXPECT_NEAR(force[1].y, -0.00066924999462089304, doublethreshold); - EXPECT_NEAR(force[1].z, -1.8634724839594607e-20, doublethreshold); - EXPECT_NEAR(force[2].x, -0.00035411224839165616, doublethreshold); - EXPECT_NEAR(force[2].y, 0.0008091080910885112, doublethreshold); - EXPECT_NEAR(force[2].z, -1.1858461261560205e-20, doublethreshold); - EXPECT_NEAR(force[3].x, 0.00050352106951368229, doublethreshold); - EXPECT_NEAR(force[3].y, -0.00096223056483784122, doublethreshold); - EXPECT_NEAR(force[3].z, 2.0328790734103208e-20, doublethreshold); + ModuleESolver::ESolver* p_esolver = new ModuleESolver::ESolver_LJ(); + MDCell mdcell = Setcell::setup_mdcell(ucell, param); + p_esolver->before_all_runners(mdcell, param.inp); + MD_func::force_virial(p_esolver, 0, mdcell, potential, true, stress, false); + const std::vector& atoms = mdcell.owned_atoms(); + EXPECT_NEAR(atoms[0].force.x, 0.00049817733089377704, doublethreshold); + EXPECT_NEAR(atoms[0].force.y, 0.00082237246837022328, doublethreshold); + EXPECT_NEAR(atoms[0].force.z, 0.0, doublethreshold); + EXPECT_NEAR(atoms[1].force.x, -0.00064758615201580339, doublethreshold); + EXPECT_NEAR(atoms[1].force.y, -0.00066924999462089304, doublethreshold); + EXPECT_NEAR(atoms[1].force.z, 0.0, doublethreshold); + EXPECT_NEAR(atoms[2].force.x, -0.00035411224839165616, doublethreshold); + EXPECT_NEAR(atoms[2].force.y, 0.0008091080910885112, doublethreshold); + EXPECT_NEAR(atoms[2].force.z, 0.0, doublethreshold); + EXPECT_NEAR(atoms[3].force.x, 0.00050352106951368229, doublethreshold); + EXPECT_NEAR(atoms[3].force.y, -0.00096223056483784122, doublethreshold); + EXPECT_NEAR(atoms[3].force.z, 0.0, doublethreshold); +} + +TEST_F(LJ_pot_test, mdcell_cal_force) +{ + ModuleESolver::ESolver_LJ p_esolver; + MDCell mdcell = Setcell::setup_mdcell(ucell, param); + p_esolver.before_all_runners(mdcell, param.inp); + p_esolver.runner(mdcell, 0); + + ModuleBase::matrix force; + p_esolver.cal_force(mdcell, force); + for (int iat = 0; iat < mdcell.nlocal(); ++iat) + { + const LocalAtom& atom = mdcell.owned_atoms()[static_cast(iat)]; + EXPECT_DOUBLE_EQ(force(iat, 0), atom.force.x); + EXPECT_DOUBLE_EQ(force(iat, 1), atom.force.y); + EXPECT_DOUBLE_EQ(force(iat, 2), atom.force.z); + } } TEST_F(LJ_pot_test, stress) { - std::unique_ptr p_esolver(new ModuleESolver::ESolver_LJ()); - p_esolver->before_all_runners(ucell, input); - MD_func::force_virial(p_esolver.get(), 0, ucell, potential, force, true, stress); + ModuleESolver::ESolver* p_esolver = new ModuleESolver::ESolver_LJ(); + MDCell mdcell = Setcell::setup_mdcell(ucell, param); + p_esolver->before_all_runners(mdcell, param.inp); + MD_func::force_virial(p_esolver, 0, mdcell, potential, true, stress, false); EXPECT_NEAR(stress(0, 0), 8.0360222227631859e-07, doublethreshold); EXPECT_NEAR(stress(0, 1), 1.7207745586539077e-07, doublethreshold); - EXPECT_NEAR(stress(0, 2), 0, doublethreshold); + EXPECT_NEAR(stress(0, 2), 0.0, doublethreshold); EXPECT_NEAR(stress(1, 0), 1.7207745586539077e-07, doublethreshold); EXPECT_NEAR(stress(1, 1), 1.0630708613186662e-06, doublethreshold); - EXPECT_NEAR(stress(1, 2), -1.1858461261560206e-22, doublethreshold); - EXPECT_NEAR(stress(2, 0), 0, doublethreshold); - EXPECT_NEAR(stress(2, 1), -1.1858461261560206e-22, doublethreshold); + EXPECT_NEAR(stress(1, 2), 0.0, doublethreshold); + EXPECT_NEAR(stress(2, 0), 0.0, doublethreshold); + EXPECT_NEAR(stress(2, 1), 0.0, doublethreshold); EXPECT_NEAR(stress(2, 2), 6.4275429572682057e-07, doublethreshold); } +TEST_F(LJ_pot_test, mdcell_stress_includes_external_pressure) +{ + ModuleESolver::ESolver_LJ p_esolver; + MDCell mdcell = Setcell::setup_mdcell(ucell, param); + p_esolver.before_all_runners(mdcell, param.inp); + p_esolver.runner(mdcell, 0); + + Input_para& global_input = const_cast(PARAM.inp); + const double saved_press1 = global_input.press1; + const double saved_press2 = global_input.press2; + const double saved_press3 = global_input.press3; + global_input.press1 = 1.0; + global_input.press2 = 2.0; + global_input.press3 = 3.0; + + p_esolver.cal_stress(mdcell, stress); + + const double unit_transform = ModuleBase::RYDBERG_SI / pow(ModuleBase::BOHR_RADIUS_SI, 3) * 1.0e-8; + EXPECT_NEAR(stress(0, 0), p_esolver.lj_virial(0, 0) - 1.0 / unit_transform, doublethreshold); + EXPECT_NEAR(stress(1, 1), p_esolver.lj_virial(1, 1) - 2.0 / unit_transform, doublethreshold); + EXPECT_NEAR(stress(2, 2), p_esolver.lj_virial(2, 2) - 3.0 / unit_transform, doublethreshold); + + global_input.press1 = saved_press1; + global_input.press2 = saved_press2; + global_input.press3 = saved_press3; +} + TEST_F(LJ_pot_test, RcutSearchRadius) { - std::unique_ptr p_esolver(new ModuleESolver::ESolver_LJ()); + ModuleESolver::ESolver_LJ* p_esolver = new ModuleESolver::ESolver_LJ(); ucell.ntype = 2; std::vector rcut = {3.0}; p_esolver->rcut_search_radius(ucell.ntype, rcut); @@ -91,7 +173,7 @@ TEST_F(LJ_pot_test, RcutSearchRadius) TEST_F(LJ_pot_test, SetC6C12) { - std::unique_ptr p_esolver(new ModuleESolver::ESolver_LJ()); + ModuleESolver::ESolver_LJ* p_esolver = new ModuleESolver::ESolver_LJ(); ucell.ntype = 2; // no rule @@ -164,7 +246,7 @@ TEST_F(LJ_pot_test, SetC6C12) TEST_F(LJ_pot_test, CalEnShift) { - std::unique_ptr p_esolver(new ModuleESolver::ESolver_LJ()); + ModuleESolver::ESolver_LJ* p_esolver = new ModuleESolver::ESolver_LJ(); ucell.ntype = 2; std::vector rcut = {3.0}; diff --git a/source/source_md/test/md_func_test.cpp b/source/source_md/test/md_func_test.cpp index a9bae026fa8..2ae1b4b848b 100644 --- a/source/source_md/test/md_func_test.cpp +++ b/source/source_md/test/md_func_test.cpp @@ -395,6 +395,34 @@ TEST_F(MD_func_test, current_md_info) remove("Restart_md.txt"); } +TEST_F(MD_func_test, current_md_info_mdcell_accepts_step_only_restart) +{ + std::ofstream file("Restart_md.txt"); + file << 123; + file.close(); + + MDCell mdcell(ucell, 0.0, 0.0, ModuleBase::world_communication_domain()); + int istep = -1; + double temperature = 0.0; + MD_func::current_md_info(mdcell, "./", istep, temperature); + + EXPECT_EQ(istep, 123); + EXPECT_DOUBLE_EQ(temperature, 0.0); + remove("Restart_md.txt"); +} + +TEST_F(MD_func_test, global_dof_mdcell) +{ + MDCell mdcell(ucell, 0.0, 0.0, ModuleBase::world_communication_domain()); + EXPECT_EQ(MD_func::global_dof(mdcell), 9); + + for (LocalAtom& atom : mdcell.mutable_owned_atoms()) + { + atom.mbl.x = 0; + } + EXPECT_EQ(MD_func::global_dof(mdcell), 6); +} + TEST_F(MD_func_test, current_step_warning) { // Call the function and check that it outputs a warning and quits diff --git a/source/source_md/test/msst_test.cpp b/source/source_md/test/msst_test.cpp index cb68ff3d401..909df37e25c 100644 --- a/source/source_md/test/msst_test.cpp +++ b/source/source_md/test/msst_test.cpp @@ -5,8 +5,9 @@ #undef private #define private public #define protected public +#include "setcell.h" +#include "source_esolver/esolver_lj.h" #include "source_md/msst.h" -#include "md_test_fixture.h" #define doublethreshold 1e-12 /************************************************ @@ -34,24 +35,50 @@ * - output MD information such as energy, temperature, and pressure */ -class MSST_test : public MdIntegratorFixture +class MSST_test : public testing::Test { + protected: + MD_base* mdrun; + UnitCell ucell; + MDCell* mdcell; + Parameter param_in; + ModuleESolver::ESolver* p_esolver; + + void SetUp() + { + Setcell::setupcell(ucell); + Setcell::parameters(param_in.input); + + p_esolver = new ModuleESolver::ESolver_LJ(); + mdcell = new MDCell(ucell, 8.5 * ModuleBase::ANGSTROM_AU, 0.0, + ModuleBase::world_communication_domain()); + p_esolver->before_all_runners(*mdcell, param_in.inp); + mdrun = new MSST(param_in, *mdcell); + mdrun->setup(p_esolver, PARAM.sys.global_readin_dir); + } + + void TearDown() + { + delete mdrun; + delete mdcell; + delete p_esolver; + } }; TEST_F(MSST_test, setup) { - EXPECT_NEAR(mdrun->vel[0].x, -0.0001314186733659715, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].y, 7.0985331994796372e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].z, -1.3947731701005279e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].x, 0.00015227275651566311, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].y, -0.00014579875939315496, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].z, 9.5965690649087203e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].x, -0.00013311885204189453, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].y, -3.0298400368294885e-06, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].z, -5.3828659173134662e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].x, 0.00011226476889319793, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].y, 7.7843267435287586e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].z, -2.8189299775046767e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.x, -0.0001314186733659715, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.y, 7.0985331994796372e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.z, -1.3947731701005279e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.x, 0.00015227275651566311, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.y, -0.00014579875939315496, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.z, 9.5965690649087203e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.x, -0.00013311885204189453, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.y, -3.0298400368294885e-06, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.z, -5.3828659173134662e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.x, 0.00011226476889319793, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.y, 7.7843267435287586e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.z, -2.8189299775046767e-05, doublethreshold); EXPECT_NEAR(mdrun->stress(0, 0), 5.9579909955800075e-06, doublethreshold); EXPECT_NEAR(mdrun->stress(0, 1), -1.4582038138067117e-06, doublethreshold); @@ -81,31 +108,31 @@ TEST_F(MSST_test, first_half) EXPECT_NEAR(ucell.latvec.e33, 9.9959581179144905, doublethreshold); EXPECT_NEAR(ucell.omega, 999.59581179144902, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].x, -0.00054271823071484467, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].y, 0.00029442816868202821, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].z, -5.7685149290774873e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].x, 0.00062875654254500096, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].y, -0.00060353746208327032, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].z, 0.0003968957326219519, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].x, -0.00055074716824834991, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].y, -1.1576283073263842e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].z, -0.00022262503373940808, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].x, 0.00046470885642230719, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].y, 0.00032068557647491725, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].z, -0.00011658554959218052, doublethreshold); - - EXPECT_NEAR(mdrun->vel[0].x, -0.00013127726219846624, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].y, 7.121876825065284e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].z, -1.3947730561390963e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].x, 0.0001520889345949577, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].y, -0.00014598873074918282, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].z, 9.596568280810794e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].x, -0.00013321936931429457, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].y, -2.8001689685103039e-06, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].z, -5.3828654775006574e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].x, 0.00011240769691879813, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].y, 7.7570131467139791e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].z, -2.8189297471809918e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).x, -0.00054271823071484467, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).y, 0.00029442816868202821, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).z, -5.7685149290774873e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).x, 0.00062875654254500096, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).y, -0.00060353746208327032, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).z, 0.0003968957326219519, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).x, -0.00055074716824834991, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).y, -1.1576283073263842e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).z, -0.00022262503373940808, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).x, 0.00046470885642230719, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).y, 0.00032068557647491725, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).z, -0.00011658554959218052, doublethreshold); + + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.x, -0.00013127726219846624, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.y, 7.121876825065284e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.z, -1.3947730561390963e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.x, 0.0001520889345949577, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.y, -0.00014598873074918282, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.z, 9.596568280810794e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.x, -0.00013321936931429457, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.y, -2.8001689685103039e-06, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.z, -5.3828654775006574e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.x, 0.00011240769691879813, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.y, 7.7570131467139791e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.z, -2.8189297471809918e-05, doublethreshold); } TEST_F(MSST_test, second_half) @@ -127,31 +154,31 @@ TEST_F(MSST_test, second_half) EXPECT_NEAR(ucell.latvec.e33, 9.9959581179144905, doublethreshold); EXPECT_NEAR(ucell.omega, 999.59581179144902, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].x, -0.00054271823071484467, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].y, 0.00029442816868202821, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].z, -5.7685149290774873e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].x, 0.00062875654254500096, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].y, -0.00060353746208327032, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].z, 0.0003968957326219519, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].x, -0.00055074716824834991, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].y, -1.1576283073263842e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].z, -0.00022262503373940808, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].x, 0.00046470885642230719, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].y, 0.00032068557647491725, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].z, -0.00011658554959218052, doublethreshold); - - EXPECT_NEAR(mdrun->vel[0].x, -0.00013113585103096098, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].y, 7.1452204506509308e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].z, -1.3953371489538059e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].x, 0.00015190511267425228, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].y, -0.00014617870210521068, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].z, 9.600449453585996e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].x, -0.00013331988658669462, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].y, -2.5704979001911192e-06, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].z, -5.3850424881082548e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].x, 0.00011255062494439833, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].y, 7.7296995498991997e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].z, -2.8200698165338931e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).x, -0.00054271823071484467, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).y, 0.00029442816868202821, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).z, -5.7685149290774873e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).x, 0.00062875654254500096, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).y, -0.00060353746208327032, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).z, 0.0003968957326219519, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).x, -0.00055074716824834991, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).y, -1.1576283073263842e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).z, -0.00022262503373940808, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).x, 0.00046470885642230719, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).y, 0.00032068557647491725, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).z, -0.00011658554959218052, doublethreshold); + + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.x, -0.00013113585103096098, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.y, 7.1452204506509308e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.z, -1.3953371489538059e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.x, 0.00015190511267425228, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.y, -0.00014617870210521068, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.z, 9.600449453585996e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.x, -0.00013331988658669462, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.y, -2.5704979001911192e-06, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.z, -5.3850424881082548e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.x, 0.00011255062494439833, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.y, 7.7296995498991997e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.z, -2.8200698165338931e-05, doublethreshold); } TEST_F(MSST_test, write_restart) @@ -184,7 +211,7 @@ TEST_F(MSST_test, restart) mdrun->restart(PARAM.sys.global_readin_dir); remove("Restart_md.txt"); - MSST* msst = dynamic_cast(mdrun.get()); + MSST* msst = dynamic_cast(mdrun); EXPECT_EQ(mdrun->step_rst_, 3); EXPECT_EQ(msst->omega[mdrun->mdp.msst_direction], -0.00977662); EXPECT_EQ(msst->e0, -0.00768262); @@ -202,38 +229,36 @@ TEST_F(MSST_test, print_md) std::ifstream ifs("running_msst.log"); std::string output_str; getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr(" ELECTRONIC PART OF STRESS: 0.24609992")); + EXPECT_THAT(output_str, testing::HasSubstr(" ELECTRONIC PART OF STRESS: 0.24609992 kbar")); + getline(ifs, output_str); + EXPECT_THAT(output_str, + testing::HasSubstr( + " IONIC (KINETIC) PART OF STRESS: 0.8301538 kbar")); // result different from other MD methods getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr(" IONIC (KINETIC) PART OF STRESS: 0.830153796556")); // result different from other MD methods + EXPECT_THAT(output_str, + testing::HasSubstr( + " MD PRESSURE (ELECTRONS+IONS) : 1.0762537 kbar")); // result different from other MD methods getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr(" MD PRESSURE (ELECTRONS+IONS) : 1.0762537")); // result different from other MD methods - getline(ifs, output_str); getline(ifs, output_str); EXPECT_THAT( output_str, testing::HasSubstr( - " ----------------------------------------")); + " ------------------------------------------------------------------------------------------------")); getline(ifs, output_str); EXPECT_THAT( output_str, testing::HasSubstr( - " Energy (Ry) Potential (Ry) Kinetic (Ry) ")); - getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr("-0.0154507396226")); - EXPECT_THAT(output_str, testing::HasSubstr("-0.0239156372471")); - EXPECT_THAT(output_str, testing::HasSubstr("0.00846489762446")); + " Energy (Ry) Potential (Ry) Kinetic (Ry) Temperature (K) Pressure (kbar) ")); getline(ifs, output_str); EXPECT_THAT( output_str, testing::HasSubstr( - " Temperature (K) Pressure (kbar) ")); - getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr("1.07625")); + " -0.01545074 -0.023915637 0.0084648976 297 1.0762537 ")); getline(ifs, output_str); EXPECT_THAT( output_str, testing::HasSubstr( - " ----------------------------------------")); + " ------------------------------------------------------------------------------------------------")); ifs.close(); -// remove("running_msst.log"); + // remove("running_msst.log"); } diff --git a/source/source_md/test/nhchain_test.cpp b/source/source_md/test/nhchain_test.cpp index d6ea51a97c8..7293011d4b0 100644 --- a/source/source_md/test/nhchain_test.cpp +++ b/source/source_md/test/nhchain_test.cpp @@ -5,8 +5,9 @@ #undef private #define private public #define protected public +#include "setcell.h" +#include "source_esolver/esolver_lj.h" #include "source_md/nhchain.h" -#include "md_test_fixture.h" #define doublethreshold 1e-12 /************************************************ * unit test of functions in nhchain.h @@ -32,20 +33,37 @@ * - Nose_Hoover::print_md * - output MD information such as energy, temperature, and pressure */ -class NHC_test : public MdTestBase +class NHC_test : public testing::Test { protected: - std::unique_ptr mdrun; + MD_base* mdrun; + UnitCell ucell; + MDCell* mdcell; + Parameter param_in; + ModuleESolver::ESolver* p_esolver; - void SetUp() override + void SetUp() { - MdTestBase::SetUp(); + Setcell::setupcell(ucell); + Setcell::parameters(param_in.input); + + p_esolver = new ModuleESolver::ESolver_LJ(); param_in.input.mdp.md_type = "npt"; param_in.input.mdp.md_pmode = "tri"; param_in.input.mdp.md_pfirst = 1; param_in.input.mdp.md_plast = 1; - mdrun.reset(new Nose_Hoover(param_in, ucell)); - mdrun->setup(p_esolver.get(), PARAM.sys.global_readin_dir); + mdcell = new MDCell(ucell, 8.5 * ModuleBase::ANGSTROM_AU, 0.0, + ModuleBase::world_communication_domain()); + p_esolver->before_all_runners(*mdcell, param_in.inp); + mdrun = new Nose_Hoover(param_in, *mdcell); + mdrun->setup(p_esolver, PARAM.sys.global_readin_dir); + } + + void TearDown() + { + delete mdrun; + delete mdcell; + delete p_esolver; } }; @@ -67,31 +85,31 @@ TEST_F(NHC_test, first_half) { mdrun->first_half(GlobalV::ofs_running); - EXPECT_NEAR(mdrun->pos[0].x, -0.00035596392702161582, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].y, 0.00026566987683715606, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].z, -6.4082739615824722e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].x, 0.00037007414441809518, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].y, -0.00052501803299631633, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].z, 0.00044091358349508534, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].x, -0.00036876922955593201, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].y, -2.6151466573228018e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].z, -0.00024731533582713971, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].x, 0.00035465901216238645, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].y, 0.00028549962273273618, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].z, -0.00012951550805257814, doublethreshold); - - EXPECT_NEAR(mdrun->vel[0].x, -0.00010335325828338315, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].y, 6.6973537793984337e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].z, -1.4644123959592966e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].x, 0.00010943331752057692, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].y, -0.00013283409023334643, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].z, 0.00010075713383789103, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].x, -0.00010717693628353973, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].y, -6.2046899135633754e-06, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].z, -5.6516254714969195e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].x, 0.00010109687704718878, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].y, 7.2065242353013738e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].z, -2.9596755163433345e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).x, -0.00035596392702161582, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).y, 0.00026566987683715606, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).z, -6.4082739615824722e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).x, 0.00037007414441809518, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).y, -0.00052501803299631633, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).z, 0.00044091358349508534, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).x, -0.00036876922955593201, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).y, -2.6151466573228018e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).z, -0.00024731533582713971, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).x, 0.00035465901216238645, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).y, 0.00028549962273273618, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).z, -0.00012951550805257814, doublethreshold); + + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.x, -0.00010335325828338315, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.y, 6.6973537793984337e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.z, -1.4644123959592966e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.x, 0.00010943331752057692, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.y, -0.00013283409023334643, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.z, 0.00010075713383789103, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.x, -0.00010717693628353973, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.y, -6.2046899135633754e-06, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.z, -5.6516254714969195e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.x, 0.00010109687704718878, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.y, 7.2065242353013738e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.z, -2.9596755163433345e-05, doublethreshold); } TEST_F(NHC_test, second_half) @@ -99,38 +117,38 @@ TEST_F(NHC_test, second_half) mdrun->first_half(GlobalV::ofs_running); mdrun->second_half(); - EXPECT_NEAR(mdrun->pos[0].x, -0.00035596392702161582, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].y, 0.00026566987683715606, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].z, -6.4082739615824722e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].x, 0.00037007414441809518, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].y, -0.00052501803299631633, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].z, 0.00044091358349508534, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].x, -0.00036876922955593201, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].y, -2.6151466573228018e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].z, -0.00024731533582713971, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].x, 0.00035465901216238645, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].y, 0.00028549962273273618, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].z, -0.00012951550805257814, doublethreshold); - - EXPECT_NEAR(mdrun->vel[0].x, -8.4972683205367143e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].y, 6.6834262571392232e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].z, -1.6287026488367857e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].x, 7.8726485842843947e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].y, -0.00012727726730227848, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].z, 0.00011206092711573642, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].x, -9.0636235945876312e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].y, -9.9771188254262979e-06, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].z, -6.285672943672849e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].x, 9.6882433309157637e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].y, 7.0420123556394411e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].z, -3.2917171190756263e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).x, -0.00035596392702161582, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).y, 0.00026566987683715606, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).z, -6.4082739615824722e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).x, 0.00037007414441809518, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).y, -0.00052501803299631633, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).z, 0.00044091358349508534, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).x, -0.00036876922955593201, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).y, -2.6151466573228018e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).z, -0.00024731533582713971, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).x, 0.00035465901216238645, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).y, 0.00028549962273273618, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).z, -0.00012951550805257814, doublethreshold); + + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.x, -8.4972683205367143e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.y, 6.6834262571392232e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.z, -1.6287026488367857e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.x, 7.8726485842843947e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.y, -0.00012727726730227848, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.z, 0.00011206092711573642, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.x, -9.0636235945876312e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.y, -9.9771188254262979e-06, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.z, -6.285672943672849e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.x, 9.6882433309157637e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.y, 7.0420123556394411e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.z, -3.2917171190756263e-05, doublethreshold); } TEST_F(NHC_test, write_restart) { mdrun->first_half(GlobalV::ofs_running); mdrun->second_half(); - + mdrun->step_ = 1; mdrun->step_rst_ = 2; mdrun->write_restart(PARAM.sys.global_out_dir); @@ -164,7 +182,7 @@ TEST_F(NHC_test, restart) mdrun->restart(PARAM.sys.global_readin_dir); remove("Restart_md.txt"); - Nose_Hoover* nhc = dynamic_cast(mdrun.get()); + Nose_Hoover* nhc = dynamic_cast(mdrun); EXPECT_EQ(mdrun->step_rst_, 3); EXPECT_EQ(mdrun->mdp.md_tchain, 4); EXPECT_EQ(mdrun->mdp.md_pchain, 4); @@ -201,38 +219,32 @@ TEST_F(NHC_test, print_md) std::ifstream ifs("running_nhchain.log"); std::string output_str; getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr(" ELECTRONIC PART OF STRESS: 0.24609992")); + EXPECT_THAT(output_str, testing::HasSubstr(" ELECTRONIC PART OF STRESS: 0.24609992 kbar")); getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr(" IONIC (KINETIC) PART OF STRESS: 0.838539188441")); + EXPECT_THAT(output_str, testing::HasSubstr(" IONIC (KINETIC) PART OF STRESS: 0.83853919 kbar")); getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr(" MD PRESSURE (ELECTRONS+IONS) : 1.0846391")); + EXPECT_THAT(output_str, testing::HasSubstr(" MD PRESSURE (ELECTRONS+IONS) : 1.0846391 kbar")); getline(ifs, output_str); getline(ifs, output_str); EXPECT_THAT( output_str, testing::HasSubstr( - " ----------------------------------------")); + " ------------------------------------------------------------------------------------------------")); getline(ifs, output_str); EXPECT_THAT( output_str, testing::HasSubstr( - " Energy (Ry) Potential (Ry) Kinetic (Ry) ")); - getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr("-0.0153652356062")); - EXPECT_THAT(output_str, testing::HasSubstr("-0.0239156372471")); - EXPECT_THAT(output_str, testing::HasSubstr("0.00855040164087")); + " Energy (Ry) Potential (Ry) Kinetic (Ry) Temperature (K) Pressure (kbar) ")); getline(ifs, output_str); EXPECT_THAT( output_str, testing::HasSubstr( - " Temperature (K) Pressure (kbar) ")); - getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr("1.08464")); + " -0.015365236 -0.023915637 0.0085504016 300 1.0846391 ")); getline(ifs, output_str); EXPECT_THAT( output_str, testing::HasSubstr( - " ----------------------------------------")); + " ------------------------------------------------------------------------------------------------")); ifs.close(); - //remove("running_nhchain.log"); + // remove("running_nhchain.log"); } diff --git a/source/source_md/test/setcell.h b/source/source_md/test/setcell.h index 572e417ed77..118c8e948b9 100644 --- a/source/source_md/test/setcell.h +++ b/source/source_md/test/setcell.h @@ -6,9 +6,15 @@ #include "source_cell/module_neighbor/sltk_atom_arrange.h" #include "source_cell/module_neighbor/sltk_grid_driver.h" +#include "source_cell/md_cell.h" #include "source_cell/unitcell.h" +#include "source_base/constants.h" +#include "source_base/parallel_cell.h" #include "source_io/module_parameter/parameter.h" +#include +#include + Magnetism::Magnetism() { this->tot_mag = 0.0; @@ -104,6 +110,7 @@ class Setcell input.cal_stress = true; input.mdp.md_restart = false; + input.init_vel = true; input.mdp.md_dt = 1; input.mdp.md_tfirst = input.mdp.md_tlast = 300; @@ -128,6 +135,31 @@ class Setcell input.mdp.md_nraise = 2; input.mdp.md_tolerance = 0; }; + + static MDCell setup_mdcell(UnitCell& ucell, const Parameter& param) + { + double cutoff = 0.0; + for (std::size_t i = 0; i < param.inp.mdp.lj_rcut.size(); ++i) + { + cutoff = std::max(cutoff, param.inp.mdp.lj_rcut[i] * ModuleBase::ANGSTROM_AU); + } + return MDCell(ucell, cutoff, 0.0, ModuleBase::world_communication_domain()); + } + + static ModuleBase::Vector3 fractional_displacement(const LocalAtom& atom) + { + const ModuleBase::Vector3 initial_frac[] = { + ModuleBase::Vector3(0.0, 0.0, 0.0), + ModuleBase::Vector3(0.52, 0.52, 0.0), + ModuleBase::Vector3(0.51, 0.0, 0.5), + ModuleBase::Vector3(0.0, 0.53, 0.5) + }; + ModuleBase::Vector3 displacement = atom.frac - initial_frac[atom.type_index]; + displacement.x -= std::floor(displacement.x + 0.5); + displacement.y -= std::floor(displacement.y + 0.5); + displacement.z -= std::floor(displacement.z + 0.5); + return displacement; + } }; #endif diff --git a/source/source_md/test/verlet_test.cpp b/source/source_md/test/verlet_test.cpp index ab2b787cd9c..0d2e2aefbe9 100644 --- a/source/source_md/test/verlet_test.cpp +++ b/source/source_md/test/verlet_test.cpp @@ -5,12 +5,13 @@ #undef private #define private public #define protected public +#include "setcell.h" +#include "source_esolver/esolver_lj.h" #include "source_md/verlet.h" -#include "md_test_fixture.h" + #include #define doublethreshold 1e-12 - /************************************************ * unit test of functions in verlet.h ***********************************************/ @@ -36,8 +37,34 @@ * - output MD information such as energy, temperature, and pressure */ -class Verlet_test : public MdIntegratorFixture +class Verlet_test : public testing::Test { + protected: + MD_base* mdrun; + UnitCell ucell; + MDCell* mdcell; + Parameter param_in; + ModuleESolver::ESolver* p_esolver; + + void SetUp() + { + Setcell::setupcell(ucell); + Setcell::parameters(param_in.input); + + p_esolver = new ModuleESolver::ESolver_LJ(); + mdcell = new MDCell(ucell, 8.5 * ModuleBase::ANGSTROM_AU, 0.0, + ModuleBase::world_communication_domain()); + p_esolver->before_all_runners(*mdcell, param_in.inp); + mdrun = new Verlet(param_in, *mdcell); + mdrun->setup(p_esolver, PARAM.sys.global_readin_dir); + } + + void TearDown() + { + delete mdrun; + delete mdcell; + delete p_esolver; + } }; TEST_F(Verlet_test, setup) @@ -58,31 +85,31 @@ TEST_F(Verlet_test, first_half) { mdrun->first_half(GlobalV::ofs_running); - EXPECT_NEAR(mdrun->pos[0].x, -0.00054545529007222658, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].y, 0.00029590658162135359, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].z, -5.7952328034033513e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].x, 0.00063192793031220879, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].y, -0.00060657401578200095, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].z, 0.00039873402383468892, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].x, -0.00055351963726126224, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].y, -1.1639385612741475e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].z, -0.00022365616007718661, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].x, 0.00046704699702541431, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].y, 0.00032230681977380224, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].z, -0.00011712553572388214, doublethreshold); - - EXPECT_NEAR(mdrun->vel[0].x, -0.00013193932519649473, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].y, 7.1576379239356465e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].z, -1.40179977966e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].x, 0.00015285605661129458, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].y, -0.00014672323796402785, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].z, 9.6449148069800003e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].x, -0.00013388999749840003, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].y, -2.8154327428808153e-06, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].z, -5.4099838013700003e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].x, 0.0001129732660846002, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].y, 7.7962291467652202e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].z, -2.83313122596e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).x, -0.00054545529007222658, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).y, 0.00029590658162135359, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).z, -5.7952328034033513e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).x, 0.00063192793031220879, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).y, -0.00060657401578200095, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).z, 0.00039873402383468892, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).x, -0.00055351963726126224, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).y, -1.1639385612741475e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).z, -0.00022365616007718661, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).x, 0.00046704699702541431, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).y, 0.00032230681977380224, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).z, -0.00011712553572388214, doublethreshold); + + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.x, -0.00013193932519649473, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.y, 7.1576379239356465e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.z, -1.40179977966e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.x, 0.00015285605661129458, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.y, -0.00014672323796402785, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.z, 9.6449148069800003e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.x, -0.00013388999749840003, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.y, -2.8154327428808153e-06, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.z, -5.4099838013700003e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.x, 0.0001129732660846002, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.y, 7.7962291467652202e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.z, -2.83313122596e-05, doublethreshold); } TEST_F(Verlet_test, NVE) @@ -92,31 +119,31 @@ TEST_F(Verlet_test, NVE) mdrun->second_half(); ; - EXPECT_NEAR(mdrun->pos[0].x, -0.00054545529007222658, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].y, 0.00029590658162135359, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].z, -5.7952328034033513e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].x, 0.00063192793031220879, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].y, -0.00060657401578200095, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].z, 0.00039873402383468892, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].x, -0.00055351963726126224, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].y, -1.1639385612741475e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].z, -0.00022365616007718661, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].x, 0.00046704699702541431, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].y, 0.00032230681977380224, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].z, -0.00011712553572388214, doublethreshold); - - EXPECT_NEAR(mdrun->vel[0].x, -0.00013179791402898947, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].y, 7.1809815495212933e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].z, -1.40179977966e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].x, 0.00015267223469058917, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].y, -0.00014691320932005571, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].z, 9.6449148069800003e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].x, -0.00013399051477080008, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].y, -2.5857616745616307e-06, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].z, -5.4099838013700003e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].x, 0.0001131161941102004, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].y, 7.7689155499504408e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].z, -2.83313122596e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).x, -0.00054545529007222658, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).y, 0.00029590658162135359, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).z, -5.7952328034033513e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).x, 0.00063192793031220879, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).y, -0.00060657401578200095, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).z, 0.00039873402383468892, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).x, -0.00055351963726126224, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).y, -1.1639385612741475e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).z, -0.00022365616007718661, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).x, 0.00046704699702541431, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).y, 0.00032230681977380224, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).z, -0.00011712553572388214, doublethreshold); + + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.x, -0.00013179791402898947, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.y, 7.1809815495212933e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.z, -1.40179977966e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.x, 0.00015267223469058917, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.y, -0.00014691320932005571, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.z, 9.6449148069800003e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.x, -0.00013399051477080008, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.y, -2.5857616745616307e-06, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.z, -5.4099838013700003e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.x, 0.0001131161941102004, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.y, 7.7689155499504408e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.z, -2.83313122596e-05, doublethreshold); } TEST_F(Verlet_test, Anderson) @@ -127,31 +154,31 @@ TEST_F(Verlet_test, Anderson) mdrun->second_half(); ; - EXPECT_NEAR(mdrun->pos[0].x, -0.00054545529007222658, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].y, 0.00029590658162135359, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].z, -5.7952328034033513e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].x, 0.00063192793031220879, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].y, -0.00060657401578200095, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].z, 0.00039873402383468892, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].x, -0.00055351963726126224, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].y, -1.1639385612741475e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].z, -0.00022365616007718661, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].x, 0.00046704699702541431, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].y, 0.00032230681977380224, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].z, -0.00011712553572388214, doublethreshold); - - EXPECT_NEAR(mdrun->vel[0].x, -0.00013179791402898947, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].y, 7.1809815495212933e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].z, -1.40179977966e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].x, 6.9452562329904563e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].y, 7.321611395307015e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].z, -8.133446733603267e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].x, 0.00013239881096711222, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].y, 0.00030862680563211305, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].z, -0.00012925479702246553, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].x, 0.0001131161941102004, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].y, 7.7689155499504408e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].z, -2.83313122596e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).x, -0.00054545529007222658, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).y, 0.00029590658162135359, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).z, -5.7952328034033513e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).x, 0.00063192793031220879, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).y, -0.00060657401578200095, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).z, 0.00039873402383468892, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).x, -0.00055351963726126224, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).y, -1.1639385612741475e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).z, -0.00022365616007718661, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).x, 0.00046704699702541431, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).y, 0.00032230681977380224, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).z, -0.00011712553572388214, doublethreshold); + + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.x, -0.00013179791402898947, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.y, 7.1809815495212933e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.z, -1.40179977966e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.x, 6.9452562329904563e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.y, 7.321611395307015e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.z, -8.133446733603267e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.x, 0.00013239881096711222, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.y, 0.00030862680563211305, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.z, -0.00012925479702246553, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.x, 0.0001131161941102004, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.y, 7.7689155499504408e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.z, -2.83313122596e-05, doublethreshold); } TEST_F(Verlet_test, Berendsen) @@ -162,31 +189,31 @@ TEST_F(Verlet_test, Berendsen) mdrun->second_half(); ; - EXPECT_NEAR(mdrun->pos[0].x, -0.00054545529007222658, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].y, 0.00029590658162135359, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].z, -5.7952328034033513e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].x, 0.00063192793031220879, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].y, -0.00060657401578200095, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].z, 0.00039873402383468892, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].x, -0.00055351963726126224, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].y, -1.1639385612741475e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].z, -0.00022365616007718661, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].x, 0.00046704699702541431, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].y, 0.00032230681977380224, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].z, -0.00011712553572388214, doublethreshold); - - EXPECT_NEAR(mdrun->vel[0].x, -0.00013179175250738632, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].y, 7.1806458403162173e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].z, -1.4017342458487154e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].x, 0.00015266509729938552, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].y, -0.0001469063411619389, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].z, 9.6444639094723906e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].x, -0.00013398425074562592, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].y, -2.5856407908091386e-06, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].z, -5.4097308858947404e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].x, 0.00011311090595462667, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].y, 7.7685523549685863e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].z, -2.8329987777389342e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).x, -0.00054545529007222658, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).y, 0.00029590658162135359, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).z, -5.7952328034033513e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).x, 0.00063192793031220879, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).y, -0.00060657401578200095, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).z, 0.00039873402383468892, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).x, -0.00055351963726126224, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).y, -1.1639385612741475e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).z, -0.00022365616007718661, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).x, 0.00046704699702541431, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).y, 0.00032230681977380224, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).z, -0.00011712553572388214, doublethreshold); + + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.x, -0.00013179175250738632, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.y, 7.1806458403162173e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.z, -1.4017342458487154e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.x, 0.00015266509729938552, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.y, -0.0001469063411619389, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.z, 9.6444639094723906e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.x, -0.00013398425074562592, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.y, -2.5856407908091386e-06, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.z, -5.4097308858947404e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.x, 0.00011311090595462667, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.y, 7.7685523549685863e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.z, -2.8329987777389342e-05, doublethreshold); } TEST_F(Verlet_test, rescaling) @@ -197,31 +224,31 @@ TEST_F(Verlet_test, rescaling) mdrun->second_half(); ; - EXPECT_NEAR(mdrun->pos[0].x, -0.00054545529007222658, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].y, 0.00029590658162135359, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].z, -5.7952328034033513e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].x, 0.00063192793031220879, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].y, -0.00060657401578200095, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].z, 0.00039873402383468892, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].x, -0.00055351963726126224, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].y, -1.1639385612741475e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].z, -0.00022365616007718661, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].x, 0.00046704699702541431, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].y, 0.00032230681977380224, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].z, -0.00011712553572388214, doublethreshold); - - EXPECT_NEAR(mdrun->vel[0].x, -0.00013178559069770653, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].y, 7.1803101154153484e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].z, -1.4016687089734539e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].x, 0.00015265795957447931, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].y, -0.0001468994726827073, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].z, 9.6440129908834563e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].x, -0.00013397798642758268, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].y, -2.5855199014048311e-06, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].z, -5.4094779585946356e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].x, 0.0001131056175518098, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].y, 7.7681891430058639e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].z, -2.8328663233253657e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).x, -0.00054545529007222658, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).y, 0.00029590658162135359, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).z, -5.7952328034033513e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).x, 0.00063192793031220879, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).y, -0.00060657401578200095, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).z, 0.00039873402383468892, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).x, -0.00055351963726126224, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).y, -1.1639385612741475e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).z, -0.00022365616007718661, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).x, 0.00046704699702541431, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).y, 0.00032230681977380224, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).z, -0.00011712553572388214, doublethreshold); + + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.x, -0.00013178559069770653, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.y, 7.1803101154153484e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.z, -1.4016687089734539e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.x, 0.00015265795957447931, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.y, -0.0001468994726827073, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.z, 9.6440129908834563e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.x, -0.00013397798642758268, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.y, -2.5855199014048311e-06, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.z, -5.4094779585946356e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.x, 0.0001131056175518098, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.y, 7.7681891430058639e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.z, -2.8328663233253657e-05, doublethreshold); } TEST_F(Verlet_test, rescale_v) @@ -232,36 +259,37 @@ TEST_F(Verlet_test, rescale_v) mdrun->second_half(); ; - EXPECT_NEAR(mdrun->pos[0].x, -0.00054545529007222658, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].y, 0.00029590658162135359, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].z, -5.7952328034033513e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].x, 0.00063192793031220879, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].y, -0.00060657401578200095, doublethreshold); - EXPECT_NEAR(mdrun->pos[1].z, 0.00039873402383468892, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].x, -0.00055351963726126224, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].y, -1.1639385612741475e-05, doublethreshold); - EXPECT_NEAR(mdrun->pos[2].z, -0.00022365616007718661, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].x, 0.00046704699702541431, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].y, 0.00032230681977380224, doublethreshold); - EXPECT_NEAR(mdrun->pos[3].z, -0.00011712553572388214, doublethreshold); - - EXPECT_NEAR(mdrun->vel[0].x, -0.00013178559069770653, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].y, 7.1803101154153484e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[0].z, -1.4016687089734539e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].x, 0.00015265795957447931, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].y, -0.0001468994726827073, doublethreshold); - EXPECT_NEAR(mdrun->vel[1].z, 9.6440129908834563e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].x, -0.00013397798642758268, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].y, -2.5855199014048311e-06, doublethreshold); - EXPECT_NEAR(mdrun->vel[2].z, -5.4094779585946356e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].x, 0.0001131056175518098, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].y, 7.7681891430058639e-05, doublethreshold); - EXPECT_NEAR(mdrun->vel[3].z, -2.8328663233253657e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).x, -0.00054545529007222658, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).y, 0.00029590658162135359, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).z, -5.7952328034033513e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).x, 0.00063192793031220879, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).y, -0.00060657401578200095, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(1)]).z, 0.00039873402383468892, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).x, -0.00055351963726126224, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).y, -1.1639385612741475e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(2)]).z, -0.00022365616007718661, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).x, 0.00046704699702541431, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).y, 0.00032230681977380224, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(3)]).z, -0.00011712553572388214, doublethreshold); + + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.x, -0.00013178559069770653, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.y, 7.1803101154153484e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(0)].vel.z, -1.4016687089734539e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.x, 0.00015265795957447931, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.y, -0.0001468994726827073, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(1)].vel.z, 9.6440129908834563e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.x, -0.00013397798642758268, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.y, -2.5855199014048311e-06, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(2)].vel.z, -5.4094779585946356e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.x, 0.0001131056175518098, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.y, 7.7681891430058639e-05, doublethreshold); + EXPECT_NEAR(mdcell->owned_atoms()[static_cast(3)].vel.z, -2.8328663233253657e-05, doublethreshold); } TEST_F(Verlet_test, CSVR) { - mdrun->first_half(GlobalV::ofs_running); + std::ofstream ofs; + mdrun->first_half(ofs); param_in.input.mdp.md_type = "nvt"; param_in.input.mdp.md_thermostat = "csvr"; param_in.input.mdp.md_csvr_tau = 100.0; @@ -269,9 +297,9 @@ TEST_F(Verlet_test, CSVR) mdrun->second_half(); // Check that positions are updated correctly - EXPECT_NEAR(mdrun->pos[0].x, -0.00054545529007222658, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].y, 0.00029590658162135359, doublethreshold); - EXPECT_NEAR(mdrun->pos[0].z, -5.7952328034033513e-05, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).x, -0.00054545529007222658, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).y, 0.00029590658162135359, doublethreshold); + EXPECT_NEAR(Setcell::fractional_displacement(mdcell->owned_atoms()[static_cast(0)]).z, -5.7952328034033513e-05, doublethreshold); // Check that temperature is in reasonable range double temp = mdrun->t_current * ModuleBase::Hartree_to_K; @@ -309,38 +337,32 @@ TEST_F(Verlet_test, print_md) std::ifstream ifs("running_verlet.log"); std::string output_str; getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr(" ELECTRONIC PART OF STRESS: 0.24609992")); + EXPECT_THAT(output_str, testing::HasSubstr(" ELECTRONIC PART OF STRESS: 0.24609992 kbar")); getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr(" IONIC (KINETIC) PART OF STRESS: 0.838539188441")); + EXPECT_THAT(output_str, testing::HasSubstr(" IONIC (KINETIC) PART OF STRESS: 0.83853919 kbar")); getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr(" MD PRESSURE (ELECTRONS+IONS) : 1.0846391")); + EXPECT_THAT(output_str, testing::HasSubstr(" MD PRESSURE (ELECTRONS+IONS) : 1.0846391 kbar")); getline(ifs, output_str); getline(ifs, output_str); EXPECT_THAT( output_str, testing::HasSubstr( - " ----------------------------------------")); + " ------------------------------------------------------------------------------------------------")); getline(ifs, output_str); EXPECT_THAT( output_str, testing::HasSubstr( - " Energy (Ry) Potential (Ry) Kinetic (Ry) ")); - getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr("-0.0153652356062")); - EXPECT_THAT(output_str, testing::HasSubstr("-0.0239156372471")); - EXPECT_THAT(output_str, testing::HasSubstr("0.00855040164087")); + " Energy (Ry) Potential (Ry) Kinetic (Ry) Temperature (K) Pressure (kbar) ")); getline(ifs, output_str); EXPECT_THAT( output_str, testing::HasSubstr( - " Temperature (K) Pressure (kbar) ")); - getline(ifs, output_str); - EXPECT_THAT(output_str, testing::HasSubstr("1.08464")); + " -0.015365236 -0.023915637 0.0085504016 300 1.0846391 ")); getline(ifs, output_str); EXPECT_THAT( output_str, testing::HasSubstr( - " ----------------------------------------")); + " ------------------------------------------------------------------------------------------------")); ifs.close(); -// remove("running_verlet.log"); + // remove("running_verlet.log"); } diff --git a/source/source_md/verlet.cpp b/source/source_md/verlet.cpp index 2d22cdc1621..9d979fca81d 100644 --- a/source/source_md/verlet.cpp +++ b/source/source_md/verlet.cpp @@ -3,7 +3,11 @@ #include "md_func.h" #include "source_base/timer.h" -Verlet::Verlet(const Parameter& param_in, UnitCell& unit_in) : MD_base(param_in, unit_in) +#ifdef __MPI +#include +#endif + +Verlet::Verlet(const Parameter& param_in, MDCell& mdcell_in) : MD_base(param_in, mdcell_in) { } @@ -28,7 +32,7 @@ void Verlet::first_half(std::ofstream& ofs) ModuleBase::TITLE("Verlet", "first_half"); ModuleBase::timer::start("Verlet", "first_half"); - MD_base::update_vel(force); + MD_base::update_vel(); MD_base::update_pos(); ModuleBase::timer::end("Verlet", "first_half"); @@ -40,7 +44,7 @@ void Verlet::second_half() ModuleBase::TITLE("Verlet", "second_half"); ModuleBase::timer::start("Verlet", "second_half"); - MD_base::update_vel(force); + MD_base::update_vel(); apply_thermostat(); ModuleBase::timer::end("Verlet", "second_half"); @@ -50,7 +54,7 @@ void Verlet::second_half() void Verlet::apply_thermostat(void) { double t_target = 0.0; - t_current = MD_func::current_temp(kinetic, ucell.nat, frozen_freedom_, allmass, vel); + t_current = MD_func::current_temp(kinetic, mdcell, frozen_freedom_); if (mdp.md_type == "nve") { @@ -73,27 +77,20 @@ void Verlet::apply_thermostat(void) } else if (mdp.md_thermostat == "anderson") { - if (my_rank == 0) + for (LocalAtom& atom : mdcell.mutable_owned_atoms()) { - double deviation = 0.0; - for (int i = 0; i < ucell.nat; ++i) + if (static_cast(std::rand()) / RAND_MAX <= 1.0 / mdp.md_nraise) { - if (static_cast(std::rand()) / RAND_MAX <= 1.0 / mdp.md_nraise) + const double deviation = sqrt(md_tlast / atom.mass); + for (int k = 0; k < 3; ++k) { - deviation = sqrt(md_tlast / allmass[i]); - for (int k = 0; k < 3; ++k) + if (atom.mbl[k]) { - if (ionmbl[i][k]) - { - vel[i][k] = deviation * MD_func::gaussrand(); - } + atom.vel[k] = deviation * MD_func::gaussrand(); } } } } -#ifdef __MPI - MPI_Bcast(vel, ucell.nat * 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); -#endif } else if (mdp.md_thermostat == "berendsen") { @@ -124,12 +121,7 @@ void Verlet::thermalize(const int& nraise, const double& current_temp, const dou fac = sqrt(target_temp / current_temp); } - const int nat = ucell.nat; -#pragma omp parallel for schedule(static) if (nat >= 256) - for (int i = 0; i < nat; ++i) - { - vel[i] *= fac; - } + for (LocalAtom& atom : mdcell.mutable_owned_atoms()) atom.vel *= fac; } @@ -144,10 +136,10 @@ void Verlet::apply_csvr(const double& current_temp, const double& target_temp) } // Get degrees of freedom (3N - frozen) - int ndeg = 3 * ucell.nat - frozen_freedom_; + std::int64_t ndeg = MD_func::global_dof(mdcell); // Calculate kinetic energies - double kin_energy = current_temp * ndeg * 0.5; // in Hartree + double kin_energy = current_temp * static_cast(ndeg) * 0.5; // in Hartree double kin_target = target_temp * ndeg * 0.5; // in Hartree // Calculate tau parameter (characteristic time scale / dt) @@ -160,34 +152,46 @@ void Verlet::apply_csvr(const double& current_temp, const double& target_temp) factor = exp(-1.0 / taut); } - // Generate Gaussian random numbers using MD_func - double rr = MD_func::gaussrand(); - - // Calculate sum of squared Gaussian random numbers (ndeg - 1) - double sumnoises = 0.0; - for (int i = 0; i < ndeg - 1; ++i) + double scale = 1.0; +#ifdef __MPI + if (mdcell.mpi_size() > 1) + { + if (mdcell.mpi_rank() == 0) + { + const double rr = MD_func::gaussrand(); + double sumnoises = 0.0; + for (int i = 0; i < ndeg - 1; ++i) + { + const double random_value = MD_func::gaussrand(); + sumnoises += random_value * random_value; + } + const double factor2 = (1.0 - factor) * kin_target / kin_energy / ndeg; + const double resample = std::max(0.0, + factor + factor2 * (rr * rr + sumnoises) + + 2.0 * rr * sqrt(factor * factor2)); + scale = sqrt(resample); + } + MPI_Bcast(&scale, 1, MPI_DOUBLE, 0, mdcell.communicator()); + } + else +#endif { - double r = MD_func::gaussrand(); - sumnoises += r * r; + const double rr = MD_func::gaussrand(); + double sumnoises = 0.0; + for (int i = 0; i < ndeg - 1; ++i) + { + const double random_value = MD_func::gaussrand(); + sumnoises += random_value * random_value; + } + const double factor2 = (1.0 - factor) * kin_target / kin_energy / ndeg; + const double resample = std::max(0.0, + factor + factor2 * (rr * rr + sumnoises) + + 2.0 * rr * sqrt(factor * factor2)); + scale = sqrt(resample); } - // CSVR core formula (simplified) - double factor2 = (1.0 - factor) * kin_target / kin_energy / ndeg; - double resample = factor + factor2 * (rr * rr + sumnoises) + 2.0 * rr * sqrt(factor * factor2); - - // Ensure non-negative - resample = std::max(0.0, resample); - - // Calculate scaling factor - double scale = sqrt(resample); - // Apply velocity scaling - const int nat = ucell.nat; -#pragma omp parallel for schedule(static) if (nat >= 256) - for (int i = 0; i < nat; ++i) - { - vel[i] *= scale; - } + for (LocalAtom& atom : mdcell.mutable_owned_atoms()) atom.vel *= scale; } diff --git a/source/source_md/verlet.h b/source/source_md/verlet.h index 2e309cb57d2..d253eee4367 100644 --- a/source/source_md/verlet.h +++ b/source/source_md/verlet.h @@ -10,7 +10,7 @@ class Verlet : public MD_base { public: - Verlet(const Parameter& param_in, UnitCell& unit_in); + Verlet(const Parameter& param_in, MDCell& mdcell_in); ~Verlet(); private: diff --git a/tests/04_FF/01_LJ_Anderson/result.ref b/tests/04_FF/01_LJ_Anderson/result.ref index c85bb75c6ff..16a98ae73c7 100644 --- a/tests/04_FF/01_LJ_Anderson/result.ref +++ b/tests/04_FF/01_LJ_Anderson/result.ref @@ -1,5 +1,5 @@ -etotref -2.232421383009092 -etotperatomref -0.0697631682 -totalforceref 2.504346 -totalstressref 28.501927 -totaltimeref 0.03 +etotref -2.239520155656396 +etotperatomref -0.0699850049 +totalforceref 2.331355 +totalstressref 28.360820 +totaltimeref 0.02 diff --git a/tests/04_FF/04_LJ_Langevin/result.ref b/tests/04_FF/04_LJ_Langevin/result.ref index 6977a11110b..a8dca870f10 100644 --- a/tests/04_FF/04_LJ_Langevin/result.ref +++ b/tests/04_FF/04_LJ_Langevin/result.ref @@ -1,5 +1,5 @@ -etotref -2.238380961358246 -etotperatomref -0.0699494050 -totalforceref 2.316970 -totalstressref 28.313998 -totaltimeref 0.04 +etotref -2.24671151561839 +etotperatomref -0.0702097349 +totalforceref 2.191421 +totalstressref 28.146284 +totaltimeref 0.02