matsci-parse 0.0.3 → 0.1.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/dist/main.js +360 -222
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -1,222 +1,379 @@
|
|
|
1
|
-
class
|
|
2
|
-
constructor(e,
|
|
3
|
-
this.speciesIndex = e, this.cart =
|
|
1
|
+
class x {
|
|
2
|
+
constructor(e, t, n = {}) {
|
|
3
|
+
this.speciesIndex = e, this.cart = t, this.props = n;
|
|
4
4
|
}
|
|
5
5
|
getProp(e) {
|
|
6
6
|
return this.props[e];
|
|
7
7
|
}
|
|
8
|
-
setProp(e,
|
|
9
|
-
this.props[e] =
|
|
8
|
+
setProp(e, t) {
|
|
9
|
+
this.props[e] = t;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
|
-
function
|
|
13
|
-
return
|
|
12
|
+
function T(s) {
|
|
13
|
+
return s.sites.some((e) => Array.isArray(e.props.selectiveDynamics));
|
|
14
14
|
}
|
|
15
|
-
|
|
15
|
+
function E(s) {
|
|
16
|
+
return s * Math.PI / 180;
|
|
17
|
+
}
|
|
18
|
+
function $(s, e) {
|
|
19
|
+
return s.map(
|
|
20
|
+
(t) => t[0] * e[0] + t[1] * e[1] + t[2] * e[2]
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
function L(s, e, t, n, o, i) {
|
|
24
|
+
const c = E(n), l = E(o), f = E(i), d = [s, 0, 0], u = [
|
|
25
|
+
e * Math.cos(f),
|
|
26
|
+
e * Math.sin(f),
|
|
27
|
+
0
|
|
28
|
+
], p = t * Math.cos(l), m = t * (Math.cos(c) - Math.cos(l) * Math.cos(f)) / Math.sin(f), _ = Math.sqrt(t * t - p * p - m * m);
|
|
29
|
+
return [d, u, [p, m, _]];
|
|
30
|
+
}
|
|
31
|
+
function C(s, e) {
|
|
32
|
+
const [t, n, o] = e;
|
|
33
|
+
return [
|
|
34
|
+
s[0] * t[0] + s[1] * n[0] + s[2] * o[0],
|
|
35
|
+
s[0] * t[1] + s[1] * n[1] + s[2] * o[1],
|
|
36
|
+
s[0] * t[2] + s[1] * n[2] + s[2] * o[2]
|
|
37
|
+
];
|
|
38
|
+
}
|
|
39
|
+
class w {
|
|
40
|
+
/**
|
|
41
|
+
* Creates a new CrystalStructure.
|
|
42
|
+
*
|
|
43
|
+
* @param props - Object containing lattice, species, and sites
|
|
44
|
+
* @param props.lattice - 3x3 array of Cartesian lattice vectors
|
|
45
|
+
* @param props.species - List of chemical species
|
|
46
|
+
* @param props.sites - List of Site instances or objects with speciesIndex and Cartesian coordinates
|
|
47
|
+
*
|
|
48
|
+
* @throws Will throw an error if lattice is not 3x3, species is not an array of strings, or sites are invalid
|
|
49
|
+
*/
|
|
16
50
|
constructor({
|
|
17
51
|
lattice: e,
|
|
18
|
-
species:
|
|
19
|
-
sites:
|
|
52
|
+
species: t,
|
|
53
|
+
sites: n
|
|
20
54
|
}) {
|
|
21
|
-
this.lattice = this._validateLattice(e), this.species = this._validateSpecies(
|
|
55
|
+
this.lattice = this._validateLattice(e), this.species = this._validateSpecies(t), this.sites = this._validateSites(n);
|
|
22
56
|
}
|
|
23
57
|
// ---------- Simple methods ----------
|
|
58
|
+
/** Number of sites in the structure */
|
|
24
59
|
get numSites() {
|
|
25
60
|
return this.sites.length;
|
|
26
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Returns the site at the specified index.
|
|
64
|
+
* @param i - Site index
|
|
65
|
+
*/
|
|
27
66
|
site(e) {
|
|
28
67
|
return this.sites[e];
|
|
29
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Returns the Cartesian coordinates of a site.
|
|
71
|
+
* @param i - Site index
|
|
72
|
+
*/
|
|
30
73
|
cartCoords(e) {
|
|
31
74
|
return this.sites[e].cart;
|
|
32
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Returns the chemical species of a site.
|
|
78
|
+
* @param i - Site index
|
|
79
|
+
*/
|
|
33
80
|
siteSpecies(e) {
|
|
34
81
|
return this.species[this.sites[e].speciesIndex];
|
|
35
82
|
}
|
|
83
|
+
/** Returns the array of elements (species) in the structure */
|
|
36
84
|
get elements() {
|
|
37
85
|
return this.species;
|
|
38
86
|
}
|
|
39
|
-
|
|
40
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Adds a new site to the crystal.
|
|
89
|
+
* If the species is not already in the structure, it is added automatically.
|
|
90
|
+
*
|
|
91
|
+
* @param species - Name of the species
|
|
92
|
+
* @param cart - Cartesian coordinates of the new site
|
|
93
|
+
* @param position - Optional index at which to insert the site. Defaults to appending at the end.
|
|
94
|
+
*/
|
|
95
|
+
addSite(e, t, n) {
|
|
96
|
+
let o = this.species.indexOf(e);
|
|
97
|
+
o === -1 && (this.species.push(e), o = this.species.length - 1);
|
|
98
|
+
const i = new x(o, t);
|
|
99
|
+
n === void 0 || n >= this.sites.length ? this.sites.push(i) : n < 0 ? this.sites.unshift(i) : this.sites.splice(n, 0, i);
|
|
41
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Removes a site from the crystal.
|
|
103
|
+
* Automatically removes species from the species array if no other site uses it.
|
|
104
|
+
* Updates speciesIndex for remaining sites if necessary.
|
|
105
|
+
*
|
|
106
|
+
* @param index - Index of the site to remove
|
|
107
|
+
*
|
|
108
|
+
* @throws Will throw an error if index is out of bounds
|
|
109
|
+
*/
|
|
42
110
|
removeSite(e) {
|
|
43
|
-
this.sites.
|
|
111
|
+
if (e < 0 || e >= this.sites.length)
|
|
112
|
+
throw new Error("siteIndex out of bounds");
|
|
113
|
+
const n = this.sites.splice(e, 1)[0].speciesIndex;
|
|
114
|
+
this.sites.some(
|
|
115
|
+
(i) => i.speciesIndex === n
|
|
116
|
+
) || (this.species.splice(n, 1), this.sites.forEach((i) => {
|
|
117
|
+
i.speciesIndex > n && (i.speciesIndex -= 1);
|
|
118
|
+
}));
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Replaces the species of a site at the given index.
|
|
122
|
+
* Internally calls `removeSite` and `addSite` to ensure species array cleanup
|
|
123
|
+
* and proper indexing. The site’s coordinates are preserved.
|
|
124
|
+
*
|
|
125
|
+
* @param siteIndex - Index of the site to replace
|
|
126
|
+
* @param newSpecies - Name of the new species
|
|
127
|
+
*
|
|
128
|
+
* @throws Will throw an error if siteIndex is out of bounds
|
|
129
|
+
*/
|
|
130
|
+
replaceSite(e, t) {
|
|
131
|
+
if (e < 0 || e >= this.sites.length)
|
|
132
|
+
throw new Error("siteIndex out of bounds");
|
|
133
|
+
const n = [...this.sites[e].cart];
|
|
134
|
+
this.removeSite(e), this.addSite(t, n, e);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Returns a new CrystalStructure transformed by a linear matrix.
|
|
138
|
+
*
|
|
139
|
+
* Can be used for uniform scaling, diagonal scaling, or applying a full 3x3 transformation matrix.
|
|
140
|
+
*
|
|
141
|
+
* @param scale - Transformation to apply:
|
|
142
|
+
* - single number: uniform scaling along all axes
|
|
143
|
+
* - 3-element array: diagonal scaling [sx, sy, sz]
|
|
144
|
+
* - 3x3 matrix: full linear transformation
|
|
145
|
+
* @returns A new CrystalStructure instance with transformed lattice and sites
|
|
146
|
+
*
|
|
147
|
+
* @throws Will throw an error if scale is not a number, a 3-element array, or a 3x3 matrix
|
|
148
|
+
*/
|
|
149
|
+
applyLatticeTransformation(e) {
|
|
150
|
+
let t;
|
|
151
|
+
if (typeof e == "number")
|
|
152
|
+
t = [
|
|
153
|
+
[e, 0, 0],
|
|
154
|
+
[0, e, 0],
|
|
155
|
+
[0, 0, e]
|
|
156
|
+
];
|
|
157
|
+
else if (Array.isArray(e) && e.length === 3 && e.every((i) => typeof i == "number"))
|
|
158
|
+
t = [
|
|
159
|
+
[e[0], 0, 0],
|
|
160
|
+
[0, e[1], 0],
|
|
161
|
+
[0, 0, e[2]]
|
|
162
|
+
];
|
|
163
|
+
else if (Array.isArray(e) && e.length === 3 && e.every((i) => Array.isArray(i) && i.length === 3))
|
|
164
|
+
t = e;
|
|
165
|
+
else
|
|
166
|
+
throw new Error(
|
|
167
|
+
"Scale must be a number, a 3-element array, or a 3x3 matrix"
|
|
168
|
+
);
|
|
169
|
+
const n = this.lattice.map(
|
|
170
|
+
(i) => $(t, i)
|
|
171
|
+
), o = this.sites.map((i) => {
|
|
172
|
+
const c = $(
|
|
173
|
+
t,
|
|
174
|
+
i.cart
|
|
175
|
+
);
|
|
176
|
+
return new x(i.speciesIndex, c, i.props);
|
|
177
|
+
});
|
|
178
|
+
return new w({
|
|
179
|
+
lattice: n,
|
|
180
|
+
species: [...this.species],
|
|
181
|
+
sites: o
|
|
182
|
+
});
|
|
44
183
|
}
|
|
45
184
|
// ---------- Internal validation ----------
|
|
185
|
+
/**
|
|
186
|
+
* Validates that the lattice is a 3x3 array of Cartesian vectors.
|
|
187
|
+
* @throws Will throw an error if lattice is invalid
|
|
188
|
+
*/
|
|
46
189
|
_validateLattice(e) {
|
|
47
190
|
if (!Array.isArray(e) || e.length !== 3)
|
|
48
191
|
throw new Error("Lattice must be a 3x3 matrix");
|
|
49
|
-
return e.forEach((
|
|
50
|
-
if (!Array.isArray(
|
|
192
|
+
return e.forEach((t) => {
|
|
193
|
+
if (!Array.isArray(t) || t.length !== 3)
|
|
51
194
|
throw new Error("Lattice vectors must be length 3");
|
|
52
195
|
}), e;
|
|
53
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* Validates that species is an array of strings.
|
|
199
|
+
* @throws Will throw an error if species array is invalid
|
|
200
|
+
*/
|
|
54
201
|
_validateSpecies(e) {
|
|
55
202
|
if (!Array.isArray(e)) throw new Error("Species must be an array");
|
|
56
|
-
return e.forEach((
|
|
57
|
-
if (typeof
|
|
203
|
+
return e.forEach((t) => {
|
|
204
|
+
if (typeof t != "string")
|
|
58
205
|
throw new Error("Species entries must be strings");
|
|
59
206
|
}), e;
|
|
60
207
|
}
|
|
208
|
+
/**
|
|
209
|
+
* Validates the sites array, ensuring each site is a Site instance or a valid object.
|
|
210
|
+
* @throws Will throw an error if sites array is invalid
|
|
211
|
+
*/
|
|
61
212
|
_validateSites(e) {
|
|
62
213
|
if (!Array.isArray(e)) throw new Error("Sites must be an array");
|
|
63
|
-
return e.map((
|
|
64
|
-
if (
|
|
65
|
-
if (typeof
|
|
66
|
-
return this._validateSpeciesIndex(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
214
|
+
return e.map((t) => {
|
|
215
|
+
if (t instanceof x) return t;
|
|
216
|
+
if (typeof t == "object" && typeof t.speciesIndex == "number" && Array.isArray(t.cart) && t.cart.length === 3)
|
|
217
|
+
return this._validateSpeciesIndex(t.speciesIndex), new x(
|
|
218
|
+
t.speciesIndex,
|
|
219
|
+
t.cart,
|
|
220
|
+
t.props ?? {}
|
|
70
221
|
);
|
|
71
222
|
throw new Error(
|
|
72
223
|
"Each site must be a Site instance or a valid site object"
|
|
73
224
|
);
|
|
74
225
|
});
|
|
75
226
|
}
|
|
227
|
+
/**
|
|
228
|
+
* Validates that a species index is within bounds.
|
|
229
|
+
* @throws Will throw an error if index is out of range
|
|
230
|
+
*/
|
|
76
231
|
_validateSpeciesIndex(e) {
|
|
77
232
|
if (e < 0 || e >= this.species.length)
|
|
78
233
|
throw new Error("speciesIndex out of bounds");
|
|
79
234
|
}
|
|
80
235
|
}
|
|
81
|
-
function
|
|
82
|
-
return
|
|
236
|
+
function F(s) {
|
|
237
|
+
return s.split(/\r?\n/).map((e) => e.trim()).filter(Boolean);
|
|
83
238
|
}
|
|
84
|
-
function
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
239
|
+
function P(s, e = 6) {
|
|
240
|
+
const t = [], n = T(s);
|
|
241
|
+
t.push("Generated by matsci-parse"), t.push("1.0"), s.lattice.forEach((c) => {
|
|
242
|
+
t.push(c.map((l) => l.toFixed(e)).join(" "));
|
|
88
243
|
});
|
|
89
|
-
const
|
|
90
|
-
new Set(
|
|
91
|
-
),
|
|
92
|
-
(
|
|
244
|
+
const o = Array.from(
|
|
245
|
+
new Set(s.sites.map((c) => s.species[c.speciesIndex]))
|
|
246
|
+
), i = o.map(
|
|
247
|
+
(c) => s.sites.filter((l) => s.species[l.speciesIndex] === c).length
|
|
93
248
|
);
|
|
94
|
-
return
|
|
95
|
-
|
|
96
|
-
const
|
|
97
|
-
if (
|
|
98
|
-
const
|
|
99
|
-
|
|
249
|
+
return t.push(o.join(" ")), t.push(i.join(" ")), n && t.push("Selective dynamics"), t.push("Cartesian"), o.forEach((c) => {
|
|
250
|
+
s.sites.filter((l) => s.species[l.speciesIndex] === c).forEach((l) => {
|
|
251
|
+
const f = l.cart.map((d) => d.toFixed(e)).join(" ");
|
|
252
|
+
if (n) {
|
|
253
|
+
const u = (Array.isArray(l.props?.selectiveDynamics) ? l.props.selectiveDynamics : [!0, !0, !0]).map((p) => p ? "T" : "F").join(" ");
|
|
254
|
+
t.push(`${f} ${u}`);
|
|
100
255
|
} else
|
|
101
|
-
|
|
256
|
+
t.push(f);
|
|
102
257
|
});
|
|
103
|
-
}),
|
|
258
|
+
}), t.join(`
|
|
104
259
|
`);
|
|
105
260
|
}
|
|
106
|
-
function
|
|
261
|
+
function j(s) {
|
|
107
262
|
let e = 0;
|
|
108
263
|
e++;
|
|
109
|
-
const
|
|
110
|
-
for (let
|
|
111
|
-
|
|
112
|
-
|
|
264
|
+
const t = parseFloat(s[e++]), n = [];
|
|
265
|
+
for (let p = 0; p < 3; p++)
|
|
266
|
+
n.push(
|
|
267
|
+
s[e++].split(/\s+/).map((m) => parseFloat(m) * t)
|
|
113
268
|
);
|
|
114
|
-
let o =
|
|
115
|
-
/^[A-Za-z]/.test(o) && (
|
|
116
|
-
const c =
|
|
117
|
-
|
|
269
|
+
let o = s[e].trim(), i;
|
|
270
|
+
/^[A-Za-z]/.test(o) && (i = o.split(/\s+/), e++);
|
|
271
|
+
const c = s[e++].split(/\s+/).map(Number);
|
|
272
|
+
i || (i = c.map((p, m) => `X${m + 1}`));
|
|
118
273
|
let l = !1;
|
|
119
|
-
|
|
120
|
-
const
|
|
121
|
-
return
|
|
122
|
-
for (let _ = 0; _ < c[
|
|
123
|
-
const r =
|
|
124
|
-
let
|
|
125
|
-
|
|
126
|
-
r[0] *
|
|
127
|
-
r[0] *
|
|
128
|
-
r[0] *
|
|
129
|
-
] :
|
|
130
|
-
const
|
|
274
|
+
s[e]?.toLowerCase().startsWith("s") && (l = !0, e++);
|
|
275
|
+
const d = s[e++].toLowerCase().startsWith("d"), u = [];
|
|
276
|
+
return i.forEach((p, m) => {
|
|
277
|
+
for (let _ = 0; _ < c[m]; _++) {
|
|
278
|
+
const r = s[e++].split(/\s+/).map(Number);
|
|
279
|
+
let h;
|
|
280
|
+
d ? h = [
|
|
281
|
+
r[0] * n[0][0] + r[1] * n[1][0] + r[2] * n[2][0],
|
|
282
|
+
r[0] * n[0][1] + r[1] * n[1][1] + r[2] * n[2][1],
|
|
283
|
+
r[0] * n[0][2] + r[1] * n[1][2] + r[2] * n[2][2]
|
|
284
|
+
] : h = r.slice(0, 3);
|
|
285
|
+
const y = {};
|
|
131
286
|
if (l) {
|
|
132
|
-
const
|
|
133
|
-
|
|
287
|
+
const g = r.slice(3, 6).map((a) => a === 1);
|
|
288
|
+
g.length === 3 && (y.selectiveDynamics = g);
|
|
134
289
|
}
|
|
135
|
-
|
|
290
|
+
u.push(new x(m, h, y));
|
|
136
291
|
}
|
|
137
292
|
}), {
|
|
138
|
-
structure: new
|
|
293
|
+
structure: new w({ lattice: n, species: i, sites: u }),
|
|
139
294
|
linesConsumed: e
|
|
140
295
|
};
|
|
141
296
|
}
|
|
142
|
-
function
|
|
143
|
-
const e =
|
|
144
|
-
return
|
|
297
|
+
function R(s) {
|
|
298
|
+
const e = F(s);
|
|
299
|
+
return j(e).structure;
|
|
145
300
|
}
|
|
146
|
-
function
|
|
147
|
-
const
|
|
148
|
-
return
|
|
149
|
-
|
|
150
|
-
}),
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
301
|
+
function O(s, e = 6) {
|
|
302
|
+
const t = [];
|
|
303
|
+
return t.push("CRYSTAL"), t.push("PRIMVEC"), s.lattice.forEach((n) => {
|
|
304
|
+
t.push(n.map((o) => o.toFixed(e)).join(" "));
|
|
305
|
+
}), t.push("PRIMCOORD"), t.push(`${s.numSites} 1`), s.sites.forEach((n) => {
|
|
306
|
+
const o = s.species[n.speciesIndex];
|
|
307
|
+
t.push(
|
|
308
|
+
`${o} ${n.cart.map((i) => i.toFixed(e)).join(" ")}`
|
|
309
|
+
);
|
|
310
|
+
}), t.join(`
|
|
154
311
|
`);
|
|
155
312
|
}
|
|
156
|
-
function W(
|
|
157
|
-
const e =
|
|
158
|
-
let
|
|
159
|
-
for (;
|
|
160
|
-
if (
|
|
161
|
-
|
|
313
|
+
function W(s) {
|
|
314
|
+
const e = F(s), t = [], n = [], o = [];
|
|
315
|
+
let i = 0;
|
|
316
|
+
for (; i < e.length && e[i].toUpperCase() !== "PRIMVEC"; ) i++;
|
|
317
|
+
if (i === e.length) throw new Error("PRIMVEC block not found in XSF");
|
|
318
|
+
i++;
|
|
162
319
|
for (let l = 0; l < 3; l++)
|
|
163
|
-
|
|
164
|
-
for (;
|
|
165
|
-
if (
|
|
166
|
-
|
|
167
|
-
const [c] = e[
|
|
320
|
+
t.push(e[i++].split(/\s+/).map(Number));
|
|
321
|
+
for (; i < e.length && e[i].toUpperCase() !== "PRIMCOORD"; ) i++;
|
|
322
|
+
if (i === e.length) throw new Error("PRIMCOORD block not found in XSF");
|
|
323
|
+
i++;
|
|
324
|
+
const [c] = e[i++].split(/\s+/).map(Number);
|
|
168
325
|
for (let l = 0; l < c; l++) {
|
|
169
|
-
const
|
|
170
|
-
let
|
|
171
|
-
|
|
326
|
+
const f = e[i++].split(/\s+/), d = f[0], u = f.slice(1, 4).map(Number);
|
|
327
|
+
let p = n.indexOf(d);
|
|
328
|
+
p === -1 && (n.push(d), p = n.length - 1), o.push(new x(p, u));
|
|
172
329
|
}
|
|
173
|
-
return new
|
|
330
|
+
return new w({ lattice: t, species: n, sites: o });
|
|
174
331
|
}
|
|
175
|
-
function
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
].join(" "),
|
|
332
|
+
function X(s, e = 6) {
|
|
333
|
+
const t = [], n = s.sites.length;
|
|
334
|
+
t.push(String(n));
|
|
335
|
+
const o = T(s), i = s.lattice, c = [
|
|
336
|
+
i[0][0],
|
|
337
|
+
i[1][0],
|
|
338
|
+
i[2][0],
|
|
339
|
+
i[0][1],
|
|
340
|
+
i[1][1],
|
|
341
|
+
i[2][1],
|
|
342
|
+
i[0][2],
|
|
343
|
+
i[1][2],
|
|
344
|
+
i[2][2]
|
|
345
|
+
].join(" "), l = [
|
|
189
346
|
"species:S:1",
|
|
190
347
|
"pos:R:3",
|
|
191
|
-
|
|
348
|
+
o ? "selectiveDynamics:L:3" : null
|
|
192
349
|
].filter(Boolean).join(":");
|
|
193
|
-
|
|
194
|
-
for (const
|
|
195
|
-
const
|
|
196
|
-
let
|
|
197
|
-
if (
|
|
198
|
-
const
|
|
199
|
-
|
|
350
|
+
t.push(`Lattice="${c}" Properties=${l}`);
|
|
351
|
+
for (const f of s.sites) {
|
|
352
|
+
const d = s.species[f.speciesIndex], [u, p, m] = f.cart;
|
|
353
|
+
let _ = `${d} ${u.toFixed(e)} ${p.toFixed(e)} ${m.toFixed(e)}`;
|
|
354
|
+
if (o) {
|
|
355
|
+
const r = Array.isArray(f.props?.selectiveDynamics) ? f.props.selectiveDynamics : [!0, !0, !0];
|
|
356
|
+
_ += " " + r.map((h) => h ? "T" : "F").join(" ");
|
|
200
357
|
}
|
|
201
|
-
|
|
358
|
+
t.push(_);
|
|
202
359
|
}
|
|
203
|
-
return
|
|
360
|
+
return t.join(`
|
|
204
361
|
`);
|
|
205
362
|
}
|
|
206
|
-
function
|
|
207
|
-
const e =
|
|
208
|
-
let
|
|
209
|
-
const
|
|
210
|
-
if (!Number.isFinite(
|
|
363
|
+
function N(s) {
|
|
364
|
+
const e = F(s);
|
|
365
|
+
let t = 0;
|
|
366
|
+
const n = parseInt(e[t++], 10);
|
|
367
|
+
if (!Number.isFinite(n))
|
|
211
368
|
throw new Error("Invalid XYZ: first line must be atom count");
|
|
212
|
-
const o = e[
|
|
369
|
+
const o = e[t++], i = {}, c = /(\w+)=(".*?"|\S+)/g;
|
|
213
370
|
for (const r of o.matchAll(c)) {
|
|
214
|
-
let
|
|
215
|
-
|
|
371
|
+
let h = r[2];
|
|
372
|
+
h.startsWith('"') && (h = h.slice(1, -1)), i[r[1]] = h;
|
|
216
373
|
}
|
|
217
374
|
let l;
|
|
218
|
-
if (
|
|
219
|
-
const r =
|
|
375
|
+
if (i.Lattice) {
|
|
376
|
+
const r = i.Lattice.split(/\s+/).map(Number);
|
|
220
377
|
if (r.length !== 9) throw new Error("Invalid Lattice in extended XYZ");
|
|
221
378
|
l = [
|
|
222
379
|
[r[0], r[3], r[6]],
|
|
@@ -225,95 +382,76 @@ function X(t) {
|
|
|
225
382
|
];
|
|
226
383
|
} else
|
|
227
384
|
throw new Error("Lattice must be present in extended XYZ format");
|
|
228
|
-
let
|
|
229
|
-
if (
|
|
230
|
-
const r =
|
|
231
|
-
let
|
|
232
|
-
for (let
|
|
233
|
-
const
|
|
234
|
-
|
|
385
|
+
let f = 0, d = 1, u = null;
|
|
386
|
+
if (i.Properties) {
|
|
387
|
+
const r = i.Properties.split(":");
|
|
388
|
+
let h = 0;
|
|
389
|
+
for (let y = 0; y < r.length; y += 3) {
|
|
390
|
+
const g = r[y], a = parseInt(r[y + 2], 10);
|
|
391
|
+
g === "species" && (f = h), g === "pos" && (d = h), g === "selectiveDynamics" && (u = h), h += a;
|
|
235
392
|
}
|
|
236
393
|
}
|
|
237
|
-
const
|
|
238
|
-
for (let r = 0; r <
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
const
|
|
242
|
-
if (
|
|
243
|
-
const
|
|
244
|
-
|
|
394
|
+
const p = [], m = /* @__PURE__ */ new Map(), _ = [];
|
|
395
|
+
for (let r = 0; r < n; r++) {
|
|
396
|
+
const h = e[t++].split(/\s+/), y = h[f];
|
|
397
|
+
m.has(y) || (m.set(y, p.length), p.push(y));
|
|
398
|
+
const g = m.get(y), a = h.slice(d, d + 3).map(Number), S = {};
|
|
399
|
+
if (u !== null) {
|
|
400
|
+
const I = h.slice(u, u + 3).map((b) => b.toUpperCase() === "T");
|
|
401
|
+
I.length === 3 && (S.selectiveDynamics = I);
|
|
245
402
|
}
|
|
246
|
-
_.push(new
|
|
403
|
+
_.push(new x(g, a, S));
|
|
247
404
|
}
|
|
248
|
-
return new
|
|
249
|
-
}
|
|
250
|
-
function E(t) {
|
|
251
|
-
return t * Math.PI / 180;
|
|
252
|
-
}
|
|
253
|
-
function C(t, e, s, i, o, n) {
|
|
254
|
-
const c = E(i), l = E(o), u = E(n), m = [t, 0, 0], p = [
|
|
255
|
-
e * Math.cos(u),
|
|
256
|
-
e * Math.sin(u),
|
|
257
|
-
0
|
|
258
|
-
], h = s * Math.cos(l), f = s * (Math.cos(c) - Math.cos(l) * Math.cos(u)) / Math.sin(u), _ = Math.sqrt(s * s - h * h - f * f);
|
|
259
|
-
return [m, p, [h, f, _]];
|
|
260
|
-
}
|
|
261
|
-
function j(t, e) {
|
|
262
|
-
const [s, i, o] = e;
|
|
263
|
-
return [
|
|
264
|
-
t[0] * s[0] + t[1] * i[0] + t[2] * o[0],
|
|
265
|
-
t[0] * s[1] + t[1] * i[1] + t[2] * o[1],
|
|
266
|
-
t[0] * s[2] + t[1] * i[2] + t[2] * o[2]
|
|
267
|
-
];
|
|
405
|
+
return new w({ lattice: l, species: p, sites: _ });
|
|
268
406
|
}
|
|
269
|
-
function
|
|
270
|
-
return
|
|
407
|
+
function v(s, e) {
|
|
408
|
+
return s[0] * e[0] + s[1] * e[1] + s[2] * e[2];
|
|
271
409
|
}
|
|
272
|
-
function
|
|
273
|
-
return Math.sqrt(
|
|
410
|
+
function A(s) {
|
|
411
|
+
return Math.sqrt(v(s, s));
|
|
274
412
|
}
|
|
275
|
-
function
|
|
276
|
-
return
|
|
413
|
+
function M(s) {
|
|
414
|
+
return s * 180 / Math.PI;
|
|
277
415
|
}
|
|
278
|
-
function
|
|
279
|
-
const [
|
|
280
|
-
if (Math.abs(
|
|
416
|
+
function D(s, e) {
|
|
417
|
+
const [t, n, o] = e, i = t[0] * (n[1] * o[2] - n[2] * o[1]) - t[1] * (n[0] * o[2] - n[2] * o[0]) + t[2] * (n[0] * o[1] - n[1] * o[0]);
|
|
418
|
+
if (Math.abs(i) < 1e-12)
|
|
281
419
|
throw new Error("Singular lattice matrix");
|
|
282
420
|
const c = [
|
|
283
421
|
[
|
|
284
|
-
(
|
|
285
|
-
(
|
|
286
|
-
(
|
|
422
|
+
(n[1] * o[2] - n[2] * o[1]) / i,
|
|
423
|
+
(t[2] * o[1] - t[1] * o[2]) / i,
|
|
424
|
+
(t[1] * n[2] - t[2] * n[1]) / i
|
|
287
425
|
],
|
|
288
426
|
[
|
|
289
|
-
(
|
|
290
|
-
(
|
|
291
|
-
(
|
|
427
|
+
(n[2] * o[0] - n[0] * o[2]) / i,
|
|
428
|
+
(t[0] * o[2] - t[2] * o[0]) / i,
|
|
429
|
+
(t[2] * n[0] - t[0] * n[2]) / i
|
|
292
430
|
],
|
|
293
431
|
[
|
|
294
|
-
(
|
|
295
|
-
(
|
|
296
|
-
(
|
|
432
|
+
(n[0] * o[1] - n[1] * o[0]) / i,
|
|
433
|
+
(t[1] * o[0] - t[0] * o[1]) / i,
|
|
434
|
+
(t[0] * n[1] - t[1] * n[0]) / i
|
|
297
435
|
]
|
|
298
436
|
];
|
|
299
437
|
return [
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
438
|
+
s[0] * c[0][0] + s[1] * c[1][0] + s[2] * c[2][0],
|
|
439
|
+
s[0] * c[0][1] + s[1] * c[1][1] + s[2] * c[2][1],
|
|
440
|
+
s[0] * c[0][2] + s[1] * c[1][2] + s[2] * c[2][2]
|
|
303
441
|
];
|
|
304
442
|
}
|
|
305
|
-
function
|
|
306
|
-
const [
|
|
443
|
+
function z(s, e = 6) {
|
|
444
|
+
const [t, n, o] = s.lattice, i = A(t), c = A(n), l = A(o), f = M(Math.acos(v(n, o) / (c * l))), d = M(Math.acos(v(t, o) / (i * l))), u = M(Math.acos(v(t, n) / (i * c)));
|
|
307
445
|
let p = `data_made_with_matsci-parse
|
|
308
446
|
_symmetry_space_group_name_H-M 'P 1'
|
|
309
447
|
_symmetry_Int_Tables_number 1
|
|
310
448
|
|
|
311
|
-
_cell_length_a ${
|
|
312
|
-
_cell_length_b ${
|
|
313
|
-
_cell_length_c ${
|
|
314
|
-
_cell_angle_alpha ${
|
|
315
|
-
_cell_angle_beta ${
|
|
316
|
-
_cell_angle_gamma ${
|
|
449
|
+
_cell_length_a ${i.toFixed(e)}
|
|
450
|
+
_cell_length_b ${c.toFixed(e)}
|
|
451
|
+
_cell_length_c ${l.toFixed(e)}
|
|
452
|
+
_cell_angle_alpha ${f.toFixed(e)}
|
|
453
|
+
_cell_angle_beta ${d.toFixed(e)}
|
|
454
|
+
_cell_angle_gamma ${u.toFixed(e)}
|
|
317
455
|
|
|
318
456
|
loop_
|
|
319
457
|
_atom_site_label
|
|
@@ -322,44 +460,44 @@ function N(t) {
|
|
|
322
460
|
_atom_site_fract_y
|
|
323
461
|
_atom_site_fract_z
|
|
324
462
|
`;
|
|
325
|
-
return
|
|
326
|
-
const
|
|
327
|
-
p += `${
|
|
463
|
+
return s.sites.forEach((m, _) => {
|
|
464
|
+
const r = s.species[m.speciesIndex], h = D(m.cart, s.lattice);
|
|
465
|
+
p += `${r}${_ + 1} ${r} ${h[0].toFixed(e)} ${h[1].toFixed(
|
|
328
466
|
6
|
|
329
|
-
)} ${
|
|
467
|
+
)} ${h[2].toFixed(e)}
|
|
330
468
|
`;
|
|
331
469
|
}), p;
|
|
332
470
|
}
|
|
333
|
-
function
|
|
334
|
-
const e =
|
|
335
|
-
let
|
|
336
|
-
const
|
|
337
|
-
let
|
|
471
|
+
function V(s) {
|
|
472
|
+
const e = F(s);
|
|
473
|
+
let t = 0, n = 0, o = 0, i = 0, c = 0, l = 0;
|
|
474
|
+
const f = [];
|
|
475
|
+
let d = !1, u = [];
|
|
338
476
|
for (const a of e)
|
|
339
|
-
a.startsWith("_cell_length_a") ?
|
|
340
|
-
const
|
|
341
|
-
if (r < 0 ||
|
|
477
|
+
a.startsWith("_cell_length_a") ? t = parseFloat(a.split(/\s+/)[1]) : a.startsWith("_cell_length_b") ? n = parseFloat(a.split(/\s+/)[1]) : a.startsWith("_cell_length_c") ? o = parseFloat(a.split(/\s+/)[1]) : a.startsWith("_cell_angle_alpha") ? i = parseFloat(a.split(/\s+/)[1]) : a.startsWith("_cell_angle_beta") ? c = parseFloat(a.split(/\s+/)[1]) : a.startsWith("_cell_angle_gamma") ? l = parseFloat(a.split(/\s+/)[1]) : a.startsWith("loop_") ? (d = !0, u = []) : d && a.startsWith("_") ? u.push(a) : d && a && !a.startsWith("_") && f.push(a.split(/\s+/));
|
|
478
|
+
const p = L(t, n, o, i, c, l), m = [], _ = [], r = u.findIndex((a) => a.includes("fract_x")), h = u.findIndex((a) => a.includes("fract_y")), y = u.findIndex((a) => a.includes("fract_z")), g = u.findIndex((a) => a.includes("type_symbol"));
|
|
479
|
+
if (r < 0 || h < 0 || y < 0 || g < 0)
|
|
342
480
|
throw new Error("CIF missing required _atom_site columns");
|
|
343
|
-
for (const a of
|
|
344
|
-
const
|
|
481
|
+
for (const a of f) {
|
|
482
|
+
const S = [
|
|
345
483
|
parseFloat(a[r]),
|
|
346
|
-
parseFloat(a[
|
|
347
|
-
parseFloat(a[
|
|
348
|
-
],
|
|
349
|
-
let
|
|
350
|
-
|
|
484
|
+
parseFloat(a[h]),
|
|
485
|
+
parseFloat(a[y])
|
|
486
|
+
], I = C(S, p);
|
|
487
|
+
let b = m.indexOf(a[g]);
|
|
488
|
+
b === -1 && (b = m.length, m.push(a[g])), _.push(new x(b, I));
|
|
351
489
|
}
|
|
352
|
-
return new
|
|
490
|
+
return new w({ lattice: p, species: m, sites: _ });
|
|
353
491
|
}
|
|
354
492
|
export {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
493
|
+
w as CrystalStructure,
|
|
494
|
+
x as Site,
|
|
495
|
+
V as cifToStructure,
|
|
496
|
+
R as poscarToStructure,
|
|
497
|
+
z as structureToCif,
|
|
498
|
+
P as structureToPoscar,
|
|
499
|
+
O as structureToXsf,
|
|
500
|
+
X as structureToXyz,
|
|
363
501
|
W as xsfToStructure,
|
|
364
|
-
|
|
502
|
+
N as xyzToStructure
|
|
365
503
|
};
|