Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion src/base/parserLibrary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,25 @@ Parser<double> real()
// A parser that accepts a 3-vector of floating point numbers
Parser<Vector3> vector3()
{
return (real() & spaces() >> real() & spaces() >> real())
// 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())
Comment thread
rprospero marked this conversation as resolved.
.apply([](double x, double y, double z) { return Vector3(x, y, z); });
}
// A parser that accepts a 3-vector of integers
Parser<Vector3i> vector3i()
{
return (integer() & maybe(spaces()) >> integer() & maybe(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> 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
7 changes: 7 additions & 0 deletions src/base/parserLibrary.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
#pragma once

#include "base/applicative.h"
#include "math/matrix3.h"
#include "math/vector3.h"
#include "math/vector3i.h"

namespace Parsers
{
Expand All @@ -20,5 +22,10 @@ Parser<double> real();

// A parser that accepts a 3-vector of floating point numbers
Parser<Vector3> vector3();
// A parser that accepts a 3-vector of integers
Parser<Vector3i> vector3i();

// A parser that accepts a 3x3 matrix of floating point numbers
Parser<Matrix3> matrix3();

}; // namespace Parsers
140 changes: 73 additions & 67 deletions src/nodes/importDLPOLYStructure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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<std::vector<Vector3>> 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();
Expand All @@ -82,47 +77,43 @@ 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?
Expand All @@ -131,3 +122,18 @@ NodeConstants::ProcessResult ImportDLPOLYStructureNode::read(LineParser &parser,

return NodeConstants::ProcessResult::Success;
}

Parsers::Parser<std::tuple<std::string, int, int, std::optional<int>>> ImportDLPOLYStructureNode::header()
{
using namespace Parsers;
return inlines() << newlines() & maybe(inlineSpaces()) >> natural() << inlineSpaces() & natural() &
maybe(inlineSpaces() >> natural() << maybe(inlineSpaces() << real())) << spaces();
}

Parsers::Parser<std::tuple<Vector3, std::optional<Vector3>, std::optional<Vector3>>> 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());
}
7 changes: 5 additions & 2 deletions src/nodes/importDLPOLYStructure.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma once

#include "base/applicative.h"
#include "classes/structure.h"
#include "nodes/node.h"

Expand Down Expand Up @@ -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<std::vector<Vector3>> forces = {});
};
static Parsers::Parser<std::tuple<std::string, int, int, std::optional<int>>> header();
static Parsers::Parser<std::tuple<Vector3, std::optional<Vector3>, std::optional<Vector3>>> atom();
};
30 changes: 19 additions & 11 deletions src/nodes/importDLPOLYTrajectory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 <stepNo> <nAtoms> <keytrj> <imcon>
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);
Comment thread
rprospero marked this conversation as resolved.

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<std::tuple<int, int, int, int, double>> ImportDLPOLYTrajectoryNode::header()
{
using namespace Parsers;
return literal("timestep") >> inlineSpaces() >> natural() << inlineSpaces() & natural() << inlineSpaces() &
natural() << inlineSpaces() & natural() << inlineSpaces() & real() << spaces();
}
7 changes: 6 additions & 1 deletion src/nodes/importDLPOLYTrajectory.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma once

#include "base/applicative.h"
#include "classes/structure.h"
#include "nodes/node.h"

Expand Down Expand Up @@ -37,4 +38,8 @@ class ImportDLPOLYTrajectoryNode : public Node
protected:
// Perform processing
NodeConstants::ProcessResult process() override;
};

public:
// Parse file header
static Parsers::Parser<std::tuple<int, int, int, int, double>> header();
};
Loading
Loading