@molcrafts/molrs 0.0.8 → 0.0.13

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/molrs_bg.js CHANGED
@@ -169,6 +169,83 @@ export class Block {
169
169
  }
170
170
  return takeFromExternrefTable0(ret[0]);
171
171
  }
172
+ /**
173
+ * Allocate a zero-filled float column at `key` with the given shape.
174
+ *
175
+ * Pair with [`viewColF`](Block::view_col_f) for zero-copy writes from JS:
176
+ *
177
+ * ```js
178
+ * block.createColF("x", [N]); // allocate
179
+ * const view = block.viewColF("x"); // zero-copy view into the column
180
+ * for (let i = 0; i < N; i++) view[i] = src[i]; // direct write
181
+ * ```
182
+ *
183
+ * # Arguments
184
+ *
185
+ * * `key` - Column name
186
+ * * `shape` - Shape of the column (e.g. `[N]` for 1D, `[N, 3]` for Nx3)
187
+ *
188
+ * # Errors
189
+ *
190
+ * Throws if the shape is empty, or if the leading dimension conflicts
191
+ * with existing columns in this block.
192
+ * @param {string} key
193
+ * @param {Uint32Array} shape
194
+ */
195
+ createColF(key, shape) {
196
+ const ptr0 = passStringToWasm0(key, wasm.__wbindgen_malloc_command_export, wasm.__wbindgen_realloc_command_export);
197
+ const len0 = WASM_VECTOR_LEN;
198
+ const ptr1 = passArray32ToWasm0(shape, wasm.__wbindgen_malloc_command_export);
199
+ const len1 = WASM_VECTOR_LEN;
200
+ const ret = wasm.block_createColF(this.__wbg_ptr, ptr0, len0, ptr1, len1);
201
+ if (ret[1]) {
202
+ throw takeFromExternrefTable0(ret[0]);
203
+ }
204
+ }
205
+ /**
206
+ * Allocate a zero-filled i32 column at `key` with the given shape.
207
+ *
208
+ * See [`createColF`](Block::create_col_f) for the zero-copy write pattern.
209
+ *
210
+ * # Errors
211
+ *
212
+ * Throws if the shape is empty, or if the leading dimension conflicts
213
+ * with existing columns.
214
+ * @param {string} key
215
+ * @param {Uint32Array} shape
216
+ */
217
+ createColI32(key, shape) {
218
+ const ptr0 = passStringToWasm0(key, wasm.__wbindgen_malloc_command_export, wasm.__wbindgen_realloc_command_export);
219
+ const len0 = WASM_VECTOR_LEN;
220
+ const ptr1 = passArray32ToWasm0(shape, wasm.__wbindgen_malloc_command_export);
221
+ const len1 = WASM_VECTOR_LEN;
222
+ const ret = wasm.block_createColI32(this.__wbg_ptr, ptr0, len0, ptr1, len1);
223
+ if (ret[1]) {
224
+ throw takeFromExternrefTable0(ret[0]);
225
+ }
226
+ }
227
+ /**
228
+ * Allocate a zero-filled u32 column at `key` with the given shape.
229
+ *
230
+ * See [`createColF`](Block::create_col_f) for the zero-copy write pattern.
231
+ *
232
+ * # Errors
233
+ *
234
+ * Throws if the shape is empty, or if the leading dimension conflicts
235
+ * with existing columns.
236
+ * @param {string} key
237
+ * @param {Uint32Array} shape
238
+ */
239
+ createColU32(key, shape) {
240
+ const ptr0 = passStringToWasm0(key, wasm.__wbindgen_malloc_command_export, wasm.__wbindgen_realloc_command_export);
241
+ const len0 = WASM_VECTOR_LEN;
242
+ const ptr1 = passArray32ToWasm0(shape, wasm.__wbindgen_malloc_command_export);
243
+ const len1 = WASM_VECTOR_LEN;
244
+ const ret = wasm.block_createColU32(this.__wbg_ptr, ptr0, len0, ptr1, len1);
245
+ if (ret[1]) {
246
+ throw takeFromExternrefTable0(ret[0]);
247
+ }
248
+ }
172
249
  /**
173
250
  * Return the data type string for a column.
174
251
  *
@@ -1651,6 +1728,38 @@ export class Frame {
1651
1728
  }
1652
1729
  return ret[0] === 0 ? undefined : Grid.__wrap(ret[0]);
1653
1730
  }
1731
+ /**
1732
+ * Read a per-frame metadata value as a numeric scalar.
1733
+ *
1734
+ * Returns `Some(v)` if the meta key exists AND its string value parses
1735
+ * as an `f64`. Returns `None` if the key is missing or the value is
1736
+ * non-numeric (e.g., `config="trans"`).
1737
+ *
1738
+ * `frame.meta` is a `HashMap<String, String>`; the ExtXYZ parser stores
1739
+ * all comment-line values as strings. This accessor reads numeric ones
1740
+ * via `str::parse::<f64>`.
1741
+ *
1742
+ * # Arguments
1743
+ *
1744
+ * * `name` — Meta key to look up (e.g., `"energy"`, `"temp"`).
1745
+ *
1746
+ * # Example (JavaScript)
1747
+ *
1748
+ * ```js
1749
+ * const energy = frame.getMetaScalar("energy");
1750
+ * if (energy !== undefined) {
1751
+ * console.log("Energy:", energy);
1752
+ * }
1753
+ * ```
1754
+ * @param {string} name
1755
+ * @returns {number | undefined}
1756
+ */
1757
+ getMetaScalar(name) {
1758
+ const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc_command_export, wasm.__wbindgen_realloc_command_export);
1759
+ const len0 = WASM_VECTOR_LEN;
1760
+ const ret = wasm.frame_getMetaScalar(this.__wbg_ptr, ptr0, len0);
1761
+ return ret[0] === 0 ? undefined : ret[1];
1762
+ }
1654
1763
  /**
1655
1764
  * Return the names of all grids attached to this frame.
1656
1765
  *
@@ -1766,6 +1875,26 @@ export class Frame {
1766
1875
  throw takeFromExternrefTable0(ret[0]);
1767
1876
  }
1768
1877
  }
1878
+ /**
1879
+ * Return the names of all metadata keys on this frame.
1880
+ *
1881
+ * Includes all keys regardless of whether their values are numeric
1882
+ * or categorical. To filter to numeric keys, iterate and call
1883
+ * [`getMetaScalar`](Self::get_meta_scalar) on each.
1884
+ *
1885
+ * # Example (JavaScript)
1886
+ *
1887
+ * ```js
1888
+ * const names = frame.metaNames(); // e.g. ["energy", "config", "temp"]
1889
+ * ```
1890
+ * @returns {string[]}
1891
+ */
1892
+ metaNames() {
1893
+ const ret = wasm.frame_metaNames(this.__wbg_ptr);
1894
+ var v1 = getArrayJsValueFromWasm0(ret[0], ret[1]).slice();
1895
+ wasm.__wbindgen_free_command_export(ret[0], ret[1] * 4, 4);
1896
+ return v1;
1897
+ }
1769
1898
  /**
1770
1899
  * Create a new, empty `Frame` with no blocks and no simulation box.
1771
1900
  *
@@ -1912,6 +2041,44 @@ export class Frame {
1912
2041
  }
1913
2042
  return ret[0] !== 0;
1914
2043
  }
2044
+ /**
2045
+ * Set a per-frame metadata value.
2046
+ *
2047
+ * Stores `value` as the string backing for `name` on `frame.meta`.
2048
+ * Numeric values are read back via
2049
+ * [`getMetaScalar`](Self::get_meta_scalar) by parsing the string
2050
+ * form. `frame.meta` is the single source of truth for per-frame
2051
+ * scalars — no separate aggregation layer is needed on the JS side.
2052
+ *
2053
+ * # Arguments
2054
+ *
2055
+ * * `name` — Meta key (e.g., `"energy"`, `"temp"`).
2056
+ * * `value` — String value. For numeric labels, the caller is
2057
+ * responsible for converting (e.g., `num.toString()`).
2058
+ *
2059
+ * # Errors
2060
+ *
2061
+ * Throws a `JsValue` string if the frame has been dropped.
2062
+ *
2063
+ * # Example (JavaScript)
2064
+ *
2065
+ * ```js
2066
+ * frame.setMeta("energy", "-3.14");
2067
+ * frame.setMeta("note", "run-42");
2068
+ * ```
2069
+ * @param {string} name
2070
+ * @param {string} value
2071
+ */
2072
+ setMeta(name, value) {
2073
+ const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc_command_export, wasm.__wbindgen_realloc_command_export);
2074
+ const len0 = WASM_VECTOR_LEN;
2075
+ const ptr1 = passStringToWasm0(value, wasm.__wbindgen_malloc_command_export, wasm.__wbindgen_realloc_command_export);
2076
+ const len1 = WASM_VECTOR_LEN;
2077
+ const ret = wasm.frame_setMeta(this.__wbg_ptr, ptr0, len0, ptr1, len1);
2078
+ if (ret[1]) {
2079
+ throw takeFromExternrefTable0(ret[0]);
2080
+ }
2081
+ }
1915
2082
  /**
1916
2083
  * Attach or detach a simulation box.
1917
2084
  *
@@ -2288,6 +2455,10 @@ export class GyrationTensor {
2288
2455
  }
2289
2456
  /**
2290
2457
  * Compute gyration tensors. Returns a flat float typed array (9 values per cluster).
2458
+ *
2459
+ * Internally computes the cluster geometric centers (via
2460
+ * [`RsClusterCenters`]) since the new compute trait exposes them as a
2461
+ * required upstream — the old single-frame wasm API hides this detail.
2291
2462
  * @param {Frame} frame
2292
2463
  * @param {ClusterResult} cluster_result
2293
2464
  * @returns {Float64Array}
@@ -2328,6 +2499,10 @@ export class InertiaTensor {
2328
2499
  }
2329
2500
  /**
2330
2501
  * Compute inertia tensors. Returns a flat float typed array (9 values per cluster).
2502
+ *
2503
+ * Internally computes the cluster centers of mass (via
2504
+ * [`RsCenterOfMass`]) since the new compute trait consumes them as a
2505
+ * required upstream — the old single-frame wasm API hides this detail.
2331
2506
  * @param {Frame} frame
2332
2507
  * @param {ClusterResult} cluster_result
2333
2508
  * @returns {Float64Array}
@@ -2357,83 +2532,6 @@ export class InertiaTensor {
2357
2532
  }
2358
2533
  if (Symbol.dispose) InertiaTensor.prototype[Symbol.dispose] = InertiaTensor.prototype.free;
2359
2534
 
2360
- /**
2361
- * LAMMPS dump trajectory file reader.
2362
- *
2363
- * Reads multi-frame LAMMPS dump files (the format produced by the
2364
- * `dump` command). Each frame produces a [`Frame`] containing an
2365
- * `"atoms"` block with columns matching the dump header (e.g.
2366
- * `id`, `type`, `x`, `y`, `z`, `vx`, `vy`, `vz`).
2367
- *
2368
- * # Example (JavaScript)
2369
- *
2370
- * ```js
2371
- * const reader = new LAMMPSDumpReader(dumpContent);
2372
- * console.log(reader.len()); // number of timesteps
2373
- * const frame = reader.read(0);
2374
- * const atoms = frame.getBlock("atoms");
2375
- * ```
2376
- */
2377
- export class LAMMPSDumpReader {
2378
- __destroy_into_raw() {
2379
- const ptr = this.__wbg_ptr;
2380
- this.__wbg_ptr = 0;
2381
- LAMMPSDumpReaderFinalization.unregister(this);
2382
- return ptr;
2383
- }
2384
- free() {
2385
- const ptr = this.__destroy_into_raw();
2386
- wasm.__wbg_lammpsdumpreader_free(ptr, 0);
2387
- }
2388
- /**
2389
- * Check whether the file contains no frames.
2390
- * @returns {boolean}
2391
- */
2392
- isEmpty() {
2393
- const ret = wasm.lammpsdumpreader_isEmpty(this.__wbg_ptr);
2394
- if (ret[2]) {
2395
- throw takeFromExternrefTable0(ret[1]);
2396
- }
2397
- return ret[0] !== 0;
2398
- }
2399
- /**
2400
- * Return the number of frames in the dump file.
2401
- * @returns {number}
2402
- */
2403
- len() {
2404
- const ret = wasm.lammpsdumpreader_len(this.__wbg_ptr);
2405
- if (ret[2]) {
2406
- throw takeFromExternrefTable0(ret[1]);
2407
- }
2408
- return ret[0] >>> 0;
2409
- }
2410
- /**
2411
- * Create a new LAMMPS dump reader from string content.
2412
- * @param {string} content
2413
- */
2414
- constructor(content) {
2415
- const ptr0 = passStringToWasm0(content, wasm.__wbindgen_malloc_command_export, wasm.__wbindgen_realloc_command_export);
2416
- const len0 = WASM_VECTOR_LEN;
2417
- const ret = wasm.lammpsdumpreader_new(ptr0, len0);
2418
- this.__wbg_ptr = ret >>> 0;
2419
- LAMMPSDumpReaderFinalization.register(this, this.__wbg_ptr, this);
2420
- return this;
2421
- }
2422
- /**
2423
- * Read a frame at the given step index.
2424
- * @param {number} step
2425
- * @returns {Frame | undefined}
2426
- */
2427
- read(step) {
2428
- const ret = wasm.lammpsdumpreader_read(this.__wbg_ptr, step);
2429
- if (ret[2]) {
2430
- throw takeFromExternrefTable0(ret[1]);
2431
- }
2432
- return ret[0] === 0 ? undefined : Frame.__wrap(ret[0]);
2433
- }
2434
- }
2435
- if (Symbol.dispose) LAMMPSDumpReader.prototype[Symbol.dispose] = LAMMPSDumpReader.prototype.free;
2436
-
2437
2535
  /**
2438
2536
  * LAMMPS data file reader.
2439
2537
  *
@@ -2556,6 +2654,83 @@ export class LAMMPSReader {
2556
2654
  }
2557
2655
  if (Symbol.dispose) LAMMPSReader.prototype[Symbol.dispose] = LAMMPSReader.prototype.free;
2558
2656
 
2657
+ /**
2658
+ * LAMMPS dump trajectory file reader.
2659
+ *
2660
+ * Reads multi-frame LAMMPS dump files (the format produced by the
2661
+ * `dump` command). Each frame produces a [`Frame`] containing an
2662
+ * `"atoms"` block with columns matching the dump header (e.g.
2663
+ * `id`, `type`, `x`, `y`, `z`, `vx`, `vy`, `vz`).
2664
+ *
2665
+ * # Example (JavaScript)
2666
+ *
2667
+ * ```js
2668
+ * const reader = new LAMMPSTrajReader(dumpContent);
2669
+ * console.log(reader.len()); // number of timesteps
2670
+ * const frame = reader.read(0);
2671
+ * const atoms = frame.getBlock("atoms");
2672
+ * ```
2673
+ */
2674
+ export class LAMMPSTrajReader {
2675
+ __destroy_into_raw() {
2676
+ const ptr = this.__wbg_ptr;
2677
+ this.__wbg_ptr = 0;
2678
+ LAMMPSTrajReaderFinalization.unregister(this);
2679
+ return ptr;
2680
+ }
2681
+ free() {
2682
+ const ptr = this.__destroy_into_raw();
2683
+ wasm.__wbg_lammpstrajreader_free(ptr, 0);
2684
+ }
2685
+ /**
2686
+ * Check whether the file contains no frames.
2687
+ * @returns {boolean}
2688
+ */
2689
+ isEmpty() {
2690
+ const ret = wasm.lammpstrajreader_isEmpty(this.__wbg_ptr);
2691
+ if (ret[2]) {
2692
+ throw takeFromExternrefTable0(ret[1]);
2693
+ }
2694
+ return ret[0] !== 0;
2695
+ }
2696
+ /**
2697
+ * Return the number of frames in the dump file.
2698
+ * @returns {number}
2699
+ */
2700
+ len() {
2701
+ const ret = wasm.lammpstrajreader_len(this.__wbg_ptr);
2702
+ if (ret[2]) {
2703
+ throw takeFromExternrefTable0(ret[1]);
2704
+ }
2705
+ return ret[0] >>> 0;
2706
+ }
2707
+ /**
2708
+ * Create a new LAMMPS dump reader from string content.
2709
+ * @param {string} content
2710
+ */
2711
+ constructor(content) {
2712
+ const ptr0 = passStringToWasm0(content, wasm.__wbindgen_malloc_command_export, wasm.__wbindgen_realloc_command_export);
2713
+ const len0 = WASM_VECTOR_LEN;
2714
+ const ret = wasm.lammpstrajreader_new(ptr0, len0);
2715
+ this.__wbg_ptr = ret >>> 0;
2716
+ LAMMPSTrajReaderFinalization.register(this, this.__wbg_ptr, this);
2717
+ return this;
2718
+ }
2719
+ /**
2720
+ * Read a frame at the given step index.
2721
+ * @param {number} step
2722
+ * @returns {Frame | undefined}
2723
+ */
2724
+ read(step) {
2725
+ const ret = wasm.lammpstrajreader_read(this.__wbg_ptr, step);
2726
+ if (ret[2]) {
2727
+ throw takeFromExternrefTable0(ret[1]);
2728
+ }
2729
+ return ret[0] === 0 ? undefined : Frame.__wrap(ret[0]);
2730
+ }
2731
+ }
2732
+ if (Symbol.dispose) LAMMPSTrajReader.prototype[Symbol.dispose] = LAMMPSTrajReader.prototype.free;
2733
+
2559
2734
  /**
2560
2735
  * Cell-list (linked-cell) based neighbor search.
2561
2736
  *
@@ -2734,25 +2909,23 @@ export class MSD {
2734
2909
  /**
2735
2910
  * Feed a frame into the MSD analysis.
2736
2911
  *
2737
- * The first frame sets the reference configuration.
2738
- * Subsequent frames compute MSD relative to that reference.
2912
+ * Internally clones the frame's core data so subsequent mutations on
2913
+ * the JS side (e.g. trajectory playback overwriting buffers) do not
2914
+ * race against pending [`results`](Self::results) calls. The first
2915
+ * frame sets the reference configuration.
2739
2916
  *
2740
2917
  * # Arguments
2741
2918
  *
2742
2919
  * * `frame` - Frame with `"atoms"` block containing
2743
2920
  * `x`, `y`, `z` (F) columns
2744
2921
  *
2745
- * # Errors
2746
- *
2747
- * Throws if the frame is missing required columns or has a
2748
- * different number of atoms than the reference.
2749
- *
2750
2922
  * # Example (JavaScript)
2751
2923
  *
2752
2924
  * ```js
2753
2925
  * const msd = new MSD();
2754
2926
  * msd.feed(frame0); // sets reference
2755
- * msd.feed(frame1); // computes MSD vs frame0
2927
+ * msd.feed(frame1); // added to trajectory
2928
+ * const series = msd.results();
2756
2929
  * ```
2757
2930
  * @param {Frame} frame
2758
2931
  */
