@mat3ra/made 2026.7.18-0 → 2026.7.29-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.
@@ -1,111 +1,111 @@
1
1
  {
2
2
  "CUB": [
3
- ["Г", "X", "M", "Г", "R", "X"],
3
+ ["Γ", "X", "M", "Γ", "R", "X"],
4
4
  ["M", "R"]
5
5
  ],
6
6
  "BCC": [
7
- ["Г", "H", "N", "Г", "P", "H"],
7
+ ["Γ", "H", "N", "Γ", "P", "H"],
8
8
  ["P", "N"]
9
9
  ],
10
10
  "FCC": [
11
- ["Г", "X", "W", "K", "Г", "L", "U", "W", "L"],
11
+ ["Γ", "X", "W", "K", "Γ", "L", "U", "W", "L"],
12
12
  ["U", "X"]
13
13
  ],
14
14
  "TET": [
15
- ["Г", "X", "M", "Г", "Z", "R", "A", "Z"],
15
+ ["Γ", "X", "M", "Γ", "Z", "R", "A", "Z"],
16
16
  ["X", "R"],
17
17
  ["M", "A"]
18
18
  ],
19
19
  "BCT-1": [
20
- ["Г", "X", "M", "Г", "Z", "P", "N", "Z1", "M"],
20
+ ["Γ", "X", "M", "Γ", "Z", "P", "N", "Z1", "M"],
21
21
  ["X", "P"]
22
22
  ],
23
23
  "BCT-2": [
24
- ["Г", "X", "Y", "∑", "Г", "Z", "∑1", "N", "P", "Y1", "Z"],
24
+ ["Γ", "X", "Y", "∑", "Γ", "Z", "∑1", "N", "P", "Y1", "Z"],
25
25
  ["X", "P"]
26
26
  ],
27
27
  "ORC": [
28
- ["Г", "X", "S", "Y", "Г", "Z", "U", "R", "T", "Z"],
28
+ ["Γ", "X", "S", "Y", "Γ", "Z", "U", "R", "T", "Z"],
29
29
  ["Y", "T"],
30
30
  ["U", "X"],
31
31
  ["S", "R"]
32
32
  ],
33
33
  "ORCF-1": [
34
- ["Г", "Y", "T", "Z", "Г", "X", "A1", "Y"],
34
+ ["Γ", "Y", "T", "Z", "Γ", "X", "A1", "Y"],
35
35
  ["T", "X1"],
36
36
  ["X", "A", "Z"],
37
- ["L", "Г"]
37
+ ["L", "Γ"]
38
38
  ],
39
39
  "ORCF-2": [
40
- ["Г", "Y", "C", "D", "X", "Г", "Z", "D1", "H", "C"],
40
+ ["Γ", "Y", "C", "D", "X", "Γ", "Z", "D1", "H", "C"],
41
41
  ["C1", "Z"],
42
42
  ["X", "H1"],
43
43
  ["H", "Y"],
44
- ["L", "Г"]
44
+ ["L", "Γ"]
45
45
  ],
46
46
  "ORCF-3": [
47
- ["Г", "Y", "T", "Z", "Г", "X", "A1", "Y"],
47
+ ["Γ", "Y", "T", "Z", "Γ", "X", "A1", "Y"],
48
48
  ["X", "A", "Z"],
49
- ["L", "Г"]
49
+ ["L", "Γ"]
50
50
  ],
51
51
  "ORCI": [
52
- ["Г", "X", "L", "T", "W", "R", "X1", "Z", "Г", "Y", "S", "W"],
52
+ ["Γ", "X", "L", "T", "W", "R", "X1", "Z", "Γ", "Y", "S", "W"],
53
53
  ["L1", "Y"],
54
54
  ["Y1", "Z"]
55
55
  ],
56
56
  "ORCC": [
57
- ["Г", "X", "S", "R", "A", "Z", "Г", "Y", "X1", "A1", "T", "Y"],
57
+ ["Γ", "X", "S", "R", "A", "Z", "Γ", "Y", "X1", "A1", "T", "Y"],
58
58
  ["Z", "T"]
59
59
  ],
60
60
  "HEX": [
61
- ["Г", "M", "K", "Г", "A", "L", "H", "A"],
61
+ ["Γ", "M", "K", "Γ", "A", "L", "H", "A"],
62
62
  ["L", "M"],
63
63
  ["K", "H"]
64
64
  ],
65
65
  "RHL-1": [
66
- ["Г", "L", "B1"],
67
- ["B", "Z", "Г", "X"],
66
+ ["Γ", "L", "B1"],
67
+ ["B", "Z", "Γ", "X"],
68
68
  ["Q", "F", "P1", "Z"],
69
69
  ["L", "P"]
70
70
  ],
71
- "RHL-2": [["Г", "P", "Z", "Q", "Г", "F", "P1", "Q1", "L", "Z"]],
71
+ "RHL-2": [["Γ", "P", "Z", "Q", "Γ", "F", "P1", "Q1", "L", "Z"]],
72
72
  "MCL": [
73
- ["Г", "Y", "H", "C", "E", "M1", "A", "X", "H1"],
73
+ ["Γ", "Y", "H", "C", "E", "M1", "A", "X", "H1"],
74
74
  ["M", "D", "Z"],
75
75
  ["Y", "D"]
76
76
  ],
77
77
  "MCLC-1": [
78
- ["Г", "Y", "Г", "L", "I"],
78
+ ["Γ", "Y", "Γ", "L", "I"],
79
79
  ["I1", "Z", "F1"],
80
80
  ["Y", "X1"],
81
- ["X", "Г", "N"],
82
- ["M", "Г"]
81
+ ["X", "Γ", "N"],
82
+ ["M", "Γ"]
83
83
  ],
84
84
  "MCLC-2": [
85
- ["Г", "Y", "F", "L", "I"],
85
+ ["Γ", "Y", "F", "L", "I"],
86
86
  ["I1", "Z", "F1"],
87
- ["N", "Г", "M"]
87
+ ["N", "Γ", "M"]
88
88
  ],
89
89
  "MCLC-3": [
90
- ["Г", "Y", "F", "H", "Z", "I", "F1"],
91
- ["H1", "Y1", "X", "Г", "N"],
92
- ["M", "Г"]
90
+ ["Γ", "Y", "F", "H", "Z", "I", "F1"],
91
+ ["H1", "Y1", "X", "Γ", "N"],
92
+ ["M", "Γ"]
93
93
  ],
94
94
  "MCLC-4": [
95
- ["Г", "Y", "F", "H", "Z", "I"],
96
- ["H1", "Y1", "X", "Г", "N"],
97
- ["M", "Г"]
95
+ ["Γ", "Y", "F", "H", "Z", "I"],
96
+ ["H1", "Y1", "X", "Γ", "N"],
97
+ ["M", "Γ"]
98
98
  ],
99
99
  "MCLC-5": [
100
- ["Г", "Y", "F", "L", "I"],
100
+ ["Γ", "Y", "F", "L", "I"],
101
101
  ["I1", "Z", "H", "F1"],
102
- ["H1", "Y1", "X", "Г", "N"],
103
- ["M", "Г"]
102
+ ["H1", "Y1", "X", "Γ", "N"],
103
+ ["M", "Γ"]
104
104
  ],
105
105
  "TRI": [
106
- ["X", "Г", "Y"],
107
- ["L", "Г", "Z"],
108
- ["N", "Г", "M"],
109
- ["R", "Г"]
106
+ ["X", "Γ", "Y"],
107
+ ["L", "Γ", "Z"],
108
+ ["N", "Γ", "M"],
109
+ ["R", "Γ"]
110
110
  ]
111
111
  }
