@mat3ra/made 2026.7.4-0 → 2026.7.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 (47) hide show
  1. package/dist/js/basis/basis.js +8 -8
  2. package/dist/js/basis/coordinates.js +2 -2
  3. package/dist/js/cell/cell.js +11 -10
  4. package/dist/js/cell/primitive_cell.js +18 -19
  5. package/dist/js/lattice/lattice.js +25 -23
  6. package/dist/js/lattice/reciprocal/lattice_reciprocal.js +16 -16
  7. package/dist/js/parsers/poscar.js +1 -2
  8. package/dist/js/parsers/xyz_combinatorial_basis.js +2 -2
  9. package/dist/js/tools/basis.js +3 -3
  10. package/dist/js/tools/cell.js +3 -3
  11. package/dist/js/tools/material.js +3 -3
  12. package/dist/js/tools/supercell.js +3 -3
  13. package/dist/js/tools/surface.js +14 -12
  14. package/package.json +3 -2
  15. package/pyproject.toml +1 -1
  16. package/src/js/basis/basis.ts +9 -8
  17. package/src/js/basis/coordinates.ts +3 -2
  18. package/src/js/cell/cell.ts +12 -10
  19. package/src/js/cell/primitive_cell.ts +23 -19
  20. package/src/js/lattice/lattice.ts +25 -23
  21. package/src/js/lattice/reciprocal/lattice_reciprocal.ts +19 -18
  22. package/src/js/parsers/poscar.ts +2 -2
  23. package/src/js/parsers/xyz_combinatorial_basis.ts +3 -2
  24. package/src/js/tools/basis.ts +4 -3
  25. package/src/js/tools/cell.ts +4 -3
  26. package/src/js/tools/material.ts +5 -4
  27. package/src/js/tools/supercell.ts +4 -3
  28. package/src/js/tools/surface.ts +18 -12
  29. package/src/py/mat3ra/made/basis/__init__.py +6 -3
  30. package/src/py/mat3ra/made/tools/analyze/solid_solution_analyzer.py +171 -0
  31. package/src/py/mat3ra/made/tools/analyze/utils.py +25 -0
  32. package/src/py/mat3ra/made/tools/build/defective_structures/three_dimensional/__init__.py +1 -0
  33. package/src/py/mat3ra/made/tools/build/defective_structures/three_dimensional/solid_solution/__init__.py +9 -0
  34. package/src/py/mat3ra/made/tools/build/defective_structures/three_dimensional/solid_solution/builder.py +37 -0
  35. package/src/py/mat3ra/made/tools/build/defective_structures/three_dimensional/solid_solution/configuration.py +30 -0
  36. package/src/py/mat3ra/made/tools/build/defective_structures/three_dimensional/solid_solution/enums.py +8 -0
  37. package/src/py/mat3ra/made/tools/build/defective_structures/three_dimensional/solid_solution/helpers.py +76 -0
  38. package/src/py/mat3ra/made/tools/build_components/entities/auxiliary/zero_dimensional/crystal_site/crystal_site.py +3 -2
  39. package/src/py/mat3ra/made/tools/build_components/entities/auxiliary/zero_dimensional/point_defect_site/builder.py +11 -10
  40. package/src/py/mat3ra/made/tools/build_components/operations/core/combinations/merge/builder.py +9 -0
  41. package/src/py/mat3ra/made/tools/helpers.py +2 -0
  42. package/tests/fixtures/hashes.json +3 -0
  43. package/tests/js/cell/cell.ts +1 -1
  44. package/tests/js/fixtures.ts +7 -1
  45. package/tests/js/material.test.ts +8 -1
  46. package/tests/py/unit/test_material.py +10 -0
  47. package/tests/py/unit/test_tools_build_defect/test_solid_solution.py +90 -0
@@ -0,0 +1,90 @@
1
+ import numpy as np
2
+ import pytest
3
+ from mat3ra.made.material import Material
4
+ from mat3ra.made.tools.build.defective_structures.three_dimensional.solid_solution.helpers import (
5
+ create_solid_solution,
6
+ )
7
+ from mat3ra.standata.materials import Materials
8
+
9
+ BULK_HfO2 = Materials.get_by_name_first_match("HfO2")
10
+
11
+
12
+ def _min_nearest_neighbor_distance(material, element):
13
+ material.to_crystal()
14
+ coords = np.array(material.basis.coordinates.values)
15
+ lv = np.array(material.lattice.vector_arrays)
16
+ idx = [i for i, e in enumerate(material.basis.elements.values) if e == element]
17
+ sub = coords[idx]
18
+ min_d = np.inf
19
+ for i in range(len(sub)):
20
+ for j in range(i + 1, len(sub)):
21
+ delta = sub[i] - sub[j]
22
+ delta -= np.round(delta)
23
+ min_d = min(min_d, np.linalg.norm(delta @ lv))
24
+ return min_d
25
+
26
+
27
+ def test_create_solid_solution_uniform_element_counts():
28
+ material = Material.create(BULK_HfO2)
29
+ result = create_solid_solution(material, "Hf", "Zr", 0.5, seed=42, site_selection_method="uniform")
30
+ elements = result.basis.elements.values
31
+ assert elements == ["Hf", "Hf", "O", "O", "O", "O", "O", "O", "O", "O", "Zr", "Zr"]
32
+
33
+
34
+ @pytest.mark.parametrize(
35
+ "concentration, expected_zr, expected_hf",
36
+ [
37
+ (0.0, 0, 4),
38
+ (0.25, 1, 3),
39
+ (0.5, 2, 2),
40
+ (1.0, 4, 0),
41
+ ],
42
+ )
43
+ def test_create_solid_solution_concentration(concentration, expected_zr, expected_hf):
44
+ material = Material.create(BULK_HfO2)
45
+ result = create_solid_solution(material, "Hf", "Zr", concentration, seed=42, site_selection_method="uniform")
46
+ elements = result.basis.elements.values
47
+ assert elements.count("Zr") == expected_zr
48
+ assert elements.count("Hf") == expected_hf
49
+
50
+
51
+ @pytest.mark.parametrize(
52
+ "concentration, expected_min_distance",
53
+ [
54
+ (0.1, 4.5),
55
+ (0.2, 3.5),
56
+ (0.33, 3.4),
57
+ ],
58
+ )
59
+ def test_create_solid_solution_uniform(concentration, expected_min_distance):
60
+ material = Material.create(BULK_HfO2)
61
+ result = create_solid_solution(
62
+ material,
63
+ "Hf",
64
+ "Zr",
65
+ concentration,
66
+ seed=42,
67
+ site_selection_method="uniform",
68
+ tolerance=0.001,
69
+ )
70
+ assert _min_nearest_neighbor_distance(result, "Zr") > expected_min_distance
71
+
72
+
73
+ def test_create_solid_solution_records_target_and_actual_concentration():
74
+ material = Material.create(BULK_HfO2)
75
+ target_concentration = 0.37
76
+ result = create_solid_solution(
77
+ material,
78
+ "Hf",
79
+ "Zr",
80
+ target_concentration,
81
+ seed=42,
82
+ tolerance=0.01,
83
+ site_selection_method="uniform",
84
+ )
85
+ build_step = result.metadata.get_build_metadata_of_type("SolidSolutionConfiguration")
86
+ assert build_step is not None
87
+ configuration = build_step.configuration
88
+ assert configuration["target_concentration"] == target_concentration
89
+ assert configuration["actual_concentration"] == pytest.approx(0.375)
90
+ assert configuration["target_concentration"] != configuration["actual_concentration"]