@mat3ra/made 2024.3.22-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/.babelrc +10 -0
- package/.eslintrc.json +11 -0
- package/.mocharc.json +5 -0
- package/.prettierignore +1 -0
- package/.prettierrc +6 -0
- package/LICENSE.md +15 -0
- package/README.md +167 -0
- package/dist/abstract/array_with_ids.d.ts +43 -0
- package/dist/abstract/array_with_ids.js +88 -0
- package/dist/abstract/scalar_with_id.d.ts +25 -0
- package/dist/abstract/scalar_with_id.js +44 -0
- package/dist/basis/basis.d.ts +269 -0
- package/dist/basis/basis.js +499 -0
- package/dist/basis/constrained_basis.d.ts +56 -0
- package/dist/basis/constrained_basis.js +90 -0
- package/dist/basis/types.d.ts +1 -0
- package/dist/basis/types.js +2 -0
- package/dist/cell/cell.d.ts +45 -0
- package/dist/cell/cell.js +88 -0
- package/dist/cell/conventional_cell.d.ts +22 -0
- package/dist/cell/conventional_cell.js +83 -0
- package/dist/cell/primitive_cell.d.ts +9 -0
- package/dist/cell/primitive_cell.js +166 -0
- package/dist/constants.d.ts +2 -0
- package/dist/constants.js +25 -0
- package/dist/constraints/constraints.d.ts +45 -0
- package/dist/constraints/constraints.js +49 -0
- package/dist/lattice/lattice.d.ts +104 -0
- package/dist/lattice/lattice.js +208 -0
- package/dist/lattice/lattice_bravais.d.ts +59 -0
- package/dist/lattice/lattice_bravais.js +120 -0
- package/dist/lattice/lattice_vectors.d.ts +46 -0
- package/dist/lattice/lattice_vectors.js +98 -0
- package/dist/lattice/reciprocal/lattice_reciprocal.d.ts +75 -0
- package/dist/lattice/reciprocal/lattice_reciprocal.js +148 -0
- package/dist/lattice/reciprocal/paths.d.ts +24 -0
- package/dist/lattice/reciprocal/paths.js +136 -0
- package/dist/lattice/reciprocal/symmetry_points.d.ts +8 -0
- package/dist/lattice/reciprocal/symmetry_points.js +866 -0
- package/dist/lattice/types.d.ts +49 -0
- package/dist/lattice/types.js +127 -0
- package/dist/lattice/unit_cell.d.ts +30 -0
- package/dist/lattice/unit_cell.js +31 -0
- package/dist/made.d.ts +40 -0
- package/dist/made.js +39 -0
- package/dist/material.d.ts +1562 -0
- package/dist/material.js +317 -0
- package/dist/math.d.ts +395 -0
- package/dist/math.js +7 -0
- package/dist/parsers/cif.d.ts +10 -0
- package/dist/parsers/cif.js +21 -0
- package/dist/parsers/errors.d.ts +5 -0
- package/dist/parsers/errors.js +11 -0
- package/dist/parsers/espresso.d.ts +10 -0
- package/dist/parsers/espresso.js +24 -0
- package/dist/parsers/native_format_parsers.d.ts +26 -0
- package/dist/parsers/native_format_parsers.js +52 -0
- package/dist/parsers/parsers.d.ts +13 -0
- package/dist/parsers/parsers.js +17 -0
- package/dist/parsers/poscar.d.ts +31 -0
- package/dist/parsers/poscar.js +180 -0
- package/dist/parsers/xyz.d.ts +62 -0
- package/dist/parsers/xyz.js +167 -0
- package/dist/parsers/xyz_combinatorial_basis.d.ts +64 -0
- package/dist/parsers/xyz_combinatorial_basis.js +241 -0
- package/dist/tools/basis.d.ts +22 -0
- package/dist/tools/basis.js +100 -0
- package/dist/tools/cell.d.ts +9 -0
- package/dist/tools/cell.js +39 -0
- package/dist/tools/index.d.ts +11 -0
- package/dist/tools/index.js +15 -0
- package/dist/tools/material.d.ts +25 -0
- package/dist/tools/material.js +54 -0
- package/dist/tools/supercell.d.ts +22 -0
- package/dist/tools/supercell.js +62 -0
- package/dist/tools/surface.d.ts +10 -0
- package/dist/tools/surface.js +147 -0
- package/dist/types.d.ts +3 -0
- package/dist/types.js +2 -0
- package/package.json +89 -0
- package/pyproject.toml +77 -0
- package/src/js/abstract/array_with_ids.ts +100 -0
- package/src/js/abstract/scalar_with_id.ts +53 -0
- package/src/js/basis/basis.ts +607 -0
- package/src/js/basis/constrained_basis.ts +107 -0
- package/src/js/basis/types.ts +1 -0
- package/src/js/cell/cell.ts +109 -0
- package/src/js/cell/conventional_cell.ts +89 -0
- package/src/js/cell/primitive_cell.ts +189 -0
- package/src/js/constants.js +4 -0
- package/src/js/constraints/constraints.ts +63 -0
- package/src/js/lattice/lattice.ts +229 -0
- package/src/js/lattice/lattice_bravais.ts +170 -0
- package/src/js/lattice/lattice_vectors.ts +126 -0
- package/src/js/lattice/reciprocal/lattice_reciprocal.js +155 -0
- package/src/js/lattice/reciprocal/paths.js +134 -0
- package/src/js/lattice/reciprocal/symmetry_points.ts +886 -0
- package/src/js/lattice/types.ts +142 -0
- package/src/js/lattice/unit_cell.ts +66 -0
- package/src/js/made.js +36 -0
- package/src/js/material.ts +398 -0
- package/src/js/math.js +6 -0
- package/src/js/parsers/cif.js +22 -0
- package/src/js/parsers/errors.js +7 -0
- package/src/js/parsers/espresso.ts +30 -0
- package/src/js/parsers/native_format_parsers.js +51 -0
- package/src/js/parsers/parsers.js +13 -0
- package/src/js/parsers/poscar.ts +201 -0
- package/src/js/parsers/xyz.ts +216 -0
- package/src/js/parsers/xyz_combinatorial_basis.js +243 -0
- package/src/js/tools/basis.js +116 -0
- package/src/js/tools/cell.js +36 -0
- package/src/js/tools/index.js +11 -0
- package/src/js/tools/material.js +60 -0
- package/src/js/tools/supercell.ts +80 -0
- package/src/js/tools/surface.js +176 -0
- package/src/js/types.ts +4 -0
- package/src/py/__init__.py +0 -0
- package/src/py/mat3ra/__init__.py +0 -0
- package/src/py/mat3ra/made/__init__.py +5 -0
- package/tests/.gitattributes +1 -0
- package/tests/fixtures/AsGe-basis.json +3 -0
- package/tests/fixtures/C2H4-translated.json +3 -0
- package/tests/fixtures/C2H4.json +3 -0
- package/tests/fixtures/FeLiSi-basis.json +3 -0
- package/tests/fixtures/FeO.json +3 -0
- package/tests/fixtures/Ge2-basis.json +3 -0
- package/tests/fixtures/Graphene.json +3 -0
- package/tests/fixtures/Graphene.poscar +3 -0
- package/tests/fixtures/H2+H-final.json +3 -0
- package/tests/fixtures/H2+H-image.json +3 -0
- package/tests/fixtures/H2+H-initial.json +3 -0
- package/tests/fixtures/H2O.poscar +3 -0
- package/tests/fixtures/LiFeSi-basis.json +3 -0
- package/tests/fixtures/Na.json +3 -0
- package/tests/fixtures/Na4Cl4-cartesian.json +3 -0
- package/tests/fixtures/Na4Cl4.json +3 -0
- package/tests/fixtures/Na4Cl4.poscar +3 -0
- package/tests/fixtures/Ni-hex.json +3 -0
- package/tests/fixtures/Ni-hex.poscar +3 -0
- package/tests/fixtures/OSi-basis.json +3 -0
- package/tests/fixtures/Si-hex.json +3 -0
- package/tests/fixtures/Si-hex.poscar +3 -0
- package/tests/fixtures/Si-pwscf.in +3 -0
- package/tests/fixtures/Si-slab.json +3 -0
- package/tests/fixtures/Si-supercell.json +3 -0
- package/tests/fixtures/Si.json +3 -0
- package/tests/fixtures/Si2-basis-repeated.json +3 -0
- package/tests/fixtures/Si2-basis.json +3 -0
- package/tests/fixtures/Zr1H23Zr1H1.json +3 -0
- package/tests/fixtures/Zr1H23Zr1H1.poscar +3 -0
- package/tests/fixtures/atomic-constraints.json +3 -0
- package/tests/js/basis/basis.js +221 -0
- package/tests/js/cell/cell.js +21 -0
- package/tests/js/cell/primitive_cell.js +17 -0
- package/tests/js/constraints/constraints.js +27 -0
- package/tests/js/enums.js +40 -0
- package/tests/js/lattice/lattice.js +31 -0
- package/tests/js/lattice/lattice_bravais.js +17 -0
- package/tests/js/lattice/lattice_reciprocal.js +99 -0
- package/tests/js/lattice/lattice_vectors.js +10 -0
- package/tests/js/material.test.js +11 -0
- package/tests/js/parsers/espresso.js +12 -0
- package/tests/js/parsers/native_formats.js +30 -0
- package/tests/js/parsers/poscar.js +21 -0
- package/tests/js/parsers/xyz.js +25 -0
- package/tests/js/parsers/xyz_combinatorial_basis.js +153 -0
- package/tests/js/setup.js +6 -0
- package/tests/js/tools/basis.js +18 -0
- package/tests/js/tools/supercell.js +23 -0
- package/tests/js/tools/surface.js +12 -0
- package/tests/js/utils.js +17 -0
- package/tests/py/__init__.py +0 -0
- package/tests/py/unit/__init__.py +0 -0
- package/tests/py/unit/test_sample.py +10 -0
- package/tsconfig.json +3 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/* eslint-disable max-classes-per-file */
|
|
2
|
+
import _ from "underscore";
|
|
3
|
+
import * as s from "underscore.string";
|
|
4
|
+
|
|
5
|
+
import { Basis } from "../basis/basis";
|
|
6
|
+
import math from "../math";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @summary Combinatorial XYZ basis class and related. Create and get all information about basis and elements in it.
|
|
10
|
+
* Constructor accepts string in extended XYZ format. Extended XYZ format is as follows:
|
|
11
|
+
*
|
|
12
|
+
* 1. Regular XYZ
|
|
13
|
+
* ```
|
|
14
|
+
* Si 0.0 0.0 0.0
|
|
15
|
+
* Li 0.5 0.5 0.5
|
|
16
|
+
* ```
|
|
17
|
+
* 2. Permutation (slash-separated)
|
|
18
|
+
* ```
|
|
19
|
+
* Si/Ge/As 0.0 0.0 0.0
|
|
20
|
+
* Si/Ge 0.5 0.5 0.0
|
|
21
|
+
* ```
|
|
22
|
+
* 3. Combination (comma-separated)
|
|
23
|
+
* ```
|
|
24
|
+
* Si,Ge,As 0.0 0.0 0.0
|
|
25
|
+
* Si,Ge 0.5 0.5 0.0
|
|
26
|
+
* ```
|
|
27
|
+
* More at: https://exabyte.atlassian.net/wiki/display/PD/Combinatorial+materials+set
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Regular expression for basis line.
|
|
32
|
+
* @type {RegExp}
|
|
33
|
+
*/
|
|
34
|
+
// eslint-disable-next-line max-len
|
|
35
|
+
const LINE_REGEX =
|
|
36
|
+
/^([A-Z][a-z]?\/?,?)+\s+(-?\d+\.?\d*|\.\d+)\s+(-?\d+\.?\d*|\.\d+)\s+(-?\d+\.?\d*|\.\d+)\s*$/gi;
|
|
37
|
+
// vacancy characters will be used to create vacancies on basis generation
|
|
38
|
+
const VACANCY_CHARACTER = "VAC";
|
|
39
|
+
const COMBINATION_DELIMITER = ",";
|
|
40
|
+
const PERMUTATION_DELIMITER = "/";
|
|
41
|
+
/**
|
|
42
|
+
* Basis validation error codes.
|
|
43
|
+
* @type {{MIXING_IN_SINGLE_LINE: number, MIXING_IN_MULTI_LINES: number, REGEX_NOT_PASSED: number}}
|
|
44
|
+
*/
|
|
45
|
+
const ERROR_CODES = {
|
|
46
|
+
MIXING_IN_SINGLE_LINE: 1,
|
|
47
|
+
MIXING_IN_MULTI_LINES: 2,
|
|
48
|
+
REGEX_NOT_PASSED: 3,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export class WrongBasisFormat extends Error {
|
|
52
|
+
constructor(xyz, message, type) {
|
|
53
|
+
super(message, type);
|
|
54
|
+
this.xyz = xyz;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export class CombinatorialBasis {
|
|
59
|
+
/**
|
|
60
|
+
* Creates Combinatorial basis
|
|
61
|
+
* @param eXYZ
|
|
62
|
+
*/
|
|
63
|
+
constructor(eXYZ) {
|
|
64
|
+
this._xyz = eXYZ;
|
|
65
|
+
this._lines = s
|
|
66
|
+
.lines(eXYZ)
|
|
67
|
+
.map((x) => x.trim())
|
|
68
|
+
.filter((x) => x !== "")
|
|
69
|
+
.map(this._parseBasisLine);
|
|
70
|
+
|
|
71
|
+
this._hasPermutationLine = this._lines.reduce((mem, a) => {
|
|
72
|
+
return mem || a.isPermutation;
|
|
73
|
+
}, false);
|
|
74
|
+
this._hasCombinationLine = this._lines.reduce((mem, a) => {
|
|
75
|
+
return mem || a.isCombination;
|
|
76
|
+
}, false);
|
|
77
|
+
|
|
78
|
+
if (this._hasPermutationLine && this._hasCombinationLine) {
|
|
79
|
+
throw new WrongBasisFormat(
|
|
80
|
+
this._xyz,
|
|
81
|
+
"Basis contains mixed permutation and combination.",
|
|
82
|
+
ERROR_CODES.MIXING_IN_MULTI_LINES,
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Parses combinatorial basis line and returns result as Object. Throws exception if line is not valid:
|
|
89
|
+
* - does not meet RegExp
|
|
90
|
+
* - mixes permutation and combination
|
|
91
|
+
* @param str {String} Combinatorial basis' line
|
|
92
|
+
* @param index {Number} order of the
|
|
93
|
+
* @return {{displayName: string, isCombination: boolean, isPermutation: boolean, elements: Array, coordinates: *[]}}
|
|
94
|
+
* @private
|
|
95
|
+
*/
|
|
96
|
+
_parseBasisLine(str, index) {
|
|
97
|
+
if (!str.match(LINE_REGEX)) {
|
|
98
|
+
throw new WrongBasisFormat(
|
|
99
|
+
this._xyz,
|
|
100
|
+
`Line #${index + 1}: "${str}" contains errors. ` +
|
|
101
|
+
'Allowed formats: "Si 0 0 0", "Si/Li 0.5 0.5 0.5", "Si,Ge 0.7 0.7 0.8"',
|
|
102
|
+
ERROR_CODES.REGEX_NOT_PASSED,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const containsPermutation = str.indexOf(PERMUTATION_DELIMITER) > -1;
|
|
107
|
+
const containsCombination = str.indexOf(COMBINATION_DELIMITER) > -1;
|
|
108
|
+
|
|
109
|
+
if (containsCombination && containsPermutation) {
|
|
110
|
+
throw new WrongBasisFormat(
|
|
111
|
+
this._xyz,
|
|
112
|
+
`Line #${index} contains mixed permutation and combination.`,
|
|
113
|
+
ERROR_CODES.MIXING_IN_SINGLE_LINE,
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
let elements = [];
|
|
118
|
+
|
|
119
|
+
const words = s
|
|
120
|
+
.words(str)
|
|
121
|
+
.map((x) => x.trim())
|
|
122
|
+
.filter((x) => x != null);
|
|
123
|
+
|
|
124
|
+
if (containsCombination) {
|
|
125
|
+
elements = words[0].split(COMBINATION_DELIMITER).map((x) => x.trim());
|
|
126
|
+
} else if (containsPermutation) {
|
|
127
|
+
elements = words[0].split(PERMUTATION_DELIMITER).map((x) => x.trim());
|
|
128
|
+
} else {
|
|
129
|
+
elements = [words[0]];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const coordinates = [parseFloat(words[1]), parseFloat(words[2]), parseFloat(words[3])];
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
displayName: `ELEMENT_${index}`,
|
|
136
|
+
isCombination: containsCombination,
|
|
137
|
+
isPermutation: containsPermutation,
|
|
138
|
+
elements,
|
|
139
|
+
coordinates,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Returns array of ALL unique elements used in basis.
|
|
145
|
+
* @return {String[]}
|
|
146
|
+
*/
|
|
147
|
+
get uniqueElements() {
|
|
148
|
+
return _.chain(this._lines)
|
|
149
|
+
.map((line) => line.elements)
|
|
150
|
+
.flatten()
|
|
151
|
+
.unique()
|
|
152
|
+
.value()
|
|
153
|
+
.sort();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
static toBasisConfig(array, units = "crystal", cell = Basis.defaultCell) {
|
|
157
|
+
return {
|
|
158
|
+
elements: _.pluck(array, "element"),
|
|
159
|
+
coordinates: _.pluck(array, "coordinates"),
|
|
160
|
+
units,
|
|
161
|
+
cell,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Returns array of regular bases extracted from current combinatorial basis.
|
|
167
|
+
* @return {Basis[]|Object[]}
|
|
168
|
+
*/
|
|
169
|
+
get allBasisConfigs() {
|
|
170
|
+
let result = [];
|
|
171
|
+
if (this._hasPermutationLine) {
|
|
172
|
+
result = this._permutation();
|
|
173
|
+
} else if (this._hasCombinationLine) {
|
|
174
|
+
result = this._combination();
|
|
175
|
+
} else {
|
|
176
|
+
const items = [];
|
|
177
|
+
this._lines.forEach((line) => {
|
|
178
|
+
items.push({
|
|
179
|
+
element: line.elements[0],
|
|
180
|
+
coordinates: line.coordinates,
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
result = [items];
|
|
184
|
+
}
|
|
185
|
+
return result.map((x) => CombinatorialBasis.toBasisConfig(x));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Returns array of regular bases extracted from current combinatorial basis with combinations.
|
|
190
|
+
* @private
|
|
191
|
+
*/
|
|
192
|
+
_combination() {
|
|
193
|
+
const dimensions = [];
|
|
194
|
+
this._lines.forEach((line) => {
|
|
195
|
+
const itemsSet = [];
|
|
196
|
+
line.elements.forEach((element) => {
|
|
197
|
+
// omit vacancy characters
|
|
198
|
+
itemsSet.push({
|
|
199
|
+
element,
|
|
200
|
+
coordinates: line.coordinates,
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
dimensions.push(itemsSet);
|
|
204
|
+
});
|
|
205
|
+
const basisSet = math.cartesianProduct.apply(null, dimensions);
|
|
206
|
+
return basisSet.map((basis) =>
|
|
207
|
+
basis.filter((entry) => entry.element !== VACANCY_CHARACTER),
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Returns array of regular bases extracted from current combinatorial basis with permutations.
|
|
213
|
+
* @return {Basis[]}
|
|
214
|
+
* @private
|
|
215
|
+
*/
|
|
216
|
+
_permutation() {
|
|
217
|
+
const maxLen = Math.max(...this._lines.map((x) => x.elements.length));
|
|
218
|
+
const bases = [];
|
|
219
|
+
for (let i = 0; i < maxLen; i++) {
|
|
220
|
+
const items = [];
|
|
221
|
+
this._lines.forEach((line) => {
|
|
222
|
+
const element =
|
|
223
|
+
line.elements.length <= i ? _.last(line.elements) : line.elements[i];
|
|
224
|
+
if (element !== VACANCY_CHARACTER) {
|
|
225
|
+
items.push({
|
|
226
|
+
element,
|
|
227
|
+
coordinates: line.coordinates,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
bases.push(items);
|
|
232
|
+
}
|
|
233
|
+
return bases;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Returns true if current combinatorial basis contains more than one regular basis.
|
|
238
|
+
* @return {Boolean}
|
|
239
|
+
*/
|
|
240
|
+
isCombinatorial() {
|
|
241
|
+
return this._hasCombinationLine || this._hasPermutationLine;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import _ from "underscore";
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line no-unused-vars
|
|
4
|
+
import { Basis } from "../basis/basis";
|
|
5
|
+
import math from "../math";
|
|
6
|
+
|
|
7
|
+
const ADD = math.add;
|
|
8
|
+
const MULT = math.multiply;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Returns a repeated basis of a crystal.
|
|
12
|
+
* @param basis {Basis} Original basis.
|
|
13
|
+
* @param repetitions{Number[]} Repetition vector `[x, y, z]`, in each spatial dimension.
|
|
14
|
+
* @return {Basis} New Basis.
|
|
15
|
+
*/
|
|
16
|
+
function repeat(basis, repetitions) {
|
|
17
|
+
let i, j, k;
|
|
18
|
+
let shiftI = 0;
|
|
19
|
+
let shiftJ = 0;
|
|
20
|
+
let shiftK = 0;
|
|
21
|
+
|
|
22
|
+
// clone original basis and assert it is in cartesian coordinates
|
|
23
|
+
const newBasis = basis.clone();
|
|
24
|
+
const basisCloneInCrystalCoordinates = basis.clone();
|
|
25
|
+
|
|
26
|
+
newBasis.toCrystal();
|
|
27
|
+
basisCloneInCrystalCoordinates.toCrystal();
|
|
28
|
+
|
|
29
|
+
for (i = 1; i <= repetitions[0]; i += 1) {
|
|
30
|
+
for (j = 1; j <= repetitions[1]; j += 1) {
|
|
31
|
+
for (k = 1; k <= repetitions[2]; k += 1) {
|
|
32
|
+
// for each atom in original basis add one with a repetition
|
|
33
|
+
// eslint-disable-next-line no-loop-func
|
|
34
|
+
basisCloneInCrystalCoordinates.elements.forEach((element, index) => {
|
|
35
|
+
const coord = basisCloneInCrystalCoordinates.getCoordinateByIndex(index);
|
|
36
|
+
// only add atoms if shifts are non-zero
|
|
37
|
+
if (shiftI || shiftJ || shiftK) {
|
|
38
|
+
newBasis.addAtom({
|
|
39
|
+
element,
|
|
40
|
+
coordinate: [coord[0] + shiftI, coord[1] + shiftJ, coord[2] + shiftK],
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
shiftK += 1;
|
|
45
|
+
}
|
|
46
|
+
shiftK = 0;
|
|
47
|
+
shiftJ += 1;
|
|
48
|
+
}
|
|
49
|
+
shiftJ = 0;
|
|
50
|
+
shiftI += 1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (basis.isInCartesianUnits) newBasis.toCartesian();
|
|
54
|
+
|
|
55
|
+
return newBasis;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Calculates linear function `y = kx + b` for vectors. Isolated for modularity.
|
|
60
|
+
* @param initialCoordinates {Array} - b.
|
|
61
|
+
* @param delta {Array} - x.
|
|
62
|
+
* @param normalizedStepIndex {Number} - k.
|
|
63
|
+
* @return {Basis[]} List of all bases.
|
|
64
|
+
*/
|
|
65
|
+
function _linearInterpolation(initialCoordinates, delta, normalizedStepIndex) {
|
|
66
|
+
return ADD(initialCoordinates, MULT(delta, normalizedStepIndex));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Returns a set of Bases for a crystal interpolated from initial to final crystal.
|
|
71
|
+
* Can be used to generate atomic configurations along a chemical reaction path, for example.
|
|
72
|
+
* @param initialBasis {Basis} Original initialBasis.
|
|
73
|
+
* @param finalBasis {Basis} Final initialBasis.
|
|
74
|
+
* @param numberOfSteps{Number} Number of intermediate steps.
|
|
75
|
+
* @return {Basis[]} List of all bases.
|
|
76
|
+
*/
|
|
77
|
+
function interpolate(initialBasis, finalBasis, numberOfSteps = 1) {
|
|
78
|
+
// check that initial and final basis have the same cell
|
|
79
|
+
if (!initialBasis.hasEquivalentCellTo(finalBasis))
|
|
80
|
+
throw new Error("basis.interpolate: Basis cells are not equal");
|
|
81
|
+
|
|
82
|
+
// clone original initialBasis and assert it is in cartesian coordinates
|
|
83
|
+
const initialBasisCopy = initialBasis.clone();
|
|
84
|
+
const finalBasisCopy = finalBasis.clone();
|
|
85
|
+
|
|
86
|
+
initialBasisCopy.toCrystal();
|
|
87
|
+
finalBasisCopy.toCrystal();
|
|
88
|
+
|
|
89
|
+
const initialCoordinates = _.flatten(initialBasisCopy.coordinatesAsArray);
|
|
90
|
+
const finalCoordinates = _.flatten(finalBasisCopy.coordinatesAsArray);
|
|
91
|
+
const delta = ADD(finalCoordinates, MULT(initialCoordinates, -1));
|
|
92
|
+
const resultingListOfBases = [];
|
|
93
|
+
|
|
94
|
+
for (let i = 1; i <= numberOfSteps; i++) {
|
|
95
|
+
const normalizedStepIndex = i / (numberOfSteps + 1);
|
|
96
|
+
const intermediateCoordinates = _linearInterpolation(
|
|
97
|
+
initialCoordinates,
|
|
98
|
+
delta,
|
|
99
|
+
normalizedStepIndex,
|
|
100
|
+
);
|
|
101
|
+
const vectorSize = 3;
|
|
102
|
+
const intermediateCoordinatesAsNestedArray = _.toArray(
|
|
103
|
+
_.groupBy(intermediateCoordinates, (a, b) => Math.floor(b / vectorSize)),
|
|
104
|
+
);
|
|
105
|
+
const intermediateBasis = initialBasis.clone();
|
|
106
|
+
intermediateBasis.coordinates = intermediateCoordinatesAsNestedArray;
|
|
107
|
+
resultingListOfBases.push(intermediateBasis);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return resultingListOfBases;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export default {
|
|
114
|
+
repeat,
|
|
115
|
+
interpolate,
|
|
116
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Cell } from "../cell/cell";
|
|
2
|
+
import math from "../math";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Returns the list of points on the original lattice contained in the supercell in fractional coordinates.
|
|
6
|
+
* Source: https://pymatgen.org/_modules/pymatgen/util/coord.html
|
|
7
|
+
*/
|
|
8
|
+
function latticePointsInSupercell(supercellMatrix) {
|
|
9
|
+
const supercell = new Cell(supercellMatrix);
|
|
10
|
+
const diagonals = [
|
|
11
|
+
[0, 0, 0],
|
|
12
|
+
[0, 0, 1],
|
|
13
|
+
[0, 1, 0],
|
|
14
|
+
[0, 1, 1],
|
|
15
|
+
[1, 0, 0],
|
|
16
|
+
[1, 0, 1],
|
|
17
|
+
[1, 1, 0],
|
|
18
|
+
[1, 1, 1],
|
|
19
|
+
];
|
|
20
|
+
const d_points = diagonals.map((p) => supercell.convertPointToCartesian(p));
|
|
21
|
+
const mins = [0, 1, 2].map((i) => math.min(...d_points.map((p) => p[i])));
|
|
22
|
+
const maxes = [0, 1, 2].map((i) => math.max(...d_points.map((p) => p[i])) + 1);
|
|
23
|
+
const points = [];
|
|
24
|
+
for (let i = mins[0]; i <= maxes[0]; i++) {
|
|
25
|
+
for (let j = mins[1]; j <= maxes[1]; j++) {
|
|
26
|
+
for (let k = mins[2]; k <= maxes[2]; k++) {
|
|
27
|
+
points.push(supercell.convertPointToFractional([i, j, k]));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return points;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default {
|
|
35
|
+
latticePointsInSupercell,
|
|
36
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import BasisTools from "./basis";
|
|
2
|
+
import MaterialTools from "./material";
|
|
3
|
+
import SupercellTools from "./supercell";
|
|
4
|
+
import SurfaceTools from "./surface";
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
surface: SurfaceTools,
|
|
8
|
+
supercell: SupercellTools,
|
|
9
|
+
material: MaterialTools,
|
|
10
|
+
basis: BasisTools,
|
|
11
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import math from "mathjs";
|
|
2
|
+
|
|
3
|
+
import { ATOMIC_COORD_UNITS } from "../constants";
|
|
4
|
+
import { Lattice } from "../lattice/lattice";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Scales one lattice vector for the given material
|
|
8
|
+
* @param material {Material} The material acted upon.
|
|
9
|
+
* @param key {String} Lattice vector key.
|
|
10
|
+
* @param factor {Number} Float scaling factor.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
function scaleOneLatticeVector(material, key = "a", factor = 1.0) {
|
|
14
|
+
material.toCartesian();
|
|
15
|
+
|
|
16
|
+
const { lattice } = material;
|
|
17
|
+
lattice[key] *= factor;
|
|
18
|
+
|
|
19
|
+
material.lattice = lattice;
|
|
20
|
+
|
|
21
|
+
material.toCrystal();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Updates the size of a materials lattice using the minimumLatticeSize function.
|
|
26
|
+
* The new size of the material is calculated based on the materials basis.
|
|
27
|
+
* @param material {Material}
|
|
28
|
+
*/
|
|
29
|
+
function scaleLatticeToMakeNonPeriodic(material) {
|
|
30
|
+
material.lattice = new Lattice({
|
|
31
|
+
a: material.Basis.getMinimumLatticeSize(),
|
|
32
|
+
type: "CUB",
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Updates the basis of a material by translating the coordinates
|
|
38
|
+
* so that the center of the material and lattice are aligned.
|
|
39
|
+
* @param material {Material}
|
|
40
|
+
* */
|
|
41
|
+
function getBasisConfigTranslatedToCenter(material) {
|
|
42
|
+
const originalUnits = material.Basis.units;
|
|
43
|
+
material.toCartesian();
|
|
44
|
+
const updatedBasis = material.Basis;
|
|
45
|
+
const centerOfCoordinates = updatedBasis.centerOfCoordinatesPoint;
|
|
46
|
+
const centerOfLattice = math.multiply(
|
|
47
|
+
0.5,
|
|
48
|
+
material.Lattice.vectorArrays.reduce((a, b) => math.add(a, b)),
|
|
49
|
+
);
|
|
50
|
+
const translationVector = math.subtract(centerOfLattice, centerOfCoordinates);
|
|
51
|
+
updatedBasis.translateByVector(translationVector);
|
|
52
|
+
material.setBasis(updatedBasis.toJSON());
|
|
53
|
+
if (originalUnits !== ATOMIC_COORD_UNITS.cartesian) material.toCrystal();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export default {
|
|
57
|
+
scaleOneLatticeVector,
|
|
58
|
+
scaleLatticeToMakeNonPeriodic,
|
|
59
|
+
getBasisConfigTranslatedToCenter,
|
|
60
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Basis } from "../basis/basis";
|
|
2
|
+
import { Coordinate } from "../basis/types";
|
|
3
|
+
import { Cell } from "../cell/cell";
|
|
4
|
+
import { LatticeBravais } from "../lattice/lattice_bravais";
|
|
5
|
+
// eslint-disable-next-line import/no-cycle
|
|
6
|
+
import { Material } from "../material";
|
|
7
|
+
import math from "../math";
|
|
8
|
+
import cellTools from "./cell";
|
|
9
|
+
|
|
10
|
+
const ADD = math.add;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @summary Generates new basis for a supercell. For each site from basis generates shifts that are within supercell.
|
|
14
|
+
*/
|
|
15
|
+
function generateNewBasisWithinSupercell(
|
|
16
|
+
basis: Basis,
|
|
17
|
+
cell: Cell,
|
|
18
|
+
supercell: Cell,
|
|
19
|
+
supercellMatrix: number[][],
|
|
20
|
+
): Basis {
|
|
21
|
+
const oldBasis = basis.clone();
|
|
22
|
+
const newBasis = basis.clone({ isEmpty: true });
|
|
23
|
+
|
|
24
|
+
oldBasis.toCrystal();
|
|
25
|
+
newBasis.toCrystal();
|
|
26
|
+
|
|
27
|
+
oldBasis.elements.forEach((element) => {
|
|
28
|
+
const coordinate = oldBasis.getCoordinateByIndex(element.id);
|
|
29
|
+
const cartesianCoordinate = cell.convertPointToCartesian(coordinate);
|
|
30
|
+
const shifts = cellTools.latticePointsInSupercell(supercellMatrix);
|
|
31
|
+
shifts.forEach((comb) => {
|
|
32
|
+
// "combination" is effectively a point in fractional coordinates here, hence the below
|
|
33
|
+
const newPoint = ADD(cartesianCoordinate, supercell.convertPointToCartesian(comb));
|
|
34
|
+
if (supercell.isPointInsideCell(newPoint)) {
|
|
35
|
+
newBasis.addAtom({
|
|
36
|
+
element: element.value,
|
|
37
|
+
coordinate: supercell.convertPointToFractional(newPoint) as Coordinate,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return newBasis;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @summary Generates supercell config for the specified material.
|
|
48
|
+
* @param material
|
|
49
|
+
* @param supercellMatrix {Number[][]}
|
|
50
|
+
*/
|
|
51
|
+
function generateConfig(material: Material, supercellMatrix: number[][]) {
|
|
52
|
+
const det = math.det(supercellMatrix);
|
|
53
|
+
if (det === 0) {
|
|
54
|
+
throw new Error("Scaling matrix is degenerate.");
|
|
55
|
+
}
|
|
56
|
+
const cell = material.Lattice.Cell;
|
|
57
|
+
const supercell = cell.cloneAndScaleByMatrix(supercellMatrix);
|
|
58
|
+
const newBasis = generateNewBasisWithinSupercell(
|
|
59
|
+
material.Basis,
|
|
60
|
+
cell,
|
|
61
|
+
supercell,
|
|
62
|
+
supercellMatrix,
|
|
63
|
+
);
|
|
64
|
+
const newLattice = LatticeBravais.fromVectors({
|
|
65
|
+
a: supercell.vector1,
|
|
66
|
+
b: supercell.vector2,
|
|
67
|
+
c: supercell.vector3,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
name: `${material.name} - supercell ${JSON.stringify(supercellMatrix)}`,
|
|
72
|
+
basis: newBasis.toJSON(),
|
|
73
|
+
lattice: newLattice.toJSON(),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export default {
|
|
78
|
+
generateConfig,
|
|
79
|
+
generateNewBasisWithinSupercell,
|
|
80
|
+
};
|