@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.
Files changed (66) hide show
  1. package/.mocharc.json +2 -2
  2. package/dist/js/Material.d.ts +219 -0
  3. package/dist/js/Material.js +457 -0
  4. package/dist/js/basis/basis.d.ts +14 -9
  5. package/dist/js/basis/basis.js +15 -13
  6. package/dist/js/basis/constrained_basis.d.ts +9 -7
  7. package/dist/js/basis/constrained_basis.js +4 -4
  8. package/dist/js/generated/MaterialSchemaMixin.d.ts +5 -0
  9. package/dist/js/generated/MaterialSchemaMixin.js +69 -0
  10. package/dist/js/lattice/lattice.d.ts +4 -3
  11. package/dist/js/lattice/lattice.js +1 -2
  12. package/dist/js/made.d.ts +12 -12
  13. package/dist/js/made.js +38 -5
  14. package/dist/js/parsers/espresso.d.ts +2 -3
  15. package/dist/js/parsers/espresso.js +0 -1
  16. package/dist/js/parsers/native_format_parsers.d.ts +9 -8
  17. package/dist/js/parsers/native_format_parsers.js +6 -6
  18. package/dist/js/parsers/parsers.d.ts +6 -6
  19. package/dist/js/parsers/poscar.d.ts +5 -4
  20. package/dist/js/parsers/poscar.js +3 -2
  21. package/dist/js/parsers/xyz.d.ts +3 -5
  22. package/dist/js/parsers/xyz.js +3 -4
  23. package/dist/js/parsers/xyz_combinatorial_basis.js +3 -1
  24. package/dist/js/tools/basis.d.ts +1 -1
  25. package/dist/js/tools/index.d.ts +7 -7
  26. package/dist/js/tools/material.d.ts +1 -1
  27. package/dist/js/tools/material.js +8 -7
  28. package/dist/js/tools/supercell.d.ts +4 -5
  29. package/dist/js/tools/supercell.js +2 -4
  30. package/dist/js/tools/surface.d.ts +4 -4
  31. package/dist/js/tools/surface.js +2 -7
  32. package/package.json +6 -6
  33. package/scripts/generate-mixins.ts +28 -0
  34. package/src/js/Material.ts +618 -0
  35. package/src/js/basis/basis.ts +38 -25
  36. package/src/js/basis/constrained_basis.ts +12 -11
  37. package/src/js/basis/coordinates.ts +0 -1
  38. package/src/js/cell/cell.ts +0 -1
  39. package/src/js/generated/MaterialSchemaMixin.ts +79 -0
  40. package/src/js/lattice/lattice.ts +6 -4
  41. package/src/js/lattice/reciprocal/lattice_reciprocal.ts +19 -6
  42. package/src/js/made.ts +1 -1
  43. package/src/js/parsers/espresso.ts +2 -3
  44. package/src/js/parsers/native_format_parsers.ts +9 -8
  45. package/src/js/parsers/poscar.ts +12 -6
  46. package/src/js/parsers/xyz.ts +9 -6
  47. package/src/js/parsers/xyz_combinatorial_basis.ts +5 -2
  48. package/src/js/tools/basis.ts +0 -1
  49. package/src/js/tools/cell.ts +0 -1
  50. package/src/js/tools/material.ts +13 -11
  51. package/src/js/tools/supercell.ts +8 -7
  52. package/src/js/tools/surface.ts +7 -17
  53. package/src/py/mat3ra/made/material.py +6 -5
  54. package/tests/fixtures/si-standata.json +2 -2
  55. package/tests/js/basis/basis.ts +8 -8
  56. package/tests/js/fixtures.ts +12 -9
  57. package/tests/js/material/material.ts +161 -0
  58. package/tests/js/parsers/espresso.ts +2 -5
  59. package/tests/js/parsers/poscar.ts +2 -2
  60. package/tests/js/register-esse-schemas.cjs +10 -0
  61. package/tests/js/tools/supercell.ts +2 -2
  62. package/tests/js/tools/surface.ts +6 -10
  63. package/dist/js/material.d.ts +0 -169
  64. package/dist/js/material.js +0 -362
  65. package/src/js/material.ts +0 -458
  66. package/tests/js/material.test.ts +0 -42
@@ -1,13 +1,17 @@
1
1
  // @ts-ignore
2
2
  import { getElectronegativity, getElementAtomicRadius } from "@exabyte-io/periodic-table.js";
3
3
  import { InMemoryEntity } from "@mat3ra/code/dist/js/entity";
