matsci-parse 0.0.3 → 0.1.1

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 (2) hide show
  1. package/dist/main.js +396 -232
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -1,319 +1,457 @@
1
- class y {
2
- constructor(e, s, i = {}) {
3
- this.speciesIndex = e, this.cart = s, this.props = i;
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, s) {
9
- this.props[e] = s;
8
+ setProp(e, t) {
9
+ this.props[e] = t;
10
10
  }
11
11
  }
12
- function A(t) {
13
- return t.sites.some((e) => Array.isArray(e.props.selectiveDynamics));
12
+ function C(s) {
13
+ return s.sites.some((e) => Array.isArray(e.props.selectiveDynamics));
14
14
  }
15
- class S {
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 T(s, e, t, n, o, i) {
24
+ const a = E(n), c = E(o), h = E(i), m = [s, 0, 0], p = [
25
+ e * Math.cos(h),
26
+ e * Math.sin(h),
27
+ 0
28
+ ], u = t * Math.cos(c), l = t * (Math.cos(a) - Math.cos(c) * Math.cos(h)) / Math.sin(h), d = Math.sqrt(t * t - u * u - l * l);
29
+ return [m, p, [u, l, d]];
30
+ }
31
+ function L(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: s,
19
- sites: i
52
+ species: t,
53
+ sites: n
20
54
  }) {
21
- this.lattice = this._validateLattice(e), this.species = this._validateSpecies(s), this.sites = this._validateSites(i);
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
- addSite(e, s) {
40
- this._validateSpeciesIndex(e), this.sites.push(new y(e, s));
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.splice(e, 1);
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 a = $(
173
+ t,
174
+ i.cart
175
+ );
176
+ return new x(i.speciesIndex, a, 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((s) => {
50
- if (!Array.isArray(s) || s.length !== 3)
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((s) => {
57
- if (typeof s != "string")
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((s) => {
64
- if (s instanceof y) return s;
65
- if (typeof s == "object" && typeof s.speciesIndex == "number" && Array.isArray(s.cart) && s.cart.length === 3)
66
- return this._validateSpeciesIndex(s.speciesIndex), new y(
67
- s.speciesIndex,
68
- s.cart,
69
- s.props ?? {}
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 I(t) {
82
- return t.split(/\r?\n/).map((e) => e.trim()).filter(Boolean);
236
+ function F(s) {
237
+ return s.split(/\r?\n/).map((e) => e.trim()).filter(Boolean);
83
238
  }
84
- function D(t) {
85
- const e = [], s = A(t);
86
- e.push("Generated by matsci-parse"), e.push("1.0"), t.lattice.forEach((n) => {
87
- e.push(n.map((c) => c.toFixed(10)).join(" "));
239
+ function P(s, e = 6) {
240
+ const t = [], n = C(s);
241
+ t.push("Generated by matsci-parse"), t.push("1.0"), s.lattice.forEach((a) => {
242
+ t.push(a.map((c) => c.toFixed(e)).join(" "));
88
243
  });
89
- const i = Array.from(
90
- new Set(t.sites.map((n) => t.species[n.speciesIndex]))
91
- ), o = i.map(
92
- (n) => t.sites.filter((c) => t.species[c.speciesIndex] === n).length
244
+ const o = Array.from(
245
+ new Set(s.sites.map((a) => s.species[a.speciesIndex]))
246
+ ), i = o.map(
247
+ (a) => s.sites.filter((c) => s.species[c.speciesIndex] === a).length
93
248
  );
94
- return e.push(i.join(" ")), e.push(o.join(" ")), s && e.push("Selective dynamics"), e.push("Cartesian"), i.forEach((n) => {
95
- t.sites.filter((c) => t.species[c.speciesIndex] === n).forEach((c) => {
96
- const l = c.cart.map((u) => u.toFixed(10)).join(" ");
97
- if (s) {
98
- const m = (Array.isArray(c.props?.selectiveDynamics) ? c.props.selectiveDynamics : [!0, !0, !0]).map((p) => p ? "T" : "F").join(" ");
99
- e.push(`${l} ${m}`);
249
+ return t.push(o.join(" ")), t.push(i.join(" ")), n && t.push("Selective dynamics"), t.push("Cartesian"), o.forEach((a) => {
250
+ s.sites.filter((c) => s.species[c.speciesIndex] === a).forEach((c) => {
251
+ const h = c.cart.map((m) => m.toFixed(e)).join(" ");
252
+ if (n) {
253
+ const p = (Array.isArray(c.props?.selectiveDynamics) ? c.props.selectiveDynamics : [!0, !0, !0]).map((u) => u ? "T" : "F").join(" ");
254
+ t.push(`${h} ${p}`);
100
255
  } else
101
- e.push(l);
256
+ t.push(h);
102
257
  });
103
- }), e.join(`
258
+ }), t.join(`
104
259
  `);
105
260
  }
106
- function T(t) {
261
+ function j(s) {
107
262
  let e = 0;
108
263
  e++;
109
- const s = parseFloat(t[e++]), i = [];
110
- for (let h = 0; h < 3; h++)
111
- i.push(
112
- t[e++].split(/\s+/).map((f) => parseFloat(f) * s)
264
+ const t = parseFloat(s[e++]), n = [];
265
+ for (let u = 0; u < 3; u++)
266
+ n.push(
267
+ s[e++].split(/\s+/).map((l) => parseFloat(l) * t)
113
268
  );
114
- let o = t[e].trim(), n;
115
- /^[A-Za-z]/.test(o) && (n = o.split(/\s+/), e++);
116
- const c = t[e++].split(/\s+/).map(Number);
117
- n || (n = c.map((h, f) => `X${f + 1}`));
118
- let l = !1;
119
- t[e]?.toLowerCase().startsWith("s") && (l = !0, e++);
120
- const m = t[e++].toLowerCase().startsWith("d"), p = [];
121
- return n.forEach((h, f) => {
122
- for (let _ = 0; _ < c[f]; _++) {
123
- const r = t[e++].split(/\s+/).map(Number);
124
- let d;
125
- m ? d = [
126
- r[0] * i[0][0] + r[1] * i[1][0] + r[2] * i[2][0],
127
- r[0] * i[0][1] + r[1] * i[1][1] + r[2] * i[2][1],
128
- r[0] * i[0][2] + r[1] * i[1][2] + r[2] * i[2][2]
129
- ] : d = r.slice(0, 3);
269
+ let o = s[e].trim(), i;
270
+ /^[A-Za-z]/.test(o) && (i = o.split(/\s+/), e++);
271
+ const a = s[e++].split(/\s+/).map(Number);
272
+ i || (i = a.map((u, l) => `X${l + 1}`));
273
+ let c = !1;
274
+ s[e]?.toLowerCase().startsWith("s") && (c = !0, e++);
275
+ const m = s[e++].toLowerCase().startsWith("d"), p = [];
276
+ return i.forEach((u, l) => {
277
+ for (let d = 0; d < a[l]; d++) {
278
+ const r = s[e++].split(/\s+/).map(Number);
279
+ let f;
280
+ m ? f = [
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
+ ] : f = r.slice(0, 3);
130
285
  const g = {};
131
- if (l) {
132
- const x = r.slice(3, 6).map((a) => a === 1);
133
- x.length === 3 && (g.selectiveDynamics = x);
286
+ if (c) {
287
+ const y = r.slice(3, 6).map((_) => _ === 1);
288
+ y.length === 3 && (g.selectiveDynamics = y);
134
289
  }
135
- p.push(new y(f, d, g));
290
+ p.push(new x(l, f, g));
136
291
  }
137
292
  }), {
138
- structure: new S({ lattice: i, species: n, sites: p }),
293
+ structure: new w({ lattice: n, species: i, sites: p }),
139
294
  linesConsumed: e
140
295
  };
141
296
  }
142
- function P(t) {
143
- const e = I(t);
144
- return T(e).structure;
297
+ function R(s) {
298
+ const e = F(s);
299
+ return j(e).structure;
145
300
  }
146
- function R(t) {
147
- const e = [];
148
- return e.push("CRYSTAL"), e.push("PRIMVEC"), t.lattice.forEach((s) => {
149
- e.push(s.map((i) => i.toFixed(10)).join(" "));
150
- }), e.push("PRIMCOORD"), e.push(`${t.numSites} 1`), t.sites.forEach((s) => {
151
- const i = t.species[s.speciesIndex];
152
- e.push(`${i} ${s.cart.map((o) => o.toFixed(10)).join(" ")}`);
153
- }), e.join(`
301
+ function W(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(t) {
157
- const e = I(t), s = [], i = [], o = [];
158
- let n = 0;
159
- for (; n < e.length && e[n].toUpperCase() !== "PRIMVEC"; ) n++;
160
- if (n === e.length) throw new Error("PRIMVEC block not found in XSF");
161
- n++;
162
- for (let l = 0; l < 3; l++)
163
- s.push(e[n++].split(/\s+/).map(Number));
164
- for (; n < e.length && e[n].toUpperCase() !== "PRIMCOORD"; ) n++;
165
- if (n === e.length) throw new Error("PRIMCOORD block not found in XSF");
166
- n++;
167
- const [c] = e[n++].split(/\s+/).map(Number);
168
- for (let l = 0; l < c; l++) {
169
- const u = e[n++].split(/\s+/), m = u[0], p = u.slice(1, 4).map(Number);
170
- let h = i.indexOf(m);
171
- h === -1 && (i.push(m), h = i.length - 1), o.push(new y(h, p));
313
+ function O(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++;
319
+ for (let c = 0; c < 3; c++)
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 [a] = e[i++].split(/\s+/).map(Number);
325
+ for (let c = 0; c < a; c++) {
326
+ const h = e[i++].split(/\s+/), m = h[0], p = h.slice(1, 4).map(Number);
327
+ let u = n.indexOf(m);
328
+ u === -1 && (n.push(m), u = n.length - 1), o.push(new x(u, p));
172
329
  }
173
- return new S({ lattice: s, species: i, sites: o });
330
+ return new w({ lattice: t, species: n, sites: o });
174
331
  }
175
- function O(t) {
176
- const e = [], s = t.sites.length;
177
- e.push(String(s));
178
- const i = A(t), o = t.lattice, n = [
179
- o[0][0],
180
- o[1][0],
181
- o[2][0],
182
- o[0][1],
183
- o[1][1],
184
- o[2][1],
185
- o[0][2],
186
- o[1][2],
187
- o[2][2]
332
+ function X(s, e = 6) {
333
+ const t = [], n = s.sites.length;
334
+ t.push(String(n));
335
+ const o = C(s), i = s.lattice, a = [
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]
188
345
  ].join(" "), c = [
189
346
  "species:S:1",
190
347
  "pos:R:3",
191
- i ? "selectiveDynamics:L:3" : null
348
+ o ? "selectiveDynamics:L:3" : null
192
349
  ].filter(Boolean).join(":");
193
- e.push(`Lattice="${n}" Properties=${c}`);
194
- for (const l of t.sites) {
195
- const u = t.species[l.speciesIndex], [m, p, h] = l.cart;
196
- let f = `${u} ${m.toFixed(10)} ${p.toFixed(10)} ${h.toFixed(10)}`;
197
- if (i) {
198
- const _ = Array.isArray(l.props?.selectiveDynamics) ? l.props.selectiveDynamics : [!0, !0, !0];
199
- f += " " + _.map((r) => r ? "T" : "F").join(" ");
350
+ t.push(`Lattice="${a}" Properties=${c}`);
351
+ for (const h of s.sites) {
352
+ const m = s.species[h.speciesIndex], [p, u, l] = h.cart;
353
+ let d = `${m} ${p.toFixed(e)} ${u.toFixed(e)} ${l.toFixed(e)}`;
354
+ if (o) {
355
+ const r = Array.isArray(h.props?.selectiveDynamics) ? h.props.selectiveDynamics : [!0, !0, !0];
356
+ d += " " + r.map((f) => f ? "T" : "F").join(" ");
200
357
  }
201
- e.push(f);
358
+ t.push(d);
202
359
  }
203
- return e.join(`
360
+ return t.join(`
204
361
  `);
205
362
  }
206
- function X(t) {
207
- const e = I(t);
208
- let s = 0;
209
- const i = parseInt(e[s++], 10);
210
- if (!Number.isFinite(i))
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[s++], n = {}, c = /(\w+)=(".*?"|\S+)/g;
213
- for (const r of o.matchAll(c)) {
214
- let d = r[2];
215
- d.startsWith('"') && (d = d.slice(1, -1)), n[r[1]] = d;
369
+ const o = e[t++], i = {}, a = /(\w+)=(".*?"|\S+)/g;
370
+ for (const r of o.matchAll(a)) {
371
+ let f = r[2];
372
+ f.startsWith('"') && (f = f.slice(1, -1)), i[r[1]] = f;
216
373
  }
217
- let l;
218
- if (n.Lattice) {
219
- const r = n.Lattice.split(/\s+/).map(Number);
374
+ let c;
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
- l = [
378
+ c = [
222
379
  [r[0], r[3], r[6]],
223
380
  [r[1], r[4], r[7]],
224
381
  [r[2], r[5], r[8]]
225
382
  ];
226
383
  } else
227
384
  throw new Error("Lattice must be present in extended XYZ format");
228
- let u = 0, m = 1, p = null;
229
- if (n.Properties) {
230
- const r = n.Properties.split(":");
231
- let d = 0;
385
+ let h = 0, m = 1, p = null;
386
+ if (i.Properties) {
387
+ const r = i.Properties.split(":");
388
+ let f = 0;
232
389
  for (let g = 0; g < r.length; g += 3) {
233
- const x = r[g], a = parseInt(r[g + 2], 10);
234
- x === "species" && (u = d), x === "pos" && (m = d), x === "selectiveDynamics" && (p = d), d += a;
390
+ const y = r[g], _ = parseInt(r[g + 2], 10);
391
+ y === "species" && (h = f), y === "pos" && (m = f), y === "selectiveDynamics" && (p = f), f += _;
235
392
  }
236
393
  }
237
- const h = [], f = /* @__PURE__ */ new Map(), _ = [];
238
- for (let r = 0; r < i; r++) {
239
- const d = e[s++].split(/\s+/), g = d[u];
240
- f.has(g) || (f.set(g, h.length), h.push(g));
241
- const x = f.get(g), a = d.slice(m, m + 3).map(Number), b = {};
394
+ const u = [], l = /* @__PURE__ */ new Map(), d = [];
395
+ for (let r = 0; r < n; r++) {
396
+ const f = e[t++].split(/\s+/), g = f[h];
397
+ l.has(g) || (l.set(g, u.length), u.push(g));
398
+ const y = l.get(g), _ = f.slice(m, m + 3).map(Number), S = {};
242
399
  if (p !== null) {
243
- const v = d.slice(p, p + 3).map((w) => w.toUpperCase() === "T");
244
- v.length === 3 && (b.selectiveDynamics = v);
400
+ const I = f.slice(p, p + 3).map((b) => b.toUpperCase() === "T");
401
+ I.length === 3 && (S.selectiveDynamics = I);
245
402
  }
246
- _.push(new y(x, a, b));
403
+ d.push(new x(y, _, S));
247
404
  }
248
- return new S({ lattice: l, species: h, sites: _ });
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: c, species: u, sites: d });
268
406
  }
269
- function F(t, e) {
270
- return t[0] * e[0] + t[1] * e[1] + t[2] * e[2];
407
+ function v(s, e) {
408
+ return s[0] * e[0] + s[1] * e[1] + s[2] * e[2];
271
409
  }
272
- function M(t) {
273
- return Math.sqrt(F(t, t));
410
+ function A(s) {
411
+ return Math.sqrt(v(s, s));
274
412
  }
275
- function $(t) {
276
- return t * 180 / Math.PI;
413
+ function M(s) {
414
+ return s * 180 / Math.PI;
277
415
  }
278
- function L(t, e) {
279
- const [s, i, o] = e, n = s[0] * (i[1] * o[2] - i[2] * o[1]) - s[1] * (i[0] * o[2] - i[2] * o[0]) + s[2] * (i[0] * o[1] - i[1] * o[0]);
280
- if (Math.abs(n) < 1e-12)
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
- const c = [
420
+ const a = [
283
421
  [
284
- (i[1] * o[2] - i[2] * o[1]) / n,
285
- (s[2] * o[1] - s[1] * o[2]) / n,
286
- (s[1] * i[2] - s[2] * i[1]) / n
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
- (i[2] * o[0] - i[0] * o[2]) / n,
290
- (s[0] * o[2] - s[2] * o[0]) / n,
291
- (s[2] * i[0] - s[0] * i[2]) / n
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
- (i[0] * o[1] - i[1] * o[0]) / n,
295
- (s[1] * o[0] - s[0] * o[1]) / n,
296
- (s[0] * i[1] - s[1] * i[0]) / n
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
- t[0] * c[0][0] + t[1] * c[1][0] + t[2] * c[2][0],
301
- t[0] * c[0][1] + t[1] * c[1][1] + t[2] * c[2][1],
302
- t[0] * c[0][2] + t[1] * c[1][2] + t[2] * c[2][2]
438
+ s[0] * a[0][0] + s[1] * a[1][0] + s[2] * a[2][0],
439
+ s[0] * a[0][1] + s[1] * a[1][1] + s[2] * a[2][1],
440
+ s[0] * a[0][2] + s[1] * a[1][2] + s[2] * a[2][2]
303
441
  ];
304
442
  }
305
- function N(t) {
306
- const [e, s, i] = t.lattice, o = M(e), n = M(s), c = M(i), l = $(Math.acos(F(s, i) / (n * c))), u = $(Math.acos(F(e, i) / (o * c))), m = $(Math.acos(F(e, s) / (o * n)));
307
- let p = `data_made_with_matsci-parse
443
+ function z(s, e = 6) {
444
+ const [t, n, o] = s.lattice, i = A(t), a = A(n), c = A(o), h = M(Math.acos(v(n, o) / (a * c))), m = M(Math.acos(v(t, o) / (i * c))), p = M(Math.acos(v(t, n) / (i * a)));
445
+ let u = `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 ${o.toFixed(6)}
312
- _cell_length_b ${n.toFixed(6)}
313
- _cell_length_c ${c.toFixed(6)}
314
- _cell_angle_alpha ${l.toFixed(6)}
315
- _cell_angle_beta ${u.toFixed(6)}
316
- _cell_angle_gamma ${m.toFixed(6)}
449
+ _cell_length_a ${i.toFixed(e)}
450
+ _cell_length_b ${a.toFixed(e)}
451
+ _cell_length_c ${c.toFixed(e)}
452
+ _cell_angle_alpha ${h.toFixed(e)}
453
+ _cell_angle_beta ${m.toFixed(e)}
454
+ _cell_angle_gamma ${p.toFixed(e)}
317
455
 
318
456
  loop_
319
457
  _atom_site_label
@@ -322,44 +460,70 @@ function N(t) {
322
460
  _atom_site_fract_y
323
461
  _atom_site_fract_z
324
462
  `;
325
- return t.sites.forEach((h, f) => {
326
- const _ = t.species[h.speciesIndex], r = L(h.cart, t.lattice);
327
- p += `${_}${f + 1} ${_} ${r[0].toFixed(6)} ${r[1].toFixed(
463
+ return s.sites.forEach((l, d) => {
464
+ const r = s.species[l.speciesIndex], f = D(l.cart, s.lattice);
465
+ u += `${r}${d + 1} ${r} ${f[0].toFixed(e)} ${f[1].toFixed(
328
466
  6
329
- )} ${r[2].toFixed(6)}
467
+ )} ${f[2].toFixed(e)}
330
468
  `;
331
- }), p;
469
+ }), u;
332
470
  }
333
- function z(t) {
334
- const e = I(t);
335
- let s = 0, i = 0, o = 0, n = 0, c = 0, l = 0;
336
- const u = [];
337
- let m = !1, p = [];
338
- for (const a of e)
339
- a.startsWith("_cell_length_a") ? s = parseFloat(a.split(/\s+/)[1]) : a.startsWith("_cell_length_b") ? i = parseFloat(a.split(/\s+/)[1]) : a.startsWith("_cell_length_c") ? o = parseFloat(a.split(/\s+/)[1]) : a.startsWith("_cell_angle_alpha") ? n = 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_") ? (m = !0, p = []) : m && a.startsWith("_") ? p.push(a) : m && a && !a.startsWith("_") && u.push(a.split(/\s+/));
340
- const h = C(s, i, o, n, c, l), f = [], _ = [], r = p.findIndex((a) => a.includes("fract_x")), d = p.findIndex((a) => a.includes("fract_y")), g = p.findIndex((a) => a.includes("fract_z")), x = p.findIndex((a) => a.includes("type_symbol"));
341
- if (r < 0 || d < 0 || g < 0 || x < 0)
342
- throw new Error("CIF missing required _atom_site columns");
343
- for (const a of u) {
344
- const b = [
345
- parseFloat(a[r]),
346
- parseFloat(a[d]),
347
- parseFloat(a[g])
348
- ], v = j(b, h);
349
- let w = f.indexOf(a[x]);
350
- w === -1 && (w = f.length, f.push(a[x])), _.push(new y(w, v));
471
+ function V(s) {
472
+ const e = F(s);
473
+ let t = 0, n = 0, o = 0, i = 0, a = 0, c = 0;
474
+ const h = [], m = [];
475
+ let p = 0;
476
+ for (; p < e.length; ) {
477
+ const l = e[p].trim();
478
+ if (l.startsWith("_cell_length_a")) t = parseFloat(l.split(/\s+/)[1]);
479
+ else if (l.startsWith("_cell_length_b"))
480
+ n = parseFloat(l.split(/\s+/)[1]);
481
+ else if (l.startsWith("_cell_length_c"))
482
+ o = parseFloat(l.split(/\s+/)[1]);
483
+ else if (l.startsWith("_cell_angle_alpha"))
484
+ i = parseFloat(l.split(/\s+/)[1]);
485
+ else if (l.startsWith("_cell_angle_beta"))
486
+ a = parseFloat(l.split(/\s+/)[1]);
487
+ else if (l.startsWith("_cell_angle_gamma"))
488
+ c = parseFloat(l.split(/\s+/)[1]);
489
+ else if (l.startsWith("loop_")) {
490
+ p++;
491
+ const d = [];
492
+ for (; p < e.length && e[p].trim().startsWith("_"); )
493
+ d.push(e[p].trim()), p++;
494
+ if (d.some((r) => r.includes("_atom_site_"))) {
495
+ const r = d.findIndex((_) => _.includes("fract_x")), f = d.findIndex((_) => _.includes("fract_y")), g = d.findIndex((_) => _.includes("fract_z")), y = d.findIndex((_) => _.includes("type_symbol"));
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
+ }
510
+ continue;
511
+ }
512
+ }
513
+ p++;
351
514
  }
352
- return new S({ lattice: h, species: f, sites: _ });
515
+ const u = T(t, n, o, i, a, c);
516
+ return new w({ lattice: u, species: h, sites: m });
353
517
  }
354
518
  export {
355
- S as CrystalStructure,
356
- y as Site,
357
- z as cifToStructure,
358
- P as poscarToStructure,
359
- N as structureToCif,
360
- D as structureToPoscar,
361
- R as structureToXsf,
362
- O as structureToXyz,
363
- W as xsfToStructure,
364
- X as xyzToStructure
519
+ w as CrystalStructure,
520
+ x as Site,
521
+ V as cifToStructure,
522
+ R as poscarToStructure,
523
+ z as structureToCif,
524
+ P as structureToPoscar,
525
+ W as structureToXsf,
526
+ X as structureToXyz,
527
+ O as xsfToStructure,
528
+ N as xyzToStructure
365
529
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matsci-parse",
3
- "version": "0.0.3",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "main": "dist/main.js",
6
6
  "module": "dist/main.js",