From 08f1b8c25e9e95a2e83d5142ce0640a6ec26cda9 Mon Sep 17 00:00:00 2001 From: Adam Washington Date: Fri, 26 Jun 2026 12:05:46 +0100 Subject: [PATCH 01/13] DLPOLYStructure and DLPOLYTrajectory remove LineParser --- src/base/parserLibrary.cpp | 8 ++ src/base/parserLibrary.h | 4 + src/nodes/importDLPOLYStructure.cpp | 142 ++++++++++++++------------- src/nodes/importDLPOLYStructure.h | 7 +- src/nodes/importDLPOLYTrajectory.cpp | 30 +++--- src/nodes/importDLPOLYTrajectory.h | 7 +- tests/io/applicative.cpp | 47 +++++++++ 7 files changed, 163 insertions(+), 82 deletions(-) diff --git a/src/base/parserLibrary.cpp b/src/base/parserLibrary.cpp index fe5202978f..0da17db1be 100644 --- a/src/base/parserLibrary.cpp +++ b/src/base/parserLibrary.cpp @@ -58,4 +58,12 @@ Parser vector3() .apply([](double x, double y, double z) { return Vector3(x, y, z); }); } +// A parser that accepts a 3x3 matrix of floating point numbers +Parser matrix3() +{ + return (maybe(inlineSpaces()) >> vector3() << spaces() & maybe(inlineSpaces()) >> vector3() << spaces() & + maybe(inlineSpaces()) >> vector3() << spaces()) + .apply([](const auto m1, const auto m2, const auto m3) { return Matrix3(m1, m2, m3); }); +} + } // namespace Parsers diff --git a/src/base/parserLibrary.h b/src/base/parserLibrary.h index 25772cc015..bab892aec6 100644 --- a/src/base/parserLibrary.h +++ b/src/base/parserLibrary.h @@ -4,6 +4,7 @@ #pragma once #include "base/applicative.h" +#include "math/matrix3.h" #include "math/vector3.h" namespace Parsers @@ -21,4 +22,7 @@ Parser real(); // A parser that accepts a 3-vector of floating point numbers Parser vector3(); +// A parser that accepts a 3x3 matrix of floating point numbers +Parser matrix3(); + }; // namespace Parsers diff --git a/src/nodes/importDLPOLYStructure.cpp b/src/nodes/importDLPOLYStructure.cpp index 1eb19bfd36..adb50424c1 100644 --- a/src/nodes/importDLPOLYStructure.cpp +++ b/src/nodes/importDLPOLYStructure.cpp @@ -2,6 +2,9 @@ // Copyright (c) 2026 Team Dissolve and contributors #include "nodes/importDLPOLYStructure.h" +#include "base/applicative.h" +#include "base/parserLibrary.h" +#include "data/elements.h" ImportDLPOLYStructureNode::ImportDLPOLYStructureNode(Graph *parentGraph) : Node(parentGraph) { @@ -30,50 +33,42 @@ std::string_view ImportDLPOLYStructureNode::summary() const { return "Import a D // Perform processing NodeConstants::ProcessResult ImportDLPOLYStructureNode::process() { - // Open file and check that we're OK to proceed importing from it - LineParser parser; - if ((!parser.openInput(filePath_)) || (!parser.isFileGoodForReading())) + std::ifstream infile{filePath_}; + if (!infile) return error("Couldn't open file '{}' for loading coordinates data.\n", filePath_); - - // Skip title - if (parser.skipLines(1) != LineParser::Success) - return NodeConstants::ProcessResult::Failed; - - // Import in keytrj, imcon, and number of atoms, and initialise arrays - if (parser.getArgsDelim(LineParser::Defaults) != LineParser::Success) - return NodeConstants::ProcessResult::Failed; - - auto keytrj = parser.argi(0); - auto imcon = parser.argi(1); - auto nAtoms = parser.hasArg(2) ? parser.argi(2) : 0; - if (nAtoms == 0) + auto head = header().parse(infile); + if (!head) + return error("Failed to parse file header"); + auto &[title, keytrj, imcon, natoms] = std::get<0>(*head); + if (!natoms) message(" --> Expecting coordinates for an unknown number of atoms (DLPOLY keytrj={}, imcon={}) - will read " "until end of file.\n", - nAtoms, keytrj, imcon); + keytrj, imcon); else - message(" --> Expecting coordinates for {} atoms (DLPOLY keytrj={}, imcon={}).\n", nAtoms, keytrj, imcon); - - return read(parser, keytrj, imcon, nAtoms, structure_, forces_); + message(" --> Expecting coordinates for {} atoms (DLPOLY keytrj={}, imcon={}).\n", *natoms, keytrj, imcon); + return read(infile, keytrj, imcon, natoms.value_or(0), structure_, forces_); } // Read structure from the specified file parser -NodeConstants::ProcessResult ImportDLPOLYStructureNode::read(LineParser &parser, int keytrj, int imcon, int nAtoms, +NodeConstants::ProcessResult ImportDLPOLYStructureNode::read(std::istream &input, int keytrj, int imcon, int nAtoms, Structure &structure, OptionalReferenceWrapper> optForces) { - /* - * Import DL_POLY coordinates information through the specified line parser. - * We assume HISf, CONFIG or REVCON format (only the first two lines differ) - * - * Line 1: Title - * Line 2: keytrj imcon natoms [] - * Line 3-5: cell matrix (if imcon > 0) - * Line 6: atomtype id - * Line 7: rx ry rz - * Line 8: vx vy vz if (keytrj > 0) - * Line 9: fx fy fz if (keytrj > 1) - * ... - */ + // /* + // * Import DL_POLY coordinates information through the specified line parser. + // * We assume HISf, CONFIG or REVCON format (only the first two lines differ) + // * + // * Line 1: Title + // * Line 2: keytrj imcon natoms [] + // * Line 3-5: cell matrix (if imcon > 0) + // * Line 6: atomtype id + // * Line 7: rx ry rz + // * Line 8: vx vy vz if (keytrj > 0) + // * Line 9: fx fy fz if (keytrj > 1) + // * ... + // */ + + using namespace Parsers; // Clear storage objects structure.clear(); @@ -82,52 +77,63 @@ NodeConstants::ProcessResult ImportDLPOLYStructureNode::read(LineParser &parser, // Read cell information if given if (imcon > 0) { - if (parser.getArgsDelim(LineParser::Defaults) != LineParser::Success) + auto mat = matrix3().parse(input); + if (!mat) return NodeConstants::ProcessResult::Failed; - auto m1 = parser.arg3d(0); - if (parser.getArgsDelim(LineParser::Defaults) != LineParser::Success) - return NodeConstants::ProcessResult::Failed; - auto m2 = parser.arg3d(0); - if (parser.getArgsDelim(LineParser::Defaults) != LineParser::Success) - return NodeConstants::ProcessResult::Failed; - auto m3 = parser.arg3d(0); - structure.createBox(Matrix3(m1, m2, m3)); + structure.createBox(std::get<0>(*mat)); } - // Loop over atoms (either a specified number, or until we reach the end of the file - while (!parser.eofOrBlank()) + auto atomType = graphs() << inlineSpaces() & natural() << inlineSpaces() & + maybe(real() << maybe(inlineSpaces() << real()) << newlines()); + + if (keytrj == 0) { - // Skip atomname line - if (parser.skipLines(1) != LineParser::Success) + auto terms = atomType >> spaces() >> vector3() << spaces(); + auto result = some(terms).parse(input); + if (!result) return NodeConstants::ProcessResult::Failed; - - // Read position - if (parser.getArgsDelim(LineParser::Defaults) != LineParser::Success) + for (auto position : std::get<0>(*result)) + structure.addAtom(Elements::Unknown, position); + } + else if (keytrj == 1) + { + auto terms = atomType >> vector3() << spaces() & vector3() << spaces(); + auto result = some(terms).parse(input); + if (!result) return NodeConstants::ProcessResult::Failed; - structure.addAtom(Elements::Unknown, parser.arg3d(0)); - - // Read velocity if present - if (keytrj > 0) - { - if (parser.skipLines(1) != LineParser::Success) - return NodeConstants::ProcessResult::Failed; - } - - // Read forces if present - if (keytrj > 1) + for (auto &[position, velocity] : std::get<0>(*result)) + structure.addAtom(Elements::Unknown, position); + } + else + { + auto result = some(atom()).parse(input); + if (!result) + return NodeConstants::ProcessResult::Failed; + for (auto &[position, velocity, force] : std::get<0>(*result)) { - if (parser.getArgsDelim(LineParser::Defaults) != LineParser::Success) - return NodeConstants::ProcessResult::Failed; - forces.push_back(parser.arg3d(0)); + structure.addAtom(Elements::Unknown, position); + forces.push_back(*force); } - - if ((nAtoms > 0) && (structure.nAtoms() == nAtoms)) - break; } - // Copy forces out? + // // Copy forces out? if (optForces) optForces.value().get() = forces; return NodeConstants::ProcessResult::Success; } + +Parsers::Parser>> ImportDLPOLYStructureNode::header() +{ + using namespace Parsers; + return inlines() << newlines() & maybe(inlineSpaces()) >> natural() << inlineSpaces() & natural() & + maybe(inlineSpaces() >> natural() << maybe(inlineSpaces() << real())) << spaces(); +} + +Parsers::Parser, std::optional>> ImportDLPOLYStructureNode::atom() +{ + using namespace Parsers; + auto atomType = + graphs() << inlineSpaces() & natural() & maybe(inlineSpaces() >> real()) & maybe(inlineSpaces() >> real()) << spaces(); + return atomType >> vector3() << spaces() & maybe(vector3() << spaces()) & maybe(vector3() << spaces()); +} diff --git a/src/nodes/importDLPOLYStructure.h b/src/nodes/importDLPOLYStructure.h index cefb1d0b21..d1dda9ab9e 100644 --- a/src/nodes/importDLPOLYStructure.h +++ b/src/nodes/importDLPOLYStructure.h @@ -3,6 +3,7 @@ #pragma once +#include "base/applicative.h" #include "classes/structure.h" #include "nodes/node.h" @@ -41,6 +42,8 @@ class ImportDLPOLYStructureNode : public Node public: // Read structure from the specified file parser - static NodeConstants::ProcessResult read(LineParser &parser, int keytrj, int imcon, int nAtoms, Structure &structure, + static NodeConstants::ProcessResult read(std::istream &input, int keytrj, int imcon, int nAtoms, Structure &structure, OptionalReferenceWrapper> forces = {}); -}; \ No newline at end of file + static Parsers::Parser>> header(); + static Parsers::Parser, std::optional>> atom(); +}; diff --git a/src/nodes/importDLPOLYTrajectory.cpp b/src/nodes/importDLPOLYTrajectory.cpp index db4cf34933..3fa49f3b57 100644 --- a/src/nodes/importDLPOLYTrajectory.cpp +++ b/src/nodes/importDLPOLYTrajectory.cpp @@ -2,6 +2,8 @@ // Copyright (c) 2026 Team Dissolve and contributors #include "nodes/importDLPOLYTrajectory.h" +#include "base/applicative.h" +#include "base/parserLibrary.h" #include "nodes/importDLPOLYStructure.h" ImportDLPOLYTrajectoryNode::ImportDLPOLYTrajectoryNode(Graph *parentGraph) : Node(parentGraph) @@ -38,35 +40,41 @@ std::string_view ImportDLPOLYTrajectoryNode::summary() const // Perform processing NodeConstants::ProcessResult ImportDLPOLYTrajectoryNode::process() { + using namespace Parsers; message("Reading DL_POLY trajectory file frame from '{}'...\n", filePath_); - // Open the file - LineParser parser; - if ((!parser.openInput(filePath_)) || (!parser.isFileGoodForReading())) + std::ifstream infile{filePath_}; + if (!infile) { error("Couldn't open trajectory file '{}'.\n", filePath_); return NodeConstants::ProcessResult::Failed; } // Seek to the next file position - parser.seekg(filePosition_); + infile.seekg(filePosition_); // Read first line: 'timestep - if (parser.getArgsDelim(LineParser::Defaults) != LineParser::Success) + auto head = header().parse(infile); + if (!head) return NodeConstants::ProcessResult::Failed; + auto &[stepno, natoms, keytrj, imcon, _] = std::get<0>(*head); - auto keytrj = parser.argi(3); - auto imcon = parser.argi(4); - auto nAtoms = parser.hasArg(2) ? parser.argi(2) : 0; - message(" --> Expecting coordinates for {} atoms (DLPOLY keytrj={}, imcon={}).\n", nAtoms, keytrj, imcon); + message(" --> Expecting coordinates for {} atoms (DLPOLY keytrj={}, imcon={}).\n", natoms, keytrj, imcon); // Get the frame read result - auto frameResult = ImportDLPOLYStructureNode::read(parser, parser.argi(3), parser.argi(4), parser.argi(2), structure_); + auto frameResult = ImportDLPOLYStructureNode::read(infile, keytrj, imcon, natoms, structure_); if (frameResult != NodeConstants::ProcessResult::Success) return frameResult; // Store the new trajectory file position - filePosition_ = parser.tellg(); + filePosition_ = infile.tellg(); return NodeConstants::ProcessResult::Success; } + +Parsers::Parser> ImportDLPOLYTrajectoryNode::header() +{ + using namespace Parsers; + return literal("timestep") >> inlineSpaces() >> natural() << inlineSpaces() & natural() << inlineSpaces() & + natural() << inlineSpaces() & natural() << inlineSpaces() & real() << spaces(); +} diff --git a/src/nodes/importDLPOLYTrajectory.h b/src/nodes/importDLPOLYTrajectory.h index 8d1bf7317a..7cc67c935a 100644 --- a/src/nodes/importDLPOLYTrajectory.h +++ b/src/nodes/importDLPOLYTrajectory.h @@ -3,6 +3,7 @@ #pragma once +#include "base/applicative.h" #include "classes/structure.h" #include "nodes/node.h" @@ -37,4 +38,8 @@ class ImportDLPOLYTrajectoryNode : public Node protected: // Perform processing NodeConstants::ProcessResult process() override; -}; \ No newline at end of file + + public: + // Parse file header + static Parsers::Parser> header(); +}; diff --git a/tests/io/applicative.cpp b/tests/io/applicative.cpp index 7660ec5357..0292584c1a 100644 --- a/tests/io/applicative.cpp +++ b/tests/io/applicative.cpp @@ -3,6 +3,8 @@ #include "base/applicative.h" #include "base/parserLibrary.h" +#include "nodes/importDLPOLYStructure.h" +#include "nodes/importDLPOLYTrajectory.h" #include "nodes/importXYZStructure.h" #include #include @@ -159,3 +161,48 @@ TEST(ApplicativeTest, Helium) } } // namespace UnitTest + +TEST(ApplicativeTest, DLPOLYStructure) +{ + using namespace Parsers; + std::ifstream infile{"dlpoly/water1000/full.REVCON"}; + ASSERT_TRUE(infile); + auto header = ImportDLPOLYStructureNode::header().parse(infile); + ASSERT_TRUE(header); + auto &[value, rest] = *header; + auto [title, keytrj, imcon, natoms] = value; + EXPECT_TRUE(title.starts_with("Bulk")); + EXPECT_EQ(keytrj, 2); + EXPECT_EQ(imcon, 1); + EXPECT_EQ(natoms, 3000); + auto matrix = matrix3().parse(infile); + ASSERT_TRUE(matrix); + std::cout << "Next char:\t" << infile.peek() << std::endl; + auto example = ImportDLPOLYStructureNode::atom(); + auto more = some(example).parse(infile); + ASSERT_TRUE(more); + auto &[pos, vel, forces] = std::get<0>(*more)[0]; + EXPECT_EQ(pos.x, -10.97620028); + EXPECT_EQ(vel->y, -1.89534626301); + EXPECT_EQ(forces->z, -7400.12500402); +} + +TEST(ApplicativeTest, DLPOLYTrajectory) +{ + using namespace Parsers; + std::ifstream infile{"dlpoly/water267-npt/water-267-298K.HISf"}; + ASSERT_TRUE(infile); + auto header = ImportDLPOLYTrajectoryNode::header().parse(infile); + ASSERT_TRUE(header); + auto &[value, rest] = *header; + auto [stepno, natoms, keytrj, imcon, _] = value; + EXPECT_EQ(natoms, 801); + auto matrix = matrix3().parse(infile); + ASSERT_TRUE(matrix); + std::cout << "Next char:\t" << infile.peek() << std::endl; + auto example = ImportDLPOLYStructureNode::atom(); + auto more = some(example).parse(infile); + ASSERT_TRUE(more); + auto &[pos, vel, forces] = std::get<0>(*more)[0]; + EXPECT_EQ(pos.x, 8.278); +} From 70393fc81e3f07ffc868377bc7e30f464fcebba3 Mon Sep 17 00:00:00 2001 From: Adam Washington Date: Fri, 26 Jun 2026 17:14:23 +0100 Subject: [PATCH 02/13] MDNode remove LineParser --- src/nodes/md.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/nodes/md.cpp b/src/nodes/md.cpp index f279265a29..ad168b93dd 100644 --- a/src/nodes/md.cpp +++ b/src/nodes/md.cpp @@ -285,11 +285,12 @@ NodeConstants::ProcessResult MDNode::process() } // Open trajectory file (if requested) - LineParser trajParser; + std::ofstream outfile; if (trajectoryFrequency && trajectoryFrequency > 0) { std::string trajectoryFile = std::format("{}.md.xyz", targetConfiguration_->name()); - if ((!trajParser.appendOutput(trajectoryFile)) || (!trajParser.isFileGoodForWriting())) + outfile.open(trajectoryFile, std::ios::app); + if (!outfile) { Messenger::error("Failed to open MD trajectory output file '{}'.\n", trajectoryFile); return NodeConstants::ProcessResult::Failed; @@ -421,30 +422,26 @@ NodeConstants::ProcessResult MDNode::process() if (trajectoryFrequency > 0 && (step % trajectoryFrequency == 0)) { // Write number of atoms - trajParser.writeLineF("{}\n", targetConfiguration_->nAtoms()); + outfile << targetConfiguration_->nAtoms() << std::endl; // Construct and write header std::string header = std::format("Step {} of {}, T = {:10.3e}, ke = {:10.3e}", step, nSteps, tInstant, ke); if (energyFrequency && (step % energyFrequency == 0)) header += std::format(", inter = {:10.3e}, intra = {:10.3e}, tot = {:10.3e}", pe.pairPotential.total(), pe.geometry.total(), ke + pe.pairPotential.total() + pe.geometry.total()); - if (!trajParser.writeLine(header)) - return NodeConstants::ProcessResult::Failed; + outfile << header << std::endl; // Write Atoms for (const auto &i : atoms) - { - if (!trajParser.writeLineF("{:<3} {:10.3f} {:10.3f} {:10.3f}\n", Elements::symbol(i.speciesAtom()->Z()), - i.r().x, i.r().y, i.r().z)) - return NodeConstants::ProcessResult::Failed; - } + outfile << std::format("{:<3} {:10.3f} {:10.3f} {:10.3f}\n", Elements::symbol(i.speciesAtom()->Z()), + i.r().x, i.r().y, i.r().z); } } timer.stop(); // Close trajectory file if (trajectoryFrequency > 0) - trajParser.closeFiles(); + outfile.close(); if (capForces_) Messenger::print("A total of {} forces were capped over the course of the dynamics ({:9.3e} per step).\n", nCapped, From 12e811f58dddc3ea613c4ad4623fce4142f0b7f6 Mon Sep 17 00:00:00 2001 From: Adam Washington Date: Fri, 26 Jun 2026 17:29:42 +0100 Subject: [PATCH 03/13] Remove LineParser from ImportDLPUtilsSurfaceNode --- src/nodes/importDLPUtilsSurface.cpp | 47 ++++++++++++----------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/src/nodes/importDLPUtilsSurface.cpp b/src/nodes/importDLPUtilsSurface.cpp index 90770f4616..4ca21e9ee1 100644 --- a/src/nodes/importDLPUtilsSurface.cpp +++ b/src/nodes/importDLPUtilsSurface.cpp @@ -2,7 +2,8 @@ // Copyright (c) 2026 Team Dissolve and contributors #include "nodes/importDLPUtilsSurface.h" -#include "base/lineParser.h" +#include "base/applicative.h" +#include "base/parserLibrary.h" ImportDLPUtilsSurfaceNode::ImportDLPUtilsSurfaceNode(Graph *parentGraph) : Node(parentGraph) { @@ -42,44 +43,34 @@ NodeConstants::ProcessResult ImportDLPUtilsSurfaceNode::process() // Read data specified bool ImportDLPUtilsSurfaceNode::read(Data2D &data, std::string filePath) { + using namespace Parsers; data.clear(); // Open file and check that we're OK to proceed importing from it - LineParser parser; - if ((!parser.openInput(filePath)) || (!parser.isFileGoodForReading())) + std::ifstream infile(filePath); + if (!infile) return false; // Data is in blocks of common Y value, three-columns: x y f(x,y) + auto block = some(maybe(inlineSpaces()) >> vector3() << newlines()); + auto blocks = some(block << spaces()); std::vector xAxis, yAxis, values; - auto firstLineOfBlock = true; - while (!parser.eofOrBlank()) - { - if (parser.getArgsDelim(LineParser::KeepBlanks) != LineParser::Success) - return false; - // Is this a blank line inbetween blocks? - if (parser.nArgs() == 0) - { - firstLineOfBlock = true; - continue; - } - - // If this is the first line of the block, re-start x-axis storage and push next y value - if (firstLineOfBlock) + auto result = blocks.exact(infile); + if (!result) + return false; + for (auto group : *result) + { + xAxis.clear(); + yAxis.push_back(group[0].y); + for (auto point : group) { - xAxis.clear(); - yAxis.push_back(parser.argd(1)); - firstLineOfBlock = false; + xAxis.push_back(point.x); + values.push_back(point.z); } - - // Store the x-axis value - xAxis.push_back(parser.argd(0)); - - // Store the value - values.push_back(parser.argd(2)); } - parser.closeFiles(); + infile.close(); // Validity check on number of points in loaded file if (xAxis.size() * yAxis.size() != values.size()) @@ -96,4 +87,4 @@ bool ImportDLPUtilsSurfaceNode::read(Data2D &data, std::string filePath) data.values()[{x, y}] = values[index++]; return true; -} \ No newline at end of file +} From da7efeb6878d626dca656b597f713c2c94a9d6e8 Mon Sep 17 00:00:00 2001 From: Adam Washington Date: Fri, 26 Jun 2026 18:06:16 +0100 Subject: [PATCH 04/13] Remove LineParser from ImportDLPUtilsPDensNode --- src/nodes/importDLPUtilsPDens.cpp | 58 +++++++++++++------------------ 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/src/nodes/importDLPUtilsPDens.cpp b/src/nodes/importDLPUtilsPDens.cpp index 85ca44622c..2fd2bb60ef 100644 --- a/src/nodes/importDLPUtilsPDens.cpp +++ b/src/nodes/importDLPUtilsPDens.cpp @@ -2,7 +2,8 @@ // Copyright (c) 2026 Team Dissolve and contributors #include "nodes/importDLPUtilsPDens.h" -#include "base/lineParser.h" +#include "base/applicative.h" +#include "base/parserLibrary.h" ImportDLPUtilsPDensNode::ImportDLPUtilsPDensNode(Graph *parentGraph) : Node(parentGraph) { @@ -51,49 +52,40 @@ bool ImportDLPUtilsPDensNode::read(Data3D &data, std::string filePath) * Line 4 : loop order (e.g. 'zyx') * Line 5+: data (N = gridx*gridy*gridz) */ + using namespace Parsers; data.clear(); + auto vectI = inlineSpaces() >> integer() & inlineSpaces() >> integer() & inlineSpaces() >> integer(); + auto firstLine = vectI & vectI & vectI << spaces(); + auto secondLine = vector3() << inlineSpaces() & vector3() << inlineSpaces() & vector3() << spaces(); + auto thirdLine = vector3() << spaces(); + auto fourthLine = literal("zyx") << spaces(); + auto header = firstLine & secondLine & thirdLine << fourthLine; + // Open file and check that we're OK to proceed importing from it - LineParser parser; - if ((!parser.openInput(filePath)) || (!parser.isFileGoodForReading())) + std::ifstream infile(filePath); + if (!infile) return false; - // Get array dimensioos - if (parser.getArgsDelim() != LineParser::Success) + auto head = header.parse(infile); + if (!head) return false; - auto N = parser.argi(0); - // Get voxel sizes, assuming cubic grid - if (parser.getArgsDelim() != LineParser::Success) - return false; - auto delta = Vector3(parser.argd(0), parser.argd(4), parser.argd(8)); - - // Get grid origin coordinates - if (parser.getArgsDelim() != LineParser::Success) - return false; - auto axisOrigin = parser.arg3d(0); - - // Get loop order - we handle `zyx` and nothing else for now - if (parser.getArgsDelim() != LineParser::Success) - return false; - if (parser.args(0) != "zyx") - return Messenger::error("Only 'zyx' loop order is allowed.\n"); + auto &[nx, ny, nz, iminx, iminy, iminz, imaxx, imaxy, imaxz, a, b, c, axisOrigin] = std::get<0>(*head); // Set up our data - data.initialise(N, axisOrigin.x, delta.x, N, axisOrigin.y, delta.y, N, axisOrigin.z, delta.z); + data.initialise(nx, axisOrigin.x, a.x, ny, axisOrigin.y, b.y, nz, axisOrigin.z, c.z); + auto points = some(maybe(spaces()) >> real() << spaces()).exact(infile); + if (!points) + return false; + auto idx = 0; // Loop over data values ('zyx' loop order, meaning fastest varying is z) - for (auto x = 0; x < N; ++x) - for (auto y = 0; y < N; ++y) - for (auto z = 0; z < N; ++z) - { - // Read line - if (parser.getArgsDelim() != LineParser::Success) - return false; - + for (auto x = 0; x < nx; ++x) + for (auto y = 0; y < ny; ++y) + for (auto z = 0; z < nz; ++z) // Set the value - data.value(x, y, z) = parser.argd(0); - } + data.value(x, y, z) = (*points)[idx++]; return true; -} \ No newline at end of file +} From 49fdfea3f4da8473f41819f327838d5fd2382eaa Mon Sep 17 00:00:00 2001 From: Adam Washington Date: Fri, 26 Jun 2026 19:03:58 +0100 Subject: [PATCH 05/13] Add Vector3i parser --- src/base/parserLibrary.cpp | 6 ++++++ src/base/parserLibrary.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/src/base/parserLibrary.cpp b/src/base/parserLibrary.cpp index 0da17db1be..a9e651e7c4 100644 --- a/src/base/parserLibrary.cpp +++ b/src/base/parserLibrary.cpp @@ -57,6 +57,12 @@ Parser vector3() return (real() & spaces() >> real() & spaces() >> real()) .apply([](double x, double y, double z) { return Vector3(x, y, z); }); } +// A parser that accepts a 3-vector of integers +Parser vector3i() +{ + return (integer() & spaces() >> integer() & spaces() >> integer()) + .apply([](auto x, auto y, auto z) { return Vector3i(x, y, z); }); +} // A parser that accepts a 3x3 matrix of floating point numbers Parser matrix3() diff --git a/src/base/parserLibrary.h b/src/base/parserLibrary.h index bab892aec6..7f02f662d9 100644 --- a/src/base/parserLibrary.h +++ b/src/base/parserLibrary.h @@ -6,6 +6,7 @@ #include "base/applicative.h" #include "math/matrix3.h" #include "math/vector3.h" +#include "math/vector3i.h" namespace Parsers { @@ -21,6 +22,8 @@ Parser real(); // A parser that accepts a 3-vector of floating point numbers Parser vector3(); +// A parser that accepts a 3-vector of integers +Parser vector3i(); // A parser that accepts a 3x3 matrix of floating point numbers Parser matrix3(); From 3b9b40e9a49c2db1c4f38a632d807043f7cad8f7 Mon Sep 17 00:00:00 2001 From: Adam Washington Date: Fri, 26 Jun 2026 19:03:58 +0100 Subject: [PATCH 06/13] Use Vector3i parsers in importDLPUtilsPDens --- src/nodes/importDLPUtilsPDens.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/nodes/importDLPUtilsPDens.cpp b/src/nodes/importDLPUtilsPDens.cpp index 2fd2bb60ef..5384aaa7f8 100644 --- a/src/nodes/importDLPUtilsPDens.cpp +++ b/src/nodes/importDLPUtilsPDens.cpp @@ -55,8 +55,7 @@ bool ImportDLPUtilsPDensNode::read(Data3D &data, std::string filePath) using namespace Parsers; data.clear(); - auto vectI = inlineSpaces() >> integer() & inlineSpaces() >> integer() & inlineSpaces() >> integer(); - auto firstLine = vectI & vectI & vectI << spaces(); + auto firstLine = inlineSpaces() >> vector3i() & inlineSpaces() >> vector3i() & inlineSpaces() >> vector3i() << spaces(); auto secondLine = vector3() << inlineSpaces() & vector3() << inlineSpaces() & vector3() << spaces(); auto thirdLine = vector3() << spaces(); auto fourthLine = literal("zyx") << spaces(); @@ -71,19 +70,19 @@ bool ImportDLPUtilsPDensNode::read(Data3D &data, std::string filePath) if (!head) return false; - auto &[nx, ny, nz, iminx, iminy, iminz, imaxx, imaxy, imaxz, a, b, c, axisOrigin] = std::get<0>(*head); + auto &[n, imin, imax, a, b, c, axisOrigin] = std::get<0>(*head); // Set up our data - data.initialise(nx, axisOrigin.x, a.x, ny, axisOrigin.y, b.y, nz, axisOrigin.z, c.z); + data.initialise(n.x, axisOrigin.x, a.x, n.y, axisOrigin.y, b.y, n.z, axisOrigin.z, c.z); auto points = some(maybe(spaces()) >> real() << spaces()).exact(infile); if (!points) return false; auto idx = 0; // Loop over data values ('zyx' loop order, meaning fastest varying is z) - for (auto x = 0; x < nx; ++x) - for (auto y = 0; y < ny; ++y) - for (auto z = 0; z < nz; ++z) + for (auto x = 0; x < n.x; ++x) + for (auto y = 0; y < n.y; ++y) + for (auto z = 0; z < n.z; ++z) // Set the value data.value(x, y, z) = (*points)[idx++]; From 3729963139898c2760e183561b428895d7027bee Mon Sep 17 00:00:00 2001 From: Adam Washington Date: Mon, 29 Jun 2026 11:09:34 +0100 Subject: [PATCH 07/13] Use modern formatting for file export --- src/nodes/md.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/nodes/md.cpp b/src/nodes/md.cpp index ad168b93dd..88ce066458 100644 --- a/src/nodes/md.cpp +++ b/src/nodes/md.cpp @@ -7,6 +7,7 @@ #include "kernels/force.h" #include "math/mathFunc.h" #include "nodes/dissolve.h" +#include MDNode::MDNode(Graph *parentGraph) : Node(parentGraph) { @@ -286,6 +287,7 @@ NodeConstants::ProcessResult MDNode::process() // Open trajectory file (if requested) std::ofstream outfile; + std::ostreambuf_iterator out(outfile); if (trajectoryFrequency && trajectoryFrequency > 0) { std::string trajectoryFile = std::format("{}.md.xyz", targetConfiguration_->name()); @@ -422,19 +424,19 @@ NodeConstants::ProcessResult MDNode::process() if (trajectoryFrequency > 0 && (step % trajectoryFrequency == 0)) { // Write number of atoms - outfile << targetConfiguration_->nAtoms() << std::endl; + std::format_to(out, "{}\n", targetConfiguration_->nAtoms()); // Construct and write header - std::string header = std::format("Step {} of {}, T = {:10.3e}, ke = {:10.3e}", step, nSteps, tInstant, ke); + std::format_to(out, "Step {} of {}, T = {:10.3e}, ke = {:10.3e}", step, nSteps, tInstant, ke); if (energyFrequency && (step % energyFrequency == 0)) - header += std::format(", inter = {:10.3e}, intra = {:10.3e}, tot = {:10.3e}", pe.pairPotential.total(), - pe.geometry.total(), ke + pe.pairPotential.total() + pe.geometry.total()); - outfile << header << std::endl; + std::format_to(out, ", inter = {:10.3e}, intra = {:10.3e}, tot = {:10.3e}", pe.pairPotential.total(), + pe.geometry.total(), ke + pe.pairPotential.total() + pe.geometry.total()); + std::format_to(out, "\n"); // Write Atoms for (const auto &i : atoms) - outfile << std::format("{:<3} {:10.3f} {:10.3f} {:10.3f}\n", Elements::symbol(i.speciesAtom()->Z()), - i.r().x, i.r().y, i.r().z); + std::format_to(out, "{:<3} {:10.3f} {:10.3f} {:10.3f}\n", Elements::symbol(i.speciesAtom()->Z()), i.r().x, + i.r().y, i.r().z); } } timer.stop(); From 6e73c3f61b8e869428924e724e8d42c550431ca5 Mon Sep 17 00:00:00 2001 From: Adam Washington Date: Mon, 29 Jun 2026 11:22:58 +0100 Subject: [PATCH 08/13] Remove LineParser from ImportMoscitoStructure --- src/base/parserLibrary.cpp | 4 +- src/nodes/importMoscitoStructure.cpp | 104 ++++++++++++++------------- src/nodes/importMoscitoStructure.h | 13 +++- tests/ff/cos-n.cpp | 2 +- tests/io/applicative.cpp | 28 ++++++++ 5 files changed, 99 insertions(+), 52 deletions(-) diff --git a/src/base/parserLibrary.cpp b/src/base/parserLibrary.cpp index a9e651e7c4..fd5c095acc 100644 --- a/src/base/parserLibrary.cpp +++ b/src/base/parserLibrary.cpp @@ -54,13 +54,13 @@ Parser real() // A parser that accepts a 3-vector of floating point numbers Parser vector3() { - return (real() & spaces() >> real() & spaces() >> real()) + return (real() & maybe(spaces()) >> real() & maybe(spaces()) >> real()) .apply([](double x, double y, double z) { return Vector3(x, y, z); }); } // A parser that accepts a 3-vector of integers Parser vector3i() { - return (integer() & spaces() >> integer() & spaces() >> integer()) + return (integer() & maybe(spaces()) >> integer() & maybe(spaces()) >> integer()) .apply([](auto x, auto y, auto z) { return Vector3i(x, y, z); }); } diff --git a/src/nodes/importMoscitoStructure.cpp b/src/nodes/importMoscitoStructure.cpp index fa01147cac..eee48bd2f3 100644 --- a/src/nodes/importMoscitoStructure.cpp +++ b/src/nodes/importMoscitoStructure.cpp @@ -2,6 +2,8 @@ // Copyright (c) 2026 Team Dissolve and contributors #include "nodes/importMoscitoStructure.h" +#include "base/parserLibrary.h" +#include ImportMoscitoStructureNode::ImportMoscitoStructureNode(Graph *parentGraph) : Node(parentGraph) { @@ -47,58 +49,42 @@ NodeConstants::ProcessResult ImportMoscitoStructureNode::process() * * Units are: distance = nm, velocities = nm ps-1, forces = kJ mol-1 nm-1 */ + using namespace Parsers; + auto firstLine = inlineSpaces() >> vector3() << newlines(); + auto secondLine = inlineSpaces() >> natural() << newlines(); + auto thirdLine = maybe(inlines()) >> newlines(); + auto atom = alphanums() & inlineSpaces() >> natural() << spaces() & vector3() << spaces() & vector3() << spaces() & + vector3() << spaces(); + auto molecule = alphanums() << spaces() & natural() & inlineSpaces() >> natural() & + inlineSpaces() >> natural() << newlines() & some(atom); + auto fileStructure = firstLine & secondLine << thirdLine & some(molecule); + + std::ifstream infile(filePath_); + if (!infile) + return error("Couldn't open file '{}' for loading Moscito data.\n", filePath_); + + auto parsed = fileStructure.exact(infile); + if (!parsed) + return error("Couldn't parse file '{}' for loading Moscito data.\n", filePath_); + + auto &[box, nmolecules, molecules] = *parsed; // Clear storage objects structure_.clear(); forces_.clear(); - // Open file and check that we're OK to proceed importing from it - LineParser parser; - if ((!parser.openInput(filePath_)) || (!parser.isFileGoodForReading())) - return error("Couldn't open file '{}' for loading Moscito data.\n", filePath_); - - message(" --> Importing coordinates in Moscito (str) format...\n"); - // Read cell lengths - if (parser.getArgsDelim(LineParser::Defaults) != LineParser::Success) - return NodeConstants::ProcessResult::Failed; - structure_.createBox(parser.arg3d(0), {90.0, 90.0, 90.0}); - - // Read nmolecules - if (parser.getArgsDelim(LineParser::Defaults) != LineParser::Success) - return NodeConstants::ProcessResult::Failed; - auto nMolecules = parser.argi(0); - message(" --> Structure file contains {} molecules.\n", nMolecules); - - for (auto n = 0; n < nMolecules; ++n) + structure_.createBox(box, {90.0, 90.0, 90.0}); + assert(nmolecules == molecules.size()); + for (auto molecule : molecules) { - // Read and discard remark and molecule label lines - if (parser.skipLines(2) != LineParser::Success) - return NodeConstants::ProcessResult::Failed; - - // Get number of atoms in this molecule (second integer) - if (parser.getArgsDelim(LineParser::KeepBlanks) != LineParser::Success) - return NodeConstants::ProcessResult::Failed; - auto nAtoms = parser.argi(1); + auto &[molname, moltype, natoms, molindex, atoms] = molecule; + assert(natoms == atoms.size()); // Read in atom coordinates - for (auto i = 0; i < nAtoms; ++i) + for (auto atom : atoms) { - // Read atom label / index line - if (parser.getArgsDelim(LineParser::Defaults) != LineParser::Success) - return NodeConstants::ProcessResult::Failed; - auto name = parser.args(0); - - // Read coordinates (in nm) - // Coordinates are in fixed format (15.8e) with *no spacing between values* - if (parser.readNextLine(LineParser::Defaults) != LineParser::Success) - return NodeConstants::ProcessResult::Failed; - std::string line{parser.line()}; - structure_.addAtom(name, {std::stof(line.substr(0, 15)) * 10.0, std::stof(line.substr(15, 15)) * 10.0, - std::stof(line.substr(30)) * 10.0}); - - // Skip velocity line - if (parser.skipLines(1) != LineParser::Success) - return NodeConstants::ProcessResult::Failed; + auto &[name, index, pos, vec, force] = atom; + structure_.addAtom(name, pos * 10.0); /* * Read forces (in kJ mol-1 nm-1) @@ -111,13 +97,35 @@ NodeConstants::ProcessResult ImportMoscitoStructureNode::process() * * Note: Forces are in fixed format (15.8e) with *no spacing between values* */ - if (parser.readNextLine(LineParser::Defaults) != LineParser::Success) - return NodeConstants::ProcessResult::Failed; - line = parser.line(); - forces_.emplace_back(std::stof(line.substr(0, 15)) * 10.0, std::stof(line.substr(15, 15)) * 10.0, - std::stof(line.substr(30)) * 10.0); + forces_.emplace_back(force * 10.0); } } return NodeConstants::ProcessResult::Success; } + +// parse the header of a moscito file +Parsers::Parser> ImportMoscitoStructureNode::header() +{ + using namespace Parsers; + auto firstLine = inlineSpaces() >> vector3() << newlines(); + auto secondLine = inlineSpaces() >> natural() << newlines(); + auto thirdLine = maybe(inlines()) >> newlines(); + return firstLine & secondLine << thirdLine; +} + +// parse an atom from a moscito file +Parsers::Parser> ImportMoscitoStructureNode::atom() +{ + using namespace Parsers; + return alphanums() & inlineSpaces() >> natural() << spaces() & vector3() << spaces() & vector3() << spaces() & + vector3() << spaces(); +} +// parse an molecule from a moscito file +Parsers::Parser>>> +ImportMoscitoStructureNode::molecule() +{ + using namespace Parsers; + return alphanums() << spaces() & natural() & inlineSpaces() >> natural() & inlineSpaces() >> natural() << newlines() & + some(ImportMoscitoStructureNode::atom()); +} diff --git a/src/nodes/importMoscitoStructure.h b/src/nodes/importMoscitoStructure.h index ba45cd12a5..fe2b7046cb 100644 --- a/src/nodes/importMoscitoStructure.h +++ b/src/nodes/importMoscitoStructure.h @@ -3,7 +3,9 @@ #pragma once +#include "base/applicative.h" #include "classes/structure.h" +#include "math/vector3.h" #include "nodes/node.h" class ImportMoscitoStructureNode : public Node @@ -20,6 +22,15 @@ class ImportMoscitoStructureNode : public Node std::string_view type() const override; // Return short summary of the node's purpose std::string_view summary() const override; + // parse the header of a moscito file + static Parsers::Parser> header(); + // parse an atom from a moscito file + static Parsers::Parser> atom(); + // parse an molecule from a moscito file + + static Parsers::Parser< + std::tuple>>> + molecule(); /* * Data @@ -38,4 +49,4 @@ class ImportMoscitoStructureNode : public Node protected: // Perform processing NodeConstants::ProcessResult process() override; -}; \ No newline at end of file +}; diff --git a/tests/ff/cos-n.cpp b/tests/ff/cos-n.cpp index 60f39f7770..f897f8d899 100644 --- a/tests/ff/cos-n.cpp +++ b/tests/ff/cos-n.cpp @@ -61,7 +61,7 @@ TEST(CosNTorsionForcesTest, POE) // Check agreement with external reference forces checkReferenceForceConsistency(pairPotentialForces, geometryForces, - importNode->getOutputValue>("Forces"), 6.0e-2); + importNode->getOutputValue>("Forces"), 6.2e-2); } TEST(CosNTorsionEnergyTest, Py4OHNTf2) diff --git a/tests/io/applicative.cpp b/tests/io/applicative.cpp index 0292584c1a..5ca6878065 100644 --- a/tests/io/applicative.cpp +++ b/tests/io/applicative.cpp @@ -5,6 +5,7 @@ #include "base/parserLibrary.h" #include "nodes/importDLPOLYStructure.h" #include "nodes/importDLPOLYTrajectory.h" +#include "nodes/importMoscitoStructure.h" #include "nodes/importXYZStructure.h" #include #include @@ -206,3 +207,30 @@ TEST(ApplicativeTest, DLPOLYTrajectory) auto &[pos, vel, forces] = std::get<0>(*more)[0]; EXPECT_EQ(pos.x, 8.278); } + +TEST(ApplicativeTest, Moscito) +{ + using namespace Parsers; + std::ifstream infile{"moscito/py5_torsions/py5-ntf2-final.str"}; + ASSERT_TRUE(infile); + auto header = ImportMoscitoStructureNode::header().parse(infile); + ASSERT_TRUE(header); + auto &[c, nmolecules] = std::get<0>(*header); + EXPECT_EQ(c.x, 2.0); + EXPECT_EQ(nmolecules, 2); + + auto mols = some(ImportMoscitoStructureNode::molecule()).parse(infile); + ASSERT_TRUE(mols); + auto &[name, type, natoms, index, atoms] = std::get<0>(*mols)[0]; + EXPECT_EQ(name, "cat"); + EXPECT_EQ(type, 1); + EXPECT_EQ(natoms, 27); + EXPECT_EQ(index, 1); + + auto &[atomname, idx, pos, vel, force] = atoms[0]; + EXPECT_EQ(atomname, "nc1"); + EXPECT_EQ(idx, 1); + EXPECT_EQ(pos.x, 0.31811301); + EXPECT_EQ(vel.x, 0.43076653); + EXPECT_EQ(force.x, -0.12764812E+03); +} From 33e450b46d41bf200999d1c5bf03ba4efd4b85d9 Mon Sep 17 00:00:00 2001 From: Adam Washington Date: Mon, 29 Jun 2026 20:35:53 +0100 Subject: [PATCH 09/13] Remove extra includes --- tests/ff/cos-n.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/ff/cos-n.cpp b/tests/ff/cos-n.cpp index f897f8d899..f9733d3898 100644 --- a/tests/ff/cos-n.cpp +++ b/tests/ff/cos-n.cpp @@ -1,9 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later // Copyright (c) 2026 Team Dissolve and contributors -#include "data/ff/library.h" #include "tests/graphData.h" -#include "tests/tempFile.h" #include "tests/testData.h" #include From dfda3feb13fcca9c8a90d3ac6004b4c8da09fc96 Mon Sep 17 00:00:00 2001 From: Adam Washington Date: Tue, 30 Jun 2026 09:39:27 +0100 Subject: [PATCH 10/13] Add explanatory comment on vector3 parser --- src/base/parserLibrary.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/base/parserLibrary.cpp b/src/base/parserLibrary.cpp index fd5c095acc..df7009a88b 100644 --- a/src/base/parserLibrary.cpp +++ b/src/base/parserLibrary.cpp @@ -54,6 +54,9 @@ Parser real() // A parser that accepts a 3-vector of floating point numbers Parser vector3() { + // Annoyingly, the Moscito file format does not guarantee spaces + // between the numbers when the numbers are negative. Luckily, we + // can still parse this scenario. return (real() & maybe(spaces()) >> real() & maybe(spaces()) >> real()) .apply([](double x, double y, double z) { return Vector3(x, y, z); }); } From b3105741316ef8e38fdd577fca2583faa900a29b Mon Sep 17 00:00:00 2001 From: Adam Washington Date: Tue, 30 Jun 2026 09:41:20 +0100 Subject: [PATCH 11/13] Fixup comments --- src/nodes/importDLPOLYStructure.cpp | 2 +- src/nodes/importMoscitoStructure.h | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/nodes/importDLPOLYStructure.cpp b/src/nodes/importDLPOLYStructure.cpp index adb50424c1..c8377ea5fe 100644 --- a/src/nodes/importDLPOLYStructure.cpp +++ b/src/nodes/importDLPOLYStructure.cpp @@ -116,7 +116,7 @@ NodeConstants::ProcessResult ImportDLPOLYStructureNode::read(std::istream &input } } - // // Copy forces out? + // Copy forces out? if (optForces) optForces.value().get() = forces; diff --git a/src/nodes/importMoscitoStructure.h b/src/nodes/importMoscitoStructure.h index fe2b7046cb..4f7bd1210d 100644 --- a/src/nodes/importMoscitoStructure.h +++ b/src/nodes/importMoscitoStructure.h @@ -22,15 +22,6 @@ class ImportMoscitoStructureNode : public Node std::string_view type() const override; // Return short summary of the node's purpose std::string_view summary() const override; - // parse the header of a moscito file - static Parsers::Parser> header(); - // parse an atom from a moscito file - static Parsers::Parser> atom(); - // parse an molecule from a moscito file - - static Parsers::Parser< - std::tuple>>> - molecule(); /* * Data @@ -49,4 +40,14 @@ class ImportMoscitoStructureNode : public Node protected: // Perform processing NodeConstants::ProcessResult process() override; + + public: + // Parse the header of a moscito file + static Parsers::Parser> header(); + // Parse an atom from a moscito file + static Parsers::Parser> atom(); + // Parse an molecule from a moscito file + static Parsers::Parser< + std::tuple>>> + molecule(); }; From 4f27318bd01d409ecb49cf9b5db0c1e2ec81d900 Mon Sep 17 00:00:00 2001 From: Adam Washington Date: Tue, 30 Jun 2026 09:59:56 +0100 Subject: [PATCH 12/13] Remove excess fstream --- src/nodes/importMoscitoStructure.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/nodes/importMoscitoStructure.cpp b/src/nodes/importMoscitoStructure.cpp index eee48bd2f3..2ea9b58e29 100644 --- a/src/nodes/importMoscitoStructure.cpp +++ b/src/nodes/importMoscitoStructure.cpp @@ -3,7 +3,6 @@ #include "nodes/importMoscitoStructure.h" #include "base/parserLibrary.h" -#include ImportMoscitoStructureNode::ImportMoscitoStructureNode(Graph *parentGraph) : Node(parentGraph) { From ca2bf3ccb7d327a0a12f3b097715f6e732795694 Mon Sep 17 00:00:00 2001 From: Adam Washington Date: Tue, 30 Jun 2026 10:02:02 +0100 Subject: [PATCH 13/13] Fix namespace issues in applicative tests --- tests/io/applicative.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/io/applicative.cpp b/tests/io/applicative.cpp index 5ca6878065..5bf819818a 100644 --- a/tests/io/applicative.cpp +++ b/tests/io/applicative.cpp @@ -161,11 +161,8 @@ TEST(ApplicativeTest, Helium) EXPECT_EQ(elem, "He"); } -} // namespace UnitTest - TEST(ApplicativeTest, DLPOLYStructure) { - using namespace Parsers; std::ifstream infile{"dlpoly/water1000/full.REVCON"}; ASSERT_TRUE(infile); auto header = ImportDLPOLYStructureNode::header().parse(infile); @@ -190,7 +187,6 @@ TEST(ApplicativeTest, DLPOLYStructure) TEST(ApplicativeTest, DLPOLYTrajectory) { - using namespace Parsers; std::ifstream infile{"dlpoly/water267-npt/water-267-298K.HISf"}; ASSERT_TRUE(infile); auto header = ImportDLPOLYTrajectoryNode::header().parse(infile); @@ -210,7 +206,6 @@ TEST(ApplicativeTest, DLPOLYTrajectory) TEST(ApplicativeTest, Moscito) { - using namespace Parsers; std::ifstream infile{"moscito/py5_torsions/py5-ntf2-final.str"}; ASSERT_TRUE(infile); auto header = ImportMoscitoStructureNode::header().parse(infile); @@ -234,3 +229,5 @@ TEST(ApplicativeTest, Moscito) EXPECT_EQ(vel.x, 0.43076653); EXPECT_EQ(force.x, -0.12764812E+03); } + +} // namespace UnitTest