4
- import { BasisSchema, Coordinate3DSchema, Vector3DSchema } from "@mat3ra/esse/dist/js/types";
4
+ import {
5
+ BaseInMemoryEntitySchema,
6
+ BasisSchema,
7
+ Coordinate3DSchema,
8
+ Vector3DSchema,
9
+ } from "@mat3ra/esse/dist/js/types";
5
10
  import { Utils } from "@mat3ra/utils";
6
11
  import { chain, toPairs, uniq, values } from "lodash";
7
12
 
8
13
  import { Cell } from "../cell/cell";
9
14
  import { ATOMIC_COORD_UNITS, HASH_TOLERANCE } from "../constants";
10
-
11
15
  import {
12
16
  defaultNonPeriodicMinimumLatticeSize,
13
17
  diatomicLatticePaddingFactor,
@@ -72,7 +76,11 @@ const DEFAULT_BASIS_CONFIG = {
72
76
  units: "crystal",
73
77
  };
74
78
 
75
- export class Basis extends InMemoryEntity implements BasisSchema {
79
+ type BasisEntitySchema<S extends BasisConfig = BasisConfig> = S & BaseInMemoryEntitySchema;
80
+
81
+ // Keep `{` on same line as `implements` to satisfy brace-style (conflicts with Prettier multi-line heritage).
82
+ // prettier-ignore
83
+ export class Basis<S extends BasisConfig = BasisConfig> extends InMemoryEntity<BasisEntitySchema<S>> implements BasisSchema {
76
84
  static defaultConfig: BasisSchema = DEFAULT_BASIS_CONFIG as BasisSchema;
77
85
 
78
86
  units: BasisSchema["units"];
@@ -122,8 +130,9 @@ export class Basis extends InMemoryEntity implements BasisSchema {
122
130
  );
123
131
  }
124
132
 
125
- constructor(config: BasisConfig = Basis.defaultConfig) {
126
- super(config);
133
+ // NoInfer: keep default S (or an explicit type arg) instead of inferring S from the config literal.
134
+ constructor(config: NoInfer<S> = Basis.defaultConfig as NoInfer<S>) {
135
+ super(config as BasisEntitySchema<S>);
127
136
  const { elements, coordinates, units, labels } = config;
128
137
  this.cell = new Cell(config.cell);
129
138
  this.units = units || (ATOMIC_COORD_UNITS.crystal as BasisSchema["units"]);
@@ -156,20 +165,19 @@ export class Basis extends InMemoryEntity implements BasisSchema {
156
165
  this._labels = Labels.fromObjects(labels || []);
157
166
  }
158
167
 
159
- // TODO: figure out how to override toJSON in the parent class with generic classes
160
- // @ts-ignore
161
- toJSON(exclude: string[] = ["cell"]): BasisSchema {
168
+ toJSON(
169
+ exclude: (keyof BasisEntitySchema<S>)[] = ["cell"] as (keyof BasisEntitySchema<S>)[],
170
+ ): BasisEntitySchema<S> {
162
171
  return {
163
172
  ...super.toJSON(exclude),
164
173
  elements: this.elements,
165
174
  coordinates: this.coordinates,
166
175
  units: this.units,
167
176
  ...(this.labels?.length ? { labels: this.labels } : {}),
168
- };
177
+ } as BasisEntitySchema<S>;
169
178
  }
170
179
 
171
- // @ts-ignore
172
- override clone(): Basis {
180
+ override clone(): this {
173
181
  const instance = super.clone();
174
182
  instance.cell = this.cell.clone();
175
183
  return instance;
@@ -205,16 +213,18 @@ export class Basis extends InMemoryEntity implements BasisSchema {
205
213
  return this.units === ATOMIC_COORD_UNITS.crystal;
206
214
  }
207
215
 
208
- toCartesian(): void {
209
- if (this.isInCartesianUnits) return;
216
+ toCartesian() {
217
+ if (this.isInCartesianUnits) return this;
210
218
  this._coordinates.mapArrayInPlace((point) => this.cell.convertPointToCartesian(point));
211
219
  this.units = ATOMIC_COORD_UNITS.cartesian as BasisSchema["units"];
220
+ return this;
212
221
  }
213
222
 
214
- toCrystal(): void {
215
- if (this.isInCrystalUnits) return;
223
+ toCrystal() {
224
+ if (this.isInCrystalUnits) return this;
216
225
  this._coordinates.mapArrayInPlace((point) => this.cell.convertPointToCrystal(point));
217
226
  this.units = ATOMIC_COORD_UNITS.crystal as BasisSchema["units"];
227
+ return this;
218
228
  }
219
229
 
220
230
  getElementByIndex(idx: number): AtomicElementValue {
@@ -393,7 +403,9 @@ export class Basis extends InMemoryEntity implements BasisSchema {
393
403
  const element = entry[0];
394
404
  const coordinate = entry[1];
395
405
  const atomicLabel = entry[2];
396
- const toleratedCoordinate = coordinate.map((x) => Utils.math.roundCustom(x, HASH_TOLERANCE));
406
+ const toleratedCoordinate = coordinate.map((x) =>
407
+ Utils.math.roundCustom(x, HASH_TOLERANCE),
408
+ );
397
409
  return `${element}${atomicLabel} ${toleratedCoordinate.join()}`;
398
410
  });
399
411
  return `${standardRep.sort().join(";")};`;
@@ -416,7 +428,7 @@ export class Basis extends InMemoryEntity implements BasisSchema {
416
428
 
417
429
  /* Returns array of atomic labels E.g., ["1", "2", "", ""] */
418
430
  get atomicLabelsArray(): string[] {
419
- const labelsArray = Array.from({ length: this.elements.length }, (_) => "");
431
+ const labelsArray = Array.from({ length: this.elements.length }, () => "");
420
432
  // https://dev.to/maafaishal/benchmarking-for-while-forof-and-arrayforeach-using-performancenow-1jjg
421
433
  if (this.labels?.length) {
422
434
  for (let i = 0; i < this.labels.length; i++) {
@@ -461,7 +473,7 @@ export class Basis extends InMemoryEntity implements BasisSchema {
461
473
  * @summary Returns true if bases are equal, otherwise - false.
462
474
  * @param anotherBasisClsInstance {Basis} Another Basis.
463
475
  */
464
- isEqualTo(anotherBasisClsInstance: Basis): boolean {
476
+ isEqualTo(anotherBasisClsInstance: { hashString: string }): boolean {
465
477
  return this.hashString === anotherBasisClsInstance.hashString;
466
478
  }
467
479
 
@@ -469,7 +481,7 @@ export class Basis extends InMemoryEntity implements BasisSchema {
469
481
  * @summary Returns true if basis cells are equal, otherwise - false.
470
482
  * @param anotherBasisClsInstance {Basis} Another Basis.
471
483
  */
472
- hasEquivalentCellTo(anotherBasisClsInstance: Basis): boolean {
484
+ hasEquivalentCellTo(anotherBasisClsInstance: { cell: Cell }): boolean {
473
485
  return !this.cell.vectorArrays
474
486
  .map((vector, idx) => {
475
487
  return Utils.math.vEqualWithTolerance(
@@ -576,12 +588,13 @@ export class Basis extends InMemoryEntity implements BasisSchema {
576
588
  this._coordinates.getElementValueByIndex(i) as Coordinate3DSchema,
577
589
  this._coordinates.getElementValueByIndex(j) as Coordinate3DSchema,
578
590
  );
579
- if (!distance) continue;
580
- if (extremum === "max" && distance > resultDistance) {
581
- resultDistance = distance;
582
- }
583
- if (extremum === "min" && distance < resultDistance) {
584
- resultDistance = distance;
591
+ if (distance) {
592
+ if (extremum === "max" && distance > resultDistance) {
593
+ resultDistance = distance;
594
+ }
595
+ if (extremum === "min" && distance < resultDistance) {
596
+ resultDistance = distance;
597
+ }
585
598
  }
586
599
  }
587
600
  }
@@ -1,14 +1,16 @@
1
- import { AtomicConstraintsSchema } from "@mat3ra/esse/dist/js/types";
1
+ import { AtomicConstraintsSchema, BasisConstrainedSchema } from "@mat3ra/esse/dist/js/types";
2
2
 
3
+ import { Cell } from "../cell/cell";
3
4
  import { AtomicConstraints, AtomicConstraintValue, Constraint } from "../constraints/constraints";
4
- import { Basis, BasisConfig, ElementsAndCoordinatesConfig } from "./basis";
5
+ import { Basis, ElementsAndCoordinatesConfig } from "./basis";
5
6
  import { AtomicCoordinateValue, Coordinate } from "./coordinates";
6
7
  import { AtomicElementValue } from "./elements";
7
8
  import { ElementWithLabel } from "./helpers";
8
9
  import { AtomicLabelValue } from "./labels";
9
10
 
10
- export interface ConstrainedBasisConfig extends BasisConfig {
11
- constraints: AtomicConstraintsSchema;
11
+ export interface ConstrainedBasisConfig extends BasisConstrainedSchema {
12
+ cell?: Cell;
13
+ isEmpty?: boolean;
12
14
  }
13
15
 
14
16
  export interface ElementsCoordinatesAndConstraintsConfig extends ElementsAndCoordinatesConfig {
@@ -19,13 +21,12 @@ export interface ElementsCoordinatesAndConstraintsConfig extends ElementsAndCoor
19
21
  * @summary Extension of the Basis class able to deal with atomic constraints.
20
22
  * @extends Basis
21
23
  */
22
- export class ConstrainedBasis extends Basis {
23
- _constraints: AtomicConstraints;
24
+ export class ConstrainedBasis extends Basis<ConstrainedBasisConfig> {
25
+ private _constraints: AtomicConstraints;
24
26
 
25
27
  constructor(config: ConstrainedBasisConfig) {
26
28
  super(config);
27
- const { constraints } = config;
28
- this._constraints = AtomicConstraints.fromObjects(constraints || []); // `constraints` is an Array with ids
29
+ this._constraints = AtomicConstraints.fromObjects(config.constraints ?? []); // `constraints` is an Array with ids
29
30
  }
30
31
 
31
32
  static fromElementsCoordinatesAndConstraints(
@@ -51,9 +52,9 @@ export class ConstrainedBasis extends Basis {
51
52
  return AtomicConstraints.fromObjects(this.constraints);
52
53
  }
53
54
 
54
- override toJSON(): ConstrainedBasisConfig {
55
+ override toJSON(exclude: (keyof ConstrainedBasisConfig)[] = ["cell"]): ConstrainedBasisConfig {
55
56
  return {
56
- ...super.toJSON(),
57
+ ...super.toJSON(exclude as (keyof ConstrainedBasisConfig)[]),
57
58
  constraints: this.constraints,
58
59
  };
59
60
  }
@@ -75,7 +76,7 @@ export class ConstrainedBasis extends Basis {
75
76
  AtomicCoordinateValue,
76
77
  AtomicConstraintValue,
77
78
  ][] {
78
- return this._elements.values.map((element: any, idx: number) => {
79
+ return this._elements.values.map((element: AtomicElementValue, idx: number) => {
79
80
  const coordinate = this.getCoordinateValueByIndex(idx);
80
81
  const constraint = this.getConstraintByIndex(idx);
81
82
  const label = this.atomicLabelsArray[idx];
@@ -8,7 +8,6 @@ import {
8
8
  import { Utils } from "@mat3ra/utils";
9
9
  import { sprintf } from "underscore.string";
10
10
 
11
-
12
11
  export type AtomicCoordinateValue = AtomicCoordinateSchema["value"];
13
12
 
14
13
  type AxisType = "x" | "y" | "z";
@@ -9,7 +9,6 @@ import { Utils } from "@mat3ra/utils";
9
9
 
10
10
  import constants from "../constants";
11
11
 
12
-
13
12
  const MATRIX = Utils.math.matrix;
14
13
  const MULT = Utils.math.multiply;
15
14
  const INV = Utils.math.inv;
@@ -0,0 +1,79 @@
1
+ import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity";
2
+ import type {
3
+ BaseInMemoryEntitySchema,
4
+ MaterialPropertiesSchema,
5
+ } from "@mat3ra/esse/dist/js/types";
6
+
7
+ export type MaterialSchemaMixin = MaterialPropertiesSchema;
8
+
9
+ export type MaterialInMemoryEntity = InMemoryEntity<BaseInMemoryEntitySchema & MaterialSchemaMixin>;
10
+
11
+ export function materialSchemaMixin<T extends InMemoryEntity>(
12
+ item: InMemoryEntity,
13
+ ): asserts item is T & MaterialSchemaMixin {
14
+ // @ts-expect-error
15
+ const properties: InMemoryEntity<MaterialSchemaMixin> & MaterialSchemaMixin = {
16
+ get formula() {
17
+ return this.prop("formula");
18
+ },
19
+ set formula(value: MaterialPropertiesSchema["formula"]) {
20
+ this.setProp("formula", value);
21
+ },
22
+ get unitCellFormula() {
23
+ return this.prop("unitCellFormula");
24
+ },
25
+ set unitCellFormula(value: MaterialPropertiesSchema["unitCellFormula"]) {
26
+ this.setProp("unitCellFormula", value);
27
+ },
28
+ get basis() {
29
+ return this.requiredProp("basis");
30
+ },
31
+ set basis(value: MaterialPropertiesSchema["basis"]) {
32
+ this.setProp("basis", value);
33
+ },
34
+ get lattice() {
35
+ return this.requiredProp("lattice");
36
+ },
37
+ set lattice(value: MaterialPropertiesSchema["lattice"]) {
38
+ this.setProp("lattice", value);
39
+ },
40
+ get derivedProperties() {
41
+ return this.prop("derivedProperties");
42
+ },
43
+ set derivedProperties(value: MaterialPropertiesSchema["derivedProperties"]) {
44
+ this.setProp("derivedProperties", value);
45
+ },
46
+ get external() {
47
+ return this.prop("external");
48
+ },
49
+ set external(value: MaterialPropertiesSchema["external"]) {
50
+ this.setProp("external", value);
51
+ },
52
+ get src() {
53
+ return this.prop("src");
54
+ },
55
+ set src(value: MaterialPropertiesSchema["src"]) {
56
+ this.setProp("src", value);
57
+ },
58
+ get icsdId() {
59
+ return this.prop("icsdId");
60
+ },
61
+ set icsdId(value: MaterialPropertiesSchema["icsdId"]) {
62
+ this.setProp("icsdId", value);
63
+ },
64
+ get isNonPeriodic() {
65
+ return this.prop("isNonPeriodic");
66
+ },
67
+ set isNonPeriodic(value: MaterialPropertiesSchema["isNonPeriodic"]) {
68
+ this.setProp("isNonPeriodic", value);
69
+ },
70
+ get consistencyChecks() {
71
+ return this.prop("consistencyChecks");
72
+ },
73
+ set consistencyChecks(value: MaterialPropertiesSchema["consistencyChecks"]) {
74
+ this.setProp("consistencyChecks", value);
75
+ },
76
+ };
77
+
78
+ Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties));
79
+ }
@@ -1,5 +1,6 @@
1
1
  import { InMemoryEntity } from "@mat3ra/code/dist/js/entity";
2
2
  import {
3
+ BaseInMemoryEntitySchema,
3
4
  Coordinate3DSchema,
4
5
  LatticeSchema,
5
6
  LatticeTypeEnum,
@@ -30,7 +31,9 @@ export class LatticeVectors extends Cell implements LatticeVectorsSchema {}
30
31
 
31
32
  export type { LatticeVectorsSchema };
32
33
 
33
- export class Lattice extends InMemoryEntity implements LatticeSchema {
34
+ type LatticeEntitySchema = LatticeSchema & BaseInMemoryEntitySchema;
35
+
36
+ export class Lattice extends InMemoryEntity<LatticeEntitySchema> implements LatticeSchema {
34
37
  static defaultConfig: LatticeSchema = {
35
38
  a: 1,
36
39
  b: 1,
@@ -296,11 +299,10 @@ export class Lattice extends InMemoryEntity implements LatticeSchema {
296
299
  return object;
297
300
  }
298
301
 
299
- // @ts-ignore
300
- toJSON(exclude?: string[]): LatticeSchema {
302
+ toJSON(exclude: (keyof LatticeSchema)[] = []): LatticeSchema {
301
303
  return {
302
304
  ...super.toJSON(exclude),
303
305
  vectors: this.vectors.toJSON(),
304
- } as LatticeSchema;
306
+ };
305
307
  }
306
308
  }
@@ -7,7 +7,6 @@ import { Lattice } from "../lattice";
7
7
  import { paths } from "./paths";
8
8
  import { symmetryPoints } from "./symmetry_points";
9
9
 
10
-
11
10
  export type KPointCoordinates = number[];
12
11
  export type KPointPath = Array<{
13
12
  point: string;
@@ -47,9 +46,18 @@ export class ReciprocalLattice extends Lattice {
47
46
  Utils.math.cross(vectors_[1], vectors_[2]),
48
47
  ) as unknown as number) / a;
49
48
  return [
50
- Utils.math.multiply(Utils.math.cross(vectors_[1], vectors_[2]), 1 / divider) as Vector3DSchema,
51
- Utils.math.multiply(Utils.math.cross(vectors_[2], vectors_[0]), 1 / divider) as Vector3DSchema,
52
- Utils.math.multiply(Utils.math.cross(vectors_[0], vectors_[1]), 1 / divider) as Vector3DSchema,
49
+ Utils.math.multiply(
50
+ Utils.math.cross(vectors_[1], vectors_[2]),
51
+ 1 / divider,
52
+ ) as Vector3DSchema,
53
+ Utils.math.multiply(
54
+ Utils.math.cross(vectors_[2], vectors_[0]),
55
+ 1 / divider,
56
+ ) as Vector3DSchema,
57
+ Utils.math.multiply(
58
+ Utils.math.cross(vectors_[0], vectors_[1]),
59
+ 1 / divider,
60
+ ) as Vector3DSchema,
53
61
  ];
54
62
  }
55
63
 
@@ -57,7 +65,9 @@ export class ReciprocalLattice extends Lattice {
57
65
  * Norms of reciprocal vectors.
58
66
  */
59
67
  get reciprocalVectorNorms(): Vector3DSchema {
60
- return this.reciprocalVectors.map((vec) => Utils.math.norm(vec) as number) as Vector3DSchema;
68
+ return this.reciprocalVectors.map(
69
+ (vec) => Utils.math.norm(vec) as number,
70
+ ) as Vector3DSchema;
61
71
  }
62
72
 
63
73
  /**
@@ -167,7 +177,10 @@ export class ReciprocalLattice extends Lattice {
167
177
  getDimensionsFromSpacing(spacing: number, units: string = ATOMIC_COORD_UNITS.cartesian) {
168
178
  const factor: number = this.conversionTable[units][ATOMIC_COORD_UNITS.cartesian] || 1;
169
179
  return this.reciprocalVectorNorms.map((norm: number) => {
170
- return Utils.math.max(1, Utils.math.ceil(lodash.round(norm / (spacing * factor), 4))) as number;
180
+ return Utils.math.max(
181
+ 1,
182
+ Utils.math.ceil(lodash.round(norm / (spacing * factor), 4)),
183
+ ) as number;
171
184
  }) as Vector3DSchema;
172
185
  }
173
186
 
package/src/js/made.ts CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  import { DEFAULT_LATTICE_UNITS, LATTICE_TYPE_CONFIGS } from "./lattice/lattice_types";
12
12
  import { ReciprocalLattice } from "./lattice/reciprocal/lattice_reciprocal";
13
13
  import { UnitCell } from "./lattice/unit_cell";
14
- import { defaultMaterialConfig, Material } from "./material";
14
+ import Material, { defaultMaterialConfig } from "./Material";
15
15
  import parsers from "./parsers/parsers";
16
16
  import tools from "./tools/index";
17
17
 
@@ -1,4 +1,4 @@
1
- import { MaterialSchema } from "@mat3ra/esse/dist/js/types";
1
+ import { MaterialEnhancedSchema, MaterialSchema } from "@mat3ra/esse/dist/js/types";
2
2
  import { map } from "lodash";
3
3
  import s from "underscore.string";
4
4
 
@@ -7,9 +7,8 @@ import xyz from "./xyz";
7
7
 
8
8
  /**
9
9
  * Construct textual representation of a materialOrConfig according to Quantum ESPRESSO pw.x input format.
10
- * @param materialOrConfig - material class instance or its config object
11
10
  */
12
- function toEspressoFormat(materialOrConfig: MaterialSchema): string {
11
+ function toEspressoFormat(materialOrConfig: MaterialSchema | MaterialEnhancedSchema): string {
13
12
  const l = new Lattice(materialOrConfig.lattice);
14
13
  const vectors = l.vectorArrays;
15
14
  const vectorsAsString = map(vectors, (v) => {
@@ -1,3 +1,4 @@
1
+ import type { MaterialConfig } from "../Material";
1
2
  import Poscar from "./poscar";
2
3
 
3
4
  const NATIVE_FORMAT = {
@@ -7,13 +8,13 @@ const NATIVE_FORMAT = {
7
8
  PWX: "pwx",
8
9
  XYZ: "xyz",
9
10
  UNKNOWN: "unknown",
10
- };
11
+ } as const;
11
12
 
12
13
  /**
13
14
  * @summary Detects the format of the input string
14
- * @throws {Error} - If the input string is unknown format
15
- * @param {string} text - input string to detect format
16
- * @returns {NATIVE_FORMAT} - Format of the input string
15
+ * @throws If the input string is unknown format
16
+ * @param text input string to detect format
17
+ * @returns Format of the input string
17
18
  */
18
19
  function detectFormat(text: string) {
19
20
  const jsonRegex = /^\s*\{/;
@@ -25,11 +26,11 @@ function detectFormat(text: string) {
25
26
 
26
27
  /**
27
28
  * @summary Function to handle conversion from native formats
28
- * @param {String} text - input string to detect format and convert
29
- * @throws {Error} - If the input string is of unknown format
30
- * @return {Object} - Material config
29
+ * @param text - input string to detect format and convert
30
+ * @throws If the input string is of unknown format
31
+ * @return Material config
31
32
  */
32
- function convertFromNativeFormat(text: string) {
33
+ function convertFromNativeFormat(text: string): MaterialConfig {
33
34
  const format = detectFormat(text);
34
35
 
35
36
  switch (format) {
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  BasisSchema,
3
3
  Coordinate3DSchema,
4
+ MaterialEnhancedSchema,
4
5
  MaterialSchema,
5
6
  Vector3DSchema,
6
7
  } from "@mat3ra/esse/dist/js/types";
@@ -14,7 +15,7 @@ import { Cell } from "../cell/cell";
14
15
  import { ATOMIC_COORD_UNITS } from "../constants";
15
16
  import { AtomicConstraintValue } from "../constraints/constraints";
16
17
  import { Lattice } from "../lattice/lattice";
17
-
18
+ import type { MaterialConfig } from "../Material";
18
19
 
19
20
  const _print = (x: number, printFormat = "%14.9f") => s.sprintf(printFormat, Utils.math.precise(x));
20
21
  const _latticeVectorsToString = (vectors: Vector3DSchema[]) =>
@@ -24,15 +25,20 @@ const atomicConstraintsCharFromBool = (bool: boolean): string => (bool ? "T" : "
24
25
  /**
25
26
  * Obtain a textual representation of a material in POSCAR format.
26
27
  * @param materialOrConfig - material class instance or config object.
27
- * @param omitConstraints - whether to discard constraints passed with material.
28
+ * @param omitConstraints - whether to discard constraints when serializing.
28
29
  */
29
- function toPoscar(materialOrConfig: MaterialSchema, omitConstraints = false): string {
30
+ function toPoscar(
31
+ materialOrConfig: MaterialSchema | MaterialEnhancedSchema,
32
+ omitConstraints = false,
33
+ ): string {
30
34
  const lattice = new Lattice(materialOrConfig.lattice);
31
35
  const vectorsAsString = _latticeVectorsToString(lattice.vectorArrays);
32
- // @ts-ignore
36
+ const constraints =
37
+ "constraints" in materialOrConfig.basis ? materialOrConfig.basis.constraints : [];
33
38
  const basis = new ConstrainedBasis({
34
39
  ...materialOrConfig.basis,
35
40
  cell: Cell.fromVectorsArray(lattice.vectorArrays),
41
+ constraints: omitConstraints ? [] : constraints,
36
42
  });
37
43
  const BasisLines: string[] = [];
38
44
  let addSelectiveDynamics = false;
@@ -78,7 +84,7 @@ export function atomsCount(poscarFileContent: string): number {
78
84
  * @param fileContent - POSCAR file content.
79
85
  * @return Material config.
80
86
  */
81
- function fromPoscar(fileContent: string): object {
87
+ function fromPoscar(fileContent: string): MaterialConfig {
82
88
  const cleanContent = Utils.str.removeCommentsFromSourceCode(fileContent, "fortran");
83
89
  const lines = cleanContent.split("\n");
84
90
 
@@ -151,7 +157,7 @@ function fromPoscar(fileContent: string): object {
151
157
  constraints,
152
158
  });
153
159
 
154
- const materialConfig = {
160
+ const materialConfig: MaterialConfig = {
155
161
  lattice: lattice.toJSON(),
156
162
  basis: basis.toJSON(),
157
163
  name: comment,
@@ -1,4 +1,4 @@
1
- import { MaterialSchema } from "@mat3ra/esse/dist/js/types";
1
+ import { MaterialEnhancedSchema, MaterialSchema } from "@mat3ra/esse/dist/js/types";
2
2
  import { isEmpty, isNaN, map } from "lodash";
3
3
  import s from "underscore.string";
4
4
 
@@ -161,16 +161,19 @@ function fromBasis(basisClsInstance: ConstrainedBasis, coordinatePrintFormat: st
161
161
 
162
162
  /**
163
163
  * Create XYZ from Material class instance (or its JSON config).
164
- * @param materialOrConfig Material.
165
- * @param fractional Coordinate units as fractional.
166
- * @return Class Instance
164
+ * Prefer fromBasis when you already have a ConstrainedBasis instance.
167
165
  */
168
- function fromMaterial(materialOrConfig: MaterialSchema, fractional = false): string {
166
+ function fromMaterial(
167
+ materialOrConfig: MaterialSchema | MaterialEnhancedSchema,
168
+ fractional = false,
169
+ ): string {
169
170
  const lattice = new Lattice(materialOrConfig.lattice);
170
- // @ts-ignore
171
+ const constraints =
172
+ "constraints" in materialOrConfig.basis ? materialOrConfig.basis.constraints : [];
171
173
  const basis = new ConstrainedBasis({
172
174
  ...materialOrConfig.basis,
173
175
  cell: Cell.fromVectorsArray(lattice.vectorArrays),
176
+ constraints,
174
177
  });
175
178
  if (fractional) {
176
179
  basis.toCrystal();
@@ -8,7 +8,6 @@ import { AtomicCoordinateValue } from "../basis/coordinates";
8
8
  import { AtomicElementValue } from "../basis/elements";
9
9
  import { Cell } from "../cell/cell";
10
10
 
11
-
12
11
  /**
13
12
  * @summary Combinatorial XYZ basis class and related. Create and get all information about basis and elements in it.
14
13
  * Constructor accepts string in extended XYZ format. Extended XYZ format is as follows:
@@ -225,7 +224,11 @@ export class CombinatorialBasis {
225
224
  dimensions.push(itemsSet);
226
225
  });
227
226
  // @ts-ignore // We're multiplying objects with math, not numbers. No type casting will help.
228
- const basisSet = Utils.math.cartesianProduct.apply(null, dimensions) as ElementWithCoordinate[][];
227
+ const basisSet = Utils.math.cartesianProduct.apply(
228
+ null,
229
+ // @ts-ignore
230
+ dimensions,
231
+ ) as ElementWithCoordinate[][];
229
232
  return basisSet.map((basis: ElementWithCoordinate[]) =>
230
233
  basis.filter((entry) => entry.element !== VACANCY_CHARACTER),
231
234
  );
@@ -5,7 +5,6 @@ import { chunk, flatten } from "lodash";
5
5
  import { Basis } from "../basis/basis";
6
6
  import { AtomicCoordinateValue, Coordinate } from "../basis/coordinates";
7
7
 
8
-
9
8
  const ADD = Utils.math.add;
10
9
  const MULT = Utils.math.multiply;
11
10
 
@@ -3,7 +3,6 @@ import { Utils } from "@mat3ra/utils";
3
3
 
4
4
  import { Cell } from "../cell/cell";
5
5
 
6
-
7
6
  /**
8
7
  * Returns the list of points on the original lattice contained in the supercell in fractional coordinates.
9
8
  * Source: https://pymatgen.org/_modules/pymatgen/util/coord.html
@@ -3,8 +3,7 @@ import { Utils } from "@mat3ra/utils";
3
3
 
4
4
  import { ATOMIC_COORD_UNITS } from "../constants";
5
5
  import { Lattice } from "../lattice/lattice";
6
- import { Material } from "../material";
7
-
6
+ import Material from "../Material";
8
7
 
9
8
  /**
10
9
  * Scales one lattice vector for the given material
@@ -18,9 +17,9 @@ function scaleOneLatticeVector(material: Material, key: "a" | "b" | "c" = "a", f
18
17
  if (lattice.vectors === undefined) {
19
18
  throw new Error("Lattice vectors are undefined");
20
19
  }
21
- lattice.vectors[key] = lattice.vectors![key].map((v) => v * factor) as Vector3DSchema;
20
+ lattice.vectors[key] = lattice.vectors[key].map((v) => v * factor) as Vector3DSchema;
22
21
 
23
- material.lattice = Lattice.fromVectors(lattice.vectors).toJSON();
22
+ material.setLattice(Lattice.fromVectors(lattice.vectors).toJSON());
24
23
  }
25
24
 
26
25
  /**
@@ -29,10 +28,12 @@ function scaleOneLatticeVector(material: Material, key: "a" | "b" | "c" = "a", f
29
28
  * @param material {Material}
30
29
  */
31
30
  function scaleLatticeToMakeNonPeriodic(material: Material) {
32
- material.lattice = Lattice.fromConfigPartial({
33
- a: material.Basis.getMinimumLatticeSize(),
34
- type: "CUB",
35
- } as LatticeSchema).toJSON();
31
+ material.setLattice(
32
+ Lattice.fromConfigPartial({
33
+ a: material.getBasis().getMinimumLatticeSize(),
34
+ type: "CUB",
35
+ } as LatticeSchema).toJSON(),
36
+ );
36
37
  }
37
38
 
38
39
  /**
@@ -41,13 +42,14 @@ function scaleLatticeToMakeNonPeriodic(material: Material) {
41
42
  * @param material {Material}
42
43
  * */
43
44
  function translateAtomsToCenter(material: Material) {
44
- const originalUnits = material.Basis.units;
45
+ const basis = material.getBasis();
46
+ const originalUnits = basis.units;
45
47
  material.toCartesian();
46
- const updatedBasis = material.Basis;
48
+ const updatedBasis = basis.toCartesian();
47
49
  const centerOfCoordinates = updatedBasis.centerOfCoordinatesPoint;
48
50
  const centerOfLattice = Utils.math.multiply(
49
51
  0.5,
50
- material.Lattice.vectorArrays.reduce((a, b) => Utils.math.add(a, b) as Vector3DSchema),
52
+ material.getLattice().vectorArrays.reduce((a, b) => Utils.math.add(a, b) as Vector3DSchema),
51
53
  );
52
54
  const translationVector = Utils.math.subtract(centerOfLattice, centerOfCoordinates);
53
55
  updatedBasis.translateByVector(translationVector as Vector3DSchema);