diff --git a/changes/user/enhancement.print-inter-region-center-xyz.md b/changes/user/enhancement.print-inter-region-center-xyz.md new file mode 100644 index 000000000..c459af857 --- /dev/null +++ b/changes/user/enhancement.print-inter-region-center-xyz.md @@ -0,0 +1 @@ +- Print the inner region center of hybrid type calculations (e.g. QM/MM) to a separate output file with the file ending .center.xyz diff --git a/docs/sphinx/src/featureList/featureList.rst b/docs/sphinx/src/featureList/featureList.rst index db118f25a..f5afdbeb5 100644 --- a/docs/sphinx/src/featureList/featureList.rst +++ b/docs/sphinx/src/featureList/featureList.rst @@ -18,7 +18,9 @@ The supported :ref:`jobtype ` values are: * ``mm-md`` - molecular-mechanics molecular dynamics * ``qm-md`` - quantum-mechanics molecular dynamics * ``qm-rpmd`` - quantum-mechanics ring-polymer molecular dynamics +* ``qmmm-md`` - hybrid quantum mechanics - molecular mechanics molecular dynamics * ``mm-opt`` - molecular-mechanics geometry optimization +* ``mm-hessian`` - molecular mechanics Hessian calculation ******************* Molecular Mechanics @@ -113,7 +115,6 @@ Planned Items The following items are planned for future releases: -* hybrid QM/MM job type * MM-RPMD * Verlet-list force evaluation * Ewald summation diff --git a/docs/sphinx/src/userGuide/inputFile.rst b/docs/sphinx/src/userGuide/inputFile.rst index e0f775c68..b9fc94f74 100644 --- a/docs/sphinx/src/userGuide/inputFile.rst +++ b/docs/sphinx/src/userGuide/inputFile.rst @@ -97,7 +97,7 @@ Possible options are: 3. **qm-rpmd** - Represents a full quantum mechanics ring polymer molecular dynamics simulation. For more information see the :ref:`ringpolymermdKeys` section - 4. **qmmm-md** - Represents a hybrid quantum mechanics - molecular mechanics molecular dynamics simulation. (Not implemented yet) + 4. **qmmm-md** - Represents a hybrid quantum mechanics - molecular mechanics molecular dynamics simulation. 5. **mm-opt** - represents a geometry optimization calculation using molecular mechanics. @@ -476,6 +476,24 @@ The ``traj_file`` keyword sets the name for the :ref:`trajectoryFile`, which sto .. centered:: *default value* = "default.xyz" +.. _hybridcenterfilekey: + +Hybrid Center File +================== + +.. admonition:: Key + :class: tip + + hybrid_center_file = {file} -> "default.center.xyz" + +The ``hybrid_center_file`` keyword sets the name for the :ref:`hybridCenterFile`, which stores the position of the inner region center in a hybrid type MD simulation. + +.. centered:: *default value* = "default.center.xyz" + +.. Note:: + + The ``hybrid_center_file`` keyword is ignored for non-hybrid-type calculations. + .. _velocityfilekey: Velocity File diff --git a/docs/sphinx/src/userGuide/outputFiles.rst b/docs/sphinx/src/userGuide/outputFiles.rst index babef568f..f26b23c40 100644 --- a/docs/sphinx/src/userGuide/outputFiles.rst +++ b/docs/sphinx/src/userGuide/outputFiles.rst @@ -143,6 +143,24 @@ Hessian Info File Stores metadata for a generated Hessian, including the matrix filename, Hessian builder, optimization flag, finite-difference displacement, sign convention, unit and matrix dimensions. The file starts with ``format = pq-hessian-info-v1`` so downstream tools can identify the metadata format. +.. _hybridCenterFile: + +****************** +Hybrid Center File +****************** + +**File Type:** ``.center.xyz`` + +Stores the coordinates (*x*, *y*, *z*) of the inner region center in ``.xyz`` file format: + + | **line 1:** 1 + | **line 2:** empty or "# step = step_number" + | **line 3:** X *x* *y* *z* + +There is one dummy atom used to denote the position of the inner region center. +The atom has the name ``X`` and its coordinates are denoted by *x* *y* *z* in Å. +The file is only written for :ref:`hybrid type calculations `. + .. _instantEnergyFile: ******************** diff --git a/include/config/defaults.hpp b/include/config/defaults.hpp index 542ef85aa..43db9003b 100644 --- a/include/config/defaults.hpp +++ b/include/config/defaults.hpp @@ -32,23 +32,24 @@ */ struct DefaultFiles { - static constexpr auto restartFile = "default.rst"; - static constexpr auto energyFile = "default.en"; - static constexpr auto instEnFile = "default.instant_en"; - static constexpr auto momentumFile = "default.mom"; - static constexpr auto trajFile = "default.xyz"; - static constexpr auto velFile = "default.vel"; - static constexpr auto forceFile = "default.force"; - static constexpr auto chargeFile = "default.charge"; - static constexpr auto logFile = "default.log"; - static constexpr auto stdoutFile = "default.stdout"; - static constexpr auto refFile = "default.ref"; - static constexpr auto infoFile = "default.info"; - static constexpr auto virialFile = "default.vir"; - static constexpr auto stressFile = "default.stress"; - static constexpr auto boxFile = "default.box"; - static constexpr auto optFile = "default.opt"; - static constexpr auto timingsFile = "default.timings"; + static constexpr auto restartFile = "default.rst"; + static constexpr auto energyFile = "default.en"; + static constexpr auto instEnFile = "default.instant_en"; + static constexpr auto momentumFile = "default.mom"; + static constexpr auto trajFile = "default.xyz"; + static constexpr auto hybridCenterFile = "default.center.xyz"; + static constexpr auto velFile = "default.vel"; + static constexpr auto forceFile = "default.force"; + static constexpr auto chargeFile = "default.charge"; + static constexpr auto logFile = "default.log"; + static constexpr auto stdoutFile = "default.stdout"; + static constexpr auto refFile = "default.ref"; + static constexpr auto infoFile = "default.info"; + static constexpr auto virialFile = "default.vir"; + static constexpr auto stressFile = "default.stress"; + static constexpr auto boxFile = "default.box"; + static constexpr auto optFile = "default.opt"; + static constexpr auto timingsFile = "default.timings"; static constexpr auto rpmdRstFile = "default.rpmd.rst"; static constexpr auto rpmdTrajFile = "default.rpmd.xyz"; @@ -83,6 +84,8 @@ namespace defaults static constexpr bool HESSIAN_OPTIMIZE_DEFAULT = true; static constexpr auto* HESSIAN_BUILDER_DEFAULT = "central"; + static constexpr char INNER_REGION_CENTER_ATOM_NAME = 'X'; + static constexpr double COULOMB_CUT_OFF_DEFAULT = 12.5; // in Angstrom static constexpr double SCALE_14_COULOMB_DEFAULT = 1.0; static constexpr double SCALE_14_VAN_DER_WAALS_DEFAULT = 1.0; diff --git a/include/engine/engineOutput.hpp b/include/engine/engineOutput.hpp index 144ecd6e9..eb7773a50 100644 --- a/include/engine/engineOutput.hpp +++ b/include/engine/engineOutput.hpp @@ -45,6 +45,11 @@ #include "trajectoryOutput.hpp" #include "virialOutput.hpp" +namespace configurator +{ + class HybridConfigurator; // forward declaration +} // namespace configurator + namespace engine { /** @@ -61,6 +66,7 @@ namespace engine std::unique_ptr _infoOutput; std::unique_ptr _xyzOutput; + std::unique_ptr _xyzHybridCenterOutput; std::unique_ptr _velOutput; std::unique_ptr _forceOutput; std::unique_ptr _chargeOutput; @@ -97,7 +103,12 @@ namespace engine const size_t step, const physicalData::PhysicalData & ); + void writeXyzFile(simulationBox::SimulationBox &, const size_t); + void writeHybridCenterXyzFile( + const configurator::HybridConfigurator &, + const size_t + ); void writeVelFile(simulationBox::SimulationBox &, const size_t); void writeForceFile(simulationBox::SimulationBox &, const size_t); void writeChargeFile(simulationBox::SimulationBox &, const size_t); @@ -154,6 +165,7 @@ namespace engine [[nodiscard]] output::EnergyOutput &getEnergyOutput(); [[nodiscard]] output::EnergyOutput &getInstantEnergyOutput(); [[nodiscard]] output::TrajectoryOutput &getXyzOutput(); + [[nodiscard]] output::TrajectoryOutput &getXyzHybridCenterOutput(); [[nodiscard]] output::TrajectoryOutput &getVelOutput(); [[nodiscard]] output::TrajectoryOutput &getForceOutput(); [[nodiscard]] output::TrajectoryOutput &getChargeOutput(); diff --git a/include/engine/hybridMDEngine.hpp b/include/engine/hybridMDEngine.hpp index c1a045fcd..94fd13d4b 100644 --- a/include/engine/hybridMDEngine.hpp +++ b/include/engine/hybridMDEngine.hpp @@ -24,7 +24,6 @@ #define _HYBRID_MD_ENGINE_HPP_ -#include "hybridConfigurator.hpp" #include "mdEngine.hpp" #include "qmCapableEngine.hpp" @@ -41,8 +40,6 @@ namespace engine class HybridMDEngine : virtual public MDEngine, public QMCapableEngine { protected: - configurator::HybridConfigurator _configurator{}; - void combineInnerOuterForces(); void addCurrentForcesToInnerAndReset( diff --git a/include/engine/mdEngine.hpp b/include/engine/mdEngine.hpp index a2a8d079c..7021c7cdd 100644 --- a/include/engine/mdEngine.hpp +++ b/include/engine/mdEngine.hpp @@ -49,7 +49,8 @@ namespace engine class MDEngine : public Engine { protected: - resetKinetics::ResetKinetics _resetKinetics; + resetKinetics::ResetKinetics _resetKinetics; + configurator::HybridConfigurator _configurator{}; std::unique_ptr _integrator; std::unique_ptr _thermostat; @@ -79,6 +80,7 @@ namespace engine [[nodiscard]] manostat::Manostat &getManostat(); [[nodiscard]] output::EnergyOutput &getInstantEnergyOutput(); [[nodiscard]] output::MomentumOutput &getMomentumOutput(); + [[nodiscard]] output::TrajectoryOutput &getXyzHybridCenterOutput(); [[nodiscard]] output::TrajectoryOutput &getVelOutput(); [[nodiscard]] output::TrajectoryOutput &getChargeOutput(); [[nodiscard]] output::VirialOutput &getVirialOutput(); diff --git a/include/input/inputFileParser/outputInputParser.hpp b/include/input/inputFileParser/outputInputParser.hpp index 1c2c999f9..4816ff770 100644 --- a/include/input/inputFileParser/outputInputParser.hpp +++ b/include/input/inputFileParser/outputInputParser.hpp @@ -76,6 +76,11 @@ namespace input const size_t ); + void parseHybridCenterFilename( + const std::vector &, + const size_t + ); + void parseVelocityFilename( const std::vector &, const size_t diff --git a/include/output/trajectoryOutput.hpp b/include/output/trajectoryOutput.hpp index 2861abaea..a16360403 100644 --- a/include/output/trajectoryOutput.hpp +++ b/include/output/trajectoryOutput.hpp @@ -26,6 +26,7 @@ #include // for size_t +#include "hybridConfigurator.hpp" #include "output.hpp" // for Output namespace simulationBox @@ -33,6 +34,11 @@ namespace simulationBox class SimulationBox; // forward declaration } // namespace simulationBox +namespace configurator +{ + class HybridConfigurator; // forward declaration +} // namespace configurator + namespace output { /** @@ -48,6 +54,10 @@ namespace output void writeHeader(const simulationBox::SimulationBox &); void writeXyz(simulationBox::SimulationBox &, const size_t); + void writeHybridCenterXyz( + const configurator::HybridConfigurator &configurator, + const size_t step + ); void writeVelocities(simulationBox::SimulationBox &, const size_t); void writeForces(simulationBox::SimulationBox &, const size_t); void writeCharges(simulationBox::SimulationBox &, const size_t); diff --git a/include/settings/outputFileSettings.hpp b/include/settings/outputFileSettings.hpp index 67a70986a..d2e40c8ce 100644 --- a/include/settings/outputFileSettings.hpp +++ b/include/settings/outputFileSettings.hpp @@ -48,17 +48,20 @@ namespace settings static inline bool _filePrefixSet = false; static inline std::string _filePrefix; - static inline std::string _energyFile = DefaultFiles::energyFile; - static inline std::string _instEnFile = DefaultFiles::instEnFile; - static inline std::string _rstFile = DefaultFiles::restartFile; - static inline std::string _momFile = DefaultFiles::momentumFile; - static inline std::string _trajFile = DefaultFiles::trajFile; - static inline std::string _velFile = DefaultFiles::velFile; - static inline std::string _forceFile = DefaultFiles::forceFile; - static inline std::string _chargeFile = DefaultFiles::chargeFile; - static inline std::string _logFile = DefaultFiles::logFile; - static inline std::string _refFile = DefaultFiles::refFile; - static inline std::string _infoFile = DefaultFiles::infoFile; + // clang-format off + static inline std::string _energyFile = DefaultFiles::energyFile; + static inline std::string _instEnFile = DefaultFiles::instEnFile; + static inline std::string _rstFile = DefaultFiles::restartFile; + static inline std::string _momFile = DefaultFiles::momentumFile; + static inline std::string _trajFile = DefaultFiles::trajFile; + static inline std::string _hybridCenterFile = DefaultFiles::hybridCenterFile; + static inline std::string _velFile = DefaultFiles::velFile; + static inline std::string _forceFile = DefaultFiles::forceFile; + static inline std::string _chargeFile = DefaultFiles::chargeFile; + static inline std::string _logFile = DefaultFiles::logFile; + static inline std::string _refFile = DefaultFiles::refFile; + static inline std::string _infoFile = DefaultFiles::infoFile; + // clang-format on static inline std::string _virialFile = DefaultFiles::virialFile; static inline std::string _stressFile = DefaultFiles::stressFile; @@ -96,6 +99,7 @@ namespace settings static void setInstantEnergyFileName(const std::string_view); static void setMomentumFileName(const std::string_view); static void setTrajectoryFileName(const std::string_view); + static void setHybridCenterFileName(const std::string_view); static void setVelocityFileName(const std::string_view); static void setForceFileName(const std::string_view); static void setChargeFileName(const std::string_view); @@ -135,6 +139,7 @@ namespace settings [[nodiscard]] static std::string getInstantEnergyFileName(); [[nodiscard]] static std::string getMomentumFileName(); [[nodiscard]] static std::string getTrajectoryFileName(); + [[nodiscard]] static std::string getHybridCenterFileName(); [[nodiscard]] static std::string getVelocityFileName(); [[nodiscard]] static std::string getForceFileName(); [[nodiscard]] static std::string getChargeFileName(); diff --git a/src/engine/engineOutput.cpp b/src/engine/engineOutput.cpp index d1603cd43..92f501699 100644 --- a/src/engine/engineOutput.cpp +++ b/src/engine/engineOutput.cpp @@ -27,6 +27,7 @@ #include "boxOutput.hpp" #include "defaults.hpp" #include "energyOutput.hpp" +#include "hybridConfigurator.hpp" #include "infoOutput.hpp" #include "logOutput.hpp" #include "momentumOutput.hpp" @@ -55,6 +56,7 @@ using namespace engine; using namespace simulationBox; using namespace physicalData; using namespace thermostat; +using namespace configurator; using output::BoxFileOutput; using output::EnergyOutput; @@ -81,6 +83,7 @@ EngineOutput::EngineOutput() _instantEnergyOutput(std::make_unique(DefaultFiles::instEnFile)), _infoOutput(std::make_unique(DefaultFiles::infoFile)), _xyzOutput(std::make_unique(DefaultFiles::trajFile)), + _xyzHybridCenterOutput(std::make_unique(DefaultFiles::hybridCenterFile)), _velOutput(std::make_unique(DefaultFiles::velFile)), _forceOutput(std::make_unique(DefaultFiles::forceFile)), _chargeOutput(std::make_unique(DefaultFiles::chargeFile)), @@ -161,6 +164,21 @@ void EngineOutput::writeXyzFile(SimulationBox &simulationBox, const size_t step) _xyzOutput->writeXyz(simulationBox, step); } +/** + * @brief wrapper for hybrid center xyz file output function + * + * @param configurator + * @param step + */ +void EngineOutput::writeHybridCenterXyzFile( + const HybridConfigurator &configurator, + const size_t step +) +{ + auto _ = scoped("TrajectoryOutput"); + _xyzHybridCenterOutput->writeHybridCenterXyz(configurator, step); +} + /** * @brief wrapper for velocity file output function * @@ -443,6 +461,16 @@ MomentumOutput &EngineOutput::getMomentumOutput() { return *_momentumOutput; } */ TrajectoryOutput &EngineOutput::getXyzOutput() { return *_xyzOutput; } +/** + * @brief getter for hybrid center xyz output + * + * @return TrajectoryOutput + */ +TrajectoryOutput &EngineOutput::getXyzHybridCenterOutput() +{ + return *_xyzHybridCenterOutput; +} + /** * @brief getter for velocity output * diff --git a/src/engine/mdEngine.cpp b/src/engine/mdEngine.cpp index 94d02185e..8c1cb2737 100644 --- a/src/engine/mdEngine.cpp +++ b/src/engine/mdEngine.cpp @@ -251,6 +251,9 @@ void MDEngine::writeOutput() ); // use physicalData instead of averagePhysicalData _engineOutput.writeBoxFile(effStep, _simulationBox->getBox()); + + if (Settings::isHybridJobtype()) + _engineOutput.writeHybridCenterXyzFile(_configurator, effStep); } // NOTE: @@ -335,6 +338,16 @@ output::MomentumOutput &MDEngine::getMomentumOutput() return _engineOutput.getMomentumOutput(); } +/** + * @brief get the reference to the xyz hybrid center output + * + * @return output::TrajectoryOutput& + */ +output::TrajectoryOutput &MDEngine::getXyzHybridCenterOutput() +{ + return _engineOutput.getXyzHybridCenterOutput(); +} + /** * @brief get the reference to the vel output * diff --git a/src/input/inputFileParser/outputInputParser.cpp b/src/input/inputFileParser/outputInputParser.cpp index f3bddaf59..02e33bc32 100644 --- a/src/input/inputFileParser/outputInputParser.cpp +++ b/src/input/inputFileParser/outputInputParser.cpp @@ -111,6 +111,11 @@ OutputInputParser::OutputInputParser(Engine &engine) : InputFileParser(engine) bindMember(&OutputInputParser::parseTrajectoryFilename, this), false ); + addKeyword( + std::string("hybrid_center_file"), + bindMember(&OutputInputParser::parseHybridCenterFilename, this), + false + ); addKeyword( std::string("vel_file"), bindMember(&OutputInputParser::parseVelocityFilename, this), @@ -343,6 +348,22 @@ void OutputInputParser::parseTrajectoryFilename( OutputFileSettings::setTrajectoryFileName(lineElements[2]); } +/** + * @brief parse hybrid center filename of simulation and add it to output + * + * @details default value is default.center.xyz + * + * @param lineElements + */ +void OutputInputParser::parseHybridCenterFilename( + const std::vector &lineElements, + const size_t lineNumber +) +{ + checkCommand(lineElements, lineNumber); + OutputFileSettings::setHybridCenterFileName(lineElements[2]); +} + /** * @brief parse velocity filename of simulation and add it to output * diff --git a/src/output/CMakeLists.txt b/src/output/CMakeLists.txt index d89ebfab3..8df81af75 100644 --- a/src/output/CMakeLists.txt +++ b/src/output/CMakeLists.txt @@ -32,6 +32,7 @@ target_include_directories(output target_link_libraries(output PUBLIC utilities + hybridConfigurator physicalData simulationBox optimization diff --git a/src/output/trajectoryOutput.cpp b/src/output/trajectoryOutput.cpp index 249930787..cfc6267ce 100644 --- a/src/output/trajectoryOutput.cpp +++ b/src/output/trajectoryOutput.cpp @@ -27,10 +27,14 @@ #include // for ofstream, basic_ostream, operator<< #include // for ostringstream +#include "defaults.hpp" +#include "hybridConfigurator.hpp" #include "molecule.hpp" // for Molecule #include "simulationBox.hpp" // for SimulationBox using namespace output; +using namespace defaults; +using namespace configurator; using namespace simulationBox; /** @@ -77,6 +81,39 @@ void TrajectoryOutput::writeXyz(SimulationBox &simBox, const size_t step) _fp << std::flush; } +/** + * @brief Write hybrid center xyz file + * + * @param simBox + * @param step + */ +void TrajectoryOutput::writeHybridCenterXyz( + const HybridConfigurator &configurator, + const size_t step +) +{ + // one dummy atom is needed to mark the inner region center + constexpr size_t numberOfCenterAtoms = 1; + constexpr char centerAtomName = INNER_REGION_CENTER_ATOM_NAME; + + // header line + _fp << numberOfCenterAtoms << '\n'; + writeComment(step); + + std::ostringstream buffer; + buffer << std::format("{:<5}\t", centerAtomName); + + const auto &pos = configurator.getInnerRegionCenter(); + + buffer << std::format("{:15.8f}\t", pos[0]); + buffer << std::format("{:15.8f}\t", pos[1]); + buffer << std::format("{:15.8f}\n", pos[2]); + + // Write the buffer to the file + _fp << buffer.str(); + _fp << std::flush; +} + /** * @brief Write velocities file * diff --git a/src/settings/outputFileSettings.cpp b/src/settings/outputFileSettings.cpp index 6c35c7a69..e2fbdfe3c 100644 --- a/src/settings/outputFileSettings.cpp +++ b/src/settings/outputFileSettings.cpp @@ -82,6 +82,9 @@ void OutputFileSettings::replaceDefaultValues(const std::string &prefix) if (DefaultFiles::trajFile == _trajFile) _trajFile = prefix + ".xyz"; + if (DefaultFiles::hybridCenterFile == _hybridCenterFile) + _hybridCenterFile = prefix + ".center.xyz"; + if (DefaultFiles::energyFile == _energyFile) _energyFile = prefix + ".en"; @@ -258,6 +261,16 @@ void OutputFileSettings::setTrajectoryFileName(const std::string_view name) _trajFile = name; } +/** + * @brief sets the hybrid center file name + * + * @param name + */ +void OutputFileSettings::setHybridCenterFileName(const std::string_view name) +{ + _hybridCenterFile = name; +} + /** * @brief sets the velocity file name * @@ -525,6 +538,16 @@ std::string OutputFileSettings::getMomentumFileName() { return _momFile; } */ std::string OutputFileSettings::getTrajectoryFileName() { return _trajFile; } +/** + * @brief get the hybrid center file name + * + * @return std::string + */ +std::string OutputFileSettings::getHybridCenterFileName() +{ + return _hybridCenterFile; +} + /** * @brief get the velocity file name * diff --git a/src/setup/outputFilesSetup.cpp b/src/setup/outputFilesSetup.cpp index c2281cc41..4d1239c08 100644 --- a/src/setup/outputFilesSetup.cpp +++ b/src/setup/outputFilesSetup.cpp @@ -114,6 +114,13 @@ void OutputFilesSetup::setup() mdEngine.getStressOutput().setFilename(stressFile); mdEngine.getBoxFileOutput().setFilename(boxFile); + if (Settings::isHybridJobtype()) + { + const auto hybridCenterFile = + OutputFileSettings::getHybridCenterFileName(); + mdEngine.getXyzHybridCenterOutput().setFilename(hybridCenterFile); + } + if (OutputFileSettings::getIncludeOutputMetadata()) { const auto timeStep = TimingsSettings::getTimeStep(); diff --git a/tests/data/inputFileReader/keywordList.txt b/tests/data/inputFileReader/keywordList.txt index 6bda432f5..f0fe6f589 100644 --- a/tests/data/inputFileReader/keywordList.txt +++ b/tests/data/inputFileReader/keywordList.txt @@ -91,6 +91,7 @@ info_file false energy_file false instant_energy_file false traj_file false +hybrid_center_file false vel_file false restart_file false charge_file false diff --git a/tests/src/input/inputFileParsing/testOutputParser.cpp b/tests/src/input/inputFileParsing/testOutputParser.cpp index ab2afff8b..f421cfa43 100644 --- a/tests/src/input/inputFileParsing/testOutputParser.cpp +++ b/tests/src/input/inputFileParsing/testOutputParser.cpp @@ -146,6 +146,23 @@ TEST_F(TestInputFileReader, testParseTrajectoryFilename) EXPECT_EQ(OutputFileSettings::getTrajectoryFileName(), _fileName); } +/** + * @brief tests parsing the "hybrid_center_file" command + * + */ +TEST_F(TestInputFileReader, testParseHybridCenterFilename) +{ + OutputInputParser parser(*_engine); + _fileName = "center.xyz"; + const std::vector lineElements = { + "hybrid_center_file", + "=", + _fileName + }; + parser.parseHybridCenterFilename(lineElements, 0); + EXPECT_EQ(OutputFileSettings::getHybridCenterFileName(), _fileName); +} + /** * @brief tests parsing the "velocity_file" command * diff --git a/tests/src/output/testTrajectoryOutput.cpp b/tests/src/output/testTrajectoryOutput.cpp index 9142ef611..90e8b41d4 100644 --- a/tests/src/output/testTrajectoryOutput.cpp +++ b/tests/src/output/testTrajectoryOutput.cpp @@ -26,6 +26,7 @@ #include // for getline, allocator, string #include "gtest/gtest.h" // for Message, TestPartResult +#include "hybridConfigurator.hpp" #include "outputFileSettings.hpp" /** @@ -71,6 +72,58 @@ TEST_F(TestTrajectoryOutput, writeXyzMetadata) EXPECT_EQ(line, "# step = 42"); } +/** + * @brief Test the writeHybridCenterXyz method + * + */ +TEST_F(TestTrajectoryOutput, writeHybridCenterXyz) +{ + configurator::HybridConfigurator hybridConfigurator; + + _simulationBox->getAtom(1).setMass(1.0); + _simulationBox->addInnerRegionCenterAtoms({1}); + hybridConfigurator.calculateInnerRegionCenter(*_simulationBox); + + _trajectoryOutput->setFilename("default.xyz"); + _trajectoryOutput->writeHybridCenterXyz(hybridConfigurator, 7); + _trajectoryOutput->close(); + + std::ifstream file("default.xyz"); + std::string line; + getline(file, line); + EXPECT_EQ(line, "1"); + getline(file, line); + EXPECT_EQ(line, ""); + getline(file, line); + EXPECT_EQ(line, "X \t 1.00000000\t 2.00000000\t 3.00000000"); +} + +/** + * @brief Test optional step metadata in the hybrid center xyz comment line + * + */ +TEST_F(TestTrajectoryOutput, writeHybridCenterXyzMetadata) +{ + settings::OutputFileSettings::setIncludeOutputMetadata(true); + + configurator::HybridConfigurator hybridConfigurator; + + _simulationBox->getAtom(1).setMass(1.0); + _simulationBox->addInnerRegionCenterAtoms({1}); + hybridConfigurator.calculateInnerRegionCenter(*_simulationBox); + + _trajectoryOutput->setFilename("default.xyz"); + _trajectoryOutput->writeHybridCenterXyz(hybridConfigurator, 42); + _trajectoryOutput->close(); + settings::OutputFileSettings::setIncludeOutputMetadata(false); + + std::ifstream file("default.xyz"); + std::string line; + getline(file, line); + getline(file, line); + EXPECT_EQ(line, "# step = 42"); +} + /** * @brief Test the writeVelocities method * diff --git a/tests/src/settings/testOutputFileSettings.cpp b/tests/src/settings/testOutputFileSettings.cpp index ad388580c..963c4a3c0 100644 --- a/tests/src/settings/testOutputFileSettings.cpp +++ b/tests/src/settings/testOutputFileSettings.cpp @@ -69,3 +69,25 @@ TEST(TestOutputSettings, determinesMostCommonConfiguredPrefix) EXPECT_TRUE(OutputFileSettings::getOverwriteOutputFiles()); EXPECT_EQ(OutputFileSettings::getOutputFrequency(), 5); } + +TEST(TestOutputSettings, setsHybridCenterFilename) +{ + settings::OutputFileSettings::setHybridCenterFileName("center.xyz"); + EXPECT_EQ( + settings::OutputFileSettings::getHybridCenterFileName(), + "center.xyz" + ); +} + +TEST(TestOutputSettings, replacesDefaultHybridCenterFilenameWithPrefix) +{ + using settings::OutputFileSettings; + + OutputFileSettings::setHybridCenterFileName(DefaultFiles::hybridCenterFile); + OutputFileSettings::replaceDefaultValues("centerPrefix"); + + EXPECT_EQ( + OutputFileSettings::getHybridCenterFileName(), + "centerPrefix.center.xyz" + ); +} diff --git a/tests/src/setup/testOutputFilesSetup.cpp b/tests/src/setup/testOutputFilesSetup.cpp index 1fbe864bb..fa7563159 100644 --- a/tests/src/setup/testOutputFilesSetup.cpp +++ b/tests/src/setup/testOutputFilesSetup.cpp @@ -47,11 +47,12 @@ namespace void cleanupPrefix() { const std::vector suffixes = { - ".log", ".info", ".rst", ".en", ".xyz", - ".timings", ".force", ".instant_en", ".vel", ".chrg", - ".mom", ".vir", ".stress", ".box", ".rpmd.rst", - ".rpmd.xyz", ".rpmd.vel", ".rpmd.force", ".rpmd.chrg", ".rpmd.en", - ".opt", ".ref" + ".log", ".info", ".rst", ".en", + ".xyz", ".center.xyz", ".timings", ".force", + ".instant_en", ".vel", ".chrg", ".mom", + ".vir", ".stress", ".box", ".rpmd.rst", + ".rpmd.xyz", ".rpmd.vel", ".rpmd.force", ".rpmd.chrg", + ".rpmd.en", ".opt", ".ref" }; for (const auto &s : suffixes) { @@ -84,6 +85,25 @@ TEST_F(TestSetup, setupOutputFilesOptJobReplaceDefaultsAndAssignsOptFile) cleanupPrefix(); } +TEST_F(TestSetup, setupOutputFilesHybridPathAssignsCenterFile) +{ + cleanupPrefix(); + Settings::setJobtype(JobType::QMMM_MD); + Settings::setIsRingPolymerMDActivated(false); + OutputFileSettings::setFilePrefix(PREFIX); + + OutputFilesSetup s(*_mdEngine); + EXPECT_NO_THROW(s.setup()); + + EXPECT_EQ( + _mdEngine->getXyzHybridCenterOutput().getFilename(), + std::string(PREFIX) + ".center.xyz" + ); + + _mdEngine->getXyzHybridCenterOutput().close(); + cleanupPrefix(); +} + TEST_F(TestSetup, setupOutputFilesMDPathPreservesLegacyEnergyFormatByDefault) { cleanupPrefix();