@@ -1,111 +1,111 @@
1
1
  {
2
2
  "CUB": [
3
- ["Г", "X", "M", "Г", "R", "X"],
3
+ ["Γ", "X", "M", "Γ", "R", "X"],
4
4
  ["M", "R"]
5
5
  ],
6
6
  "BCC": [
7
- ["Г", "H", "N", "Г", "P", "H"],
7
+ ["Γ", "H", "N", "Γ", "P", "H"],
8
8
  ["P", "N"]
9
9
  ],
10
10
  "FCC": [
11
- ["Г", "X", "W", "K", "Г", "L", "U", "W", "L"],
11
+ ["Γ", "X", "W", "K", "Γ", "L", "U", "W", "L"],
12
12
  ["U", "X"]
13
13
  ],
14
14
  "TET": [
15
- ["Г", "X", "M", "Г", "Z", "R", "A", "Z"],
15
+ ["Γ", "X", "M", "Γ", "Z", "R", "A", "Z"],
16
16
  ["X", "R"],
17
17
  ["M", "A"]
18
18
  ],
19
19
  "BCT-1": [
20
- ["Г", "X", "M", "Г", "Z", "P", "N", "Z1", "M"],
20
+ ["Γ", "X", "M", "Γ", "Z", "P", "N", "Z1", "M"],
21
21
  ["X", "P"]
22
22
  ],
23
23
  "BCT-2": [
24
- ["Г", "X", "Y", "∑", "Г", "Z", "∑1", "N", "P", "Y1", "Z"],
24
+ ["Γ", "X", "Y", "∑", "Γ", "Z", "∑1", "N", "P", "Y1", "Z"],
25
25
  ["X", "P"]
26
26
  ],
27
27
  "ORC": [
28
- ["Г", "X", "S", "Y", "Г", "Z", "U", "R", "T", "Z"],
28
+ ["Γ", "X", "S", "Y", "Γ", "Z", "U", "R", "T", "Z"],
29
29
  ["Y", "T"],
30
30
  ["U", "X"],
31
31
  ["S", "R"]
32
32
  ],
33
33
  "ORCF-1": [
34
- ["Г", "Y", "T", "Z", "Г", "X", "A1", "Y"],
34
+ ["Γ", "Y", "T", "Z", "Γ", "X", "A1", "Y"],
35
35
  ["T", "X1"],
36
36
  ["X", "A", "Z"],
37
- ["L", "Г"]
37
+ ["L", "Γ"]
38
38
  ],
39
39
  "ORCF-2": [
40
- ["Г", "Y", "C", "D", "X", "Г", "Z", "D1", "H", "C"],
40
+ ["Γ", "Y", "C", "D", "X", "Γ", "Z", "D1", "H", "C"],
41
41
  ["C1", "Z"],
42
42
  ["X", "H1"],
43
43
  ["H", "Y"],
44
- ["L", "Г"]
44
+ ["L", "Γ"]
45
45
  ],
46
46
  "ORCF-3": [
47
- ["Г", "Y", "T", "Z", "Г", "X", "A1", "Y"],
47
+ ["Γ", "Y", "T", "Z", "Γ", "X", "A1", "Y"],
48
48
  ["X", "A", "Z"],
49
- ["L", "Г"]
49
+ ["L", "Γ"]
50
50
  ],
51
51
  "ORCI": [
52
- ["Г", "X", "L", "T", "W", "R", "X1", "Z", "Г", "Y", "S", "W"],
52
+ ["Γ", "X", "L", "T", "W", "R", "X1", "Z", "Γ", "Y", "S", "W"],
53
53
  ["L1", "Y"],
54
54
  ["Y1", "Z"]
55
55
  ],
56
56
  "ORCC": [
57
- ["Г", "X", "S", "R", "A", "Z", "Г", "Y", "X1", "A1", "T", "Y"],
57
+ ["Γ", "X", "S", "R", "A", "Z", "Γ", "Y", "X1", "A1", "T", "Y"],
58
58
  ["Z", "T"]
59
59
  ],
60
60
  "HEX": [
61
- ["Г", "M", "K", "Г", "A", "L", "H", "A"],
61
+ ["Γ", "M", "K", "Γ", "A", "L", "H", "A"],
62
62
  ["L", "M"],
63
63
  ["K", "H"]
64
64
  ],
65
65
  "RHL-1": [
66
- ["Г", "L", "B1"],
67
- ["B", "Z", "Г", "X"],
66
+ ["Γ", "L", "B1"],
67
+ ["B", "Z", "Γ", "X"],
68
68
  ["Q", "F", "P1", "Z"],
69
69
  ["L", "P"]
70
70
  ],
71
- "RHL-2": [["Г", "P", "Z", "Q", "Г", "F", "P1", "Q1", "L", "Z"]],
71
+ "RHL-2": [["Γ", "P", "Z", "Q", "Γ", "F", "P1", "Q1", "L", "Z"]],
72
72
  "MCL": [
73
- ["Г", "Y", "H", "C", "E", "M1", "A", "X", "H1"],
73
+ ["Γ", "Y", "H", "C", "E", "M1", "A", "X", "H1"],
74
74
  ["M", "D", "Z"],
75
75
  ["Y", "D"]
76
76
  ],
77
77
  "MCLC-1": [
78
- ["Г", "Y", "Г", "L", "I"],
78
+ ["Γ", "Y", "Γ", "L", "I"],
79
79
  ["I1", "Z", "F1"],
80
80
  ["Y", "X1"],
81
- ["X", "Г", "N"],
82
- ["M", "Г"]
81
+ ["X", "Γ", "N"],
82
+ ["M", "Γ"]
83
83
  ],
84
84
  "MCLC-2": [
85
- ["Г", "Y", "F", "L", "I"],
85
+ ["Γ", "Y", "F", "L", "I"],
86
86
  ["I1", "Z", "F1"],
87
- ["N", "Г", "M"]
87
+ ["N", "Γ", "M"]
88
88
  ],
89
89
  "MCLC-3": [
90
- ["Г", "Y", "F", "H", "Z", "I", "F1"],
91
- ["H1", "Y1", "X", "Г", "N"],
92
- ["M", "Г"]
90
+ ["Γ", "Y", "F", "H", "Z", "I", "F1"],
91
+ ["H1", "Y1", "X", "Γ", "N"],
92
+ ["M", "Γ"]
93
93
  ],
94
94
  "MCLC-4": [
95
- ["Г", "Y", "F", "H", "Z", "I"],
96
- ["H1", "Y1", "X", "Г", "N"],
97
- ["M", "Г"]
95
+ ["Γ", "Y", "F", "H", "Z", "I"],
96
+ ["H1", "Y1", "X", "Γ", "N"],
97
+ ["M", "Γ"]
98
98
  ],
99
99
  "MCLC-5": [
100
- ["Г", "Y", "F", "L", "I"],
100
+ ["Γ", "Y", "F", "L", "I"],
101
101
  ["I1", "Z", "H", "F1"],
102
- ["H1", "Y1", "X", "Г", "N"],
103
- ["M", "Г"]
102
+ ["H1", "Y1", "X", "Γ", "N"],
103
+ ["M", "Γ"]
104
104
  ],
105
105
  "TRI": [
106
- ["X", "Г", "Y"],
107
- ["L", "Г", "Z"],
108
- ["N", "Г", "M"],
109
- ["R", "Г"]
106
+ ["X", "Γ", "Y"],
107
+ ["L", "Γ", "Z"],
108
+ ["N", "Γ", "M"],
109
+ ["R", "Γ"]
110
110
  ]
111
111
  }
