Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: xyz file parsing - nAtoms & nLines to check formatting. Created… #52

Open
wants to merge 13 commits into
base: epic/SOF-5386
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 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
30 changes: 30 additions & 0 deletions src/parsers/parsers.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,41 @@
import cif from "./cif";
// eslint-disable-next-line import/no-cycle
import espresso from "./espresso";
import poscar from "./poscar";
// eslint-disable-next-line import/no-cycle
timurbazhirov marked this conversation as resolved.
Show resolved Hide resolved
import xyz from "./xyz";

/**
* Function splits the contents of a string at each newline and returns the resulting array.
* @param fileString
* @returns {Array}
*/
export function getFileStringAsArray(fileString) {
return fileString.split(/\r?\n/);
}

/**
* Function returns the number of atoms in a file using the proper parser function based on the file extension.
* @param {String} fileExtension
* @param {String} fileContent
* @returns {Number}
*/
export function getNumberOfAtomsInFileByExtension(fileExtension, fileContent) {
let numberOfAtoms = 0;
if (fileExtension === "poscar") {
numberOfAtoms = poscar.poscarFileAtomsCount(fileContent);
}
if (fileExtension === "xyz") {
numberOfAtoms = xyz.xyzFileAtomsCount(fileContent);
}
return numberOfAtoms;
}

export default {
xyz,
poscar,
cif,
espresso,
getFileStringAsArray,
getNumberOfAtomsInFileByExtension,
};
4 changes: 2 additions & 2 deletions src/parsers/poscar.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,13 @@ function toPoscar(materialOrConfig, omitConstraints = false) {
* @param poscarFileContent
* @returns {Number}
*/
export function atomsCount(poscarFileContent) {
export function poscarFileAtomsCount(poscarFileContent) {
adewyer marked this conversation as resolved.
Show resolved Hide resolved
const atomsLine = poscarFileContent.split("\n")[6].split(" ");
return atomsLine.map((x) => parseInt(x, 10)).reduce((a, b) => a + b);
}

export default {
toPoscar,
atomicConstraintsCharFromBool,
atomsCount,
poscarFileAtomsCount,
};
31 changes: 31 additions & 0 deletions src/parsers/xyz.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import Integer from "lodash/string";
import _ from "underscore";
import s from "underscore.string";

import { Basis } from "../basis/basis";
import { ConstrainedBasis } from "../basis/constrained_basis";
import { Lattice } from "../lattice/lattice";
// eslint-disable-next-line import/no-cycle
import { defaultMaterialConfig } from "../material";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand your comment above, but we should not be introducing circular dependencies with new code. It's usually a sign of not having a correct placement of the code

import math from "../math";
import { InvalidLineError } from "./errors";
import poscar from "./poscar";
import { CombinatorialBasis } from "./xyz_combinatorial_basis";

// Regular expression for an XYZ line with atomic constraints, eg. Si 0.000000 0.500000 0.446678 1 1 1`
Expand Down Expand Up @@ -140,10 +144,37 @@ function fromMaterial(materialOrConfig, fractional = false) {
return fromBasis(basis, "%11.6f");
}

/**
* Function splits the xyzFile string at new lines and then returns the first element of the array.
* The first line of the XYZ file should contain the number of atoms in the structure.
* @param {String} xyzFile
* @returns {Number}
*/
export function xyzFileAtomsCount(xyzFile) {
return Integer.parseInt(xyzFile.split(/\r?\n/)[0]);
adewyer marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Function converts an XYZ formatted structure as a POSCAR formatted structure
* @param {String} xyzContent
* @returns {String}
*/
export function xyzToPoscar(xyzContent) {
const xyzConfig = defaultMaterialConfig;
const xyzArray = xyzContent.split(/\r?\n/);
const xyzArrayBasisOnly = xyzArray.slice(2, -1);
const xyzBasis = xyzArrayBasisOnly.join("\n");
xyzConfig.basis = toBasisConfig(xyzBasis);
xyzConfig.basis.units = "cartesian";
return poscar.toPoscar(xyzConfig);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The placement of this function seems to be bad at the moment, hence the circular dependency. We should move this functionality to resolve the problem - maybe to top-level of parsers?

}

export default {
validate,
fromMaterial,
toBasisConfig,
fromBasis,
CombinatorialBasis,
xyzFileAtomsCount,
xyzToPoscar,
};
3 changes: 3 additions & 0 deletions tests/enums.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@ export const SiPWSCFInput = readFile(path.join(FIXTURES_DIR, "Si-pwscf.in"));
export const Zr1H23Zr1H1 = readJSONFile(path.join(FIXTURES_DIR, "Zr1H23Zr1H1.json"));
export const Zr1H23Zr1H1Poscar = readFile(path.join(FIXTURES_DIR, "Zr1H23Zr1H1.poscar"));
export const H2O = readFile(path.join(FIXTURES_DIR, "H2O.poscar"));

export const CH4 = readFile(path.join(FIXTURES_DIR, "CH4.xyz"));
export const CH4POSCAR = readFile(path.join(FIXTURES_DIR, "CH4.poscar"));
3 changes: 3 additions & 0 deletions tests/fixtures/CH4.poscar
Git LFS file not shown
3 changes: 3 additions & 0 deletions tests/fixtures/CH4.xyz
Git LFS file not shown
11 changes: 10 additions & 1 deletion tests/parsers/xyz.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { expect } from "chai";

import parsers from "../../src/parsers/parsers";
import { Si } from "../enums";
import { atomsCount, xyzToPoscar } from "../../src/parsers/xyz";
import { CH4, CH4POSCAR, Si } from "../enums";
import { assertDeepAlmostEqual } from "../utils";

describe("Parsers:XYZ", () => {
Expand All @@ -11,4 +14,10 @@ describe("Parsers:XYZ", () => {
"units",
]);
});
it("should return the number of atoms for a molecule in an xyz file", () => {
expect(atomsCount(CH4)).to.be.equal(5);
});
it("should return the xyz file content in poscar file format", () => {
assertDeepAlmostEqual(xyzToPoscar(CH4), CH4POSCAR);
});
});