@mat3ra/made 2026.8.7-0 → 2026.8.13-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/.mocharc.json +2 -2
- package/dist/js/Material.d.ts +219 -0
- package/dist/js/Material.js +457 -0
- package/dist/js/basis/basis.d.ts +14 -9
- package/dist/js/basis/basis.js +15 -13
- package/dist/js/basis/constrained_basis.d.ts +9 -7
- package/dist/js/basis/constrained_basis.js +4 -4
- package/dist/js/generated/MaterialSchemaMixin.d.ts +5 -0
- package/dist/js/generated/MaterialSchemaMixin.js +69 -0
- package/dist/js/lattice/lattice.d.ts +4 -3
- package/dist/js/lattice/lattice.js +1 -2
- package/dist/js/made.d.ts +12 -12
- package/dist/js/made.js +38 -5
- package/dist/js/parsers/espresso.d.ts +2 -3
- package/dist/js/parsers/espresso.js +0 -1
- package/dist/js/parsers/native_format_parsers.d.ts +9 -8
- package/dist/js/parsers/native_format_parsers.js +6 -6
- package/dist/js/parsers/parsers.d.ts +6 -6
- package/dist/js/parsers/poscar.d.ts +5 -4
- package/dist/js/parsers/poscar.js +3 -2
- package/dist/js/parsers/xyz.d.ts +3 -5
- package/dist/js/parsers/xyz.js +3 -4
- package/dist/js/parsers/xyz_combinatorial_basis.js +3 -1
- package/dist/js/tools/basis.d.ts +1 -1
- package/dist/js/tools/index.d.ts +7 -7
- package/dist/js/tools/material.d.ts +1 -1
- package/dist/js/tools/material.js +8 -7
- package/dist/js/tools/supercell.d.ts +4 -5
- package/dist/js/tools/supercell.js +2 -4
- package/dist/js/tools/surface.d.ts +4 -4
- package/dist/js/tools/surface.js +2 -7
- package/package.json +6 -6
- package/scripts/generate-mixins.ts +28 -0
- package/src/js/Material.ts +618 -0
- package/src/js/basis/basis.ts +38 -25
- package/src/js/basis/constrained_basis.ts +12 -11
- package/src/js/basis/coordinates.ts +0 -1
- package/src/js/cell/cell.ts +0 -1
- package/src/js/generated/MaterialSchemaMixin.ts +79 -0
- package/src/js/lattice/lattice.ts +6 -4
- package/src/js/lattice/reciprocal/lattice_reciprocal.ts +19 -6
- package/src/js/made.ts +1 -1
- package/src/js/parsers/espresso.ts +2 -3
- package/src/js/parsers/native_format_parsers.ts +9 -8
- package/src/js/parsers/poscar.ts +12 -6
- package/src/js/parsers/xyz.ts +9 -6
- package/src/js/parsers/xyz_combinatorial_basis.ts +5 -2
- package/src/js/tools/basis.ts +0 -1
- package/src/js/tools/cell.ts +0 -1
- package/src/js/tools/material.ts +13 -11
- package/src/js/tools/supercell.ts +8 -7
- package/src/js/tools/surface.ts +7 -17
- package/src/py/mat3ra/made/material.py +6 -5
- package/tests/fixtures/si-standata.json +2 -2
- package/tests/js/basis/basis.ts +8 -8
- package/tests/js/fixtures.ts +12 -9
- package/tests/js/material/material.ts +161 -0
- package/tests/js/parsers/espresso.ts +2 -5
- package/tests/js/parsers/poscar.ts +2 -2
- package/tests/js/register-esse-schemas.cjs +10 -0
- package/tests/js/tools/supercell.ts +2 -2
- package/tests/js/tools/surface.ts +6 -10
- package/dist/js/material.d.ts +0 -169
- package/dist/js/material.js +0 -362
- package/src/js/material.ts +0 -458
- package/tests/js/material.test.ts +0 -42
|
@@ -5,10 +5,10 @@ import { Basis } from "../basis/basis";
|
|
|
5
5
|
import { ConstrainedBasis } from "../basis/constrained_basis";
|
|
6
6
|
import { Cell } from "../cell/cell";
|
|
7
7
|
import { Lattice } from "../lattice/lattice";
|
|
8
|
-
import type {
|
|
8
|
+
import type { MaterialSchemaMap } from "../Material";
|
|
9
|
+
import type Material from "../Material";
|
|
9
10
|
import cellTools from "./cell";
|
|
10
11
|
|
|
11
|
-
|
|
12
12
|
const ADD = Utils.math.add;
|
|
13
13
|
|
|
14
14
|
/**
|
|
@@ -53,18 +53,19 @@ function generateNewBasisWithinSupercell(
|
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
55
|
* @summary Generates supercell config for the specified material.
|
|
56
|
-
* @param material
|
|
57
|
-
* @param supercellMatrix {Number[][]}
|
|
58
56
|
*/
|
|
59
|
-
function generateConfig
|
|
57
|
+
function generateConfig<Schemas extends MaterialSchemaMap = MaterialSchemaMap>(
|
|
58
|
+
material: Material<Schemas>,
|
|
59
|
+
supercellMatrix: Matrix3X3Schema,
|
|
60
|
+
) {
|
|
60
61
|
const det = Utils.math.det(supercellMatrix);
|
|
61
62
|
if (det === 0) {
|
|
62
63
|
throw new Error("Scaling matrix is degenerate.");
|
|
63
64
|
}
|
|
64
|
-
const cell = material.
|
|
65
|
+
const cell = material.getLattice().vectors;
|
|
65
66
|
const supercell = cell.cloneAndScaleByMatrix(supercellMatrix);
|
|
66
67
|
const newBasis = generateNewBasisWithinSupercell(
|
|
67
|
-
material.
|
|
68
|
+
material.getBasis(),
|
|
68
69
|
cell,
|
|
69
70
|
supercell,
|
|
70
71
|
supercellMatrix,
|
package/src/js/tools/surface.ts
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Coordinate3DSchema,
|
|
3
|
-
MaterialSchema,
|
|
4
|
-
Matrix3X3Schema,
|
|
5
|
-
Vector3DSchema,
|
|
6
|
-
} from "@mat3ra/esse/dist/js/types";
|
|
1
|
+
import { Coordinate3DSchema, Matrix3X3Schema, Vector3DSchema } from "@mat3ra/esse/dist/js/types";
|
|
7
2
|
import { Utils } from "@mat3ra/utils";
|
|
8
3
|
|
|
9
4
|
import { Cell } from "../cell/cell";
|
|
10
5
|
import { Lattice } from "../lattice/lattice";
|
|
11
|
-
import {
|
|
6
|
+
import Material, { type MaterialConfig, type MaterialSchemaMap } from "../Material";
|
|
12
7
|
import SupercellTools from "./supercell";
|
|
13
8
|
|
|
14
9
|
const MULT = Utils.math.multiply;
|
|
@@ -36,10 +31,6 @@ function extGCD(a: number, b: number): [number, number] {
|
|
|
36
31
|
/**
|
|
37
32
|
* Generates a slab scaling matrix for the specified cell based on miller indices.
|
|
38
33
|
* Inspired by from https://gitlab.com/ase/ase/blob/master/ase/build/general_surface.py.
|
|
39
|
-
* @param cell {Cell}
|
|
40
|
-
* @param millerIndices {Number[]}
|
|
41
|
-
* @param tol {Number} Zero-value tolerance
|
|
42
|
-
* @return {Number[][]}
|
|
43
34
|
*/
|
|
44
35
|
function getMillerScalingMatrix(
|
|
45
36
|
cell: Cell,
|
|
@@ -132,7 +123,6 @@ function getMillerScalingMatrix(
|
|
|
132
123
|
* @param thickness {Number} Surface (Slab) thickness in layers (Positive Integer).
|
|
133
124
|
* @param vx {Number} Size of lateral supercell along the direction of the first (x) cell vector (Positive Integer).
|
|
134
125
|
* @param vy {Number} Size of lateral supercell along the direction of the second (y) cell vector (Positive Integer).
|
|
135
|
-
* @return {Number[][]}
|
|
136
126
|
*/
|
|
137
127
|
function getDimensionsScalingMatrix(
|
|
138
128
|
outOfPlaneAxisIndex: number,
|
|
@@ -158,7 +148,7 @@ function getDimensionsScalingMatrix(
|
|
|
158
148
|
return transformationMatrix as Matrix3X3Schema;
|
|
159
149
|
}
|
|
160
150
|
|
|
161
|
-
export type SlabConfigSchema =
|
|
151
|
+
export type SlabConfigSchema = MaterialConfig & {
|
|
162
152
|
outOfPlaneAxisIndex: number;
|
|
163
153
|
};
|
|
164
154
|
|
|
@@ -171,8 +161,8 @@ export type SlabConfigSchema = MaterialSchema & {
|
|
|
171
161
|
* @param vy {Number} Size of lateral supercell along the direction of the second (y) cell vector (Positive Integer).
|
|
172
162
|
* @return {Object}
|
|
173
163
|
*/
|
|
174
|
-
function generateConfig(
|
|
175
|
-
material: Material
|
|
164
|
+
function generateConfig<Schemas extends MaterialSchemaMap = MaterialSchemaMap>(
|
|
165
|
+
material: Material<Schemas>,
|
|
176
166
|
millerIndices: Coordinate3DSchema,
|
|
177
167
|
numberOfLayers = 1,
|
|
178
168
|
vx = 1,
|
|
@@ -181,7 +171,7 @@ function generateConfig(
|
|
|
181
171
|
if (numberOfLayers < 1)
|
|
182
172
|
throw new Error("Made.tools.surface.generateConfig: number of layers < 1.");
|
|
183
173
|
|
|
184
|
-
const cell = material.
|
|
174
|
+
const cell = material.getLattice().vectors;
|
|
185
175
|
const millerScalingMatrix = getMillerScalingMatrix(cell, millerIndices);
|
|
186
176
|
const millerSupercell = cell.cloneAndScaleByMatrix(millerScalingMatrix);
|
|
187
177
|
const millerPlanePseudoNormal = cell.convertPointToCartesian(millerIndices);
|
|
@@ -195,7 +185,7 @@ function generateConfig(
|
|
|
195
185
|
);
|
|
196
186
|
const supercellMatrix = MULT(dimensionsScalingMatrix, millerScalingMatrix);
|
|
197
187
|
const supercell = millerSupercell.cloneAndScaleByMatrix(dimensionsScalingMatrix);
|
|
198
|
-
const tempBasis = material.
|
|
188
|
+
const tempBasis = material.getBasis().clone();
|
|
199
189
|
const newBasis = SupercellTools.generateNewBasisWithinSupercell(
|
|
200
190
|
tempBasis,
|
|
201
191
|
cell,
|
|
@@ -4,7 +4,7 @@ from typing import Any, List, Optional, Union
|
|
|
4
4
|
from mat3ra.code.constants import AtomicCoordinateUnits, Units
|
|
5
5
|
from mat3ra.code.entity import HasDescriptionHasMetadataNamedDefaultableInMemoryEntityPydantic
|
|
6
6
|
from mat3ra.esse.models.material import MaterialSchema
|
|
7
|
-
from pydantic import ConfigDict, SkipValidation, computed_field
|
|
7
|
+
from pydantic import ConfigDict, SkipValidation, computed_field
|
|
8
8
|
|
|
9
9
|
from .basis import Basis
|
|
10
10
|
from .lattice import Lattice
|
|
@@ -125,10 +125,11 @@ class Material(MaterialSchema, HasDescriptionHasMetadataNamedDefaultableInMemory
|
|
|
125
125
|
def hash(self) -> str:
|
|
126
126
|
return self.calculate_hash()
|
|
127
127
|
|
|
128
|
-
@field_serializer("scaledHash")
|
|
129
|
-
def serialize_scaled_hash(self, _scaled_hash: Optional[str]) -> str:
|
|
130
|
-
return self.scaled_hash
|
|
131
|
-
|
|
132
128
|
@property
|
|
133
129
|
def scaled_hash(self) -> str:
|
|
134
130
|
return self.calculate_hash(is_scaled=True)
|
|
131
|
+
|
|
132
|
+
@computed_field
|
|
133
|
+
@property
|
|
134
|
+
def scaledHash(self) -> str:
|
|
135
|
+
return self.scaled_hash
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
version https://git-lfs.github.com/spec/v1
|
|
2
|
-
oid sha256:
|
|
3
|
-
size
|
|
2
|
+
oid sha256:d81edc05f74463da35845fd348716de48459b8b3b5acfa5076fb621a8e23a74e
|
|
3
|
+
size 1454
|
package/tests/js/basis/basis.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { Utils } from "@mat3ra/utils";
|
|
|
5
5
|
import { expect } from "chai";
|
|
6
6
|
|
|
7
7
|
import { Basis } from "../../../src/js/basis/basis";
|
|
8
|
-
import
|
|
8
|
+
import Material from "../../../src/js/Material";
|
|
9
9
|
import {
|
|
10
10
|
AsGeBasis,
|
|
11
11
|
C2H4,
|
|
@@ -29,20 +29,20 @@ describe("Basis", () => {
|
|
|
29
29
|
});
|
|
30
30
|
|
|
31
31
|
it("should return true when basis is compared to its clone", () => {
|
|
32
|
-
const basis1 = new Material(Na4Cl4).
|
|
32
|
+
const basis1 = new Material(Na4Cl4).getBasis();
|
|
33
33
|
const basis2 = basis1.clone();
|
|
34
34
|
expect(basis1.isEqualTo(basis2)).to.be.equal(true);
|
|
35
35
|
expect(basis1.hasEquivalentCellTo(basis2)).to.be.equal(true);
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
it("should return jsonified basis", () => {
|
|
39
|
-
const basis = new Material(Na4Cl4).
|
|
39
|
+
const basis = new Material(Na4Cl4).getBasis();
|
|
40
40
|
expect(basis.toJSON()).to.be.deep.almost.equal(Na4Cl4.basis);
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
it("should return true if cells are equal", () => {
|
|
44
|
-
const basis1 = new Material(Na4Cl4).
|
|
45
|
-
const basis2 = new Material(Na4Cl4Cartesian).
|
|
44
|
+
const basis1 = new Material(Na4Cl4).getBasis();
|
|
45
|
+
const basis2 = new Material(Na4Cl4Cartesian).getBasis();
|
|
46
46
|
expect(basis1.hasEquivalentCellTo(basis2)).to.be.equal(true);
|
|
47
47
|
});
|
|
48
48
|
|
|
@@ -120,7 +120,7 @@ describe("Basis", () => {
|
|
|
120
120
|
});
|
|
121
121
|
|
|
122
122
|
it("should convert crystal to cartesian", () => {
|
|
123
|
-
const basis = new Material(Na4Cl4).
|
|
123
|
+
const basis = new Material(Na4Cl4).getBasis();
|
|
124
124
|
basis.toCartesian();
|
|
125
125
|
expect(basis.isInCartesianUnits).to.be.equal(true);
|
|
126
126
|
expect(basis.coordinates).to.be.deep.almost.equal(Na4Cl4Cartesian.basis.coordinates);
|
|
@@ -195,8 +195,8 @@ describe("Basis", () => {
|
|
|
195
195
|
*/
|
|
196
196
|
|
|
197
197
|
it("should return standard representation", () => {
|
|
198
|
-
const basis = new Material(Na4Cl4Cartesian).
|
|
199
|
-
|
|
198
|
+
const basis = new Material(Na4Cl4Cartesian).getBasis();
|
|
199
|
+
assertDeepAlmostEqual(basis.standardRepresentation, Na4Cl4.basis, ["constraints"]);
|
|
200
200
|
});
|
|
201
201
|
|
|
202
202
|
/**
|
package/tests/js/fixtures.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
AtomicConstraintsSchema,
|
|
3
|
+
BasisSchema,
|
|
4
|
+
MaterialHashedSchema,
|
|
5
|
+
MaterialSchema,
|
|
6
|
+
} from "@mat3ra/esse/dist/js/types";
|
|
2
7
|
import { MaterialStandata } from "@mat3ra/standata";
|
|
3
8
|
import fs from "fs";
|
|
4
9
|
import path from "path";
|
|
@@ -9,7 +14,6 @@ import C2H4_JSON from "../fixtures/C2H4.json";
|
|
|
9
14
|
import C2H4Translated_JSON from "../fixtures/C2H4-translated.json";
|
|
10
15
|
import FeLiSiBasis_JSON from "../fixtures/FeLiSi-basis.json";
|
|
11
16
|
import FeO_JSON from "../fixtures/FeO.json";
|
|
12
|
-
|
|
13
17
|
import Ge2Basis_JSON from "../fixtures/Ge2-basis.json";
|
|
14
18
|
import Graphene_JSON from "../fixtures/Graphene.json";
|
|
15
19
|
import H2HFinal_JSON from "../fixtures/H2+H-final.json";
|
|
@@ -28,24 +32,23 @@ import SiSlab111Gamma120_JSON from "../fixtures/si-slab-111-0.5-vacuum-gamma-120
|
|
|
28
32
|
import SiSlab111_JSON from "../fixtures/si-slab-111-0.5-vacuum-ratio.json";
|
|
29
33
|
import SiSlab111NoVacuum_JSON from "../fixtures/si-slab-111-0-vacuum.json";
|
|
30
34
|
import Silicon_JSON from "../fixtures/si-standata.json";
|
|
31
|
-
|
|
32
35
|
import SiSupercell_JSON from "../fixtures/Si-supercell.json";
|
|
33
36
|
import Si2Basis_JSON from "../fixtures/Si2-basis.json";
|
|
34
37
|
import Si2BasisRepeated_JSON from "../fixtures/Si2-basis-repeated.json";
|
|
35
38
|
import Zr1H23Zr1H1_JSON from "../fixtures/Zr1H23Zr1H1.json";
|
|
36
39
|
|
|
37
40
|
// Material
|
|
38
|
-
const Silicon = Silicon_JSON as unknown as
|
|
39
|
-
const SiSupercell = SiSupercell_JSON as unknown as
|
|
41
|
+
const Silicon = Silicon_JSON as unknown as MaterialHashedSchema;
|
|
42
|
+
const SiSupercell = SiSupercell_JSON as unknown as MaterialHashedSchema;
|
|
40
43
|
const SiSlab = SiSlab_JSON as unknown as MaterialSchema;
|
|
41
44
|
const SiSlab100 = SiSlab100_JSON as unknown as MaterialSchema;
|
|
42
45
|
const SiSlab111 = SiSlab111_JSON as unknown as MaterialSchema;
|
|
43
46
|
const SiSlab111Gamma120 = SiSlab111Gamma120_JSON as unknown as MaterialSchema;
|
|
44
47
|
const SiSlab111NoVacuum = SiSlab111NoVacuum_JSON as unknown as MaterialSchema;
|
|
45
48
|
const FeO = FeO_JSON as unknown as MaterialSchema;
|
|
46
|
-
const FeOStandata = MaterialStandata.getRuntimeDataConfigs().find(
|
|
47
|
-
|
|
48
|
-
) as
|
|
49
|
+
const FeOStandata = MaterialStandata.getRuntimeDataConfigs().find((m: any) =>
|
|
50
|
+
m.name?.includes("FeO"),
|
|
51
|
+
) as MaterialHashedSchema;
|
|
49
52
|
const Na4Cl4 = Na4Cl4_JSON as unknown as MaterialSchema;
|
|
50
53
|
const Na4Cl4Cartesian = Na4Cl4Cartesian_JSON as unknown as MaterialSchema;
|
|
51
54
|
const C2H4 = C2H4_JSON as unknown as MaterialSchema;
|
|
@@ -55,7 +58,7 @@ const H2HInitial = H2HInitial_JSON as unknown as MaterialSchema;
|
|
|
55
58
|
const H2HFinal = H2HFinal_JSON as unknown as MaterialSchema;
|
|
56
59
|
const H2HImage = H2HImage_JSON as unknown as MaterialSchema;
|
|
57
60
|
const Zr1H23Zr1H1 = Zr1H23Zr1H1_JSON as unknown as MaterialSchema;
|
|
58
|
-
const Graphene = Graphene_JSON as unknown as
|
|
61
|
+
const Graphene = Graphene_JSON as unknown as MaterialHashedSchema;
|
|
59
62
|
const NiHex = NiHex_JSON as unknown as MaterialSchema;
|
|
60
63
|
|
|
61
64
|
// Basis
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { expect } from "chai";
|
|
2
|
+
|
|
3
|
+
import Material from "../../../src/js/Material";
|
|
4
|
+
import { FeOStandata, Graphene, Na4Cl4, Silicon } from "../fixtures";
|
|
5
|
+
|
|
6
|
+
const newBasisXYZ = `Si 0.000000 0.000000 0.000000
|
|
7
|
+
Ge 0.250000 0.250000 0.250000
|
|
8
|
+
`;
|
|
9
|
+
|
|
10
|
+
describe("Material", () => {
|
|
11
|
+
it("should return unique elements", () => {
|
|
12
|
+
const material = new Material(Na4Cl4);
|
|
13
|
+
expect(material.uniqueElements).to.have.same.members(["Na", "Cl"]);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("should return cloned material", () => {
|
|
17
|
+
const material = new Material(Silicon);
|
|
18
|
+
const clonedMaterial = material.clone();
|
|
19
|
+
clonedMaterial.setBasis(newBasisXYZ, "xyz", clonedMaterial.getBasis().units);
|
|
20
|
+
expect(clonedMaterial.getBasis().elements).to.have.lengthOf(2);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("defaults missing metadata to empty object", () => {
|
|
24
|
+
const material = new Material({
|
|
25
|
+
name: Silicon.name,
|
|
26
|
+
basis: Silicon.basis,
|
|
27
|
+
lattice: Silicon.lattice,
|
|
28
|
+
});
|
|
29
|
+
expect(material.metadata).to.deep.equal({});
|
|
30
|
+
expect(material.toJSON().metadata).to.deep.equal({});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe("toJSON variants", () => {
|
|
34
|
+
const material = new Material(Silicon);
|
|
35
|
+
|
|
36
|
+
it("toJSONPure omits hash and basis.constraints", () => {
|
|
37
|
+
const json = material.toJSONPure();
|
|
38
|
+
expect(json).to.not.have.property("hash");
|
|
39
|
+
expect(json).to.not.have.property("scaledHash");
|
|
40
|
+
expect(json.basis).to.not.have.property("constraints");
|
|
41
|
+
expect(json.name).to.equal(Silicon.name);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("toJSONEnhanced includes basis.constraints and omits hash", () => {
|
|
45
|
+
const json = material.toJSONEnhanced();
|
|
46
|
+
expect(json).to.not.have.property("hash");
|
|
47
|
+
expect(json).to.not.have.property("scaledHash");
|
|
48
|
+
expect(json.basis).to.have.property("constraints").that.is.an("array");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("toJSONHashed includes hash and omits basis.constraints", () => {
|
|
52
|
+
const json = material.toJSONHashed();
|
|
53
|
+
expect(json.hash).to.be.a("string");
|
|
54
|
+
expect(json.hash.length).to.be.greaterThan(0);
|
|
55
|
+
expect(json.basis).to.not.have.property("constraints");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("toJSONEnhancedHashed includes hash and basis.constraints", () => {
|
|
59
|
+
const json = material.toJSONEnhancedHashed();
|
|
60
|
+
expect(json.hash).to.be.a("string");
|
|
61
|
+
expect(json.hash.length).to.be.greaterThan(0);
|
|
62
|
+
expect(json.basis.constraints).to.be.an("array");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("toJSON equals toJSONEnhancedHashed", () => {
|
|
66
|
+
expect(material.toJSON()).to.deep.equal(material.toJSONEnhancedHashed());
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("getBasisAsXyz includes atomic constraints via toJSONEnhanced", () => {
|
|
71
|
+
const material = new Material({
|
|
72
|
+
name: "Li-with-constraints",
|
|
73
|
+
basis: {
|
|
74
|
+
elements: [
|
|
75
|
+
{ id: 0, value: "Li" },
|
|
76
|
+
{ id: 1, value: "Li" },
|
|
77
|
+
],
|
|
78
|
+
coordinates: [
|
|
79
|
+
{ id: 0, value: [0, 0, 0] },
|
|
80
|
+
{ id: 1, value: [0.25, 0.25, 0.25] },
|
|
81
|
+
],
|
|
82
|
+
units: "crystal",
|
|
83
|
+
constraints: [
|
|
84
|
+
{ id: 0, value: [true, true, false] },
|
|
85
|
+
{ id: 1, value: [true, true, true] },
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
lattice: Silicon.lattice,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const xyz = material.getBasisAsXyz();
|
|
92
|
+
expect(xyz).to.match(/Li\s+0\.000000\s+0\.000000\s+0\.000000\s+1\s+1\s+0/);
|
|
93
|
+
expect(xyz).to.match(/Li\s+0\.250000\s+0\.250000\s+0\.250000\s+1\s+1\s+1/);
|
|
94
|
+
// Regression: toJSONPure strips constraints — must not be used for XYZ display.
|
|
95
|
+
expect(material.toJSONPure().basis).to.not.have.property("constraints");
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe("calculateHash", () => {
|
|
99
|
+
[
|
|
100
|
+
{ name: "Silicon", fixture: Silicon },
|
|
101
|
+
{ name: "Graphene", fixture: Graphene },
|
|
102
|
+
].forEach(({ name, fixture }) => {
|
|
103
|
+
it(`should match expected hash for ${name}`, () => {
|
|
104
|
+
const material = new Material(fixture);
|
|
105
|
+
expect(material.calculateHash()).to.equal(fixture.hash);
|
|
106
|
+
expect(material.scaledHash).to.equal(fixture.scaledHash);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("should match expected hash for FeO (standata)", () => {
|
|
111
|
+
// eslint-disable-next-line global-require, @typescript-eslint/no-var-requires
|
|
112
|
+
const expectedHashes = require("../../fixtures/hashes.json");
|
|
113
|
+
const material = new Material(FeOStandata);
|
|
114
|
+
expect(material.calculateHash()).to.equal(expectedHashes.FeO.hash);
|
|
115
|
+
// scaledHash is stored on schema; standata config may omit it — match main's computed getter.
|
|
116
|
+
expect(material.calculateHash("", true)).to.equal(expectedHashes.FeO.scaledHash);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("stores InChI hash for non-periodic materials when InChI is present", () => {
|
|
120
|
+
// MD5 of the InChI string — same contract as web-app MolView upload.
|
|
121
|
+
const inchi =
|
|
122
|
+
"1S/C8H18N4O2/c1-10-4-9-6-5(10)7(13)12(3)8(14)11(6)2/h5-9,13-14H,4H2,1-3H3";
|
|
123
|
+
const expectedInchiHash = "b3680772bb4f0cba602788d519531914";
|
|
124
|
+
|
|
125
|
+
const material = new Material({
|
|
126
|
+
name: "non-periodic-inchi",
|
|
127
|
+
isNonPeriodic: true,
|
|
128
|
+
basis: Silicon.basis,
|
|
129
|
+
lattice: Silicon.lattice,
|
|
130
|
+
derivedProperties: [{ name: "inchi", value: inchi }],
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
expect(material.isNonPeriodic).to.equal(true);
|
|
134
|
+
expect(material.getInchiStringForHash()).to.equal(inchi);
|
|
135
|
+
expect(material.calculateHash()).to.equal(expectedInchiHash);
|
|
136
|
+
expect(material.hash).to.equal(expectedInchiHash);
|
|
137
|
+
|
|
138
|
+
const geometricHashWithBypass = material.calculateHash("", false, true);
|
|
139
|
+
material.lattice = { ...material.lattice };
|
|
140
|
+
expect(material.hash).to.equal(expectedInchiHash);
|
|
141
|
+
expect(material.hash).to.not.equal(geometricHashWithBypass);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("uses geometric hash when non-periodic but InChI is not derived yet", () => {
|
|
145
|
+
// Designer toggle sets isNonPeriodic then scales lattice before butler adds InChI.
|
|
146
|
+
const material = new Material({
|
|
147
|
+
name: "non-periodic-no-inchi",
|
|
148
|
+
isNonPeriodic: true,
|
|
149
|
+
basis: Silicon.basis,
|
|
150
|
+
lattice: Silicon.lattice,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const expectedGeometricHash = material.calculateHash("", false, true);
|
|
154
|
+
expect(material.hash).to.equal(expectedGeometricHash);
|
|
155
|
+
expect(() => material.calculateHash()).to.throw(/Missing InChI/);
|
|
156
|
+
|
|
157
|
+
material.lattice = { ...material.lattice };
|
|
158
|
+
expect(material.hash).to.equal(material.calculateHash("", false, true));
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
});
|
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
import { MaterialSchema } from "@mat3ra/esse/dist/js/types";
|
|
2
1
|
import { expect } from "chai";
|
|
3
2
|
|
|
4
|
-
import
|
|
3
|
+
import Material from "../../../src/js/Material";
|
|
5
4
|
import parsers from "../../../src/js/parsers/parsers";
|
|
6
5
|
import { Silicon, SiPWSCFInput } from "../fixtures";
|
|
7
6
|
|
|
8
7
|
describe("Parsers:Espresso", () => {
|
|
9
8
|
it("should return textual representation of a material according to QE pw.x input format", () => {
|
|
10
9
|
const material = new Material(Silicon);
|
|
11
|
-
expect(parsers.espresso.toEspressoFormat(material
|
|
12
|
-
SiPWSCFInput,
|
|
13
|
-
);
|
|
10
|
+
expect(parsers.espresso.toEspressoFormat(material.toJSON())).to.be.equal(SiPWSCFInput);
|
|
14
11
|
});
|
|
15
12
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { expect } from "chai";
|
|
2
2
|
|
|
3
3
|
import { AtomicConstraints } from "../../../src/js/constraints/constraints";
|
|
4
|
-
import
|
|
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
7
|
import {
|
|
@@ -81,7 +81,7 @@ direct
|
|
|
81
81
|
|
|
82
82
|
const material = new Material(Silicon);
|
|
83
83
|
const clonedMaterial = material.clone();
|
|
84
|
-
clonedMaterial.setBasis(newBasisXYZ, "xyz", clonedMaterial.
|
|
84
|
+
clonedMaterial.setBasis(newBasisXYZ, "xyz", clonedMaterial.getBasis().units);
|
|
85
85
|
|
|
86
86
|
const poscar = clonedMaterial.getAsPOSCAR(true);
|
|
87
87
|
expect(poscar).to.be.equal(poscarConstraints);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registers ESSE schemas for made unit tests.
|
|
3
|
+
* Kept as CommonJS so mocha `--require` can load it without ESM JSON import issues.
|
|
4
|
+
* Library / web-app code must not import `@mat3ra/esse/dist/js/schemas.json` — the host
|
|
5
|
+
* (web-app) registers the (possibly extended) schema set once at startup.
|
|
6
|
+
*/
|
|
7
|
+
const JSONSchemasInterface = require("@mat3ra/esse/dist/js/esse/JSONSchemasInterface").default;
|
|
8
|
+
const allSchemas = require("@mat3ra/esse/dist/js/schemas.json");
|
|
9
|
+
|
|
10
|
+
JSONSchemasInterface.setSchemas(allSchemas);
|
|
@@ -4,7 +4,7 @@ import { expect } from "chai";
|
|
|
4
4
|
|
|
5
5
|
import { Basis } from "../../../src/js/basis/basis";
|
|
6
6
|
import { Made } from "../../../src/js/made";
|
|
7
|
-
import
|
|
7
|
+
import Material from "../../../src/js/Material";
|
|
8
8
|
import { Silicon, SiSupercell } from "../fixtures";
|
|
9
9
|
|
|
10
10
|
const { assertDeepAlmostEqual } = Utils.assertion;
|
|
@@ -44,7 +44,7 @@ direct
|
|
|
44
44
|
0.625000000 0.250000000 0.250000000 Ge`;
|
|
45
45
|
const material = new Material(Silicon);
|
|
46
46
|
const clonedMaterial = material.clone();
|
|
47
|
-
clonedMaterial.setBasis(newBasisXYZ, "xyz", clonedMaterial.
|
|
47
|
+
clonedMaterial.setBasis(newBasisXYZ, "xyz", clonedMaterial.getBasis().units);
|
|
48
48
|
const supercellConfig = Made.tools.supercell.generateConfig(clonedMaterial, [
|
|
49
49
|
[2, 0, 0],
|
|
50
50
|
[0, 1, 0],
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { MaterialSchema } from "@mat3ra/esse/dist/js/types";
|
|
2
2
|
import { Utils } from "@mat3ra/utils";
|
|
3
3
|
|
|
4
|
-
import
|
|
4
|
+
import Material from "../../../src/js/Material";
|
|
5
5
|
import tools from "../../../src/js/tools";
|
|
6
6
|
import { SlabConfigSchema } from "../../../src/js/tools/surface";
|
|
7
7
|
import { Silicon, SiSlab100, SiSlab111, SiSlab111NoVacuum } from "../fixtures";
|
|
@@ -39,6 +39,7 @@ describe("Tools:Surface", () => {
|
|
|
39
39
|
const adjustedSilicon: MaterialSchema = {
|
|
40
40
|
...Silicon,
|
|
41
41
|
basis: {
|
|
42
|
+
...Silicon.basis,
|
|
42
43
|
elements: [
|
|
43
44
|
{
|
|
44
45
|
id: 10,
|
|
@@ -72,9 +73,8 @@ describe("Tools:Surface", () => {
|
|
|
72
73
|
const vacuumRatio = 0.5;
|
|
73
74
|
const slabMaterial = generateSlabWithVacuum(slabConfig, vacuumRatio);
|
|
74
75
|
const expectedSlabMaterial = new Material(SiSlab111);
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
assertDeepAlmostEqual(expectedMaterialJSON, slabMaterialJSON);
|
|
76
|
+
// Structural comparison: omit hash (now included in Material.toJSON).
|
|
77
|
+
assertDeepAlmostEqual(expectedSlabMaterial.toJSONEnhanced(), slabMaterial.toJSONEnhanced());
|
|
78
78
|
});
|
|
79
79
|
|
|
80
80
|
it("should return slab (111) with vacuum for gamma = 59.999", () => {
|
|
@@ -90,9 +90,7 @@ describe("Tools:Surface", () => {
|
|
|
90
90
|
const vacuumRatio = 0.5;
|
|
91
91
|
const slabMaterial = generateSlabWithVacuum(slabConfig, vacuumRatio);
|
|
92
92
|
const expectedSlabMaterial = new Material(SiSlab111);
|
|
93
|
-
|
|
94
|
-
const slabMaterialJSON = slabMaterial.toJSON();
|
|
95
|
-
assertDeepAlmostEqual(expectedMaterialJSON, slabMaterialJSON);
|
|
93
|
+
assertDeepAlmostEqual(expectedSlabMaterial.toJSONEnhanced(), slabMaterial.toJSONEnhanced());
|
|
96
94
|
});
|
|
97
95
|
|
|
98
96
|
it("should return slab (111) with vacuum for gamma = 60.001", () => {
|
|
@@ -108,8 +106,6 @@ describe("Tools:Surface", () => {
|
|
|
108
106
|
const vacuumRatio = 0.5;
|
|
109
107
|
const slabMaterial = generateSlabWithVacuum(slabConfig, vacuumRatio);
|
|
110
108
|
const expectedSlabMaterial = new Material(SiSlab111);
|
|
111
|
-
|
|
112
|
-
const slabMaterialJSON = slabMaterial.toJSON();
|
|
113
|
-
assertDeepAlmostEqual(expectedMaterialJSON, slabMaterialJSON);
|
|
109
|
+
assertDeepAlmostEqual(expectedSlabMaterial.toJSONEnhanced(), slabMaterial.toJSONEnhanced());
|
|
114
110
|
});
|
|
115
111
|
});
|