@mat3ra/made 2026.5.28-0 → 2026.6.11-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/constants.json +13 -0
- package/dist/js/basis/basis.d.ts +7 -4
- package/dist/js/basis/basis.js +30 -13
- package/dist/js/constants/molecule.d.ts +16 -0
- package/dist/js/constants/molecule.js +19 -0
- package/dist/js/lattice/lattice.d.ts +1 -1
- package/dist/js/lattice/lattice.js +5 -2
- package/dist/js/made.d.ts +5 -4
- package/dist/js/made.js +7 -3
- package/dist/js/parsers/parsers.d.ts +0 -1
- package/dist/js/parsers/poscar.d.ts +0 -1
- package/dist/js/parsers/poscar.js +6 -4
- package/package.json +4 -3
- package/src/js/basis/basis.ts +38 -14
- package/src/js/constants/molecule.ts +18 -0
- package/src/js/lattice/lattice.ts +5 -1
- package/src/js/made.ts +12 -3
- package/src/js/parsers/poscar.ts +6 -4
- package/src/py/mat3ra/made/constants.py +11 -0
- package/src/py/mat3ra/made/tools/convert/__init__.py +18 -1
- package/src/py/mat3ra/made/tools/convert/utils.py +33 -6
- package/tests/js/basis/basis.ts +1 -1
- package/tests/js/parsers/poscar.ts +27 -0
- package/tests/py/unit/test_tools_convert.py +36 -4
package/constants.json
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"molecule": {
|
|
3
|
+
"nonPeriodicMinimumLatticeSize": 3.0,
|
|
4
|
+
"diatomicLatticePaddingFactor": 3.0,
|
|
5
|
+
"molecularLatticePaddingFactor": 2.0
|
|
6
|
+
},
|
|
7
|
+
"precision": {
|
|
8
|
+
"coordinatesCrystal": 9,
|
|
9
|
+
"coordinatesCartesian": 6,
|
|
10
|
+
"latticeLengths": 6,
|
|
11
|
+
"latticeAngles": 4
|
|
12
|
+
}
|
|
13
|
+
}
|
package/dist/js/basis/basis.d.ts
CHANGED
|
@@ -147,11 +147,12 @@ export declare class Basis extends InMemoryEntity implements BasisSchema {
|
|
|
147
147
|
*/
|
|
148
148
|
hasEquivalentCellTo(anotherBasisClsInstance: Basis): boolean;
|
|
149
149
|
/**
|
|
150
|
-
* @summary
|
|
151
|
-
*
|
|
152
|
-
*
|
|
150
|
+
* @summary Returns the minimum cubic lattice size for a non-periodic structure.
|
|
151
|
+
* Single-atom structures use the element atomic radius floored at defaultMinimumLatticeSize.
|
|
152
|
+
* Multi-atom structures scale the maximum pairwise distance by 3 when W=min/max pairwise distance
|
|
153
|
+
* is ~1 (diatomic), otherwise by 2.
|
|
153
154
|
*/
|
|
154
|
-
getMinimumLatticeSize(
|
|
155
|
+
getMinimumLatticeSize(defaultMinimumLatticeSize?: number): number;
|
|
155
156
|
/**
|
|
156
157
|
* @summary function returns an array of overlapping atoms within specified tolerance.
|
|
157
158
|
*/
|
|
@@ -172,6 +173,8 @@ export declare class Basis extends InMemoryEntity implements BasisSchema {
|
|
|
172
173
|
*
|
|
173
174
|
*/
|
|
174
175
|
get maxPairwiseDistance(): number;
|
|
176
|
+
get minPairwiseDistance(): number;
|
|
177
|
+
getPairwiseDistanceExtremum(extremum: "max" | "min"): number;
|
|
175
178
|
/**
|
|
176
179
|
* @summary Function takes basis coordinates and transposes them so that the values for each dimension of the
|
|
177
180
|
* the basis are in their own nested array.
|
package/dist/js/basis/basis.js
CHANGED
|
@@ -366,19 +366,25 @@ class Basis extends entity_1.InMemoryEntity {
|
|
|
366
366
|
.some((x) => !x);
|
|
367
367
|
}
|
|
368
368
|
/**
|
|
369
|
-
* @summary
|
|
370
|
-
*
|
|
371
|
-
*
|
|
369
|
+
* @summary Returns the minimum cubic lattice size for a non-periodic structure.
|
|
370
|
+
* Single-atom structures use the element atomic radius floored at defaultMinimumLatticeSize.
|
|
371
|
+
* Multi-atom structures scale the maximum pairwise distance by 3 when W=min/max pairwise distance
|
|
372
|
+
* is ~1 (diatomic), otherwise by 2.
|
|
372
373
|
*/
|
|
373
|
-
getMinimumLatticeSize(
|
|
374
|
-
let latticeSizeAdditiveContribution = 0;
|
|
374
|
+
getMinimumLatticeSize(defaultMinimumLatticeSize = lattice_1.defaultNonPeriodicMinimumLatticeSize) {
|
|
375
375
|
if (this._elements.values.length === 1) {
|
|
376
376
|
const elementSymbol = this._elements.getElementValueByIndex(0);
|
|
377
|
-
|
|
377
|
+
const atomicRadius = (0, periodic_table_js_1.getElementAtomicRadius)(elementSymbol);
|
|
378
|
+
return Math.max(defaultMinimumLatticeSize, atomicRadius);
|
|
378
379
|
}
|
|
379
|
-
const
|
|
380
|
-
const
|
|
381
|
-
|
|
380
|
+
const maxDistance = this.maxPairwiseDistance;
|
|
381
|
+
const minDistance = this.minPairwiseDistance;
|
|
382
|
+
const widthRatio = maxDistance > 0 ? minDistance / maxDistance : 1;
|
|
383
|
+
const latticeScalingFactor = math_1.math.almostEqual(widthRatio, 1)
|
|
384
|
+
? lattice_1.diatomicLatticePaddingFactor
|
|
385
|
+
: lattice_1.molecularLatticePaddingFactor;
|
|
386
|
+
const moleculeLatticeSize = maxDistance * latticeScalingFactor;
|
|
387
|
+
return Math.max(defaultMinimumLatticeSize, moleculeLatticeSize);
|
|
382
388
|
}
|
|
383
389
|
/**
|
|
384
390
|
* @summary function returns an array of overlapping atoms within specified tolerance.
|
|
@@ -428,22 +434,33 @@ class Basis extends entity_1.InMemoryEntity {
|
|
|
428
434
|
*
|
|
429
435
|
*/
|
|
430
436
|
get maxPairwiseDistance() {
|
|
437
|
+
return this.getPairwiseDistanceExtremum("max");
|
|
438
|
+
}
|
|
439
|
+
get minPairwiseDistance() {
|
|
440
|
+
return this.getPairwiseDistanceExtremum("min");
|
|
441
|
+
}
|
|
442
|
+
getPairwiseDistanceExtremum(extremum) {
|
|
431
443
|
const originalUnits = this.units;
|
|
432
444
|
this.toCartesian();
|
|
433
|
-
let
|
|
445
|
+
let resultDistance = extremum === "max" ? 0 : Infinity;
|
|
434
446
|
if (this._elements.values.length >= 2) {
|
|
435
447
|
for (let i = 0; i < this._elements.values.length; i++) {
|
|
436
448
|
for (let j = i + 1; j < this._elements.values.length; j++) {
|
|
437
449
|
const distance = math_1.math.vDist(this._coordinates.getElementValueByIndex(i), this._coordinates.getElementValueByIndex(j));
|
|
438
|
-
if (distance
|
|
439
|
-
|
|
450
|
+
if (!distance)
|
|
451
|
+
continue;
|
|
452
|
+
if (extremum === "max" && distance > resultDistance) {
|
|
453
|
+
resultDistance = distance;
|
|
454
|
+
}
|
|
455
|
+
if (extremum === "min" && distance < resultDistance) {
|
|
456
|
+
resultDistance = distance;
|
|
440
457
|
}
|
|
441
458
|
}
|
|
442
459
|
}
|
|
443
460
|
}
|
|
444
461
|
if (originalUnits !== constants_1.ATOMIC_COORD_UNITS.cartesian)
|
|
445
462
|
this.toCrystal();
|
|
446
|
-
return
|
|
463
|
+
return extremum === "min" && resultDistance === Infinity ? 0 : resultDistance;
|
|
447
464
|
}
|
|
448
465
|
/**
|
|
449
466
|
* @summary Function takes basis coordinates and transposes them so that the values for each dimension of the
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants for molecule handling and precision.
|
|
3
|
+
* Source of truth: /constants.json at repository root
|
|
4
|
+
*
|
|
5
|
+
* These values are duplicated here for TypeScript compilation.
|
|
6
|
+
* When updating these, also update constants.json.
|
|
7
|
+
*/
|
|
8
|
+
export declare const defaultNonPeriodicMinimumLatticeSize = 3;
|
|
9
|
+
export declare const diatomicLatticePaddingFactor = 3;
|
|
10
|
+
export declare const molecularLatticePaddingFactor = 2;
|
|
11
|
+
export declare const PRECISION_MAP: {
|
|
12
|
+
coordinatesCrystal: number;
|
|
13
|
+
coordinatesCartesian: number;
|
|
14
|
+
latticeLengths: number;
|
|
15
|
+
latticeAngles: number;
|
|
16
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Constants for molecule handling and precision.
|
|
4
|
+
* Source of truth: /constants.json at repository root
|
|
5
|
+
*
|
|
6
|
+
* These values are duplicated here for TypeScript compilation.
|
|
7
|
+
* When updating these, also update constants.json.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.PRECISION_MAP = exports.molecularLatticePaddingFactor = exports.diatomicLatticePaddingFactor = exports.defaultNonPeriodicMinimumLatticeSize = void 0;
|
|
11
|
+
exports.defaultNonPeriodicMinimumLatticeSize = 3.0;
|
|
12
|
+
exports.diatomicLatticePaddingFactor = 3.0;
|
|
13
|
+
exports.molecularLatticePaddingFactor = 2.0;
|
|
14
|
+
exports.PRECISION_MAP = {
|
|
15
|
+
coordinatesCrystal: 9,
|
|
16
|
+
coordinatesCartesian: 6,
|
|
17
|
+
latticeLengths: 6,
|
|
18
|
+
latticeAngles: 4,
|
|
19
|
+
};
|
|
@@ -6,7 +6,7 @@ import { UnitCell } from "./unit_cell";
|
|
|
6
6
|
* Scaling factor used to calculate the new lattice size for non-periodic systems.
|
|
7
7
|
* The scaling factor ensures that a non-periodic structure will have have a lattice greater than the structures size.
|
|
8
8
|
*/
|
|
9
|
-
export
|
|
9
|
+
export { defaultNonPeriodicMinimumLatticeSize, diatomicLatticePaddingFactor, molecularLatticePaddingFactor, } from "../constants/molecule";
|
|
10
10
|
export declare class LatticeVectors extends Cell implements LatticeVectorsSchema {
|
|
11
11
|
}
|
|
12
12
|
export type { LatticeVectorsSchema };
|
|
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.Lattice = exports.LatticeVectors = exports.
|
|
26
|
+
exports.Lattice = exports.LatticeVectors = exports.molecularLatticePaddingFactor = exports.diatomicLatticePaddingFactor = exports.defaultNonPeriodicMinimumLatticeSize = void 0;
|
|
27
27
|
const constants_1 = require("@mat3ra/code/dist/js/constants");
|
|
28
28
|
const entity_1 = require("@mat3ra/code/dist/js/entity");
|
|
29
29
|
const math_1 = require("@mat3ra/code/dist/js/math");
|
|
@@ -36,7 +36,10 @@ const unit_cell_1 = require("./unit_cell");
|
|
|
36
36
|
* Scaling factor used to calculate the new lattice size for non-periodic systems.
|
|
37
37
|
* The scaling factor ensures that a non-periodic structure will have have a lattice greater than the structures size.
|
|
38
38
|
*/
|
|
39
|
-
|
|
39
|
+
var molecule_1 = require("../constants/molecule");
|
|
40
|
+
Object.defineProperty(exports, "defaultNonPeriodicMinimumLatticeSize", { enumerable: true, get: function () { return molecule_1.defaultNonPeriodicMinimumLatticeSize; } });
|
|
41
|
+
Object.defineProperty(exports, "diatomicLatticePaddingFactor", { enumerable: true, get: function () { return molecule_1.diatomicLatticePaddingFactor; } });
|
|
42
|
+
Object.defineProperty(exports, "molecularLatticePaddingFactor", { enumerable: true, get: function () { return molecule_1.molecularLatticePaddingFactor; } });
|
|
40
43
|
class LatticeVectors extends cell_1.Cell {
|
|
41
44
|
}
|
|
42
45
|
exports.LatticeVectors = LatticeVectors;
|
package/dist/js/made.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Basis } from "./basis/basis";
|
|
|
2
2
|
import { Cell } from "./cell/cell";
|
|
3
3
|
import { ATOMIC_COORD_UNITS, coefficients, tolerance, units } from "./constants";
|
|
4
4
|
import { AtomicConstraints } from "./constraints/constraints";
|
|
5
|
-
import { Lattice,
|
|
5
|
+
import { Lattice, defaultNonPeriodicMinimumLatticeSize, diatomicLatticePaddingFactor, molecularLatticePaddingFactor } from "./lattice/lattice";
|
|
6
6
|
import { DEFAULT_LATTICE_UNITS, LATTICE_TYPE_CONFIGS } from "./lattice/lattice_types";
|
|
7
7
|
import { ReciprocalLattice } from "./lattice/reciprocal/lattice_reciprocal";
|
|
8
8
|
import { UnitCell } from "./lattice/unit_cell";
|
|
@@ -37,7 +37,9 @@ export declare const Made: {
|
|
|
37
37
|
Lattice: typeof Lattice;
|
|
38
38
|
Cell: typeof Cell;
|
|
39
39
|
UnitCell: typeof UnitCell;
|
|
40
|
-
|
|
40
|
+
defaultNonPeriodicMinimumLatticeSize: number;
|
|
41
|
+
diatomicLatticePaddingFactor: number;
|
|
42
|
+
molecularLatticePaddingFactor: number;
|
|
41
43
|
ReciprocalLattice: typeof ReciprocalLattice;
|
|
42
44
|
Basis: typeof Basis;
|
|
43
45
|
AtomicConstraints: typeof AtomicConstraints;
|
|
@@ -54,7 +56,6 @@ export declare const Made: {
|
|
|
54
56
|
toPoscar: (materialOrConfig: import("@mat3ra/esse/dist/js/types").MaterialSchema, omitConstraints?: boolean) => string;
|
|
55
57
|
fromPoscar: (fileContent: string) => object;
|
|
56
58
|
atomicConstraintsCharFromBool: (bool: boolean) => string;
|
|
57
|
-
atomsCount: typeof import("./parsers/poscar").atomsCount;
|
|
58
59
|
};
|
|
59
60
|
cif: {
|
|
60
61
|
parseMeta: (txt: string) => import("./parsers/cif").Meta;
|
|
@@ -99,4 +100,4 @@ export declare const Made: {
|
|
|
99
100
|
};
|
|
100
101
|
};
|
|
101
102
|
};
|
|
102
|
-
export { coefficients, tolerance, units, ATOMIC_COORD_UNITS, Material, defaultMaterialConfig, Lattice, Cell, UnitCell,
|
|
103
|
+
export { coefficients, tolerance, units, ATOMIC_COORD_UNITS, Material, defaultMaterialConfig, Lattice, Cell, UnitCell, defaultNonPeriodicMinimumLatticeSize, diatomicLatticePaddingFactor, molecularLatticePaddingFactor, ReciprocalLattice, Basis, AtomicConstraints, parsers, tools, LATTICE_TYPE_CONFIGS, DEFAULT_LATTICE_UNITS, };
|
package/dist/js/made.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.DEFAULT_LATTICE_UNITS = exports.LATTICE_TYPE_CONFIGS = exports.tools = exports.parsers = exports.AtomicConstraints = exports.Basis = exports.ReciprocalLattice = exports.
|
|
6
|
+
exports.DEFAULT_LATTICE_UNITS = exports.LATTICE_TYPE_CONFIGS = exports.tools = exports.parsers = exports.AtomicConstraints = exports.Basis = exports.ReciprocalLattice = exports.molecularLatticePaddingFactor = exports.diatomicLatticePaddingFactor = exports.defaultNonPeriodicMinimumLatticeSize = exports.UnitCell = exports.Cell = exports.Lattice = exports.defaultMaterialConfig = exports.Material = exports.ATOMIC_COORD_UNITS = exports.units = exports.tolerance = exports.coefficients = exports.Made = void 0;
|
|
7
7
|
const basis_1 = require("./basis/basis");
|
|
8
8
|
Object.defineProperty(exports, "Basis", { enumerable: true, get: function () { return basis_1.Basis; } });
|
|
9
9
|
const cell_1 = require("./cell/cell");
|
|
@@ -17,7 +17,9 @@ const constraints_1 = require("./constraints/constraints");
|
|
|
17
17
|
Object.defineProperty(exports, "AtomicConstraints", { enumerable: true, get: function () { return constraints_1.AtomicConstraints; } });
|
|
18
18
|
const lattice_1 = require("./lattice/lattice");
|
|
19
19
|
Object.defineProperty(exports, "Lattice", { enumerable: true, get: function () { return lattice_1.Lattice; } });
|
|
20
|
-
Object.defineProperty(exports, "
|
|
20
|
+
Object.defineProperty(exports, "defaultNonPeriodicMinimumLatticeSize", { enumerable: true, get: function () { return lattice_1.defaultNonPeriodicMinimumLatticeSize; } });
|
|
21
|
+
Object.defineProperty(exports, "diatomicLatticePaddingFactor", { enumerable: true, get: function () { return lattice_1.diatomicLatticePaddingFactor; } });
|
|
22
|
+
Object.defineProperty(exports, "molecularLatticePaddingFactor", { enumerable: true, get: function () { return lattice_1.molecularLatticePaddingFactor; } });
|
|
21
23
|
const lattice_types_1 = require("./lattice/lattice_types");
|
|
22
24
|
Object.defineProperty(exports, "DEFAULT_LATTICE_UNITS", { enumerable: true, get: function () { return lattice_types_1.DEFAULT_LATTICE_UNITS; } });
|
|
23
25
|
Object.defineProperty(exports, "LATTICE_TYPE_CONFIGS", { enumerable: true, get: function () { return lattice_types_1.LATTICE_TYPE_CONFIGS; } });
|
|
@@ -42,7 +44,9 @@ exports.Made = {
|
|
|
42
44
|
Lattice: lattice_1.Lattice,
|
|
43
45
|
Cell: cell_1.Cell,
|
|
44
46
|
UnitCell: unit_cell_1.UnitCell,
|
|
45
|
-
|
|
47
|
+
defaultNonPeriodicMinimumLatticeSize: lattice_1.defaultNonPeriodicMinimumLatticeSize,
|
|
48
|
+
diatomicLatticePaddingFactor: lattice_1.diatomicLatticePaddingFactor,
|
|
49
|
+
molecularLatticePaddingFactor: lattice_1.molecularLatticePaddingFactor,
|
|
46
50
|
ReciprocalLattice: lattice_reciprocal_1.ReciprocalLattice,
|
|
47
51
|
Basis: basis_1.Basis,
|
|
48
52
|
AtomicConstraints: constraints_1.AtomicConstraints,
|
|
@@ -11,7 +11,6 @@ declare const _default: {
|
|
|
11
11
|
toPoscar: (materialOrConfig: import("@mat3ra/esse/dist/js/types").MaterialSchema, omitConstraints?: boolean) => string;
|
|
12
12
|
fromPoscar: (fileContent: string) => object;
|
|
13
13
|
atomicConstraintsCharFromBool: (bool: boolean) => string;
|
|
14
|
-
atomsCount: typeof import("./poscar").atomsCount;
|
|
15
14
|
};
|
|
16
15
|
cif: {
|
|
17
16
|
parseMeta: (txt: string) => import("./cif").Meta;
|
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.atomsCount = void 0;
|
|
7
7
|
const math_1 = require("@mat3ra/code/dist/js/math");
|
|
8
|
+
const utils_1 = require("@mat3ra/utils");
|
|
8
9
|
const underscore_string_1 = __importDefault(require("underscore.string"));
|
|
9
10
|
const constrained_basis_1 = require("../basis/constrained_basis");
|
|
10
11
|
const cell_1 = require("../cell/cell");
|
|
@@ -58,7 +59,8 @@ function toPoscar(materialOrConfig, omitConstraints = false) {
|
|
|
58
59
|
* Poscar file formatting: https://www.vasp.at/wiki/index.php/POSCAR
|
|
59
60
|
*/
|
|
60
61
|
function atomsCount(poscarFileContent) {
|
|
61
|
-
const
|
|
62
|
+
const lines = utils_1.Utils.str.removeCommentsFromSourceCode(poscarFileContent).split("\n");
|
|
63
|
+
const atomsLine = lines[6].split(/\s+/);
|
|
62
64
|
return atomsLine.map((x) => parseInt(x, 10)).reduce((a, b) => a + b);
|
|
63
65
|
}
|
|
64
66
|
exports.atomsCount = atomsCount;
|
|
@@ -68,7 +70,8 @@ exports.atomsCount = atomsCount;
|
|
|
68
70
|
* @return Material config.
|
|
69
71
|
*/
|
|
70
72
|
function fromPoscar(fileContent) {
|
|
71
|
-
const
|
|
73
|
+
const cleanContent = utils_1.Utils.str.removeCommentsFromSourceCode(fileContent, "fortran");
|
|
74
|
+
const lines = cleanContent.split("\n");
|
|
72
75
|
const comment = lines[0];
|
|
73
76
|
// TODO: alat should be handled!!!!
|
|
74
77
|
// const latticeConstant = parseFloat(lines[1].trim());
|
|
@@ -143,7 +146,7 @@ function fromPoscar(fileContent) {
|
|
|
143
146
|
* @param text - string to check
|
|
144
147
|
*/
|
|
145
148
|
function isPoscar(text) {
|
|
146
|
-
const lines = text.split("\n");
|
|
149
|
+
const lines = utils_1.Utils.str.removeCommentsFromSourceCode(text, "fortran").split("\n");
|
|
147
150
|
// Checking number of lines, minimum requirement for POSCAR
|
|
148
151
|
if (lines.length < 7) {
|
|
149
152
|
return false;
|
|
@@ -178,5 +181,4 @@ exports.default = {
|
|
|
178
181
|
toPoscar,
|
|
179
182
|
fromPoscar,
|
|
180
183
|
atomicConstraintsCharFromBool,
|
|
181
|
-
atomsCount,
|
|
182
184
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mat3ra/made",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.6.11-0",
|
|
4
4
|
"description": "MAterials DEsign library",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"lint": "eslint --cache src/js tests/js && prettier --write src/js tests/js",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"@mat3ra/code": "2026.5.27-0",
|
|
38
38
|
"@mat3ra/esse": "2026.5.27-0",
|
|
39
39
|
"@mat3ra/tsconfig": "2024.6.3-0",
|
|
40
|
-
"@mat3ra/utils": "
|
|
40
|
+
"@mat3ra/utils": "^2026.6.11-0",
|
|
41
41
|
"@types/crypto-js": "^4.2.2",
|
|
42
42
|
"@typescript-eslint/eslint-plugin": "^5.9.1",
|
|
43
43
|
"@typescript-eslint/parser": "^5.9.1",
|
|
@@ -79,7 +79,8 @@
|
|
|
79
79
|
},
|
|
80
80
|
"peerDependencies": {
|
|
81
81
|
"@mat3ra/code": "*",
|
|
82
|
-
"@mat3ra/esse": "*"
|
|
82
|
+
"@mat3ra/esse": "*",
|
|
83
|
+
"@mat3ra/utils": "*"
|
|
83
84
|
},
|
|
84
85
|
"lint-staged": {
|
|
85
86
|
"*.js": "eslint --cache --fix",
|
package/src/js/basis/basis.ts
CHANGED
|
@@ -7,7 +7,11 @@ import { chain, toPairs, uniq, values } from "lodash";
|
|
|
7
7
|
|
|
8
8
|
import { Cell } from "../cell/cell";
|
|
9
9
|
import { ATOMIC_COORD_UNITS, HASH_TOLERANCE } from "../constants";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
defaultNonPeriodicMinimumLatticeSize,
|
|
12
|
+
diatomicLatticePaddingFactor,
|
|
13
|
+
molecularLatticePaddingFactor,
|
|
14
|
+
} from "../lattice/lattice";
|
|
11
15
|
import { AtomicCoordinateValue, Coordinates } from "./coordinates";
|
|
12
16
|
import { AtomicElementValue, Elements } from "./elements";
|
|
13
17
|
import { AtomicLabelValue, Labels } from "./labels";
|
|
@@ -476,19 +480,27 @@ export class Basis extends InMemoryEntity implements BasisSchema {
|
|
|
476
480
|
}
|
|
477
481
|
|
|
478
482
|
/**
|
|
479
|
-
* @summary
|
|
480
|
-
*
|
|
481
|
-
*
|
|
483
|
+
* @summary Returns the minimum cubic lattice size for a non-periodic structure.
|
|
484
|
+
* Single-atom structures use the element atomic radius floored at defaultMinimumLatticeSize.
|
|
485
|
+
* Multi-atom structures scale the maximum pairwise distance by 3 when W=min/max pairwise distance
|
|
486
|
+
* is ~1 (diatomic), otherwise by 2.
|
|
482
487
|
*/
|
|
483
|
-
getMinimumLatticeSize(
|
|
484
|
-
|
|
488
|
+
getMinimumLatticeSize(
|
|
489
|
+
defaultMinimumLatticeSize = defaultNonPeriodicMinimumLatticeSize,
|
|
490
|
+
): number {
|
|
485
491
|
if (this._elements.values.length === 1) {
|
|
486
492
|
const elementSymbol = this._elements.getElementValueByIndex(0);
|
|
487
|
-
|
|
493
|
+
const atomicRadius = getElementAtomicRadius(elementSymbol);
|
|
494
|
+
return Math.max(defaultMinimumLatticeSize, atomicRadius);
|
|
488
495
|
}
|
|
489
|
-
const
|
|
490
|
-
const
|
|
491
|
-
|
|
496
|
+
const maxDistance = this.maxPairwiseDistance;
|
|
497
|
+
const minDistance = this.minPairwiseDistance;
|
|
498
|
+
const widthRatio = maxDistance > 0 ? minDistance / maxDistance : 1;
|
|
499
|
+
const latticeScalingFactor = math.almostEqual(widthRatio, 1)
|
|
500
|
+
? diatomicLatticePaddingFactor
|
|
501
|
+
: molecularLatticePaddingFactor;
|
|
502
|
+
const moleculeLatticeSize = maxDistance * latticeScalingFactor;
|
|
503
|
+
return Math.max(defaultMinimumLatticeSize, moleculeLatticeSize);
|
|
492
504
|
}
|
|
493
505
|
|
|
494
506
|
/**
|
|
@@ -545,9 +557,17 @@ export class Basis extends InMemoryEntity implements BasisSchema {
|
|
|
545
557
|
*
|
|
546
558
|
*/
|
|
547
559
|
get maxPairwiseDistance(): number {
|
|
560
|
+
return this.getPairwiseDistanceExtremum("max");
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
get minPairwiseDistance(): number {
|
|
564
|
+
return this.getPairwiseDistanceExtremum("min");
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
getPairwiseDistanceExtremum(extremum: "max" | "min"): number {
|
|
548
568
|
const originalUnits = this.units;
|
|
549
569
|
this.toCartesian();
|
|
550
|
-
let
|
|
570
|
+
let resultDistance = extremum === "max" ? 0 : Infinity;
|
|
551
571
|
if (this._elements.values.length >= 2) {
|
|
552
572
|
for (let i = 0; i < this._elements.values.length; i++) {
|
|
553
573
|
for (let j = i + 1; j < this._elements.values.length; j++) {
|
|
@@ -555,14 +575,18 @@ export class Basis extends InMemoryEntity implements BasisSchema {
|
|
|
555
575
|
this._coordinates.getElementValueByIndex(i) as Coordinate3DSchema,
|
|
556
576
|
this._coordinates.getElementValueByIndex(j) as Coordinate3DSchema,
|
|
557
577
|
);
|
|
558
|
-
if (distance
|
|
559
|
-
|
|
578
|
+
if (!distance) continue;
|
|
579
|
+
if (extremum === "max" && distance > resultDistance) {
|
|
580
|
+
resultDistance = distance;
|
|
581
|
+
}
|
|
582
|
+
if (extremum === "min" && distance < resultDistance) {
|
|
583
|
+
resultDistance = distance;
|
|
560
584
|
}
|
|
561
585
|
}
|
|
562
586
|
}
|
|
563
587
|
}
|
|
564
588
|
if (originalUnits !== ATOMIC_COORD_UNITS.cartesian) this.toCrystal();
|
|
565
|
-
return
|
|
589
|
+
return extremum === "min" && resultDistance === Infinity ? 0 : resultDistance;
|
|
566
590
|
}
|
|
567
591
|
|
|
568
592
|
/**
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants for molecule handling and precision.
|
|
3
|
+
* Source of truth: /constants.json at repository root
|
|
4
|
+
*
|
|
5
|
+
* These values are duplicated here for TypeScript compilation.
|
|
6
|
+
* When updating these, also update constants.json.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export const defaultNonPeriodicMinimumLatticeSize = 3.0;
|
|
10
|
+
export const diatomicLatticePaddingFactor = 3.0;
|
|
11
|
+
export const molecularLatticePaddingFactor = 2.0;
|
|
12
|
+
|
|
13
|
+
export const PRECISION_MAP = {
|
|
14
|
+
coordinatesCrystal: 9,
|
|
15
|
+
coordinatesCartesian: 6,
|
|
16
|
+
latticeLengths: 6,
|
|
17
|
+
latticeAngles: 4,
|
|
18
|
+
};
|
|
@@ -20,7 +20,11 @@ import { UnitCell, UnitCellProps } from "./unit_cell";
|
|
|
20
20
|
* Scaling factor used to calculate the new lattice size for non-periodic systems.
|
|
21
21
|
* The scaling factor ensures that a non-periodic structure will have have a lattice greater than the structures size.
|
|
22
22
|
*/
|
|
23
|
-
export
|
|
23
|
+
export {
|
|
24
|
+
defaultNonPeriodicMinimumLatticeSize,
|
|
25
|
+
diatomicLatticePaddingFactor,
|
|
26
|
+
molecularLatticePaddingFactor,
|
|
27
|
+
} from "../constants/molecule";
|
|
24
28
|
|
|
25
29
|
export class LatticeVectors extends Cell implements LatticeVectorsSchema {}
|
|
26
30
|
|
package/src/js/made.ts
CHANGED
|
@@ -2,7 +2,12 @@ import { Basis } from "./basis/basis";
|
|
|
2
2
|
import { Cell } from "./cell/cell";
|
|
3
3
|
import { ATOMIC_COORD_UNITS, coefficients, tolerance, units } from "./constants";
|
|
4
4
|
import { AtomicConstraints } from "./constraints/constraints";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
Lattice,
|
|
7
|
+
defaultNonPeriodicMinimumLatticeSize,
|
|
8
|
+
diatomicLatticePaddingFactor,
|
|
9
|
+
molecularLatticePaddingFactor,
|
|
10
|
+
} from "./lattice/lattice";
|
|
6
11
|
import { DEFAULT_LATTICE_UNITS, LATTICE_TYPE_CONFIGS } from "./lattice/lattice_types";
|
|
7
12
|
import { ReciprocalLattice } from "./lattice/reciprocal/lattice_reciprocal";
|
|
8
13
|
import { UnitCell } from "./lattice/unit_cell";
|
|
@@ -21,7 +26,9 @@ export const Made = {
|
|
|
21
26
|
Lattice,
|
|
22
27
|
Cell,
|
|
23
28
|
UnitCell,
|
|
24
|
-
|
|
29
|
+
defaultNonPeriodicMinimumLatticeSize,
|
|
30
|
+
diatomicLatticePaddingFactor,
|
|
31
|
+
molecularLatticePaddingFactor,
|
|
25
32
|
ReciprocalLattice,
|
|
26
33
|
Basis,
|
|
27
34
|
AtomicConstraints,
|
|
@@ -42,7 +49,9 @@ export {
|
|
|
42
49
|
Lattice,
|
|
43
50
|
Cell,
|
|
44
51
|
UnitCell,
|
|
45
|
-
|
|
52
|
+
defaultNonPeriodicMinimumLatticeSize,
|
|
53
|
+
diatomicLatticePaddingFactor,
|
|
54
|
+
molecularLatticePaddingFactor,
|
|
46
55
|
ReciprocalLattice,
|
|
47
56
|
Basis,
|
|
48
57
|
AtomicConstraints,
|
package/src/js/parsers/poscar.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
MaterialSchema,
|
|
6
6
|
Vector3DSchema,
|
|
7
7
|
} from "@mat3ra/esse/dist/js/types";
|
|
8
|
+
import { Utils } from "@mat3ra/utils";
|
|
8
9
|
import s from "underscore.string";
|
|
9
10
|
|
|
10
11
|
import { ConstrainedBasis } from "../basis/constrained_basis";
|
|
@@ -67,7 +68,8 @@ function toPoscar(materialOrConfig: MaterialSchema, omitConstraints = false): st
|
|
|
67
68
|
* Poscar file formatting: https://www.vasp.at/wiki/index.php/POSCAR
|
|
68
69
|
*/
|
|
69
70
|
export function atomsCount(poscarFileContent: string): number {
|
|
70
|
-
const
|
|
71
|
+
const lines = Utils.str.removeCommentsFromSourceCode(poscarFileContent).split("\n");
|
|
72
|
+
const atomsLine = lines[6].split(/\s+/);
|
|
71
73
|
return atomsLine.map((x) => parseInt(x, 10)).reduce((a, b) => a + b);
|
|
72
74
|
}
|
|
73
75
|
|
|
@@ -77,7 +79,8 @@ export function atomsCount(poscarFileContent: string): number {
|
|
|
77
79
|
* @return Material config.
|
|
78
80
|
*/
|
|
79
81
|
function fromPoscar(fileContent: string): object {
|
|
80
|
-
const
|
|
82
|
+
const cleanContent = Utils.str.removeCommentsFromSourceCode(fileContent, "fortran");
|
|
83
|
+
const lines = cleanContent.split("\n");
|
|
81
84
|
|
|
82
85
|
const comment = lines[0];
|
|
83
86
|
// TODO: alat should be handled!!!!
|
|
@@ -163,7 +166,7 @@ function fromPoscar(fileContent: string): object {
|
|
|
163
166
|
* @param text - string to check
|
|
164
167
|
*/
|
|
165
168
|
function isPoscar(text: string): boolean {
|
|
166
|
-
const lines = text.split("\n");
|
|
169
|
+
const lines = Utils.str.removeCommentsFromSourceCode(text, "fortran").split("\n");
|
|
167
170
|
|
|
168
171
|
// Checking number of lines, minimum requirement for POSCAR
|
|
169
172
|
if (lines.length < 7) {
|
|
@@ -205,5 +208,4 @@ export default {
|
|
|
205
208
|
toPoscar,
|
|
206
209
|
fromPoscar,
|
|
207
210
|
atomicConstraintsCharFromBool,
|
|
208
|
-
atomsCount,
|
|
209
211
|
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
_CONSTANTS_FILE = os.path.join(os.path.dirname(__file__), "../../../../constants.json")
|
|
5
|
+
with open(_CONSTANTS_FILE) as f:
|
|
6
|
+
_CONSTANTS = json.load(f)
|
|
7
|
+
|
|
8
|
+
DEFAULT_NON_PERIODIC_MIN_LATTICE_SIZE = _CONSTANTS["molecule"]["nonPeriodicMinimumLatticeSize"]
|
|
9
|
+
DIATOMIC_LATTICE_PADDING_FACTOR = _CONSTANTS["molecule"]["diatomicLatticePaddingFactor"]
|
|
10
|
+
MOLECULAR_LATTICE_PADDING_FACTOR = _CONSTANTS["molecule"]["molecularLatticePaddingFactor"]
|
|
11
|
+
PRECISION_MAP = _CONSTANTS["precision"]
|
|
@@ -2,6 +2,7 @@ import inspect
|
|
|
2
2
|
from functools import wraps
|
|
3
3
|
from typing import Any, Callable, Dict, Union
|
|
4
4
|
|
|
5
|
+
from mat3ra.utils import remove_comments_from_source_code
|
|
5
6
|
from mat3ra.utils.mixins import RoundNumericValuesMixin
|
|
6
7
|
|
|
7
8
|
from mat3ra.made.material import Material
|
|
@@ -151,6 +152,10 @@ def to_poscar(material_or_material_data: Union[Material, Dict[str, Any]]) -> str
|
|
|
151
152
|
return poscar.get_str()
|
|
152
153
|
|
|
153
154
|
|
|
155
|
+
def clean_qe_input(poscar):
|
|
156
|
+
return remove_comments_from_source_code(remove_comments_from_source_code(poscar, "fortran"), "python")
|
|
157
|
+
|
|
158
|
+
|
|
154
159
|
def from_poscar(poscar: str) -> Dict[str, Any]:
|
|
155
160
|
"""
|
|
156
161
|
Converts a POSCAR string to a material object in ESSE format.
|
|
@@ -161,10 +166,22 @@ def from_poscar(poscar: str) -> Dict[str, Any]:
|
|
|
161
166
|
Returns:
|
|
162
167
|
dict: A dictionary containing the material information in ESSE format.
|
|
163
168
|
"""
|
|
164
|
-
|
|
169
|
+
poscar_clean = clean_qe_input(poscar)
|
|
170
|
+
structure = PymatgenStructure.from_str(poscar_clean, "poscar")
|
|
165
171
|
return from_pymatgen(structure)
|
|
166
172
|
|
|
167
173
|
|
|
174
|
+
def from_poscar_molecule(poscar: str) -> Dict[str, Any]:
|
|
175
|
+
"""
|
|
176
|
+
Converts a molecule POSCAR string to a non-periodic ESSE material.
|
|
177
|
+
"""
|
|
178
|
+
poscar_clean = clean_qe_input(poscar)
|
|
179
|
+
structure = PymatgenStructure.from_str(poscar_clean, "poscar")
|
|
180
|
+
ase_atoms = PymatgenAseAtomsAdaptor.get_atoms(structure)
|
|
181
|
+
ase_atoms.set_pbc(False)
|
|
182
|
+
return from_ase(ase_atoms)
|
|
183
|
+
|
|
184
|
+
|
|
168
185
|
def to_ase(material_or_material_data: Union[Material, Dict[str, Any]]) -> ASEAtoms:
|
|
169
186
|
"""
|
|
170
187
|
Converts material object in ESSE format to an ASE Atoms object.
|
|
@@ -2,12 +2,39 @@ import json
|
|
|
2
2
|
from typing import Any, Dict, List, Union
|
|
3
3
|
|
|
4
4
|
import numpy as np
|
|
5
|
+
from mat3ra.made.constants import (
|
|
6
|
+
DEFAULT_NON_PERIODIC_MIN_LATTICE_SIZE,
|
|
7
|
+
DIATOMIC_LATTICE_PADDING_FACTOR,
|
|
8
|
+
MOLECULAR_LATTICE_PADDING_FACTOR,
|
|
9
|
+
)
|
|
10
|
+
from mat3ra.made.utils import get_center_of_coordinates, map_array_to_array_with_id_value
|
|
5
11
|
from mat3ra.utils.object import NumpyNDArrayRoundEncoder
|
|
6
12
|
from scipy.spatial.distance import pdist
|
|
7
13
|
|
|
8
|
-
from mat3ra.made.utils import map_array_to_array_with_id_value, get_center_of_coordinates
|
|
9
|
-
from .interface_parts_enum import INTERFACE_LABELS_MAP
|
|
10
14
|
from ..third_party import ASEAtoms, PymatgenInterface, PymatgenStructure
|
|
15
|
+
from .interface_parts_enum import INTERFACE_LABELS_MAP
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _get_non_periodic_lattice_padding_factor(max_distance: float, min_distance: float) -> float:
|
|
19
|
+
if max_distance <= 0:
|
|
20
|
+
return MOLECULAR_LATTICE_PADDING_FACTOR
|
|
21
|
+
width_ratio = min_distance / max_distance
|
|
22
|
+
if np.isclose(width_ratio, 1.0):
|
|
23
|
+
return DIATOMIC_LATTICE_PADDING_FACTOR
|
|
24
|
+
return MOLECULAR_LATTICE_PADDING_FACTOR
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _get_non_periodic_lattice_size(
|
|
28
|
+
shifted_positions: np.ndarray,
|
|
29
|
+
default_min_size: float = DEFAULT_NON_PERIODIC_MIN_LATTICE_SIZE,
|
|
30
|
+
) -> float:
|
|
31
|
+
if len(shifted_positions) < 2:
|
|
32
|
+
return max(default_min_size, 10.0)
|
|
33
|
+
distances = pdist(shifted_positions)
|
|
34
|
+
max_distance = float(np.max(distances))
|
|
35
|
+
min_distance = float(np.min(distances))
|
|
36
|
+
padding_factor = _get_non_periodic_lattice_padding_factor(max_distance, min_distance)
|
|
37
|
+
return max(default_min_size, max_distance * padding_factor)
|
|
11
38
|
|
|
12
39
|
|
|
13
40
|
def extract_labels_from_pymatgen_structure(structure: PymatgenStructure) -> List[int]:
|
|
@@ -42,21 +69,21 @@ def extract_tags_from_ase_atoms(atoms: ASEAtoms) -> List[Union[str, int]]:
|
|
|
42
69
|
|
|
43
70
|
|
|
44
71
|
def calculate_padded_cell_simple_cubic(
|
|
45
|
-
coordinates: List[List[float]],
|
|
72
|
+
coordinates: List[List[float]],
|
|
73
|
+
default_min_size: float = DEFAULT_NON_PERIODIC_MIN_LATTICE_SIZE,
|
|
46
74
|
) -> List[List[float]]:
|
|
47
75
|
"""
|
|
48
76
|
Calculate values for a padded cell for a molecule based on its coordinates.
|
|
49
77
|
Args:
|
|
50
78
|
coordinates (Array[Array[float]]): A list of atomic coordinates.
|
|
51
|
-
|
|
79
|
+
default_min_size (float): Minimum cubic lattice parameter in angstroms.
|
|
52
80
|
Returns:
|
|
53
81
|
Array[float]: A list containing the final cell latice vectors with padding applied.
|
|
54
82
|
"""
|
|
55
83
|
positions = np.array(coordinates)
|
|
56
84
|
center = get_center_of_coordinates(positions)
|
|
57
85
|
shifted_positions = positions - center
|
|
58
|
-
|
|
59
|
-
padding_value = padding_factor * max_distance
|
|
86
|
+
padding_value = _get_non_periodic_lattice_size(shifted_positions, default_min_size)
|
|
60
87
|
|
|
61
88
|
return [
|
|
62
89
|
[padding_value, 0.0, 0.0],
|
package/tests/js/basis/basis.ts
CHANGED
|
@@ -217,7 +217,7 @@ describe("Basis", () => {
|
|
|
217
217
|
*/
|
|
218
218
|
it("should return minimum lattice size for an atom", () => {
|
|
219
219
|
const basis = new Basis(Na.basis);
|
|
220
|
-
const minimumLatticeSize =
|
|
220
|
+
const minimumLatticeSize = 3;
|
|
221
221
|
const latticeSize = basis.getMinimumLatticeSize();
|
|
222
222
|
expect(latticeSize).to.be.equal(minimumLatticeSize);
|
|
223
223
|
});
|
|
@@ -4,6 +4,18 @@ import { AtomicConstraints } from "../../../src/js/constraints/constraints";
|
|
|
4
4
|
import { Material } from "../../../src/js/material";
|
|
5
5
|
import parsers from "../../../src/js/parsers/parsers";
|
|
6
6
|
import { atomsCount } from "../../../src/js/parsers/poscar";
|
|
7
|
+
|
|
8
|
+
const O2_POSCAR_WITH_COMMENTS = `O2 molecule in a box
|
|
9
|
+
1.0 ! universal scaling parameters
|
|
10
|
+
12.0 0.0 0.0 ! lattice vector a(1)
|
|
11
|
+
0.0 12.0 0.0 ! lattice vector a(2)
|
|
12
|
+
0.0 0.0 12.0 ! lattice vector a(3)
|
|
13
|
+
O
|
|
14
|
+
2 ! number of atoms
|
|
15
|
+
cart ! positions in cartesian coordinates
|
|
16
|
+
0 0 0 O
|
|
17
|
+
0 0 1.21 O
|
|
18
|
+
`;
|
|
7
19
|
import {
|
|
8
20
|
atomicConstraints,
|
|
9
21
|
H2OPoscar,
|
|
@@ -29,6 +41,21 @@ describe("Parsers.POSCAR", () => {
|
|
|
29
41
|
expect(atomsCount(H2OPoscar)).to.be.equal(3);
|
|
30
42
|
});
|
|
31
43
|
|
|
44
|
+
it("should detect POSCAR with VASP-style comments", () => {
|
|
45
|
+
expect(parsers.poscar.isPoscar(O2_POSCAR_WITH_COMMENTS)).to.be.equal(true);
|
|
46
|
+
expect(parsers.nativeFormatParsers.detectFormat(O2_POSCAR_WITH_COMMENTS)).to.be.equal(
|
|
47
|
+
"poscar",
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("should parse POSCAR with VASP-style comments", () => {
|
|
52
|
+
const materialConfig = parsers.poscar.fromPoscar(O2_POSCAR_WITH_COMMENTS);
|
|
53
|
+
expect(materialConfig).to.have.property("basis");
|
|
54
|
+
expect((materialConfig as { basis: { elements: object[] } }).basis.elements).to.have.length(
|
|
55
|
+
2,
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
|
|
32
59
|
it("should return constraints as string with given map function", () => {
|
|
33
60
|
const constraints = AtomicConstraints.fromObjects(atomicConstraints);
|
|
34
61
|
expect(
|
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
import pytest
|
|
3
3
|
from ase import Atoms
|
|
4
|
+
from ase.build import molecule
|
|
4
5
|
from mat3ra.code.array_with_ids import ArrayWithIds
|
|
6
|
+
from mat3ra.made.material import Material
|
|
7
|
+
from mat3ra.made.tools.convert import from_ase, from_poscar, from_pymatgen, to_ase, to_poscar, to_pymatgen
|
|
8
|
+
from mat3ra.made.tools.convert.utils import (
|
|
9
|
+
DEFAULT_NON_PERIODIC_MIN_LATTICE_SIZE,
|
|
10
|
+
calculate_padded_cell_simple_cubic,
|
|
11
|
+
)
|
|
5
12
|
from mat3ra.utils import assertion as assertion_utils
|
|
6
13
|
from pymatgen.core.structure import Element, Lattice, Structure
|
|
7
14
|
|
|
8
|
-
from mat3ra.made.material import Material
|
|
9
|
-
from mat3ra.made.tools.convert import from_ase, from_poscar, from_pymatgen, to_ase, to_poscar, to_pymatgen
|
|
10
15
|
from .fixtures.monolayer import GRAPHENE
|
|
11
16
|
from .fixtures.thrid_party.ase_atoms import (
|
|
12
|
-
ASE_BULK_Si,
|
|
13
17
|
ASE_MOLECULE_H2O,
|
|
18
|
+
BULK_SI_LABELS,
|
|
14
19
|
BULK_SI_LATTICE_A,
|
|
15
20
|
BULK_SI_LATTICE_ALPHA,
|
|
16
|
-
|
|
21
|
+
ASE_BULK_Si,
|
|
17
22
|
)
|
|
18
23
|
|
|
19
24
|
PYMATGEN_LATTICE = Lattice.from_parameters(a=3.84, b=3.84, c=3.84, alpha=120, beta=90, gamma=60)
|
|
@@ -143,3 +148,30 @@ def test_from_ase(
|
|
|
143
148
|
assert material_data["isNonPeriodic"] == expected_is_non_periodic
|
|
144
149
|
if expected_lattice_type is not None:
|
|
145
150
|
assert material_data["lattice"]["type"] == expected_lattice_type
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
TOLERANCE = 1e-4
|
|
154
|
+
|
|
155
|
+
H2_EXPECTED_LATTICE_A = DEFAULT_NON_PERIODIC_MIN_LATTICE_SIZE
|
|
156
|
+
O2_EXPECTED_LATTICE_A = 3.7379
|
|
157
|
+
H2O_EXPECTED_LATTICE_A = 3.0530
|
|
158
|
+
C2H4_EXPECTED_LATTICE_A = 6.1754
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
@pytest.mark.parametrize(
|
|
162
|
+
"molecule_name, expected_lattice_a",
|
|
163
|
+
[
|
|
164
|
+
("H2", H2_EXPECTED_LATTICE_A),
|
|
165
|
+
("O2", O2_EXPECTED_LATTICE_A),
|
|
166
|
+
("H2O", H2O_EXPECTED_LATTICE_A),
|
|
167
|
+
("C2H4", C2H4_EXPECTED_LATTICE_A),
|
|
168
|
+
],
|
|
169
|
+
)
|
|
170
|
+
def test_calculate_padded_cell_simple_cubic(molecule_name, expected_lattice_a):
|
|
171
|
+
atoms = molecule(molecule_name)
|
|
172
|
+
cell_vectors = calculate_padded_cell_simple_cubic(atoms.get_positions().tolist())
|
|
173
|
+
lattice_a = cell_vectors[0][0]
|
|
174
|
+
assert np.isclose(lattice_a, expected_lattice_a, atol=TOLERANCE)
|
|
175
|
+
assert lattice_a >= DEFAULT_NON_PERIODIC_MIN_LATTICE_SIZE
|
|
176
|
+
assert np.isclose(cell_vectors[0][0], cell_vectors[1][1], atol=TOLERANCE)
|
|
177
|
+
assert np.isclose(cell_vectors[0][0], cell_vectors[2][2], atol=TOLERANCE)
|