@@ -2782,16 +2955,16 @@ export class MSD {
2782
2955
  return this;
2783
2956
  }
2784
2957
  /**
2785
- * Reset the analysis, clearing reference and all results.
2958
+ * Reset the analysis, clearing the trajectory buffer.
2786
2959
  */
2787
2960
  reset() {
2788
2961
  wasm.msd_reset(this.__wbg_ptr);
2789
2962
  }
2790
2963
  /**
2791
- * Return all accumulated MSD results as an array.
2964
+ * Run the stateless [`molrs_compute::MSD`] over every fed frame and
2965
+ * return the per-frame time series.
2792
2966
  *
2793
- * Returns one [`MSDResult`] per frame fed (including the
2794
- * reference frame, which has MSD = 0).
2967
+ * The first frame is always the reference, so `results()[0].mean ≈ 0`.
2795
2968
  *
2796
2969
  * # Example (JavaScript)
2797
2970
  *
@@ -2803,6 +2976,9 @@ export class MSD {
2803
2976
  */
2804
2977
  results() {
2805
2978
  const ret = wasm.msd_results(this.__wbg_ptr);
2979
+ if (ret[3]) {
2980
+ throw takeFromExternrefTable0(ret[2]);
2981
+ }
2806
2982
  var v1 = getArrayJsValueFromWasm0(ret[0], ret[1]).slice();
2807
2983
  wasm.__wbindgen_free_command_export(ret[0], ret[1] * 4, 4);
2808
2984
  return v1;
@@ -3168,15 +3344,16 @@ if (Symbol.dispose) PDBReader.prototype[Symbol.dispose] = PDBReader.prototype.fr
3168
3344
  /**
3169
3345
  * Radial distribution function g(r) analysis.
3170
3346
  *
3171
- * Computes the pair correlation function by binning neighbor-pair
3172
- * distances into a histogram and normalizing by the ideal-gas
3173
- * density (spherical shell volume normalization).
3347
+ * Bins neighbor-pair distances in `[rMin, rMax]` and normalizes by the
3348
+ * ideal-gas pair density. Defaults follow freud (`rMin = 0`). Periodic
3349
+ * systems take their normalization volume from `frame.simbox`; non-periodic
3350
+ * systems must supply it explicitly via [`computeWithVolume`].
3174
3351
  *
3175
3352
  * # Algorithm
3176
3353
  *
3177
3354
  * g(r) = n(r) / (rho * V_shell(r) * N_ref)
3178
3355
  *
3179
- * where `n(r)` is the pair count in bin `r`, `rho` is the number
3356
+ * where `n(r)` is the pair count in bin `r`, `rho = N/V` is the number
3180
3357
  * density, and `V_shell(r)` is the shell volume for that bin.
3181
3358
  *
3182
3359
  * # Example (JavaScript)
@@ -3185,11 +3362,14 @@ if (Symbol.dispose) PDBReader.prototype[Symbol.dispose] = PDBReader.prototype.fr
3185
3362
  * const lc = new LinkedCell(5.0);
3186
3363
  * const nlist = lc.build(frame);
3187
3364
  *
3188
- * const rdf = new RDF(100, 5.0);
3365
+ * const rdf = new RDF(100, 5.0); // rMin defaults to 0
3189
3366
  * const result = rdf.compute(frame, nlist);
3190
3367
  *
3191
- * const r = result.binCenters(); // Float32Array or Float64Array, bin centers in A
3192
- * const gr = result.rdf(); // Float32Array or Float64Array, g(r) values
3368
+ * // Non-periodic frame: supply the normalization volume.
3369
+ * const resultFree = rdf.computeWithVolume(nlist, volumeA3);
3370
+ *
3371
+ * const r = result.binCenters();
3372
+ * const gr = result.rdf();
3193
3373
  * ```
3194
3374
  */
3195
3375
  export class RDF {
@@ -3204,64 +3384,88 @@ export class RDF {
3204
3384
  wasm.__wbg_rdf_free(ptr, 0);
3205
3385
  }
3206
3386
  /**
3207
- * Compute the RDF from a pre-built neighbor list.
3208
- *
3209
- * The frame is needed to read the simulation box volume for
3210
- * normalization.
3387
+ * Compute g(r) using the simulation-box volume from `frame.simbox`.
3211
3388
  *
3212
3389
  * # Arguments
3213
3390
  *
3214
- * * `frame` - Frame with a `simbox` set (for volume normalization)
3391
+ * * `frame` - Frame with a `simbox` set (used only for volume)
3215
3392
  * * `neighbors` - Pre-built [`NeighborList`] from [`LinkedCell`]
3216
3393
  *
3217
- * # Returns
3394
+ * # Errors
3218
3395
  *
3219
- * An [`RDFResult`] containing bin centers, g(r) values, and raw
3220
- * pair counts.
3396
+ * Throws if the frame has no `simbox` use
3397
+ * [`computeWithVolume`](Self::compute_with_volume) for non-periodic frames.
3398
+ * @param {Frame} frame
3399
+ * @param {NeighborList} neighbors
3400
+ * @returns {RDFResult}
3401
+ */
3402
+ compute(frame, neighbors) {
3403
+ _assertClass(frame, Frame);
3404
+ _assertClass(neighbors, NeighborList);
3405
+ const ret = wasm.rdf_compute(this.__wbg_ptr, frame.__wbg_ptr, neighbors.__wbg_ptr);
3406
+ if (ret[2]) {
3407
+ throw takeFromExternrefTable0(ret[1]);
3408
+ }
3409
+ return RDFResult.__wrap(ret[0]);
3410
+ }
3411
+ /**
3412
+ * Compute g(r) using an explicit normalization volume (A^3).
3221
3413
  *
3222
- * # Errors
3414
+ * Use this for non-periodic systems or to override the box volume.
3415
+ * Internally wraps the supplied volume as a cubic SimBox since the
3416
+ * underlying [`molrs_compute::RDF`] pulls its normalization volume from
3417
+ * `frame.simbox`.
3223
3418
  *
3224
- * Throws if the frame cannot be cloned or the computation fails.
3419
+ * # Arguments
3420
+ *
3421
+ * * `neighbors` - Pre-built [`NeighborList`]
3422
+ * * `volume` - Normalization volume in A^3 (must be finite and > 0)
3225
3423
  *
3226
3424
  * # Example (JavaScript)
3227
3425
  *
3228
3426
  * ```js
3229
- * const result = rdf.compute(frame, nlist);
3230
- * const gr = result.rdf(); // Float32Array or Float64Array
3427
+ * const result = rdf.computeWithVolume(nlist, 1000.0);
3231
3428
  * ```
3232
- * @param {Frame} frame
3233
3429
  * @param {NeighborList} neighbors
3430
+ * @param {number} volume
3234
3431
  * @returns {RDFResult}
3235
3432
  */
3236
- compute(frame, neighbors) {
3237
- _assertClass(frame, Frame);
3433
+ computeWithVolume(neighbors, volume) {
3238
3434
  _assertClass(neighbors, NeighborList);
3239
- const ret = wasm.rdf_compute(this.__wbg_ptr, frame.__wbg_ptr, neighbors.__wbg_ptr);
3435
+ const ret = wasm.rdf_computeWithVolume(this.__wbg_ptr, neighbors.__wbg_ptr, volume);
3240
3436
  if (ret[2]) {
3241
3437
  throw takeFromExternrefTable0(ret[1]);
3242
3438
  }
3243
3439
  return RDFResult.__wrap(ret[0]);
3244
3440
  }
3245
3441
  /**
3246
- * Create a new RDF analysis with specified binning.
3442
+ * Create a new RDF analysis.
3247
3443
  *
3248
3444
  * # Arguments
3249
3445
  *
3250
3446
  * * `n_bins` - Number of histogram bins
3251
- * * `r_max` - Maximum radial distance in angstrom (A). Should
3252
- * match or be less than the neighbor-search cutoff.
3447
+ * * `r_max` - Upper radial cutoff in angstrom (A). Should be ≤ the
3448
+ * neighbor-search cutoff.
3449
+ * * `r_min` - Lower radial cutoff in angstrom (A). Optional, defaults
3450
+ * to 0 (freud convention). Pairs with `d < rMin` or `d == 0` are
3451
+ * excluded from the histogram.
3253
3452
  *
3254
3453
  * # Example (JavaScript)
3255
3454
  *
3256
3455
  * ```js
3257
- * const rdf = new RDF(100, 5.0); // 100 bins up to 5 A
3456
+ * const rdf = new RDF(100, 5.0); // rMin = 0
3457
+ * const rdf2 = new RDF(100, 5.0, 0.5); // exclude d < 0.5 A
3258
3458
  * ```
3259
3459
  * @param {number} n_bins
3260
3460
  * @param {number} r_max
3461
+ * @param {number | null} [r_min]
3261
3462
  */
3262
- constructor(n_bins, r_max) {
3263
- const ret = wasm.rdf_new(n_bins, r_max);
3264
- this.__wbg_ptr = ret >>> 0;
3463
+ constructor(n_bins, r_max, r_min) {
3464
+ const ret = wasm.rdf_new(n_bins, r_max, !isLikeNone(r_min), isLikeNone(r_min) ? 0 : r_min);
3465
+ if (ret[2]) {
3466
+ throw takeFromExternrefTable0(ret[1]);
3467
+ }
3468
+ this.__wbg_ptr = ret[0] >>> 0;
3265
3469
  RDFFinalization.register(this, this.__wbg_ptr, this);
3266
3470
  return this;
3267
3471
  }
@@ -3339,6 +3543,14 @@ export class RDFResult {
3339
3543
  const ret = wasm.rdfresult_pairCounts(this.__wbg_ptr);
3340
3544
  return ret;
3341
3545
  }
3546
+ /**
3547
+ * Inner cutoff in A (lower edge of bin 0).
3548
+ * @returns {number}
3549
+ */
3550
+ get rMin() {
3551
+ const ret = wasm.rdfresult_rMin(this.__wbg_ptr);
3552
+ return ret;
3553
+ }
3342
3554
  /**
3343
3555
  * Zero-copy `Float64Array` view of normalized g(r). Same invalidation
3344
3556
  * caveat.
@@ -3349,7 +3561,7 @@ export class RDFResult {
3349
3561
  return ret;
3350
3562
  }
3351
3563
  /**
3352
- * Simulation box volume used in the normalization, in A^3.
3564
+ * Normalization volume in A^3 (from the SimBox or the explicit caller value).
3353
3565
  * @returns {number}
3354
3566
  */
3355
3567
  get volume() {
@@ -3375,6 +3587,10 @@ export class RadiusOfGyration {
3375
3587
  }
3376
3588
  /**
3377
3589
  * Compute radii of gyration. Returns a float typed array of length `numClusters`.
3590
+ *
3591
+ * Internally computes the cluster centers of mass so the single-frame
3592
+ * wasm signature `(frame, cluster)` stays stable despite the new
3593
+ * compute trait needing explicit COM upstream.
3378
3594
  * @param {Frame} frame
3379
3595
  * @param {ClusterResult} cluster_result
3380
3596
  * @returns {Float64Array}
@@ -4171,6 +4387,195 @@ export class WasmArray {
4171
4387
  }
4172
4388
  if (Symbol.dispose) WasmArray.prototype[Symbol.dispose] = WasmArray.prototype.free;
4173
4389
 
4390
+ /**
4391
+ * Wrapper for [`molrs_compute::kmeans::KMeans`].
4392
+ *
4393
+ * # Example (JavaScript)
4394
+ *
4395
+ * ```js
4396
+ * const km = new WasmKMeans(3, 100, 42);
4397
+ * const labels = km.fit(coords, nRows, 2); // Int32Array
4398
+ * ```
4399
+ */
4400
+ export class WasmKMeans {
4401
+ __destroy_into_raw() {
4402
+ const ptr = this.__wbg_ptr;
4403
+ this.__wbg_ptr = 0;
4404
+ WasmKMeansFinalization.unregister(this);
4405
+ return ptr;
4406
+ }
4407
+ free() {
4408
+ const ptr = this.__destroy_into_raw();
4409
+ wasm.__wbg_wasmkmeans_free(ptr, 0);
4410
+ }
4411
+ /**
4412
+ * Cluster a row-major `n_rows × n_dims` coordinate matrix.
4413
+ *
4414
+ * # Returns
4415
+ *
4416
+ * Cluster labels in `0..k` as an owned `Int32Array`, one per row.
4417
+ *
4418
+ * # Errors
4419
+ *
4420
+ * Throws if `k > n_rows`, `n_dims == 0`, the length does not match
4421
+ * `n_rows * n_dims`, or any element is non-finite.
4422
+ * @param {Float64Array} coords
4423
+ * @param {number} n_rows
4424
+ * @param {number} n_dims
4425
+ * @returns {Int32Array}
4426
+ */
4427
+ fit(coords, n_rows, n_dims) {
4428
+ const ptr0 = passArrayF64ToWasm0(coords, wasm.__wbindgen_malloc_command_export);
4429
+ const len0 = WASM_VECTOR_LEN;
4430
+ const ret = wasm.wasmkmeans_fit(this.__wbg_ptr, ptr0, len0, n_rows, n_dims);
4431
+ if (ret[2]) {
4432
+ throw takeFromExternrefTable0(ret[1]);
4433
+ }
4434
+ return takeFromExternrefTable0(ret[0]);
4435
+ }
4436
+ /**
4437
+ * Create a new k-means configuration.
4438
+ *
4439
+ * # Arguments
4440
+ *
4441
+ * * `k` — number of clusters (>= 1).
4442
+ * * `max_iter` — maximum Lloyd iterations (>= 1).
4443
+ * * `seed` — RNG seed for k-means++ initialization. Cast to `u64`
4444
+ * internally (JS numbers are `f64`; integers up to 2^53 pass
4445
+ * through losslessly).
4446
+ *
4447
+ * # Errors
4448
+ *
4449
+ * Throws if `k == 0` or `max_iter == 0`.
4450
+ * @param {number} k
4451
+ * @param {number} max_iter
4452
+ * @param {number} seed
4453
+ */
4454
+ constructor(k, max_iter, seed) {
4455
+ const ret = wasm.wasmkmeans_new(k, max_iter, seed);
4456
+ if (ret[2]) {
4457
+ throw takeFromExternrefTable0(ret[1]);
4458
+ }
4459
+ this.__wbg_ptr = ret[0] >>> 0;
4460
+ WasmKMeansFinalization.register(this, this.__wbg_ptr, this);
4461
+ return this;
4462
+ }
4463
+ }
4464
+ if (Symbol.dispose) WasmKMeans.prototype[Symbol.dispose] = WasmKMeans.prototype.free;
4465
+
4466
+ /**
4467
+ * Stateless wrapper for [`molrs_compute::pca::Pca2`].
4468
+ *
4469
+ * All configuration lives on [`fitTransform`](Self::fit_transform).
4470
+ *
4471
+ * # Example (JavaScript)
4472
+ *
4473
+ * ```js
4474
+ * const pca = new WasmPca2();
4475
+ * const result = pca.fitTransform(matrix, nRows, nCols);
4476
+ * const coords = result.coords(); // Float64Array, length 2 * nRows
4477
+ * const variance = result.variance(); // Float64Array, length 2
4478
+ * ```
4479
+ */
4480
+ export class WasmPca2 {
4481
+ __destroy_into_raw() {
4482
+ const ptr = this.__wbg_ptr;
4483
+ this.__wbg_ptr = 0;
4484
+ WasmPca2Finalization.unregister(this);
4485
+ return ptr;
4486
+ }
4487
+ free() {
4488
+ const ptr = this.__destroy_into_raw();
4489
+ wasm.__wbg_wasmpca2_free(ptr, 0);
4490
+ }
4491
+ /**
4492
+ * Fit 2-component PCA on a row-major observation matrix and return the
4493
+ * projected coordinates + per-component variance.
4494
+ *
4495
+ * # Arguments
4496
+ *
4497
+ * * `matrix` — row-major `n_rows × n_cols` observation matrix.
4498
+ * * `n_rows` — number of observations.
4499
+ * * `n_cols` — number of features.
4500
+ *
4501
+ * # Errors
4502
+ *
4503
+ * Throws if `n_rows < 3`, `n_cols < 2`, the length does not match
4504
+ * `n_rows * n_cols`, any element is non-finite, or any column has
4505
+ * zero variance.
4506
+ * @param {Float64Array} matrix
4507
+ * @param {number} n_rows
4508
+ * @param {number} n_cols
4509
+ * @returns {WasmPcaResult}
4510
+ */
4511
+ fitTransform(matrix, n_rows, n_cols) {
4512
+ const ptr0 = passArrayF64ToWasm0(matrix, wasm.__wbindgen_malloc_command_export);
4513
+ const len0 = WASM_VECTOR_LEN;
4514
+ const ret = wasm.wasmpca2_fitTransform(this.__wbg_ptr, ptr0, len0, n_rows, n_cols);
4515
+ if (ret[2]) {
4516
+ throw takeFromExternrefTable0(ret[1]);
4517
+ }
4518
+ return WasmPcaResult.__wrap(ret[0]);
4519
+ }
4520
+ /**
4521
+ * Create a new PCA calculator. The struct carries no state — all
4522
+ * parameters are supplied on [`fitTransform`](Self::fit_transform).
4523
+ */
4524
+ constructor() {
4525
+ const ret = wasm.wasmpca2_new();
4526
+ this.__wbg_ptr = ret >>> 0;
4527
+ WasmPca2Finalization.register(this, this.__wbg_ptr, this);
4528
+ return this;
4529
+ }
4530
+ }
4531
+ if (Symbol.dispose) WasmPca2.prototype[Symbol.dispose] = WasmPca2.prototype.free;
4532
+
4533
+ /**
4534
+ * Result of a [`WasmPca2::fit_transform`] call.
4535
+ *
4536
+ * Each accessor returns an **owned** `Float64Array` (copy of the underlying
4537
+ * `Vec`) so JS is free to let this wrapper be GC'd without dangling views.
4538
+ */
4539
+ export class WasmPcaResult {
4540
+ static __wrap(ptr) {
4541
+ ptr = ptr >>> 0;
4542
+ const obj = Object.create(WasmPcaResult.prototype);
4543
+ obj.__wbg_ptr = ptr;
4544
+ WasmPcaResultFinalization.register(obj, obj.__wbg_ptr, obj);
4545
+ return obj;
4546
+ }
4547
+ __destroy_into_raw() {
4548
+ const ptr = this.__wbg_ptr;
4549
+ this.__wbg_ptr = 0;
4550
+ WasmPcaResultFinalization.unregister(this);
4551
+ return ptr;
4552
+ }
4553
+ free() {
4554
+ const ptr = this.__destroy_into_raw();
4555
+ wasm.__wbg_wasmpcaresult_free(ptr, 0);
4556
+ }
4557
+ /**
4558
+ * Projected 2D coordinates as a row-major `Float64Array` of length
4559
+ * `2 * n_rows`. `coords[2 * i + 0]` is the PC1 score for row `i`,
4560
+ * `coords[2 * i + 1]` is PC2.
4561
+ * @returns {Float64Array}
4562
+ */
4563
+ coords() {
4564
+ const ret = wasm.wasmpcaresult_coords(this.__wbg_ptr);
4565
+ return ret;
4566
+ }
4567
+ /**
4568
+ * Explained variance per component as `Float64Array` of length 2.
4569
+ * `variance[0] >= variance[1]` by construction.
4570
+ * @returns {Float64Array}
4571
+ */
4572
+ variance() {
4573
+ const ret = wasm.wasmpcaresult_variance(this.__wbg_ptr);
4574
+ return ret;
4575
+ }
4576
+ }
4577
+ if (Symbol.dispose) WasmPcaResult.prototype[Symbol.dispose] = WasmPcaResult.prototype.free;
4578
+
4174
4579
  /**
4175
4580
  * XYZ / Extended XYZ file reader.
4176
4581
  *
@@ -4592,6 +4997,14 @@ export function __wbg_new_from_slice_ede497d29b90a4ad(arg0, arg1) {
4592
4997
  const ret = new Int32Array(getArrayI32FromWasm0(arg0, arg1));
4593
4998
  return ret;
4594
4999
  }
5000
+ export function __wbg_new_with_length_33f0a4c41f7ce2fc(arg0) {
5001
+ const ret = new Int32Array(arg0 >>> 0);
5002
+ return ret;
5003
+ }
5004
+ export function __wbg_new_with_length_5cfd777b51078805(arg0) {
5005
+ const ret = new Float64Array(arg0 >>> 0);
5006
+ return ret;
5007
+ }
4595
5008
  export function __wbg_next_0340c4ae324393c3() { return handleError(function (arg0) {
4596
5009
  const ret = arg0.next();
4597
5010
  return ret;
@@ -4612,6 +5025,12 @@ export function __wbg_push_471a5b068a5295f6(arg0, arg1) {
4612
5025
  const ret = arg0.push(arg1);
4613
5026
  return ret;
4614
5027
  }
5028
+ export function __wbg_set_5637e648df81c8e5(arg0, arg1, arg2) {
5029
+ arg0.set(getArrayF64FromWasm0(arg1, arg2));
5030
+ }
5031
+ export function __wbg_set_6c7215e0274bbbf2(arg0, arg1, arg2) {
5032
+ arg0.set(getArrayI32FromWasm0(arg1, arg2));
5033
+ }
4615
5034
  export function __wbg_stack_3b0d974bbf31e44f(arg0, arg1) {
4616
5035
  const ret = arg1.stack;
4617
5036
  const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc_command_export, wasm.__wbindgen_realloc_command_export);
@@ -4685,9 +5104,9 @@ const GyrationTensorFinalization = (typeof FinalizationRegistry === 'undefined')
4685
5104
  const InertiaTensorFinalization = (typeof FinalizationRegistry === 'undefined')
4686
5105
  ? { register: () => {}, unregister: () => {} }
4687
5106
  : new FinalizationRegistry(ptr => wasm.__wbg_inertiatensor_free(ptr >>> 0, 1));
4688
- const LAMMPSDumpReaderFinalization = (typeof FinalizationRegistry === 'undefined')
5107
+ const LAMMPSTrajReaderFinalization = (typeof FinalizationRegistry === 'undefined')
4689
5108
  ? { register: () => {}, unregister: () => {} }
4690
- : new FinalizationRegistry(ptr => wasm.__wbg_lammpsdumpreader_free(ptr >>> 0, 1));
5109
+ : new FinalizationRegistry(ptr => wasm.__wbg_lammpstrajreader_free(ptr >>> 0, 1));
4691
5110
  const LAMMPSReaderFinalization = (typeof FinalizationRegistry === 'undefined')
4692
5111
  ? { register: () => {}, unregister: () => {} }
4693
5112
  : new FinalizationRegistry(ptr => wasm.__wbg_lammpsreader_free(ptr >>> 0, 1));
@@ -4727,6 +5146,15 @@ const TopologyRingInfoFinalization = (typeof FinalizationRegistry === 'undefined
4727
5146
  const WasmArrayFinalization = (typeof FinalizationRegistry === 'undefined')
4728
5147
  ? { register: () => {}, unregister: () => {} }
4729
5148
  : new FinalizationRegistry(ptr => wasm.__wbg_wasmarray_free(ptr >>> 0, 1));
5149
+ const WasmKMeansFinalization = (typeof FinalizationRegistry === 'undefined')
5150
+ ? { register: () => {}, unregister: () => {} }
5151
+ : new FinalizationRegistry(ptr => wasm.__wbg_wasmkmeans_free(ptr >>> 0, 1));
5152
+ const WasmPca2Finalization = (typeof FinalizationRegistry === 'undefined')
5153
+ ? { register: () => {}, unregister: () => {} }
5154
+ : new FinalizationRegistry(ptr => wasm.__wbg_wasmpca2_free(ptr >>> 0, 1));
5155
+ const WasmPcaResultFinalization = (typeof FinalizationRegistry === 'undefined')
5156
+ ? { register: () => {}, unregister: () => {} }
5157
+ : new FinalizationRegistry(ptr => wasm.__wbg_wasmpcaresult_free(ptr >>> 0, 1));
4730
5158
  const SmilesIRFinalization = (typeof FinalizationRegistry === 'undefined')
4731
5159
  ? { register: () => {}, unregister: () => {} }
4732
5160
  : new FinalizationRegistry(ptr => wasm.__wbg_smilesir_free(ptr >>> 0, 1));