matsci-parse 0.1.2 → 0.2.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 +368 -304
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -1,42 +1,42 @@
|
|
|
1
1
|
class x {
|
|
2
|
-
constructor(
|
|
3
|
-
this.speciesIndex =
|
|
2
|
+
constructor(t, e, i = {}) {
|
|
3
|
+
this.speciesIndex = t, this.cart = e, this.props = i;
|
|
4
4
|
}
|
|
5
|
-
getProp(
|
|
6
|
-
return this.props[
|
|
5
|
+
getProp(t) {
|
|
6
|
+
return this.props[t];
|
|
7
7
|
}
|
|
8
|
-
setProp(
|
|
9
|
-
this.props[
|
|
8
|
+
setProp(t, e) {
|
|
9
|
+
this.props[t] = e;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
function C(s) {
|
|
13
|
-
return s.sites.some((
|
|
13
|
+
return s.sites.some((t) => Array.isArray(t.props.selectiveDynamics));
|
|
14
14
|
}
|
|
15
|
-
function
|
|
15
|
+
function F(s) {
|
|
16
16
|
return s * Math.PI / 180;
|
|
17
17
|
}
|
|
18
|
-
function
|
|
18
|
+
function M(s, t) {
|
|
19
19
|
return s.map(
|
|
20
|
-
(
|
|
20
|
+
(e) => e[0] * t[0] + e[1] * t[1] + e[2] * t[2]
|
|
21
21
|
);
|
|
22
22
|
}
|
|
23
|
-
function
|
|
24
|
-
const a =
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
function P(s, t, e, i, o, n) {
|
|
24
|
+
const a = F(i), h = F(o), l = F(n), p = [s, 0, 0], f = [
|
|
25
|
+
t * Math.cos(l),
|
|
26
|
+
t * Math.sin(l),
|
|
27
27
|
0
|
|
28
|
-
],
|
|
29
|
-
return [
|
|
28
|
+
], r = e * Math.cos(h), u = e * (Math.cos(a) - Math.cos(h) * Math.cos(l)) / Math.sin(l), g = Math.sqrt(e * e - r * r - u * u);
|
|
29
|
+
return [p, f, [r, u, g]];
|
|
30
30
|
}
|
|
31
|
-
function
|
|
32
|
-
const [
|
|
31
|
+
function O(s, t) {
|
|
32
|
+
const [e, i, o] = t;
|
|
33
33
|
return [
|
|
34
|
-
s[0] *
|
|
35
|
-
s[0] *
|
|
36
|
-
s[0] *
|
|
34
|
+
s[0] * e[0] + s[1] * i[0] + s[2] * o[0],
|
|
35
|
+
s[0] * e[1] + s[1] * i[1] + s[2] * o[1],
|
|
36
|
+
s[0] * e[2] + s[1] * i[2] + s[2] * o[2]
|
|
37
37
|
];
|
|
38
38
|
}
|
|
39
|
-
class
|
|
39
|
+
class S {
|
|
40
40
|
/**
|
|
41
41
|
* Creates a new CrystalStructure.
|
|
42
42
|
*
|
|
@@ -48,11 +48,11 @@ class w {
|
|
|
48
48
|
* @throws Will throw an error if lattice is not 3x3, species is not an array of strings, or sites are invalid
|
|
49
49
|
*/
|
|
50
50
|
constructor({
|
|
51
|
-
lattice:
|
|
52
|
-
species:
|
|
53
|
-
sites:
|
|
51
|
+
lattice: t,
|
|
52
|
+
species: e,
|
|
53
|
+
sites: i
|
|
54
54
|
}) {
|
|
55
|
-
this.lattice = this._validateLattice(
|
|
55
|
+
this.lattice = this._validateLattice(t), this.species = this._validateSpecies(e), this.sites = this._validateSites(i);
|
|
56
56
|
}
|
|
57
57
|
// ---------- Simple methods ----------
|
|
58
58
|
/** Number of sites in the structure */
|
|
@@ -63,22 +63,22 @@ class w {
|
|
|
63
63
|
* Returns the site at the specified index.
|
|
64
64
|
* @param i - Site index
|
|
65
65
|
*/
|
|
66
|
-
site(
|
|
67
|
-
return this.sites[
|
|
66
|
+
site(t) {
|
|
67
|
+
return this.sites[t];
|
|
68
68
|
}
|
|
69
69
|
/**
|
|
70
70
|
* Returns the Cartesian coordinates of a site.
|
|
71
71
|
* @param i - Site index
|
|
72
72
|
*/
|
|
73
|
-
cartCoords(
|
|
74
|
-
return this.sites[
|
|
73
|
+
cartCoords(t) {
|
|
74
|
+
return this.sites[t].cart;
|
|
75
75
|
}
|
|
76
76
|
/**
|
|
77
77
|
* Returns the chemical species of a site.
|
|
78
78
|
* @param i - Site index
|
|
79
79
|
*/
|
|
80
|
-
siteSpecies(
|
|
81
|
-
return this.species[this.sites[
|
|
80
|
+
siteSpecies(t) {
|
|
81
|
+
return this.species[this.sites[t].speciesIndex];
|
|
82
82
|
}
|
|
83
83
|
/** Returns the array of elements (species) in the structure */
|
|
84
84
|
get elements() {
|
|
@@ -92,11 +92,11 @@ class w {
|
|
|
92
92
|
* @param cart - Cartesian coordinates of the new site
|
|
93
93
|
* @param position - Optional index at which to insert the site. Defaults to appending at the end.
|
|
94
94
|
*/
|
|
95
|
-
addSite(
|
|
96
|
-
let o = this.species.indexOf(
|
|
97
|
-
o === -1 && (this.species.push(
|
|
98
|
-
const
|
|
99
|
-
|
|
95
|
+
addSite(t, e, i) {
|
|
96
|
+
let o = this.species.indexOf(t);
|
|
97
|
+
o === -1 && (this.species.push(t), o = this.species.length - 1);
|
|
98
|
+
const n = new x(o, e);
|
|
99
|
+
i === void 0 || i >= this.sites.length ? this.sites.push(n) : i < 0 ? this.sites.unshift(n) : this.sites.splice(i, 0, n);
|
|
100
100
|
}
|
|
101
101
|
/**
|
|
102
102
|
* Removes a site from the crystal.
|
|
@@ -107,14 +107,14 @@ class w {
|
|
|
107
107
|
*
|
|
108
108
|
* @throws Will throw an error if index is out of bounds
|
|
109
109
|
*/
|
|
110
|
-
removeSite(
|
|
111
|
-
if (
|
|
110
|
+
removeSite(t) {
|
|
111
|
+
if (t < 0 || t >= this.sites.length)
|
|
112
112
|
throw new Error("siteIndex out of bounds");
|
|
113
|
-
const
|
|
113
|
+
const i = this.sites.splice(t, 1)[0].speciesIndex;
|
|
114
114
|
this.sites.some(
|
|
115
|
-
(
|
|
116
|
-
) || (this.species.splice(
|
|
117
|
-
|
|
115
|
+
(n) => n.speciesIndex === i
|
|
116
|
+
) || (this.species.splice(i, 1), this.sites.forEach((n) => {
|
|
117
|
+
n.speciesIndex > i && (n.speciesIndex -= 1);
|
|
118
118
|
}));
|
|
119
119
|
}
|
|
120
120
|
/**
|
|
@@ -127,11 +127,11 @@ class w {
|
|
|
127
127
|
*
|
|
128
128
|
* @throws Will throw an error if siteIndex is out of bounds
|
|
129
129
|
*/
|
|
130
|
-
replaceSite(
|
|
131
|
-
if (
|
|
130
|
+
replaceSite(t, e) {
|
|
131
|
+
if (t < 0 || t >= this.sites.length)
|
|
132
132
|
throw new Error("siteIndex out of bounds");
|
|
133
|
-
const
|
|
134
|
-
this.removeSite(
|
|
133
|
+
const i = [...this.sites[t].cart];
|
|
134
|
+
this.removeSite(t), this.addSite(e, i, t);
|
|
135
135
|
}
|
|
136
136
|
/**
|
|
137
137
|
* Returns a new CrystalStructure transformed by a linear matrix.
|
|
@@ -146,37 +146,37 @@ class w {
|
|
|
146
146
|
*
|
|
147
147
|
* @throws Will throw an error if scale is not a number, a 3-element array, or a 3x3 matrix
|
|
148
148
|
*/
|
|
149
|
-
applyLatticeTransformation(
|
|
150
|
-
let
|
|
151
|
-
if (typeof
|
|
152
|
-
|
|
153
|
-
[
|
|
154
|
-
[0,
|
|
155
|
-
[0, 0,
|
|
149
|
+
applyLatticeTransformation(t) {
|
|
150
|
+
let e;
|
|
151
|
+
if (typeof t == "number")
|
|
152
|
+
e = [
|
|
153
|
+
[t, 0, 0],
|
|
154
|
+
[0, t, 0],
|
|
155
|
+
[0, 0, t]
|
|
156
156
|
];
|
|
157
|
-
else if (Array.isArray(
|
|
158
|
-
|
|
159
|
-
[
|
|
160
|
-
[0,
|
|
161
|
-
[0, 0,
|
|
157
|
+
else if (Array.isArray(t) && t.length === 3 && t.every((n) => typeof n == "number"))
|
|
158
|
+
e = [
|
|
159
|
+
[t[0], 0, 0],
|
|
160
|
+
[0, t[1], 0],
|
|
161
|
+
[0, 0, t[2]]
|
|
162
162
|
];
|
|
163
|
-
else if (Array.isArray(
|
|
164
|
-
|
|
163
|
+
else if (Array.isArray(t) && t.length === 3 && t.every((n) => Array.isArray(n) && n.length === 3))
|
|
164
|
+
e = t;
|
|
165
165
|
else
|
|
166
166
|
throw new Error(
|
|
167
167
|
"Scale must be a number, a 3-element array, or a 3x3 matrix"
|
|
168
168
|
);
|
|
169
|
-
const
|
|
170
|
-
(
|
|
171
|
-
), o = this.sites.map((
|
|
172
|
-
const a =
|
|
173
|
-
|
|
174
|
-
|
|
169
|
+
const i = this.lattice.map(
|
|
170
|
+
(n) => M(e, n)
|
|
171
|
+
), o = this.sites.map((n) => {
|
|
172
|
+
const a = M(
|
|
173
|
+
e,
|
|
174
|
+
n.cart
|
|
175
175
|
);
|
|
176
|
-
return new x(
|
|
176
|
+
return new x(n.speciesIndex, a, n.props);
|
|
177
177
|
});
|
|
178
|
-
return new
|
|
179
|
-
lattice:
|
|
178
|
+
return new S({
|
|
179
|
+
lattice: i,
|
|
180
180
|
species: [...this.species],
|
|
181
181
|
sites: o
|
|
182
182
|
});
|
|
@@ -186,38 +186,38 @@ class w {
|
|
|
186
186
|
* Validates that the lattice is a 3x3 array of Cartesian vectors.
|
|
187
187
|
* @throws Will throw an error if lattice is invalid
|
|
188
188
|
*/
|
|
189
|
-
_validateLattice(
|
|
190
|
-
if (!Array.isArray(
|
|
189
|
+
_validateLattice(t) {
|
|
190
|
+
if (!Array.isArray(t) || t.length !== 3)
|
|
191
191
|
throw new Error("Lattice must be a 3x3 matrix");
|
|
192
|
-
return
|
|
193
|
-
if (!Array.isArray(
|
|
192
|
+
return t.forEach((e) => {
|
|
193
|
+
if (!Array.isArray(e) || e.length !== 3)
|
|
194
194
|
throw new Error("Lattice vectors must be length 3");
|
|
195
|
-
}),
|
|
195
|
+
}), t;
|
|
196
196
|
}
|
|
197
197
|
/**
|
|
198
198
|
* Validates that species is an array of strings.
|
|
199
199
|
* @throws Will throw an error if species array is invalid
|
|
200
200
|
*/
|
|
201
|
-
_validateSpecies(
|
|
202
|
-
if (!Array.isArray(
|
|
203
|
-
return
|
|
204
|
-
if (typeof
|
|
201
|
+
_validateSpecies(t) {
|
|
202
|
+
if (!Array.isArray(t)) throw new Error("Species must be an array");
|
|
203
|
+
return t.forEach((e) => {
|
|
204
|
+
if (typeof e != "string")
|
|
205
205
|
throw new Error("Species entries must be strings");
|
|
206
|
-
}),
|
|
206
|
+
}), t;
|
|
207
207
|
}
|
|
208
208
|
/**
|
|
209
209
|
* Validates the sites array, ensuring each site is a Site instance or a valid object.
|
|
210
210
|
* @throws Will throw an error if sites array is invalid
|
|
211
211
|
*/
|
|
212
|
-
_validateSites(
|
|
213
|
-
if (!Array.isArray(
|
|
214
|
-
return
|
|
215
|
-
if (
|
|
216
|
-
if (typeof
|
|
217
|
-
return this._validateSpeciesIndex(
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
212
|
+
_validateSites(t) {
|
|
213
|
+
if (!Array.isArray(t)) throw new Error("Sites must be an array");
|
|
214
|
+
return t.map((e) => {
|
|
215
|
+
if (e instanceof x) return e;
|
|
216
|
+
if (typeof e == "object" && typeof e.speciesIndex == "number" && Array.isArray(e.cart) && e.cart.length === 3)
|
|
217
|
+
return this._validateSpeciesIndex(e.speciesIndex), new x(
|
|
218
|
+
e.speciesIndex,
|
|
219
|
+
e.cart,
|
|
220
|
+
e.props ?? {}
|
|
221
221
|
);
|
|
222
222
|
throw new Error(
|
|
223
223
|
"Each site must be a Site instance or a valid site object"
|
|
@@ -228,210 +228,210 @@ class w {
|
|
|
228
228
|
* Validates that a species index is within bounds.
|
|
229
229
|
* @throws Will throw an error if index is out of range
|
|
230
230
|
*/
|
|
231
|
-
_validateSpeciesIndex(
|
|
232
|
-
if (
|
|
231
|
+
_validateSpeciesIndex(t) {
|
|
232
|
+
if (t < 0 || t >= this.species.length)
|
|
233
233
|
throw new Error("speciesIndex out of bounds");
|
|
234
234
|
}
|
|
235
235
|
}
|
|
236
|
-
function
|
|
237
|
-
return s.split(/\r?\n/).map((
|
|
236
|
+
function E(s) {
|
|
237
|
+
return s.split(/\r?\n/).map((t) => t.trim()).filter(Boolean);
|
|
238
238
|
}
|
|
239
|
-
function
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
239
|
+
function D(s, t = 6) {
|
|
240
|
+
const e = [], i = C(s);
|
|
241
|
+
e.push("Generated by matsci-parse"), e.push("1.0"), s.lattice.forEach((a) => {
|
|
242
|
+
e.push(a.map((h) => h.toFixed(t)).join(" "));
|
|
243
243
|
});
|
|
244
244
|
const o = Array.from(
|
|
245
245
|
new Set(s.sites.map((a) => s.species[a.speciesIndex]))
|
|
246
|
-
),
|
|
247
|
-
(a) => s.sites.filter((
|
|
246
|
+
), n = o.map(
|
|
247
|
+
(a) => s.sites.filter((h) => s.species[h.speciesIndex] === a).length
|
|
248
248
|
);
|
|
249
|
-
return
|
|
250
|
-
s.sites.filter((
|
|
251
|
-
const
|
|
252
|
-
if (
|
|
253
|
-
const
|
|
254
|
-
|
|
249
|
+
return e.push(o.join(" ")), e.push(n.join(" ")), i && e.push("Selective dynamics"), e.push("Cartesian"), o.forEach((a) => {
|
|
250
|
+
s.sites.filter((h) => s.species[h.speciesIndex] === a).forEach((h) => {
|
|
251
|
+
const l = h.cart.map((p) => p.toFixed(t)).join(" ");
|
|
252
|
+
if (i) {
|
|
253
|
+
const f = (Array.isArray(h.props?.selectiveDynamics) ? h.props.selectiveDynamics : [!0, !0, !0]).map((r) => r ? "T" : "F").join(" ");
|
|
254
|
+
e.push(`${l} ${f}`);
|
|
255
255
|
} else
|
|
256
|
-
|
|
256
|
+
e.push(l);
|
|
257
257
|
});
|
|
258
|
-
}),
|
|
258
|
+
}), e.join(`
|
|
259
259
|
`);
|
|
260
260
|
}
|
|
261
|
-
function
|
|
262
|
-
let
|
|
263
|
-
|
|
264
|
-
const
|
|
265
|
-
for (let
|
|
266
|
-
|
|
267
|
-
s[
|
|
261
|
+
function R(s) {
|
|
262
|
+
let t = 0;
|
|
263
|
+
t++;
|
|
264
|
+
const e = parseFloat(s[t++]), i = [];
|
|
265
|
+
for (let r = 0; r < 3; r++)
|
|
266
|
+
i.push(
|
|
267
|
+
s[t++].split(/\s+/).map((u) => parseFloat(u) * e)
|
|
268
268
|
);
|
|
269
|
-
let o = s[
|
|
270
|
-
/^[A-Za-z]/.test(o) && (
|
|
271
|
-
const a = s[
|
|
272
|
-
|
|
273
|
-
let
|
|
274
|
-
s[
|
|
275
|
-
const
|
|
276
|
-
return
|
|
277
|
-
for (let
|
|
278
|
-
const
|
|
279
|
-
let
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
] :
|
|
285
|
-
const
|
|
286
|
-
if (
|
|
287
|
-
const y =
|
|
288
|
-
y.length === 3 && (
|
|
269
|
+
let o = s[t].trim(), n;
|
|
270
|
+
/^[A-Za-z]/.test(o) && (n = o.split(/\s+/), t++);
|
|
271
|
+
const a = s[t++].split(/\s+/).map(Number);
|
|
272
|
+
n || (n = a.map((r, u) => `X${u + 1}`));
|
|
273
|
+
let h = !1;
|
|
274
|
+
s[t]?.toLowerCase().startsWith("s") && (h = !0, t++);
|
|
275
|
+
const p = s[t++].toLowerCase().startsWith("d"), f = [];
|
|
276
|
+
return n.forEach((r, u) => {
|
|
277
|
+
for (let g = 0; g < a[u]; g++) {
|
|
278
|
+
const c = s[t++].split(/\s+/).map(Number);
|
|
279
|
+
let m;
|
|
280
|
+
p ? m = [
|
|
281
|
+
c[0] * i[0][0] + c[1] * i[1][0] + c[2] * i[2][0],
|
|
282
|
+
c[0] * i[0][1] + c[1] * i[1][1] + c[2] * i[2][1],
|
|
283
|
+
c[0] * i[0][2] + c[1] * i[1][2] + c[2] * i[2][2]
|
|
284
|
+
] : m = c.slice(0, 3);
|
|
285
|
+
const w = {};
|
|
286
|
+
if (h) {
|
|
287
|
+
const y = c.slice(3, 6).map((b) => b === 1);
|
|
288
|
+
y.length === 3 && (w.selectiveDynamics = y);
|
|
289
289
|
}
|
|
290
|
-
|
|
290
|
+
f.push(new x(u, m, w));
|
|
291
291
|
}
|
|
292
292
|
}), {
|
|
293
|
-
structure: new
|
|
294
|
-
linesConsumed:
|
|
293
|
+
structure: new S({ lattice: i, species: n, sites: f }),
|
|
294
|
+
linesConsumed: t
|
|
295
295
|
};
|
|
296
296
|
}
|
|
297
|
-
function
|
|
298
|
-
const
|
|
299
|
-
return
|
|
297
|
+
function W(s) {
|
|
298
|
+
const t = E(s);
|
|
299
|
+
return R(t).structure;
|
|
300
300
|
}
|
|
301
|
-
function
|
|
302
|
-
const
|
|
303
|
-
return
|
|
304
|
-
|
|
305
|
-
}),
|
|
306
|
-
const o = s.species[
|
|
307
|
-
|
|
308
|
-
`${o} ${
|
|
301
|
+
function k(s, t = 6) {
|
|
302
|
+
const e = [];
|
|
303
|
+
return e.push("CRYSTAL"), e.push("PRIMVEC"), s.lattice.forEach((i) => {
|
|
304
|
+
e.push(i.map((o) => o.toFixed(t)).join(" "));
|
|
305
|
+
}), e.push("PRIMCOORD"), e.push(`${s.numSites} 1`), s.sites.forEach((i) => {
|
|
306
|
+
const o = s.species[i.speciesIndex];
|
|
307
|
+
e.push(
|
|
308
|
+
`${o} ${i.cart.map((n) => n.toFixed(t)).join(" ")}`
|
|
309
309
|
);
|
|
310
|
-
}),
|
|
310
|
+
}), e.join(`
|
|
311
311
|
`);
|
|
312
312
|
}
|
|
313
|
-
function
|
|
314
|
-
const
|
|
315
|
-
let
|
|
316
|
-
for (;
|
|
317
|
-
if (
|
|
318
|
-
|
|
319
|
-
for (let
|
|
320
|
-
|
|
321
|
-
for (;
|
|
322
|
-
if (
|
|
323
|
-
|
|
324
|
-
const [a] =
|
|
325
|
-
for (let
|
|
326
|
-
const
|
|
327
|
-
let
|
|
328
|
-
|
|
313
|
+
function X(s) {
|
|
314
|
+
const t = E(s), e = [], i = [], o = [];
|
|
315
|
+
let n = 0;
|
|
316
|
+
for (; n < t.length && t[n].toUpperCase() !== "PRIMVEC"; ) n++;
|
|
317
|
+
if (n === t.length) throw new Error("PRIMVEC block not found in XSF");
|
|
318
|
+
n++;
|
|
319
|
+
for (let h = 0; h < 3; h++)
|
|
320
|
+
e.push(t[n++].split(/\s+/).map(Number));
|
|
321
|
+
for (; n < t.length && t[n].toUpperCase() !== "PRIMCOORD"; ) n++;
|
|
322
|
+
if (n === t.length) throw new Error("PRIMCOORD block not found in XSF");
|
|
323
|
+
n++;
|
|
324
|
+
const [a] = t[n++].split(/\s+/).map(Number);
|
|
325
|
+
for (let h = 0; h < a; h++) {
|
|
326
|
+
const l = t[n++].split(/\s+/), p = l[0], f = l.slice(1, 4).map(Number);
|
|
327
|
+
let r = i.indexOf(p);
|
|
328
|
+
r === -1 && (i.push(p), r = i.length - 1), o.push(new x(r, f));
|
|
329
329
|
}
|
|
330
|
-
return new
|
|
330
|
+
return new S({ lattice: e, species: i, sites: o });
|
|
331
331
|
}
|
|
332
|
-
function
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
const o = C(s),
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
].join(" "),
|
|
332
|
+
function z(s, t = 6) {
|
|
333
|
+
const e = [], i = s.sites.length;
|
|
334
|
+
e.push(String(i));
|
|
335
|
+
const o = C(s), n = s.lattice, a = [
|
|
336
|
+
n[0][0],
|
|
337
|
+
n[1][0],
|
|
338
|
+
n[2][0],
|
|
339
|
+
n[0][1],
|
|
340
|
+
n[1][1],
|
|
341
|
+
n[2][1],
|
|
342
|
+
n[0][2],
|
|
343
|
+
n[1][2],
|
|
344
|
+
n[2][2]
|
|
345
|
+
].join(" "), h = [
|
|
346
346
|
"species:S:1",
|
|
347
347
|
"pos:R:3",
|
|
348
348
|
o ? "selectiveDynamics:L:3" : null
|
|
349
349
|
].filter(Boolean).join(":");
|
|
350
|
-
|
|
351
|
-
for (const
|
|
352
|
-
const
|
|
353
|
-
let
|
|
350
|
+
e.push(`Lattice="${a}" Properties=${h}`);
|
|
351
|
+
for (const l of s.sites) {
|
|
352
|
+
const p = s.species[l.speciesIndex], [f, r, u] = l.cart;
|
|
353
|
+
let g = `${p} ${f.toFixed(t)} ${r.toFixed(t)} ${u.toFixed(t)}`;
|
|
354
354
|
if (o) {
|
|
355
|
-
const
|
|
356
|
-
|
|
355
|
+
const c = Array.isArray(l.props?.selectiveDynamics) ? l.props.selectiveDynamics : [!0, !0, !0];
|
|
356
|
+
g += " " + c.map((m) => m ? "T" : "F").join(" ");
|
|
357
357
|
}
|
|
358
|
-
|
|
358
|
+
e.push(g);
|
|
359
359
|
}
|
|
360
|
-
return
|
|
360
|
+
return e.join(`
|
|
361
361
|
`);
|
|
362
362
|
}
|
|
363
|
-
function
|
|
364
|
-
const
|
|
365
|
-
let
|
|
366
|
-
const
|
|
367
|
-
if (!Number.isFinite(
|
|
363
|
+
function Z(s) {
|
|
364
|
+
const t = E(s);
|
|
365
|
+
let e = 0;
|
|
366
|
+
const i = parseInt(t[e++], 10);
|
|
367
|
+
if (!Number.isFinite(i))
|
|
368
368
|
throw new Error("Invalid XYZ: first line must be atom count");
|
|
369
|
-
const o = e
|
|
370
|
-
for (const
|
|
371
|
-
let
|
|
372
|
-
|
|
369
|
+
const o = t[e++], n = {}, a = /(\w+)=(".*?"|\S+)/g;
|
|
370
|
+
for (const c of o.matchAll(a)) {
|
|
371
|
+
let m = c[2];
|
|
372
|
+
m.startsWith('"') && (m = m.slice(1, -1)), n[c[1]] = m;
|
|
373
373
|
}
|
|
374
|
-
let
|
|
375
|
-
if (
|
|
376
|
-
const
|
|
377
|
-
if (
|
|
378
|
-
|
|
379
|
-
[
|
|
380
|
-
[
|
|
381
|
-
[
|
|
374
|
+
let h;
|
|
375
|
+
if (n.Lattice) {
|
|
376
|
+
const c = n.Lattice.split(/\s+/).map(Number);
|
|
377
|
+
if (c.length !== 9) throw new Error("Invalid Lattice in extended XYZ");
|
|
378
|
+
h = [
|
|
379
|
+
[c[0], c[3], c[6]],
|
|
380
|
+
[c[1], c[4], c[7]],
|
|
381
|
+
[c[2], c[5], c[8]]
|
|
382
382
|
];
|
|
383
383
|
} else
|
|
384
384
|
throw new Error("Lattice must be present in extended XYZ format");
|
|
385
|
-
let
|
|
386
|
-
if (
|
|
387
|
-
const
|
|
388
|
-
let
|
|
389
|
-
for (let
|
|
390
|
-
const y =
|
|
391
|
-
y === "species" && (
|
|
385
|
+
let l = 0, p = 1, f = null;
|
|
386
|
+
if (n.Properties) {
|
|
387
|
+
const c = n.Properties.split(":");
|
|
388
|
+
let m = 0;
|
|
389
|
+
for (let w = 0; w < c.length; w += 3) {
|
|
390
|
+
const y = c[w], b = parseInt(c[w + 2], 10);
|
|
391
|
+
y === "species" && (l = m), y === "pos" && (p = m), y === "selectiveDynamics" && (f = m), m += b;
|
|
392
392
|
}
|
|
393
393
|
}
|
|
394
|
-
const
|
|
395
|
-
for (let
|
|
396
|
-
const
|
|
397
|
-
|
|
398
|
-
const y =
|
|
399
|
-
if (
|
|
400
|
-
const
|
|
401
|
-
|
|
394
|
+
const r = [], u = /* @__PURE__ */ new Map(), g = [];
|
|
395
|
+
for (let c = 0; c < i; c++) {
|
|
396
|
+
const m = t[e++].split(/\s+/), w = m[l];
|
|
397
|
+
u.has(w) || (u.set(w, r.length), r.push(w));
|
|
398
|
+
const y = u.get(w), b = m.slice(p, p + 3).map(Number), I = {};
|
|
399
|
+
if (f !== null) {
|
|
400
|
+
const _ = m.slice(f, f + 3).map((d) => d.toUpperCase() === "T");
|
|
401
|
+
_.length === 3 && (I.selectiveDynamics = _);
|
|
402
402
|
}
|
|
403
|
-
|
|
403
|
+
g.push(new x(y, b, I));
|
|
404
404
|
}
|
|
405
|
-
return new
|
|
405
|
+
return new S({ lattice: h, species: r, sites: g });
|
|
406
406
|
}
|
|
407
|
-
function
|
|
408
|
-
return s[0] *
|
|
407
|
+
function A(s, t) {
|
|
408
|
+
return s[0] * t[0] + s[1] * t[1] + s[2] * t[2];
|
|
409
409
|
}
|
|
410
|
-
function
|
|
411
|
-
return Math.sqrt(
|
|
410
|
+
function T(s) {
|
|
411
|
+
return Math.sqrt(A(s, s));
|
|
412
412
|
}
|
|
413
|
-
function
|
|
413
|
+
function L(s) {
|
|
414
414
|
return s * 180 / Math.PI;
|
|
415
415
|
}
|
|
416
|
-
function
|
|
417
|
-
const [
|
|
418
|
-
if (Math.abs(
|
|
416
|
+
function j(s, t) {
|
|
417
|
+
const [e, i, o] = t, n = e[0] * (i[1] * o[2] - i[2] * o[1]) - e[1] * (i[0] * o[2] - i[2] * o[0]) + e[2] * (i[0] * o[1] - i[1] * o[0]);
|
|
418
|
+
if (Math.abs(n) < 1e-12)
|
|
419
419
|
throw new Error("Singular lattice matrix");
|
|
420
420
|
const a = [
|
|
421
421
|
[
|
|
422
|
-
(
|
|
423
|
-
(
|
|
424
|
-
(
|
|
422
|
+
(i[1] * o[2] - i[2] * o[1]) / n,
|
|
423
|
+
(e[2] * o[1] - e[1] * o[2]) / n,
|
|
424
|
+
(e[1] * i[2] - e[2] * i[1]) / n
|
|
425
425
|
],
|
|
426
426
|
[
|
|
427
|
-
(
|
|
428
|
-
(
|
|
429
|
-
(
|
|
427
|
+
(i[2] * o[0] - i[0] * o[2]) / n,
|
|
428
|
+
(e[0] * o[2] - e[2] * o[0]) / n,
|
|
429
|
+
(e[2] * i[0] - e[0] * i[2]) / n
|
|
430
430
|
],
|
|
431
431
|
[
|
|
432
|
-
(
|
|
433
|
-
(
|
|
434
|
-
(
|
|
432
|
+
(i[0] * o[1] - i[1] * o[0]) / n,
|
|
433
|
+
(e[1] * o[0] - e[0] * o[1]) / n,
|
|
434
|
+
(e[0] * i[1] - e[1] * i[0]) / n
|
|
435
435
|
]
|
|
436
436
|
];
|
|
437
437
|
return [
|
|
@@ -440,18 +440,18 @@ function D(s, e) {
|
|
|
440
440
|
s[0] * a[0][2] + s[1] * a[1][2] + s[2] * a[2][2]
|
|
441
441
|
];
|
|
442
442
|
}
|
|
443
|
-
function
|
|
444
|
-
const [
|
|
445
|
-
let
|
|
443
|
+
function V(s, t = 6) {
|
|
444
|
+
const [e, i, o] = s.lattice, n = T(e), a = T(i), h = T(o), l = L(Math.acos(A(i, o) / (a * h))), p = L(Math.acos(A(e, o) / (n * h))), f = L(Math.acos(A(e, i) / (n * a)));
|
|
445
|
+
let r = `data_made_with_matsci-parse
|
|
446
446
|
_symmetry_space_group_name_H-M 'P 1'
|
|
447
447
|
_symmetry_Int_Tables_number 1
|
|
448
448
|
|
|
449
|
-
_cell_length_a ${
|
|
450
|
-
_cell_length_b ${a.toFixed(
|
|
451
|
-
_cell_length_c ${
|
|
452
|
-
_cell_angle_alpha ${
|
|
453
|
-
_cell_angle_beta ${
|
|
454
|
-
_cell_angle_gamma ${
|
|
449
|
+
_cell_length_a ${n.toFixed(t)}
|
|
450
|
+
_cell_length_b ${a.toFixed(t)}
|
|
451
|
+
_cell_length_c ${h.toFixed(t)}
|
|
452
|
+
_cell_angle_alpha ${l.toFixed(t)}
|
|
453
|
+
_cell_angle_beta ${p.toFixed(t)}
|
|
454
|
+
_cell_angle_gamma ${f.toFixed(t)}
|
|
455
455
|
|
|
456
456
|
loop_
|
|
457
457
|
_atom_site_label
|
|
@@ -460,70 +460,134 @@ function z(s, e = 6) {
|
|
|
460
460
|
_atom_site_fract_y
|
|
461
461
|
_atom_site_fract_z
|
|
462
462
|
`;
|
|
463
|
-
return s.sites.forEach((
|
|
464
|
-
const
|
|
465
|
-
|
|
463
|
+
return s.sites.forEach((u, g) => {
|
|
464
|
+
const c = s.species[u.speciesIndex], m = j(u.cart, s.lattice);
|
|
465
|
+
r += `${c}${g + 1} ${c} ${m[0].toFixed(t)} ${m[1].toFixed(
|
|
466
466
|
6
|
|
467
|
-
)} ${
|
|
467
|
+
)} ${m[2].toFixed(t)}
|
|
468
468
|
`;
|
|
469
|
-
}),
|
|
469
|
+
}), r;
|
|
470
|
+
}
|
|
471
|
+
function U(s) {
|
|
472
|
+
const t = E(s);
|
|
473
|
+
let e = 0, i = 0, o = 0, n = 0, a = 0, h = 0, l = [];
|
|
474
|
+
const p = [];
|
|
475
|
+
let f = !1, r = [], u = !1;
|
|
476
|
+
for (const _ of t) {
|
|
477
|
+
const d = _.trim();
|
|
478
|
+
if (d) {
|
|
479
|
+
if (d.startsWith("_cell_length_a")) e = parseFloat(d.split(/\s+/)[1]);
|
|
480
|
+
else if (d.startsWith("_cell_length_b"))
|
|
481
|
+
i = parseFloat(d.split(/\s+/)[1]);
|
|
482
|
+
else if (d.startsWith("_cell_length_c"))
|
|
483
|
+
o = parseFloat(d.split(/\s+/)[1]);
|
|
484
|
+
else if (d.startsWith("_cell_angle_alpha"))
|
|
485
|
+
n = parseFloat(d.split(/\s+/)[1]);
|
|
486
|
+
else if (d.startsWith("_cell_angle_beta"))
|
|
487
|
+
a = parseFloat(d.split(/\s+/)[1]);
|
|
488
|
+
else if (d.startsWith("_cell_angle_gamma"))
|
|
489
|
+
h = parseFloat(d.split(/\s+/)[1]);
|
|
490
|
+
else if (d.startsWith("loop_")) {
|
|
491
|
+
f = !0, r = [], u = !1;
|
|
492
|
+
continue;
|
|
493
|
+
}
|
|
494
|
+
if (f && d.startsWith("_")) {
|
|
495
|
+
r.push(d), d.includes("_atom_site_") && (u = !0);
|
|
496
|
+
continue;
|
|
497
|
+
}
|
|
498
|
+
if (f && !d.startsWith("_")) {
|
|
499
|
+
u && (l.length === 0 && (l = [...r]), p.push(d.split(/\s+/)));
|
|
500
|
+
continue;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
if (l.length === 0)
|
|
505
|
+
throw new Error("No _atom_site loop found in CIF");
|
|
506
|
+
const g = P(e, i, o, n, a, h), c = [], m = [], w = l.findIndex((_) => _.includes("fract_x")), y = l.findIndex((_) => _.includes("fract_y")), b = l.findIndex((_) => _.includes("fract_z")), I = l.findIndex((_) => _.includes("type_symbol"));
|
|
507
|
+
if (w < 0 || y < 0 || b < 0 || I < 0)
|
|
508
|
+
throw new Error("CIF missing required _atom_site columns");
|
|
509
|
+
for (const _ of p) {
|
|
510
|
+
const d = [
|
|
511
|
+
parseFloat(_[w]),
|
|
512
|
+
parseFloat(_[y]),
|
|
513
|
+
parseFloat(_[b])
|
|
514
|
+
], $ = O(d, g);
|
|
515
|
+
let v = c.indexOf(_[I]);
|
|
516
|
+
v === -1 && (v = c.length, c.push(_[I])), m.push(new x(v, $));
|
|
517
|
+
}
|
|
518
|
+
return new S({ lattice: g, species: c, sites: m });
|
|
470
519
|
}
|
|
471
|
-
function
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
if (r < 0 || f < 0 || g < 0 || y < 0)
|
|
497
|
-
throw new Error("CIF missing required _atom_site columns");
|
|
498
|
-
for (; p < e.length && e[p].trim() && !e[p].trim().startsWith("_") && !e[p].trim().startsWith("loop_"); ) {
|
|
499
|
-
const _ = e[p].trim().split(/\s+/), S = [
|
|
500
|
-
parseFloat(_[r]),
|
|
501
|
-
parseFloat(_[f]),
|
|
502
|
-
parseFloat(_[g])
|
|
503
|
-
], I = L(
|
|
504
|
-
S,
|
|
505
|
-
T(t, n, o, i, a, c)
|
|
506
|
-
);
|
|
507
|
-
let b = h.indexOf(_[y]);
|
|
508
|
-
b === -1 && (b = h.length, h.push(_[y])), m.push(new x(b, I)), p++;
|
|
509
|
-
}
|
|
520
|
+
function N(s) {
|
|
521
|
+
let t = [];
|
|
522
|
+
const e = [];
|
|
523
|
+
for (let l = 0; l < s.length; l++) {
|
|
524
|
+
const p = s[l].trim();
|
|
525
|
+
if (!(!p || p.startsWith("&")) && /^CELL_PARAMETERS/i.test(p)) {
|
|
526
|
+
let f = 0, r = l + 1;
|
|
527
|
+
for (; f < 3 && r < s.length; ) {
|
|
528
|
+
const u = s[r].trim();
|
|
529
|
+
u !== "" && (t.push(u.split(/\s+/).map(Number)), f++), r++;
|
|
530
|
+
}
|
|
531
|
+
if (f < 3) throw new Error("Incomplete CELL_PARAMETERS block");
|
|
532
|
+
break;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
if (t.length !== 3)
|
|
536
|
+
throw new Error("CELL_PARAMETERS block not found or incomplete");
|
|
537
|
+
let i = !1, o = "angstrom";
|
|
538
|
+
for (let l = 0; l < s.length; l++) {
|
|
539
|
+
const p = s[l].trim();
|
|
540
|
+
if (!(!p || p.startsWith("&"))) {
|
|
541
|
+
if (/^ATOMIC_POSITIONS/i.test(p)) {
|
|
542
|
+
i = !0;
|
|
543
|
+
const f = p.match(/^ATOMIC_POSITIONS\s+(\w+)/i);
|
|
544
|
+
o = f ? f[1].toLowerCase() : "angstrom";
|
|
510
545
|
continue;
|
|
511
546
|
}
|
|
547
|
+
if (i) {
|
|
548
|
+
const f = p.split(/\s+/);
|
|
549
|
+
if (f.length < 4 || !/^[A-Za-z]/.test(f[0]) || f.slice(1, 4).some((r) => Number.isNaN(Number(r))))
|
|
550
|
+
break;
|
|
551
|
+
e.push(p);
|
|
552
|
+
}
|
|
512
553
|
}
|
|
513
|
-
p++;
|
|
514
554
|
}
|
|
515
|
-
|
|
516
|
-
|
|
555
|
+
if (e.length === 0)
|
|
556
|
+
throw new Error("ATOMIC_POSITIONS block not found");
|
|
557
|
+
const n = o === "crystal", a = [];
|
|
558
|
+
for (const l of e) {
|
|
559
|
+
const p = l.split(/\s+/)[0];
|
|
560
|
+
a.includes(p) || a.push(p);
|
|
561
|
+
}
|
|
562
|
+
const h = [];
|
|
563
|
+
for (const l of e) {
|
|
564
|
+
const p = l.split(/\s+/), f = p[0], r = p.slice(1, 4).map(Number);
|
|
565
|
+
let u;
|
|
566
|
+
n ? u = [
|
|
567
|
+
r[0] * t[0][0] + r[1] * t[1][0] + r[2] * t[2][0],
|
|
568
|
+
r[0] * t[0][1] + r[1] * t[1][1] + r[2] * t[2][1],
|
|
569
|
+
r[0] * t[0][2] + r[1] * t[1][2] + r[2] * t[2][2]
|
|
570
|
+
] : u = r, h.push(new x(a.indexOf(f), u));
|
|
571
|
+
}
|
|
572
|
+
return {
|
|
573
|
+
structure: new S({ lattice: t, species: a, sites: h }),
|
|
574
|
+
linesConsumed: s.length
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
function Y(s) {
|
|
578
|
+
const t = E(s);
|
|
579
|
+
return N(t).structure;
|
|
517
580
|
}
|
|
518
581
|
export {
|
|
519
|
-
|
|
582
|
+
S as CrystalStructure,
|
|
520
583
|
x as Site,
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
584
|
+
U as cifToStructure,
|
|
585
|
+
W as poscarToStructure,
|
|
586
|
+
Y as pwToStructure,
|
|
587
|
+
V as structureToCif,
|
|
588
|
+
D as structureToPoscar,
|
|
589
|
+
k as structureToXsf,
|
|
590
|
+
z as structureToXyz,
|
|
591
|
+
X as xsfToStructure,
|
|
592
|
+
Z as xyzToStructure
|
|
529
593
|
};
|