@@ -858,7 +858,7 @@ const POINTS = {
858
858
  function symmetryPoints(lattice) {
859
859
  return [
860
860
  {
861
- point: "Г",
861
+ point: "Γ",
862
862
  coordinates: [0.0, 0.0, 0.0],
863
863
  },
864
864
  ].concat(POINTS[lattice.type](lattice) || []);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mat3ra/made",
3
- "version": "2026.7.18-0",
3
+ "version": "2026.7.29-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",
@@ -879,7 +879,7 @@ const POINTS = {
879
879
  export function symmetryPoints(lattice: Lattice) {
880
880
  return [
881
881
  {
882
- point: "Г",
882
+ point: "Γ",
883
883
  coordinates: [0.0, 0.0, 0.0],
884
884
  },
885
885
  ].concat(POINTS[lattice.type](lattice) || []);
@@ -367,7 +367,7 @@ def get_symmetry_points(lattice: Any) -> List[dict]:
367
367
  """
368
368
  lattice_type = lattice.type.value if hasattr(lattice.type, "value") else str(lattice.type)
369
369
 
370
- gamma_point = [{"point": "Г", "coordinates": [0.0, 0.0, 0.0]}]
370
+ gamma_point = [{"point": "Γ", "coordinates": [0.0, 0.0, 0.0]}]
371
371
 
372
372
  points_fn = POINTS.get(lattice_type)
373
373
  if points_fn is None:
@@ -31,7 +31,7 @@ class SolidSolutionBuilder(MergeBuilder):
31
31
  source_element = configuration.source_element
32
32
  target_element = configuration.target_element
33
33
  material.name = (
34
- f"{formula} - Solid Solution ({source_element}\u2192{target_element} "
34
+ f"{formula} - Solid Solution ({source_element}->{target_element} "
35
35
  f"{concentration_percentage:.4g}%)"
36
36
  )
37
37
  return material
@@ -1,4 +1,4 @@
1
- from typing import Optional
1
+ from typing import Optional, Tuple
2
2
 
3
3
  from ...material import Material
4
4
  from ..analyze.other import get_surface_area
@@ -88,6 +88,31 @@ def calculate_adhesion_energy(
88
88
  return (energy_substrate_slab + energy_film_slab - energy_interface) / area
89
89
 
90
90
 
91
+ def _get_interface_with_build_metadata(interface: Material) -> MaterialWithBuildMetadata:
92
+ if isinstance(interface, MaterialWithBuildMetadata):
93
+ return interface
94
+ return MaterialWithBuildMetadata.create(interface.to_dict())
95
+
96
+
97
+ def _resolve_interface_bulk_materials(
98
+ interface: Material,
99
+ substrate_bulk: Optional[Material],
100
+ film_bulk: Optional[Material],
101
+ ) -> Tuple[Optional[Material], Optional[Material]]:
102
+ """Resolve missing bulks from interface build metadata (handles BoundaryConditions metadata)."""
103
+ try:
104
+ interface_with_metadata = _get_interface_with_build_metadata(interface)
105
+ if substrate_bulk is None:
106
+ substrate_bulk = Material.create(get_interface_bulk_crystal(interface_with_metadata, part="substrate"))
107
+ if film_bulk is None:
108
+ film_bulk = Material.create(get_interface_bulk_crystal(interface_with_metadata, part="film"))
109
+ except (ValueError, TypeError) as exc:
110
+ raise ValueError(
111
+ "The substrate and film bulk materials must be provided or defined in the interface metadata."
112
+ ) from exc
113
+ return substrate_bulk, film_bulk
114
+
115
+
91
116
  def calculate_interfacial_energy(
92
117
  interface: Material,
93
118
  substrate_slab: Optional[Material] = None,
@@ -115,14 +140,9 @@ def calculate_interfacial_energy(
115
140
  substrate_slab = get_slab(interface, part="substrate") if substrate_slab is None else substrate_slab
116
141
  film_slab = get_slab(interface, part="film") if film_slab is None else film_slab
117
142
 
118
- try:
119
- interface_with_metadata = MaterialWithBuildMetadata.create(interface.to_dict())
120
- substrate_bulk = Material.create(get_interface_bulk_crystal(interface_with_metadata, part="substrate"))
121
- film_bulk = Material.create(get_interface_bulk_crystal(interface_with_metadata, part="film"))
122
- except ValueError as exc:
123
- raise ValueError(
124
- "The substrate and film bulk materials must be provided or defined in the interface metadata."
125
- ) from exc
143
+ if substrate_bulk is None or film_bulk is None:
144
+ substrate_bulk, film_bulk = _resolve_interface_bulk_materials(interface, substrate_bulk, film_bulk)
145
+
126
146
  surface_energy_substrate = calculate_surface_energy(substrate_slab, substrate_bulk, calculator)
127
147
  surface_energy_film = calculate_surface_energy(film_slab, film_bulk, calculator)
128
148
  adhesion_energy = calculate_adhesion_energy(interface, substrate_slab, film_slab, calculator)
@@ -22,9 +22,12 @@ def supercell(material: MaterialWithBuildMetadata, supercell_matrix) -> Material
22
22
  atoms = to_ase(material)
23
23
 
24
24
  supercell_atoms = ase_make_supercell(atoms, supercell_matrix)
25
- new_material = MaterialWithBuildMetadata.create(from_ase(supercell_atoms))
26
- # if material.metadata:
27
- # new_material.metadata.update(**material.metadata.to_dict())
25
+ material_config = from_ase(supercell_atoms)
26
+ # ASE make_supercell drops atoms.info; merge prior build/boundaryConditions when present.
27
+ source_metadata = material.to_dict().get("metadata") or {}
28
+ if source_metadata:
29
+ material_config["metadata"] = {**material_config.get("metadata", {}), **source_metadata}
30
+ new_material = MaterialWithBuildMetadata.create(material_config)
28
31
  new_material.name = material.name
29
32
  return new_material
30
33
 
@@ -14,7 +14,7 @@ describe("Lattice Reciprocal", () => {
14
14
  const lattice = new ReciprocalLattice(Na4Cl4.lattice as LatticeSchema);
15
15
  const expectedPath = [
16
16
  {
17
- point: "Г",
17
+ point: "Γ",
18
18
  steps: 0,
19
19
  coordinates: [0, 0, 0],
20
20
  },
@@ -54,7 +54,7 @@ describe("Lattice Reciprocal", () => {
54
54
  const actualPoints = lattice.symmetryPoints;
55
55
  const expectedPoints = [
56
56
  {
57
- point: "Г",
57
+ point: "Γ",
58
58
  coordinates: [0, 0, 0],
59
59
  },
60
60
  {
@@ -5,7 +5,7 @@ from mat3ra.standata.materials import Materials
5
5
  BULK_SrTiO3 = Materials.get_by_name_first_match("SrTiO3")
6
6
  BULK_GRAPHITE = Materials.get_by_name_first_match("Graphite")
7
7
  BULK_SiO2 = Materials.get_by_name_first_match("SiO2")
8
- BULK_Hf2O_MCL = Materials.get_by_name_first_match("Hafnium.*MCL")
8
+ BULK_Hf2O_MCL = Materials.get_by_name_first_match("Hafnium IV Oxide, MCL")
9
9
  BULK_TiN = Materials.get_by_name_first_match("TiN")
10
10
  BULK_Ni_PRIMITIVE = Materials.get_by_name_first_match("Nickel")
11
11
  BULK_GRAPHENE = Materials.get_by_name_first_match("Graphene")
@@ -5,18 +5,18 @@ from mat3ra.utils import assertion as assertion_utils
5
5
 
6
6
 
7
7
  def test_reciprocal_lattice_symmetry_points_cub():
8
- """CUB lattice should have Г, R, X, M symmetry points."""
8
+ """CUB lattice should have Γ, R, X, M symmetry points."""
9
9
  lattice = ReciprocalLattice(a=5.64, b=5.64, c=5.64, type="CUB")
10
10
  points = lattice.symmetry_points
11
11
  labels = [p["point"] for p in points]
12
- assert labels == ["Г", "R", "X", "M"]
12
+ assert labels == ["Γ", "R", "X", "M"]
13
13
 
14
14
 
15
15
  def test_reciprocal_lattice_default_kpoint_path_cub():
16
16
  lattice = ReciprocalLattice(a=5.64, b=5.64, c=5.64, type="CUB")
17
17
  path = lattice.default_kpoint_path
18
18
  labels = [p["point"] for p in path]
19
- assert labels == ["Г", "X", "M", "Г", "R", "X", "M", "R"]
19
+ assert labels == ["Γ", "X", "M", "Γ", "R", "X", "M", "R"]
20
20
 
21
21
 
22
22
  def test_reciprocal_lattice_default_kpoint_path_bct():
@@ -32,7 +32,7 @@ def test_reciprocal_lattice_extract_kpoint_path():
32
32
  data_points = [[0, 0, 0], [0.5, 0.5, 0.5]]
33
33
  result = lattice.extract_kpoint_path(data_points)
34
34
  assert len(result) == 2
35
- assert result[0]["point"] == "Г"
35
+ assert result[0]["point"] == "Γ"
36
36
  assert result[0]["steps"] == 0
37
37
  assert result[1]["point"] == "R"
38
38
  assert result[1]["steps"] == 1
@@ -49,16 +49,16 @@ def test_reciprocal_paths_entry_structure():
49
49
  def test_reciprocal_paths_cub():
50
50
  path = RECIPROCAL_PATHS["CUB"]
51
51
  labels = [p["point"] for p in path]
52
- assert labels == ["Г", "X", "M", "Г", "R", "X", "M", "R"]
52
+ assert labels == ["Γ", "X", "M", "Γ", "R", "X", "M", "R"]
53
53
 
54
54
 
55
55
  def test_reciprocal_paths_fcc():
56
56
  path = RECIPROCAL_PATHS["FCC"]
57
57
  labels = [p["point"] for p in path]
58
- assert labels == ["Г", "X", "W", "K", "Г", "L", "U", "W", "L", "U", "X"]
58
+ assert labels == ["Γ", "X", "W", "K", "Γ", "L", "U", "W", "L", "U", "X"]
59
59
 
60
60
 
61
61
  def test_reciprocal_paths_hex():
62
62
  path = RECIPROCAL_PATHS["HEX"]
63
63
  labels = [p["point"] for p in path]
64
- assert labels == ["Г", "M", "K", "Г", "A", "L", "H", "A", "L", "M", "K", "H"]
64
+ assert labels == ["Γ", "M", "K", "Γ", "A", "L", "H", "A", "L", "M", "K", "H"]
@@ -10,7 +10,7 @@ def test_symmetry_points_gamma_always_first():
10
10
  """Gamma point should always be the first symmetry point."""
11
11
  lattice = Lattice(a=1.0, b=1.0, c=1.0, type="CUB")
12
12
  points = get_symmetry_points(lattice)
13
- assert points[0]["point"] == "Г"
13
+ assert points[0]["point"] == "Γ"
14
14
  assert points[0]["coordinates"] == [0.0, 0.0, 0.0]
15
15
 
16
16
 
@@ -18,7 +18,7 @@ def test_symmetry_points_cub():
18
18
  lattice = Lattice(a=5.64, b=5.64, c=5.64, type="CUB")
19
19
  points = get_symmetry_points(lattice)
20
20
  labels = [p["point"] for p in points]
21
- assert labels == ["Г", "R", "X", "M"]
21
+ assert labels == ["Γ", "R", "X", "M"]
22
22
  # Verify specific coordinates
23
23
  r_point = next(p for p in points if p["point"] == "R")
24
24
  assertion_utils.assert_deep_almost_equal(r_point["coordinates"], [0.5, 0.5, 0.5])
@@ -45,7 +45,7 @@ def test_symmetry_points_bcc():
45
45
  lattice = Lattice(a=3.0, b=3.0, c=3.0, type="BCC")
46
46
  points = get_symmetry_points(lattice)
47
47
  labels = [p["point"] for p in points]
48
- assert labels == ["Г", "H", "P", "N"]
48
+ assert labels == ["Γ", "H", "P", "N"]
49
49
  h_point = next(p for p in points if p["point"] == "H")
50
50
  assertion_utils.assert_deep_almost_equal(h_point["coordinates"], [0.5, -0.5, 0.5])
51
51
 
@@ -54,7 +54,7 @@ def test_symmetry_points_hex():
54
54
  lattice = Lattice(a=2.46, b=2.46, c=6.71, type="HEX")
55
55
  points = get_symmetry_points(lattice)
56
56
  labels = [p["point"] for p in points]
57
- assert set(labels) == {"Г", "A", "H", "K", "L", "M"}
57
+ assert set(labels) == {"Γ", "A", "H", "K", "L", "M"}
58
58
  k_point = next(p for p in points if p["point"] == "K")
59
59
  assertion_utils.assert_deep_almost_equal(k_point["coordinates"], [1 / 3, 1 / 3, 0.0])
60
60
 
@@ -86,14 +86,14 @@ def test_symmetry_points_tet():
86
86
  lattice = Lattice(a=3.0, b=3.0, c=5.0, type="TET")
87
87
  points = get_symmetry_points(lattice)
88
88
  labels = [p["point"] for p in points]
89
- assert set(labels) == {"Г", "A", "M", "R", "X", "Z"}
89
+ assert set(labels) == {"Γ", "A", "M", "R", "X", "Z"}
90
90
 
91
91
 
92
92
  def test_symmetry_points_orc():
93
93
  lattice = Lattice(a=2.0, b=3.0, c=4.0, type="ORC")
94
94
  points = get_symmetry_points(lattice)
95
95
  labels = [p["point"] for p in points]
96
- assert set(labels) == {"Г", "R", "S", "T", "U", "X", "Y", "Z"}
96
+ assert set(labels) == {"Γ", "R", "S", "T", "U", "X", "Y", "Z"}
97
97
 
98
98
 
99
99
  def test_symmetry_points_rhl1():
@@ -144,7 +144,7 @@ def test_symmetry_points_all_lattice_types(lattice_type):
144
144
  lattice = Lattice(a=3.0, b=4.0, c=5.0, alpha=80.0, beta=85.0, gamma=75.0, type=lattice_type)
145
145
  points = get_symmetry_points(lattice)
146
146
  assert len(points) >= 1
147
- assert points[0]["point"] == "Г"
147
+ assert points[0]["point"] == "Γ"
148
148
  # All coordinates should be lists of 3 floats
149
149
  for p in points:
150
150
  assert len(p["coordinates"]) == 3
@@ -2,18 +2,22 @@ import numpy as np
2
2
  import pytest
3
3
  from mat3ra.made.material import Material
4
4
  from mat3ra.made.tools.build_components.entities.reusable.three_dimensional.supercell.helpers import create_supercell
5
+ from mat3ra.made.tools.build_components.metadata import MaterialWithBuildMetadata
6
+ from unit.fixtures.interface.zsl import GRAPHENE_NICKEL_INTERFACE
5
7
  from unit.fixtures.supercell import SI_SUPERCELL_2X2X1
6
8
 
7
9
  from .fixtures.bulk import BULK_Si_PRIMITIVE
8
10
  from .utils import assert_two_entities_deep_almost_equal
9
11
 
12
+ SUPERCELL_MATRIX_2X2X1 = [[2, 0, 0], [0, 2, 0], [0, 0, 1]]
13
+
10
14
 
11
15
  @pytest.mark.parametrize(
12
16
  "material_config, supercell_matrix, expected_material_config",
13
17
  [
14
18
  (
15
19
  BULK_Si_PRIMITIVE,
16
- [[2, 0, 0], [0, 2, 0], [0, 0, 1]],
20
+ SUPERCELL_MATRIX_2X2X1,
17
21
  SI_SUPERCELL_2X2X1,
18
22
  ),
19
23
  ],
@@ -27,3 +31,17 @@ def test_create_supercell(material_config, supercell_matrix, expected_material_c
27
31
  expected_vectors = np.array(supercell_matrix) @ np.array(material.lattice.vector_arrays)
28
32
  actual_vectors = np.array(supercell_material.lattice.vector_arrays)
29
33
  assert np.allclose(actual_vectors, expected_vectors, atol=1e-6), "Supercell vectors do not match expected values."
34
+
35
+
36
+ def test_create_supercell_preserves_prior_build_metadata():
37
+ material = MaterialWithBuildMetadata.create(GRAPHENE_NICKEL_INTERFACE)
38
+ prior_build_types = [step.configuration.get("type") for step in material.metadata.build]
39
+
40
+ supercell_material = create_supercell(material, SUPERCELL_MATRIX_2X2X1)
41
+
42
+ result_build_types = [step.configuration.get("type") for step in supercell_material.metadata.build]
43
+ assert result_build_types[:-1] == prior_build_types
44
+ assert result_build_types[-1] == "SupercellConfiguration"
45
+ assert supercell_material.metadata.to_dict().get("boundaryConditions") == material.metadata.to_dict().get(
46
+ "boundaryConditions"
47
+ )
@@ -1,5 +1,4 @@
1
1
  import numpy as np
2
- import pytest
3
2
  from ase.build import add_adsorbate, bulk, fcc111, graphene, surface
4
3
  from ase.calculators import emt
5
4
  from mat3ra.made.material import Material
@@ -20,16 +19,15 @@ graphene_layer.cell = nickel_slab.cell
20
19
  interface = nickel_slab.copy()
21
20
  add_adsorbate(interface, graphene_layer, height=2, position="ontop")
22
21
 
23
- # Material objects setup
22
+ # Material.create yields MaterialMetadataBoundaryConditions; bulks are resolved from nested build.
24
23
  interface_material = Material.create(GRAPHENE_NICKEL_INTERFACE)
25
24
  nickel_slab_material = Material.create(from_ase(nickel_slab))
26
- nickel_bulk_material = Material.create(from_ase(bulk("Ni", "fcc", a=3.52)))
27
- graphene_layer_material = Material.create(from_ase(graphene_layer))
28
- graphene_bulk_material = graphene_layer
29
25
 
30
26
  # Calculator setup
31
27
  calculator = emt.EMT()
32
28
 
29
+ EXPECTED_INTERFACIAL_ENERGY = -0.78488
30
+
33
31
 
34
32
  def test_calculate_total_energy():
35
33
  atoms = bulk("C", cubic=True)
@@ -59,17 +57,11 @@ def test_calculate_adhesion_energy():
59
57
  assert np.isclose(adhesion_energy, 0.07345)
60
58
 
61
59
 
62
- @pytest.mark.skip(reason="This test is not working as expected")
63
60
  def test_calculate_interfacial_energy():
64
61
  interfacial_energy = calculate_interfacial_energy(
65
62
  interface_material,
66
- nickel_slab_material,
67
- nickel_bulk_material,
68
- graphene_layer,
69
- graphene_bulk_material,
70
- calculator,
71
- )
72
- assert np.isclose(
73
- interfacial_energy,
74
- -0.78488,
63
+ substrate_slab=nickel_slab_material,
64
+ film_slab=graphene_layer,
65
+ calculator=calculator,
75
66
  )
67
+ assert np.isclose(interfacial_energy, EXPECTED_INTERFACIAL_ENERGY)