Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
3 changes: 3 additions & 0 deletions src/cxx/nux/nux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ namespace nux {
void load_modules(pluginplay::ModuleManager& mm) {
mm.add_module<BOApproximation>("Born-Oppenheimer Approximation");
mm.add_module<XYZToMolecule>("XYZ To Molecule");
mm.add_module<XYZFileToMolecule>("XYZ File to Molecule");

set_defaults(mm);
}

} // namespace nux
5 changes: 5 additions & 0 deletions src/cxx/nux/nux_modules.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,10 @@ namespace nux {

DECLARE_MODULE(BOApproximation);
DECLARE_MODULE(XYZToMolecule);
DECLARE_MODULE(XYZFileToMolecule);

inline void set_defaults(pluginplay::ModuleManager& mm) {
mm.change_submod("XYZ File To Molecule", "XYZ to molecule",
"XYZ To Molecule");
}
} // namespace nux
105 changes: 75 additions & 30 deletions src/cxx/nux/xyz_to_mol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

namespace nux {

Expand All @@ -29,47 +28,93 @@ MODULE_CTOR(XYZToMolecule) {
}

MODULE_RUN(XYZToMolecule) {
const auto& [filename] = simde::MoleculeFromString::unwrap_inputs(inputs);

auto& z_from_sym = submods.at("Z from symbol");
auto& atom_from_z = submods.at("Atom from z");
const auto& [xyz_data] = simde::MoleculeFromString::unwrap_inputs(inputs);
auto& z_from_sym = submods.at("Z from symbol");
auto& atom_from_z = submods.at("Atom from z");

std::string line;
chemist::Molecule mol;

std::ifstream xyz_file(filename);

if(!xyz_file) { throw std::runtime_error("File not found: " + filename); }
std::stringstream buffer;

std::string line;
buffer << xyz_data;
if(buffer.str().empty()) {
throw std::runtime_error("File or XYZ data not valid, empty string");
}

// Skips the 1st line of the file, associated with the number of
// atoms in the file, and the 2nd line, the comment line.
std::getline(xyz_file, line);
std::getline(xyz_file, line);
int i = 0;

while(std::getline(xyz_file, line)) {
while(std::getline(buffer, line)) {
i++;
int num_atoms;
if(i == 1) {
try {
num_atoms = std::stoi(line);
} catch(const std::invalid_argument& e) {
throw std::runtime_error("Formatting of XYZ data incorrect");
}
continue;
}
if(i == 2) { continue; }
std::istringstream iss(line);
std::vector<std::string> tokens;
std::string token;
while(std::getline(iss, token, ' ')) {
if(token.size()) { tokens.emplace_back(token); }
std::string atom_string;
double x, y, z;
if(!(iss >> atom_string >> x >> y >> z)) {
throw std::runtime_error("This is not a good coordinate");
}
auto Z = z_from_sym.run_as<simde::ZFromSymbol>(tokens.at(0));
auto x = std::stod(tokens.at(1));
auto y = std::stod(tokens.at(2));
auto z = std::stod(tokens.at(3));

auto atm = atom_from_z.run_as<simde::AtomFromZ>(Z);
atm.x() = x;
atm.y() = y;
atm.z() = z;
mol.push_back(atm);
}

xyz_file.close();
auto Z = z_from_sym.run_as<simde::ZFromSymbol>(atom_string);
auto atom = atom_from_z.run_as<simde::AtomFromZ>(Z);
atom.x() = x;
atom.y() = y;
atom.z() = z;

mol.push_back(atom);

if(!(buffer.peek() == EOF)) {
continue;
} else {
if(mol.size() == num_atoms) {
continue;
} else {
throw std::runtime_error("Incorrect format for XYZ file: "
"Number of atoms and number of atom "
"coordinates do not match");
}
}
}
auto rv = results();
return simde::MoleculeFromString::wrap_results(rv, mol);
}

MODULE_CTOR(XYZFileToMolecule) {
satisfies_property_type<simde::MoleculeFromString>();
add_submodule<simde::MoleculeFromString>("XYZ to molecule");
}

MODULE_RUN(XYZFileToMolecule) {
const auto& [xyz_filename] =
simde::MoleculeFromString::unwrap_inputs(inputs);

auto& xyz_parser = submods.at("XYZ to molecule");

std::ifstream file(xyz_filename);
std::stringstream buffer;
try {
if(file.is_open()) {
buffer << file.rdbuf();
file.close();
} else {
throw std::runtime_error("");
}
} catch(const std::runtime_error& e) {
std::cerr << "File not found: " << xyz_filename << std::endl;
}

chemist::Molecule mol =
xyz_parser.run_as<simde::MoleculeFromString>(buffer.str());

auto rv = results();
return simde::MoleculeFromString::wrap_results(rv, mol);
}
} // namespace nux
31 changes: 28 additions & 3 deletions tests/cxx/unit_tests/xyz_to_mol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,19 @@ TEST_CASE("XYZToMolecule") {
xyz_mod.change_submod("Z from symbol", z_mod);
xyz_mod.change_submod("Atom from z", atom_mod);

SECTION("No XYZ file found") {
SECTION("XYZ File Non-existent") {
std::string file = "file.xyz";
REQUIRE_THROWS_AS(xyz_mod.run_as<simde::MoleculeFromString>(file),
std::runtime_error);
}

SECTION("Full XYZ To Molecule run") {
SECTION("XYZ Data Incorrect") {
std::string data = "2\nComment\nH 0 0 0";
REQUIRE_THROWS_AS(xyz_mod.run_as<simde::MoleculeFromString>(data),
std::runtime_error);
}

SECTION("Full XYZ To Molecule run: File") {
auto atom0{make_atoms(1)};
auto atom1{make_atoms(1)};
atom1.z() = 1;
Expand All @@ -60,12 +66,31 @@ TEST_CASE("XYZToMolecule") {

std::string filename = "h2.xyz";

auto mol = xyz_mod.run_as<simde::MoleculeFromString>(filename);
auto& xyz_file_mod = mm.at("XYZ File to Molecule");
auto mol = xyz_file_mod.run_as<simde::MoleculeFromString>(filename);

remove("h2.xyz");
std::ifstream del_file("h2.xyz");

REQUIRE(mol == test_mol);
REQUIRE(del_file.good() == false);
}

SECTION("Full XYZ To Molecule run: Data") {
auto atom0{make_atoms(1)};
auto atom1{make_atoms(1)};
atom1.z() = 1;

simde::type::molecule test_mol{atom0, atom1};

std::stringstream xyz_data;
xyz_data << "2\n";
xyz_data << "This is a comment!\n";
xyz_data << "H 0 0 0\n";
xyz_data << "H 0 0 1\n";

auto mol = xyz_mod.run_as<simde::MoleculeFromString>(xyz_data.str());

REQUIRE(mol == test_mol);
}
}