matterviz 0.4.0 → 0.4.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.
- package/dist/brillouin/BrillouinZone.svelte +68 -145
- package/dist/brillouin/BrillouinZone.svelte.d.ts +5 -14
- package/dist/brillouin/BrillouinZoneExportPane.svelte +43 -96
- package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +1 -1
- package/dist/brillouin/BrillouinZoneInfoPane.svelte +9 -32
- package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +2 -3
- package/dist/brillouin/BrillouinZoneScene.svelte +49 -203
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +3 -23
- package/dist/brillouin/ReciprocalVectors.svelte +39 -0
- package/dist/brillouin/ReciprocalVectors.svelte.d.ts +9 -0
- package/dist/brillouin/compute.d.ts +2 -0
- package/dist/brillouin/compute.js +80 -77
- package/dist/brillouin/geometry.d.ts +8 -0
- package/dist/brillouin/geometry.js +57 -0
- package/dist/brillouin/index.d.ts +2 -0
- package/dist/brillouin/index.js +2 -0
- package/dist/brillouin/types.d.ts +2 -2
- package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +1 -1
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +100 -191
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +4 -1
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +176 -464
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +7 -1
- package/dist/chempot-diagram/color.d.ts +3 -6
- package/dist/chempot-diagram/color.js +5 -5
- package/dist/chempot-diagram/compute.d.ts +3 -3
- package/dist/chempot-diagram/compute.js +3 -1
- package/dist/chempot-diagram/controls-state.svelte.d.ts +10 -0
- package/dist/chempot-diagram/controls-state.svelte.js +42 -0
- package/dist/chempot-diagram/export.d.ts +47 -0
- package/dist/chempot-diagram/export.js +133 -0
- package/dist/chempot-diagram/index.d.ts +1 -0
- package/dist/chempot-diagram/index.js +1 -0
- package/dist/chempot-diagram/pointer.d.ts +0 -10
- package/dist/chempot-diagram/pointer.js +4 -4
- package/dist/chempot-diagram/types.d.ts +3 -3
- package/dist/colors/index.js +2 -2
- package/dist/composition/FormulaFilter.svelte +6 -5
- package/dist/composition/PieChart.svelte +5 -5
- package/dist/composition/chem-sys.js +3 -2
- package/dist/composition/format.js +3 -2
- package/dist/composition/parse.d.ts +0 -1
- package/dist/composition/parse.js +17 -19
- package/dist/controls.d.ts +1 -0
- package/dist/controls.js +0 -1
- package/dist/convex-hull/ConvexHull.svelte +8 -10
- package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -4
- package/dist/convex-hull/ConvexHull2D.svelte +94 -175
- package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull3D.svelte +176 -680
- package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull4D.svelte +180 -680
- package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHullChrome.svelte +268 -0
- package/dist/convex-hull/ConvexHullChrome.svelte.d.ts +30 -0
- package/dist/convex-hull/ConvexHullControls.svelte +88 -7
- package/dist/convex-hull/ConvexHullControls.svelte.d.ts +7 -6
- package/dist/convex-hull/ConvexHullInfoPane.svelte +18 -5
- package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +6 -5
- package/dist/convex-hull/ConvexHullStats.svelte +29 -168
- package/dist/convex-hull/ConvexHullStats.svelte.d.ts +3 -1
- package/dist/convex-hull/ConvexHullTooltip.svelte +11 -2
- package/dist/convex-hull/ConvexHullTooltip.svelte.d.ts +2 -1
- package/dist/convex-hull/barycentric-coords.d.ts +2 -4
- package/dist/convex-hull/barycentric-coords.js +6 -33
- package/dist/convex-hull/canvas-interactions.svelte.d.ts +79 -0
- package/dist/convex-hull/canvas-interactions.svelte.js +278 -0
- package/dist/convex-hull/helpers.d.ts +39 -7
- package/dist/convex-hull/helpers.js +154 -69
- package/dist/convex-hull/hull-state.svelte.d.ts +44 -0
- package/dist/convex-hull/hull-state.svelte.js +124 -0
- package/dist/convex-hull/index.d.ts +9 -7
- package/dist/convex-hull/index.js +7 -2
- package/dist/convex-hull/thermodynamics.js +91 -920
- package/dist/convex-hull/types.d.ts +12 -4
- package/dist/convex-hull/types.js +12 -0
- package/dist/coordination/CoordinationBarPlot.svelte +4 -11
- package/dist/element/BohrAtom.svelte +2 -1
- package/dist/element/ElementTile.svelte.d.ts +1 -1
- package/dist/element/index.d.ts +4 -0
- package/dist/element/index.js +18 -0
- package/dist/feedback/DragOverlay.svelte +3 -1
- package/dist/feedback/DragOverlay.svelte.d.ts +1 -0
- package/dist/feedback/StatusMessage.svelte +13 -3
- package/dist/fermi-surface/FermiSurface.svelte +67 -146
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +5 -14
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte +72 -224
- package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +3 -23
- package/dist/fermi-surface/compute.js +11 -10
- package/dist/fermi-surface/export.js +4 -15
- package/dist/fermi-surface/index.d.ts +0 -1
- package/dist/fermi-surface/index.js +0 -1
- package/dist/fermi-surface/parse.d.ts +1 -1
- package/dist/fermi-surface/parse.js +64 -75
- package/dist/fermi-surface/types.d.ts +2 -2
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +55 -40
- package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +4 -3
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +3 -2
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +5 -5
- package/dist/heatmap-matrix/index.d.ts +3 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/io/ExportPane.svelte +166 -0
- package/dist/io/ExportPane.svelte.d.ts +17 -0
- package/dist/io/decompress.js +1 -2
- package/dist/io/export.d.ts +5 -1
- package/dist/io/export.js +32 -28
- package/dist/io/fetch.d.ts +2 -1
- package/dist/io/file-drop.d.ts +7 -0
- package/dist/io/file-drop.js +13 -0
- package/dist/io/index.d.ts +2 -0
- package/dist/io/index.js +10 -0
- package/dist/io/types.d.ts +13 -0
- package/dist/isosurface/parse.js +46 -44
- package/dist/labels.js +1 -1
- package/dist/layout/FullscreenButton.svelte +33 -0
- package/dist/layout/FullscreenButton.svelte.d.ts +10 -0
- package/dist/layout/FullscreenToggle.svelte +8 -14
- package/dist/layout/ViewerChrome.svelte +116 -0
- package/dist/layout/ViewerChrome.svelte.d.ts +17 -0
- package/dist/layout/fullscreen.d.ts +4 -0
- package/dist/layout/fullscreen.svelte.d.ts +8 -0
- package/dist/layout/fullscreen.svelte.js +37 -0
- package/dist/layout/index.d.ts +3 -0
- package/dist/layout/index.js +3 -0
- package/dist/math.d.ts +7 -3
- package/dist/math.js +18 -21
- package/dist/overlays/index.d.ts +4 -0
- package/dist/periodic-table/PeriodicTable.svelte +9 -8
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramControls.svelte +3 -2
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +4 -3
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +2 -1
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +2 -3
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +47 -132
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +3 -4
- package/dist/phase-diagram/colors.js +1 -1
- package/dist/phase-diagram/parse.d.ts +2 -1
- package/dist/plot/bar/BarPlot.svelte +79 -316
- package/dist/plot/bar/BarPlot.svelte.d.ts +7 -15
- package/dist/plot/bar/BarPlotControls.svelte.d.ts +1 -1
- package/dist/plot/bar/SpacegroupBarPlot.svelte +2 -1
- package/dist/plot/box/BoxPlot.svelte +76 -246
- package/dist/plot/box/BoxPlot.svelte.d.ts +4 -3
- package/dist/plot/box/BoxPlotControls.svelte.d.ts +1 -1
- package/dist/plot/box/Violin.svelte.d.ts +1 -1
- package/dist/plot/box/box-plot.d.ts +3 -2
- package/dist/plot/box/box-plot.js +5 -2
- package/dist/plot/box/kde.d.ts +2 -1
- package/dist/plot/box/kde.js +4 -4
- package/dist/plot/core/auto-place.d.ts +1 -1
- package/dist/plot/core/auto-place.js +4 -1
- package/dist/plot/core/components/ColorBar.svelte +5 -5
- package/dist/plot/core/components/ColorBar.svelte.d.ts +5 -4
- package/dist/plot/core/components/Line.svelte +3 -2
- package/dist/plot/core/components/Line.svelte.d.ts +3 -2
- package/dist/plot/core/components/PlotAxis.svelte +2 -1
- package/dist/plot/core/components/PlotAxis.svelte.d.ts +2 -1
- package/dist/plot/core/components/PlotControls.svelte.d.ts +1 -1
- package/dist/plot/core/components/ReferenceLine3D.svelte +2 -2
- package/dist/plot/core/components/ReferenceLine3D.svelte.d.ts +4 -4
- package/dist/plot/core/components/ReferencePlane.svelte +2 -2
- package/dist/plot/core/components/ReferencePlane.svelte.d.ts +4 -4
- package/dist/plot/core/data-cleaning.js +18 -18
- package/dist/plot/core/fill-utils.d.ts +4 -3
- package/dist/plot/core/fill-utils.js +6 -3
- package/dist/plot/core/interactions.d.ts +5 -1
- package/dist/plot/core/interactions.js +14 -0
- package/dist/plot/core/pan-zoom.svelte.d.ts +35 -0
- package/dist/plot/core/pan-zoom.svelte.js +221 -0
- package/dist/plot/core/placed-tween.svelte.d.ts +21 -0
- package/dist/plot/core/placed-tween.svelte.js +68 -0
- package/dist/plot/core/reference-line.d.ts +10 -10
- package/dist/plot/core/reference-line.js +6 -6
- package/dist/plot/core/scales.d.ts +17 -25
- package/dist/plot/core/scales.js +10 -8
- package/dist/plot/core/svg.d.ts +2 -1
- package/dist/plot/core/types.d.ts +18 -7
- package/dist/plot/core/utils/label-placement.d.ts +1 -1
- package/dist/plot/core/utils/label-placement.js +3 -3
- package/dist/plot/core/utils.d.ts +2 -1
- package/dist/plot/histogram/Histogram.svelte +77 -314
- package/dist/plot/histogram/HistogramControls.svelte.d.ts +1 -1
- package/dist/plot/sankey/Sankey.svelte +2 -5
- package/dist/plot/sankey/Sankey.svelte.d.ts +1 -1
- package/dist/plot/sankey/sankey.js +3 -1
- package/dist/plot/scatter/BinnedScatterPlot.svelte +3 -5
- package/dist/plot/scatter/BinnedScatterPlot.svelte.d.ts +4 -4
- package/dist/plot/scatter/ScatterPlot.svelte +160 -450
- package/dist/plot/scatter/ScatterPlot.svelte.d.ts +7 -15
- package/dist/plot/scatter/ScatterPlotControls.svelte.d.ts +1 -1
- package/dist/plot/scatter/binned-scatter-types.d.ts +4 -11
- package/dist/plot/scatter/index.d.ts +1 -1
- package/dist/plot/scatter-3d/ScatterPlot3D.svelte +15 -26
- package/dist/plot/scatter-3d/ScatterPlot3D.svelte.d.ts +6 -14
- package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte +9 -10
- package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte.d.ts +5 -5
- package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte +122 -121
- package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte.d.ts +5 -14
- package/dist/plot/scatter-3d/Surface3D.svelte +6 -5
- package/dist/plot/scatter-3d/Surface3D.svelte.d.ts +4 -3
- package/dist/plot/sunburst/Sunburst.svelte +16 -20
- package/dist/plot/sunburst/Sunburst.svelte.d.ts +4 -3
- package/dist/plot/sunburst/SunburstControls.svelte.d.ts +1 -1
- package/dist/plot/sunburst/sunburst.js +4 -1
- package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
- package/dist/sanitize.js +13 -2
- package/dist/scene/SceneCamera.svelte +62 -0
- package/dist/scene/SceneCamera.svelte.d.ts +19 -0
- package/dist/scene/bind-renderer.svelte.d.ts +2 -0
- package/dist/scene/bind-renderer.svelte.js +14 -0
- package/dist/scene/index.d.ts +4 -0
- package/dist/scene/index.js +5 -0
- package/dist/scene/props.js +52 -0
- package/dist/scene/types.d.ts +26 -0
- package/dist/scene/types.js +1 -0
- package/dist/settings.d.ts +14 -2
- package/dist/settings.js +59 -1
- package/dist/spectral/Bands.svelte +8 -7
- package/dist/spectral/Bands.svelte.d.ts +3 -2
- package/dist/spectral/BandsAndDos.svelte +22 -24
- package/dist/spectral/BrillouinBandsDos.svelte +3 -3
- package/dist/spectral/Dos.svelte +5 -4
- package/dist/spectral/Dos.svelte.d.ts +2 -1
- package/dist/spectral/helpers.d.ts +6 -6
- package/dist/spectral/helpers.js +43 -37
- package/dist/state.svelte.d.ts +0 -7
- package/dist/state.svelte.js +0 -6
- package/dist/structure/Arrow.svelte +2 -4
- package/dist/structure/AtomLegend.svelte.d.ts +1 -1
- package/dist/structure/CanvasTooltip.svelte +1 -0
- package/dist/structure/CellSelect.svelte +11 -3
- package/dist/structure/CellSelect.svelte.d.ts +2 -1
- package/dist/structure/Lattice.svelte +2 -2
- package/dist/structure/Structure.svelte +291 -355
- package/dist/structure/Structure.svelte.d.ts +5 -15
- package/dist/structure/StructureControls.svelte +217 -2
- package/dist/structure/StructureControls.svelte.d.ts +5 -3
- package/dist/structure/StructureExportPane.svelte +54 -156
- package/dist/structure/StructureExportPane.svelte.d.ts +4 -5
- package/dist/structure/StructureInfoPane.svelte +5 -3
- package/dist/structure/StructureInfoPane.svelte.d.ts +5 -5
- package/dist/structure/StructureScene.svelte +365 -198
- package/dist/structure/StructureScene.svelte.d.ts +22 -20
- package/dist/structure/{label-placement.d.ts → atom-label-placement.d.ts} +3 -3
- package/dist/structure/{label-placement.js → atom-label-placement.js} +12 -2
- package/dist/structure/atom-properties.d.ts +1 -1
- package/dist/structure/atom-properties.js +11 -16
- package/dist/structure/bond-order-perception.js +2 -4
- package/dist/structure/bonding.d.ts +3 -0
- package/dist/structure/bonding.js +91 -48
- package/dist/structure/export.d.ts +24 -4
- package/dist/structure/export.js +64 -122
- package/dist/structure/index.d.ts +2 -0
- package/dist/structure/index.js +2 -0
- package/dist/structure/parse.d.ts +3 -2
- package/dist/structure/parse.js +333 -370
- package/dist/structure/partial-occupancy.d.ts +0 -1
- package/dist/structure/partial-occupancy.js +1 -1
- package/dist/structure/pbc.d.ts +1 -1
- package/dist/structure/pbc.js +186 -13
- package/dist/structure/polyhedra.d.ts +41 -0
- package/dist/structure/polyhedra.js +602 -0
- package/dist/structure/site.d.ts +4 -0
- package/dist/structure/site.js +1 -0
- package/dist/structure/supercell.js +3 -2
- package/dist/structure/validation.js +5 -6
- package/dist/symmetry/SymmetryElementControls.svelte +69 -0
- package/dist/symmetry/SymmetryElementControls.svelte.d.ts +9 -0
- package/dist/symmetry/SymmetryElements.svelte +354 -0
- package/dist/symmetry/SymmetryElements.svelte.d.ts +24 -0
- package/dist/symmetry/SymmetryStats.svelte +111 -6
- package/dist/symmetry/WyckoffTable.svelte +68 -7
- package/dist/symmetry/WyckoffTable.svelte.d.ts +3 -0
- package/dist/symmetry/cell-transform.js +7 -14
- package/dist/symmetry/index.d.ts +14 -4
- package/dist/symmetry/index.js +301 -80
- package/dist/symmetry/spacegroups.d.ts +5 -1
- package/dist/symmetry/spacegroups.js +15 -1
- package/dist/symmetry/symmetry-elements.d.ts +33 -0
- package/dist/symmetry/symmetry-elements.js +521 -0
- package/dist/symmetry/wyckoff-db.d.ts +9 -0
- package/dist/symmetry/wyckoff-db.js +87 -0
- package/dist/table/HeatmapTable.svelte +4 -15
- package/dist/table/HeatmapTable.svelte.d.ts +1 -1
- package/dist/trajectory/Trajectory.svelte +58 -61
- package/dist/trajectory/Trajectory.svelte.d.ts +10 -22
- package/dist/trajectory/TrajectoryExportPane.svelte +15 -24
- package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +4 -5
- package/dist/trajectory/TrajectoryInfoPane.svelte +3 -2
- package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +3 -2
- package/dist/trajectory/constants.js +6 -2
- package/dist/trajectory/extract.js +17 -37
- package/dist/trajectory/format-detect.d.ts +0 -1
- package/dist/trajectory/format-detect.js +3 -9
- package/dist/trajectory/frame-reader.d.ts +0 -1
- package/dist/trajectory/frame-reader.js +62 -128
- package/dist/trajectory/helpers.d.ts +10 -2
- package/dist/trajectory/helpers.js +56 -36
- package/dist/trajectory/parse/ase.d.ts +9 -1
- package/dist/trajectory/parse/ase.js +47 -32
- package/dist/trajectory/parse/diagnostics.d.ts +3 -0
- package/dist/trajectory/parse/diagnostics.js +14 -0
- package/dist/trajectory/parse/index.d.ts +1 -1
- package/dist/trajectory/parse/index.js +54 -102
- package/dist/trajectory/parse/lammps.d.ts +0 -2
- package/dist/trajectory/parse/lammps.js +8 -6
- package/dist/trajectory/parse/pymatgen.d.ts +2 -0
- package/dist/trajectory/parse/pymatgen.js +74 -0
- package/dist/trajectory/parse/vasp.js +4 -3
- package/dist/trajectory/parse/xyz.d.ts +9 -21
- package/dist/trajectory/parse/xyz.js +28 -33
- package/dist/trajectory/plotting.d.ts +0 -1
- package/dist/trajectory/plotting.js +3 -100
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +1 -1
- package/dist/xrd/XrdPlot.svelte +14 -29
- package/dist/xrd/broadening.d.ts +2 -1
- package/dist/xrd/calc-xrd.js +6 -11
- package/dist/xrd/index.d.ts +2 -2
- package/package.json +29 -16
- package/dist/element/data.json +0 -11864
- package/dist/fermi-surface/marching-cubes.d.ts +0 -2
- package/dist/fermi-surface/marching-cubes.js +0 -2
- package/dist/plot/core/hover-lock.svelte.d.ts +0 -14
- package/dist/plot/core/hover-lock.svelte.js +0 -45
|
@@ -1,21 +1,31 @@
|
|
|
1
|
+
// Parsing functions for trajectory data from various formats
|
|
1
2
|
import { is_binary } from '../../io/is-binary';
|
|
2
|
-
import
|
|
3
|
-
import { parse_xyz } from '../../structure/parse';
|
|
3
|
+
import { is_plain_object } from '../../utils';
|
|
4
|
+
import { is_parsed_structure, parse_xyz } from '../../structure/parse';
|
|
4
5
|
import { INDEX_SAMPLE_RATE, LARGE_FILE_THRESHOLD } from '../constants';
|
|
5
|
-
import {
|
|
6
|
+
import { strip_compression_extensions } from '../../io';
|
|
7
|
+
import { ext_hint, FORMAT_PATTERNS, is_trajectory_file } from '../format-detect';
|
|
6
8
|
import { TrajFrameReader } from '../frame-reader';
|
|
7
|
-
import { count_xyz_frames
|
|
9
|
+
import { count_xyz_frames } from '../helpers';
|
|
8
10
|
import { parse_ase_trajectory } from './ase';
|
|
11
|
+
import { get_traj_parse_warnings, reset_traj_parse_warnings, traj_warn } from './diagnostics';
|
|
9
12
|
import { parse_torch_sim_hdf5 } from './hdf5';
|
|
10
13
|
import { parse_lammps_trajectory } from './lammps';
|
|
14
|
+
import { parse_pymatgen_trajectory } from './pymatgen';
|
|
11
15
|
import { parse_vasp_xdatcar } from './vasp';
|
|
12
16
|
import { parse_xyz_trajectory } from './xyz';
|
|
13
|
-
//
|
|
14
|
-
const
|
|
17
|
+
// Throw on a trajectory frame whose structure isn't a valid parsed structure (non-empty sites with species + coords)
|
|
18
|
+
const assert_frame_structure = (structure, label) => {
|
|
19
|
+
if (!is_parsed_structure(structure)) {
|
|
20
|
+
const context = typeof label === `number` ? `trajectory frame ${label}` : label;
|
|
21
|
+
throw new Error(`Invalid structure in ${context}: expected non-empty 'sites' array with species and coordinates`);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
15
24
|
// Re-export constants and types for consumers
|
|
16
|
-
export {
|
|
25
|
+
export { LARGE_FILE_THRESHOLD, MAX_BIN_FILE_SIZE, MAX_TEXT_FILE_SIZE, } from '../constants';
|
|
17
26
|
export { is_trajectory_file, TrajFrameReader };
|
|
18
27
|
export async function parse_trajectory_data(data, filename, atom_type_mapping) {
|
|
28
|
+
reset_traj_parse_warnings();
|
|
19
29
|
if (data instanceof ArrayBuffer) {
|
|
20
30
|
if (FORMAT_PATTERNS.ase(data, filename))
|
|
21
31
|
return parse_ase_trajectory(data, filename);
|
|
@@ -46,127 +56,62 @@ export async function parse_trajectory_data(data, filename, atom_type_mapping) {
|
|
|
46
56
|
};
|
|
47
57
|
}
|
|
48
58
|
}
|
|
49
|
-
catch
|
|
59
|
+
catch {
|
|
50
60
|
// Single-frame XYZ parsing failed, continue to JSON parsing.
|
|
51
|
-
log_parse_debug(`Single XYZ parse fallback failed for ${filename ?? `unknown file`}:`, error);
|
|
52
61
|
}
|
|
53
62
|
}
|
|
54
63
|
try {
|
|
55
64
|
data = JSON.parse(content);
|
|
56
65
|
}
|
|
57
66
|
catch (error) {
|
|
58
|
-
log_parse_debug(`JSON parse failed for ${filename ?? `unknown file`}:`, error);
|
|
59
67
|
throw new Error(`Unsupported text format`, { cause: error });
|
|
60
68
|
}
|
|
61
69
|
}
|
|
62
|
-
if (!data || typeof data !== `object`)
|
|
63
|
-
throw new Error(`Invalid data format`);
|
|
64
70
|
// Handle JSON formats
|
|
65
71
|
if (Array.isArray(data)) {
|
|
66
72
|
const frames = data.map((frame_data, idx) => {
|
|
67
73
|
const frame_obj = frame_data;
|
|
68
74
|
const frame_step = frame_obj.step;
|
|
75
|
+
const structure = frame_obj.structure ?? frame_obj;
|
|
76
|
+
assert_frame_structure(structure, idx);
|
|
69
77
|
return {
|
|
70
|
-
structure:
|
|
78
|
+
structure: structure,
|
|
71
79
|
step: typeof frame_step === `number` ? frame_step : idx,
|
|
72
80
|
metadata: frame_obj.metadata || {},
|
|
73
81
|
};
|
|
74
82
|
});
|
|
75
83
|
return { frames, metadata: { source_format: `array`, frame_count: frames.length } };
|
|
76
84
|
}
|
|
77
|
-
|
|
85
|
+
if (!is_plain_object(data))
|
|
86
|
+
throw new Error(`Invalid data format`);
|
|
78
87
|
// Pymatgen format
|
|
79
|
-
if (
|
|
80
|
-
|
|
81
|
-
const frame_elements = species.map((specie) => specie.element);
|
|
82
|
-
const coords = obj.coords;
|
|
83
|
-
const matrix = validate_3x3_matrix(obj.lattice);
|
|
84
|
-
const frame_properties = obj.frame_properties || [];
|
|
85
|
-
const frac_to_cart = math.create_frac_to_cart(matrix);
|
|
86
|
-
const frames = coords.map((frame_coords, idx) => {
|
|
87
|
-
const positions = frame_coords.map((abc) => frac_to_cart(abc));
|
|
88
|
-
// Process frame properties to extract numpy arrays
|
|
89
|
-
const raw_properties = frame_properties[idx] || {};
|
|
90
|
-
const processed_properties = {};
|
|
91
|
-
Object.entries(raw_properties).forEach(([key, value]) => {
|
|
92
|
-
if (value &&
|
|
93
|
-
typeof value === `object` &&
|
|
94
|
-
value[`@class`] === `array`) {
|
|
95
|
-
// Extract numpy array data
|
|
96
|
-
const array_obj = value;
|
|
97
|
-
processed_properties[key] = array_obj.data;
|
|
98
|
-
// Calculate force statistics for forces
|
|
99
|
-
if (key === `forces` && Array.isArray(array_obj.data)) {
|
|
100
|
-
const forces = array_obj.data;
|
|
101
|
-
const force_magnitudes = forces.map((force) => Math.hypot(...force));
|
|
102
|
-
if (force_magnitudes.length > 0) {
|
|
103
|
-
processed_properties.force_max = force_magnitudes.reduce((max_val, magnitude) => (magnitude > max_val ? magnitude : max_val), force_magnitudes[0]);
|
|
104
|
-
processed_properties.force_norm = Math.sqrt(force_magnitudes.reduce((sum, f) => sum + f ** 2, 0) / force_magnitudes.length);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
// Calculate stress statistics for stress tensor
|
|
108
|
-
if (key === `stress` && Array.isArray(array_obj.data)) {
|
|
109
|
-
const stress_tensor = array_obj.data;
|
|
110
|
-
if (!math.is_square_matrix(stress_tensor, 3)) {
|
|
111
|
-
console.warn(`Invalid stress tensor structure in frame ${idx}`);
|
|
112
|
-
}
|
|
113
|
-
else {
|
|
114
|
-
// Calculate stress components (diagonal elements represent normal stresses)
|
|
115
|
-
const normal_stresses = [
|
|
116
|
-
stress_tensor[0][0],
|
|
117
|
-
stress_tensor[1][1],
|
|
118
|
-
stress_tensor[2][2],
|
|
119
|
-
];
|
|
120
|
-
processed_properties.stress_max = Math.max(...normal_stresses.map(Math.abs));
|
|
121
|
-
// Calculate hydrostatic pressure (negative of mean normal stress)
|
|
122
|
-
processed_properties.pressure =
|
|
123
|
-
-(normal_stresses[0] + normal_stresses[1] + normal_stresses[2]) / 3;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
else {
|
|
128
|
-
processed_properties[key] = value;
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
return create_trajectory_frame(positions, frame_elements, matrix, [true, true, true], idx, processed_properties);
|
|
132
|
-
});
|
|
133
|
-
return {
|
|
134
|
-
frames,
|
|
135
|
-
metadata: {
|
|
136
|
-
filename,
|
|
137
|
-
source_format: `pymatgen_trajectory`,
|
|
138
|
-
frame_count: frames.length,
|
|
139
|
-
species_list: [...new Set(species.map((specie) => specie.element))],
|
|
140
|
-
periodic_boundary_conditions: [true, true, true],
|
|
141
|
-
},
|
|
142
|
-
};
|
|
88
|
+
if (data[`@class`] === `Trajectory` && data.species && data.coords && data.lattice) {
|
|
89
|
+
return parse_pymatgen_trajectory(data, filename);
|
|
143
90
|
}
|
|
144
91
|
// Object with frames
|
|
145
|
-
if (Array.isArray(
|
|
146
|
-
const metadata = (
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
};
|
|
92
|
+
if (Array.isArray(data.frames)) {
|
|
93
|
+
const metadata = (data.metadata ?? {});
|
|
94
|
+
const frames = data.frames;
|
|
95
|
+
frames.forEach((frame, idx) => assert_frame_structure(frame?.structure, idx));
|
|
96
|
+
return { frames, metadata: { ...metadata, source_format: `object_with_frames` } };
|
|
151
97
|
}
|
|
152
|
-
// Single structure
|
|
153
|
-
if (
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
};
|
|
98
|
+
// Single structure (treated as a 1-frame trajectory)
|
|
99
|
+
if (data.sites) {
|
|
100
|
+
assert_frame_structure(data, `single structure`);
|
|
101
|
+
const frames = [{ structure: data, step: 0, metadata: {} }];
|
|
102
|
+
const metadata = { source_format: `single_structure`, frame_count: 1 };
|
|
103
|
+
return { frames, metadata };
|
|
158
104
|
}
|
|
159
105
|
throw new Error(`Unrecognized trajectory format`);
|
|
160
106
|
}
|
|
161
107
|
export function get_unsupported_format_message(filename, content) {
|
|
162
108
|
const lower = filename.toLowerCase();
|
|
163
109
|
// Check for unsupported compression formats first
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
]
|
|
169
|
-
for (const { ext, name } of unsupported_compression) {
|
|
110
|
+
for (const [ext, name] of [
|
|
111
|
+
[`.bz2`, `BZ2`],
|
|
112
|
+
[`.xz`, `XZ`],
|
|
113
|
+
[`.zip`, `ZIP`],
|
|
114
|
+
]) {
|
|
170
115
|
if (lower.endsWith(ext)) {
|
|
171
116
|
return `🚫 ${name} compression not supported in browser\nPlease decompress the file first`;
|
|
172
117
|
}
|
|
@@ -187,10 +132,20 @@ export function get_unsupported_format_message(filename, content) {
|
|
|
187
132
|
? `🚫 Binary format not supported${filename ? `: ${filename}` : ``}`
|
|
188
133
|
: null;
|
|
189
134
|
}
|
|
135
|
+
// Attach non-fatal parse warnings (skipped atoms, dropped frames, plot-metadata
|
|
136
|
+
// extraction failures, ...) collected during parsing to the trajectory metadata so
|
|
137
|
+
// the UI can surface them instead of leaving them in the console only.
|
|
138
|
+
function attach_parse_warnings(trajectory) {
|
|
139
|
+
const parse_warnings = get_traj_parse_warnings();
|
|
140
|
+
if (parse_warnings.length === 0)
|
|
141
|
+
return trajectory;
|
|
142
|
+
return { ...trajectory, metadata: { ...trajectory.metadata, parse_warnings } };
|
|
143
|
+
}
|
|
190
144
|
// Unified async parser with streaming support
|
|
191
145
|
export async function parse_trajectory_async(data, filename, on_progress, options = {}) {
|
|
192
146
|
const { use_indexing, index_sample_rate = INDEX_SAMPLE_RATE, extract_plot_metadata = true, atom_type_mapping, } = options;
|
|
193
147
|
const update_progress = (current, stage) => on_progress?.({ current, total: 100, stage });
|
|
148
|
+
reset_traj_parse_warnings();
|
|
194
149
|
try {
|
|
195
150
|
update_progress(0, `Detecting format...`);
|
|
196
151
|
const data_size = data instanceof ArrayBuffer ? data.byteLength : new TextEncoder().encode(data).byteLength;
|
|
@@ -208,16 +163,13 @@ export async function parse_trajectory_async(data, filename, on_progress, option
|
|
|
208
163
|
ext_hint(filename, /\.(xyz|extxyz)$/) === null &&
|
|
209
164
|
count_xyz_frames(data.slice(0, 2 ** 20)) >= 1);
|
|
210
165
|
if (should_use_indexing && can_index) {
|
|
211
|
-
return await parse_with_unified_loader(data, filename, {
|
|
212
|
-
index_sample_rate,
|
|
213
|
-
extract_plot_metadata,
|
|
214
|
-
}, on_progress);
|
|
166
|
+
return attach_parse_warnings(await parse_with_unified_loader(data, filename, { index_sample_rate, extract_plot_metadata }, on_progress));
|
|
215
167
|
}
|
|
216
168
|
// Fallback to direct parsing
|
|
217
169
|
update_progress(10, `Parsing trajectory...`);
|
|
218
170
|
const result = await parse_trajectory_data(data, filename, atom_type_mapping);
|
|
219
171
|
update_progress(100, `Complete`);
|
|
220
|
-
return result;
|
|
172
|
+
return attach_parse_warnings(result);
|
|
221
173
|
}
|
|
222
174
|
catch (error) {
|
|
223
175
|
const error_message = error instanceof Error ? error.message : `Unknown error`;
|
|
@@ -259,7 +211,7 @@ async function parse_with_unified_loader(data, filename, options, on_progress) {
|
|
|
259
211
|
});
|
|
260
212
|
}
|
|
261
213
|
catch (error) {
|
|
262
|
-
|
|
214
|
+
traj_warn(`Failed to extract plot metadata`, error);
|
|
263
215
|
}
|
|
264
216
|
}
|
|
265
217
|
const stage = `Ready: ${total_frames} frames indexed`;
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import * as math from '../../math';
|
|
2
1
|
import type { TrajectoryType } from '../index';
|
|
3
2
|
import type { AtomTypeMapping } from '../types';
|
|
4
|
-
export declare function parse_lammps_box(box_lines: string[], is_triclinic: boolean): math.Matrix3x3 | null;
|
|
5
3
|
export declare function parse_lammps_trajectory(content: string, filename?: string, atom_type_mapping?: AtomTypeMapping): TrajectoryType;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { ELEM_SYMBOLS } from '../../labels';
|
|
2
2
|
import * as math from '../../math';
|
|
3
|
-
import {
|
|
3
|
+
import { coerce_elem_symbol } from '../../element';
|
|
4
|
+
import { create_trajectory_frame } from '../helpers';
|
|
5
|
+
import { traj_warn } from './diagnostics';
|
|
4
6
|
const is_periodic = (token) => token.toLowerCase().startsWith(`p`);
|
|
5
7
|
// Parse LAMMPS box bounds → lattice matrix. Handles orthogonal and triclinic boxes.
|
|
6
8
|
// Triclinic: converts bounding box to actual dims per https://docs.lammps.org/Howto_triclinic.html
|
|
7
9
|
// Lattice vectors: a=(lx,0,0), b=(xy,ly,0), c=(xz,yz,lz)
|
|
8
|
-
|
|
10
|
+
function parse_lammps_box(box_lines, is_triclinic) {
|
|
9
11
|
if (box_lines.length !== 3)
|
|
10
12
|
return null;
|
|
11
13
|
const bounds = box_lines.map((line) => line.split(/\s+/).map(Number));
|
|
@@ -100,7 +102,7 @@ export function parse_lammps_trajectory(content, filename, atom_type_mapping) {
|
|
|
100
102
|
if (pos_cols.some((col_idx) => col_idx === undefined))
|
|
101
103
|
continue;
|
|
102
104
|
if (type_col === undefined && element_col === undefined && id_col === undefined) {
|
|
103
|
-
|
|
105
|
+
traj_warn(`Skipping LAMMPS frame at timestep ${timestep}: missing type/element/id column`);
|
|
104
106
|
continue;
|
|
105
107
|
}
|
|
106
108
|
// Parse atom data
|
|
@@ -125,9 +127,9 @@ export function parse_lammps_trajectory(content, filename, atom_type_mapping) {
|
|
|
125
127
|
const raw_symbol = parts[element_col];
|
|
126
128
|
if (!raw_symbol)
|
|
127
129
|
continue;
|
|
128
|
-
element_symbol =
|
|
130
|
+
element_symbol = coerce_elem_symbol(raw_symbol);
|
|
129
131
|
if (!element_symbol) {
|
|
130
|
-
|
|
132
|
+
traj_warn(`Skipping LAMMPS atom with unknown element symbol "${raw_symbol}" at timestep ${timestep}`);
|
|
131
133
|
continue;
|
|
132
134
|
}
|
|
133
135
|
}
|
|
@@ -135,7 +137,7 @@ export function parse_lammps_trajectory(content, filename, atom_type_mapping) {
|
|
|
135
137
|
const atom_id = parseInt(parts[id_col], 10) || 1;
|
|
136
138
|
atom_types_found.add(atom_id);
|
|
137
139
|
if (!id_fallback_warning_emitted) {
|
|
138
|
-
|
|
140
|
+
traj_warn(`LAMMPS parser fallback: mapping atom IDs to elements from ID column; this may be incorrect for large or sequential IDs. Prefer a TYPE column when available.`);
|
|
139
141
|
id_fallback_warning_emitted = true;
|
|
140
142
|
}
|
|
141
143
|
element_symbol = get_element(atom_id);
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import * as math from '../../math';
|
|
2
|
+
import { calc_force_stats, create_trajectory_frame, validate_3x3_matrix, } from '../helpers';
|
|
3
|
+
import { is_plain_object } from '../../utils';
|
|
4
|
+
import { traj_warn } from './diagnostics';
|
|
5
|
+
// Non-empty array of pymatgen Species-like objects with non-empty string element
|
|
6
|
+
// symbols (predicate so callers get narrowing; rejects e.g. { element: null })
|
|
7
|
+
const is_species_array = (val) => Array.isArray(val) &&
|
|
8
|
+
val.length > 0 &&
|
|
9
|
+
val.every((sp) => sp != null &&
|
|
10
|
+
typeof sp === `object` &&
|
|
11
|
+
`element` in sp &&
|
|
12
|
+
typeof sp.element === `string` &&
|
|
13
|
+
sp.element.trim().length > 0);
|
|
14
|
+
// Parse an already-JSON-parsed pymatgen Trajectory object (detected via @class === 'Trajectory' with species/coords/lattice present)
|
|
15
|
+
export function parse_pymatgen_trajectory(obj, filename) {
|
|
16
|
+
// Validate shape upfront so malformed input fails with a clear message
|
|
17
|
+
// (callers gate only on truthiness, not structure) rather than a cryptic `.map` error
|
|
18
|
+
if (!is_species_array(obj.species)) {
|
|
19
|
+
throw new TypeError(`Invalid pymatgen Trajectory: 'species' must be a non-empty array of { element } objects`);
|
|
20
|
+
}
|
|
21
|
+
if (!Array.isArray(obj.coords)) {
|
|
22
|
+
throw new TypeError(`Invalid pymatgen Trajectory: 'coords' must be an array of frames`);
|
|
23
|
+
}
|
|
24
|
+
const frame_elements = obj.species.map((specie) => specie.element);
|
|
25
|
+
const coords = obj.coords;
|
|
26
|
+
const matrix = validate_3x3_matrix(obj.lattice);
|
|
27
|
+
const frame_properties = obj.frame_properties || [];
|
|
28
|
+
const frac_to_cart = math.create_frac_to_cart(matrix);
|
|
29
|
+
const frames = coords.map((frame_coords, idx) => {
|
|
30
|
+
const positions = frame_coords.map((abc) => frac_to_cart(abc));
|
|
31
|
+
// Process frame properties to extract numpy arrays
|
|
32
|
+
const raw_properties = frame_properties[idx] || {};
|
|
33
|
+
const processed_properties = {};
|
|
34
|
+
Object.entries(raw_properties).forEach(([key, value]) => {
|
|
35
|
+
if (is_plain_object(value) && value[`@class`] === `array`) {
|
|
36
|
+
processed_properties[key] = value.data;
|
|
37
|
+
if (key === `forces` && Array.isArray(value.data)) {
|
|
38
|
+
// Object.assign ignores the null calc_force_stats returns for empty forces
|
|
39
|
+
Object.assign(processed_properties, calc_force_stats(value.data));
|
|
40
|
+
}
|
|
41
|
+
if (key === `stress` && Array.isArray(value.data)) {
|
|
42
|
+
const stress_tensor = value.data;
|
|
43
|
+
if (!math.is_square_matrix(stress_tensor, 3)) {
|
|
44
|
+
traj_warn(`Invalid stress tensor structure in frame ${idx}`);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// Calculate stress components (diagonal elements represent normal stresses)
|
|
48
|
+
const normal_stresses = [
|
|
49
|
+
stress_tensor[0][0],
|
|
50
|
+
stress_tensor[1][1],
|
|
51
|
+
stress_tensor[2][2],
|
|
52
|
+
];
|
|
53
|
+
processed_properties.stress_max = Math.max(...normal_stresses.map(Math.abs));
|
|
54
|
+
// Calculate hydrostatic pressure (negative of mean normal stress)
|
|
55
|
+
processed_properties.pressure =
|
|
56
|
+
-(normal_stresses[0] + normal_stresses[1] + normal_stresses[2]) / 3;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
processed_properties[key] = value;
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
return create_trajectory_frame(positions, frame_elements, matrix, [true, true, true], idx, processed_properties);
|
|
65
|
+
});
|
|
66
|
+
const metadata = {
|
|
67
|
+
filename,
|
|
68
|
+
source_format: `pymatgen_trajectory`,
|
|
69
|
+
frame_count: frames.length,
|
|
70
|
+
species_list: [...new Set(frame_elements)],
|
|
71
|
+
periodic_boundary_conditions: [true, true, true],
|
|
72
|
+
};
|
|
73
|
+
return { frames, metadata };
|
|
74
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as math from '../../math';
|
|
2
|
-
import {
|
|
2
|
+
import { is_elem_symbol } from '../../element';
|
|
3
|
+
import { create_trajectory_frame, validate_3x3_matrix } from '../helpers';
|
|
3
4
|
// Parse the 7-line XDATCAR header at lines[start]: title, scale factor, 3 lattice rows
|
|
4
5
|
// (multiplied by scale), element names, element counts
|
|
5
6
|
function parse_xdatcar_header(lines, start) {
|
|
@@ -27,7 +28,7 @@ export function parse_vasp_xdatcar(content, filename) {
|
|
|
27
28
|
if (element_counts.some((count) => !Number.isFinite(count) || !Number.isInteger(count) || count <= 0)) {
|
|
28
29
|
throw new Error(`XDATCAR contains invalid element counts: expected finite positive integers`);
|
|
29
30
|
}
|
|
30
|
-
const bad_element = element_names.find((name) => !
|
|
31
|
+
const bad_element = element_names.find((name) => !is_elem_symbol(name));
|
|
31
32
|
if (bad_element)
|
|
32
33
|
throw new Error(`Invalid element symbol in XDATCAR: ${bad_element}`);
|
|
33
34
|
let elements = element_names.flatMap((name, idx) => Array(element_counts[idx]).fill(name));
|
|
@@ -46,7 +47,7 @@ export function parse_vasp_xdatcar(content, filename) {
|
|
|
46
47
|
lattice_matrix = validate_3x3_matrix(hdr.rows);
|
|
47
48
|
frac_to_cart = math.create_frac_to_cart(lattice_matrix);
|
|
48
49
|
if (hdr.names.length === hdr.counts.length &&
|
|
49
|
-
hdr.names.every(
|
|
50
|
+
hdr.names.every(is_elem_symbol) &&
|
|
50
51
|
hdr.counts.every((count) => Number.isInteger(count) && count > 0)) {
|
|
51
52
|
elements = hdr.names.flatMap((name, idx) => Array(hdr.counts[idx]).fill(name));
|
|
52
53
|
}
|
|
@@ -1,26 +1,14 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import * as math from '../../math';
|
|
3
|
-
import type { TrajectoryType } from '../index';
|
|
4
|
-
export declare function parse_extxyz_columns(comment: string): {
|
|
5
|
-
species_col: number;
|
|
6
|
-
pos_col: number;
|
|
7
|
-
forces_col: number;
|
|
8
|
-
min_cols: number;
|
|
9
|
-
};
|
|
10
|
-
export declare function parse_extxyz_lattice(comment: string): math.Matrix3x3 | undefined;
|
|
1
|
+
import type { TrajectoryFrame, TrajectoryType } from '../index';
|
|
11
2
|
export declare function parse_xyz_comment_metadata(comment: string): {
|
|
12
3
|
step?: number;
|
|
13
4
|
properties: Record<string, number>;
|
|
14
5
|
};
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
force_stats: ForceStats | null;
|
|
24
|
-
};
|
|
6
|
+
export declare function build_xyz_frame(lines: string[], frame: {
|
|
7
|
+
start: number;
|
|
8
|
+
num_atoms: number;
|
|
9
|
+
comment: string;
|
|
10
|
+
}, opts: {
|
|
11
|
+
frame_label: string;
|
|
12
|
+
default_step: number;
|
|
13
|
+
}): TrajectoryFrame;
|
|
25
14
|
export declare function parse_xyz_trajectory(content: string): TrajectoryType;
|
|
26
|
-
export {};
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import * as math from '../../math';
|
|
2
|
-
import {
|
|
2
|
+
import { coerce_elem_symbol } from '../../element';
|
|
3
|
+
import { calc_force_stats, create_trajectory_frame, iter_xyz_frames, } from '../helpers';
|
|
4
|
+
import { traj_warn } from './diagnostics';
|
|
3
5
|
// Resolve species/pos/forces column offsets from an extxyz Properties string of
|
|
4
6
|
// name:type:ncols triples (e.g. "species:S:1:pos:R:3:forces:R:3"), falling back
|
|
5
7
|
// to the conventional "symbol x y z" layout when absent or malformed
|
|
6
|
-
|
|
8
|
+
function parse_extxyz_columns(comment) {
|
|
7
9
|
const fields = /Properties\s*=\s*"?([^"\s]+)"?/i.exec(comment)?.[1].split(`:`) ?? [];
|
|
8
10
|
// Well-formed Properties is name:type:ncols triples; a non-multiple of 3 is malformed,
|
|
9
11
|
// so bail to the conventional default rather than trusting a partial layout
|
|
@@ -23,7 +25,7 @@ export function parse_extxyz_columns(comment) {
|
|
|
23
25
|
return { species_col, pos_col, forces_col, min_cols: Math.max(pos_col + 3, species_col + 1) };
|
|
24
26
|
}
|
|
25
27
|
// Parse Lattice="ax ay az bx by bz cx cy cz" from an extxyz comment line
|
|
26
|
-
|
|
28
|
+
function parse_extxyz_lattice(comment) {
|
|
27
29
|
const vals = /Lattice\s*=\s*"([^"]+)"/i.exec(comment)?.[1].trim().split(/\s+/).map(Number);
|
|
28
30
|
if (vals?.length !== 9 || !vals.every(Number.isFinite))
|
|
29
31
|
return undefined;
|
|
@@ -53,7 +55,7 @@ export function parse_xyz_comment_metadata(comment) {
|
|
|
53
55
|
// Parse num_atoms atom lines starting at lines[start], reading species/pos/forces from
|
|
54
56
|
// their Properties-declared column offsets; invalid atoms are skipped with a warning.
|
|
55
57
|
// force_stats holds raw forces plus max and RMS force magnitudes when forces are present.
|
|
56
|
-
|
|
58
|
+
function parse_xyz_atom_lines(lines, start, num_atoms, comment, frame_label) {
|
|
57
59
|
const { species_col, pos_col, forces_col, min_cols } = parse_extxyz_columns(comment);
|
|
58
60
|
const elements = [];
|
|
59
61
|
const positions = [];
|
|
@@ -64,13 +66,13 @@ export function parse_xyz_atom_lines(lines, start, num_atoms, comment, frame_lab
|
|
|
64
66
|
continue;
|
|
65
67
|
const pos = parts.slice(pos_col, pos_col + 3).map(parseFloat);
|
|
66
68
|
if (!pos.every(Number.isFinite)) {
|
|
67
|
-
|
|
69
|
+
traj_warn(`Skipping XYZ atom with invalid coordinates in ${frame_label} at line ${start + idx + 1}`);
|
|
68
70
|
continue;
|
|
69
71
|
}
|
|
70
72
|
const symbol = parts[species_col];
|
|
71
|
-
const element_symbol =
|
|
73
|
+
const element_symbol = coerce_elem_symbol(symbol);
|
|
72
74
|
if (!element_symbol) {
|
|
73
|
-
|
|
75
|
+
traj_warn(`Skipping XYZ atom with unknown element symbol "${symbol}" in ${frame_label}`);
|
|
74
76
|
continue;
|
|
75
77
|
}
|
|
76
78
|
elements.push(element_symbol);
|
|
@@ -81,36 +83,29 @@ export function parse_xyz_atom_lines(lines, start, num_atoms, comment, frame_lab
|
|
|
81
83
|
forces.push(force_vec);
|
|
82
84
|
}
|
|
83
85
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
86
|
+
const stats = calc_force_stats(forces);
|
|
87
|
+
return { elements, positions, force_stats: stats && { forces, ...stats } };
|
|
88
|
+
}
|
|
89
|
+
// Assemble a TrajectoryFrame from the XYZ frame starting at lines[start] (count line,
|
|
90
|
+
// comment line, atom lines). Shared by the eager parser and the indexed frame reader.
|
|
91
|
+
export function build_xyz_frame(lines, frame, opts) {
|
|
92
|
+
const { start, num_atoms, comment } = frame;
|
|
93
|
+
const { step, properties } = parse_xyz_comment_metadata(comment);
|
|
94
|
+
const lattice_matrix = parse_extxyz_lattice(comment);
|
|
95
|
+
const { elements, positions, force_stats } = parse_xyz_atom_lines(lines, start + 2, num_atoms, comment, opts.frame_label);
|
|
96
|
+
const metadata = { ...properties, ...force_stats };
|
|
97
|
+
if (lattice_matrix)
|
|
98
|
+
metadata.volume = math.calc_lattice_params(lattice_matrix).volume;
|
|
99
|
+
return create_trajectory_frame(positions, elements, lattice_matrix, lattice_matrix ? [true, true, true] : undefined, step ?? opts.default_step, metadata);
|
|
93
100
|
}
|
|
94
101
|
export function parse_xyz_trajectory(content) {
|
|
95
102
|
const lines = content.trim().split(/\r?\n/);
|
|
96
103
|
const frames = [];
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
const comment = lines[line_idx + 1] || ``;
|
|
105
|
-
const { step, properties } = parse_xyz_comment_metadata(comment);
|
|
106
|
-
const metadata = { ...properties };
|
|
107
|
-
const lattice_matrix = parse_extxyz_lattice(comment);
|
|
108
|
-
if (lattice_matrix)
|
|
109
|
-
metadata.volume = math.calc_lattice_params(lattice_matrix).volume;
|
|
110
|
-
const { elements, positions, force_stats } = parse_xyz_atom_lines(lines, line_idx + 2, num_atoms, comment, `frame ${frames.length}`);
|
|
111
|
-
Object.assign(metadata, force_stats);
|
|
112
|
-
frames.push(create_trajectory_frame(positions, elements, lattice_matrix, lattice_matrix ? [true, true, true] : undefined, step ?? frames.length, metadata));
|
|
113
|
-
line_idx += num_atoms + 2;
|
|
104
|
+
for (const frame of iter_xyz_frames(lines)) {
|
|
105
|
+
frames.push(build_xyz_frame(lines, frame, {
|
|
106
|
+
frame_label: `frame ${frames.length}`,
|
|
107
|
+
default_step: frames.length,
|
|
108
|
+
}));
|
|
114
109
|
}
|
|
115
110
|
return {
|
|
116
111
|
frames,
|
|
@@ -9,7 +9,6 @@ export interface PlotSeriesOptions {
|
|
|
9
9
|
default_visible_properties?: Set<string>;
|
|
10
10
|
}
|
|
11
11
|
export declare function generate_plot_series(trajectory: TrajectoryType, data_extractor: TrajectoryDataExtractor, options?: PlotSeriesOptions): DataSeries[];
|
|
12
|
-
export declare function toggle_series_visibility(series: DataSeries[], target_series_idx: number): DataSeries[];
|
|
13
12
|
export declare function should_hide_plot(trajectory: TrajectoryType | undefined, plot_series: DataSeries[], tolerance?: number): boolean;
|
|
14
13
|
export declare function generate_axis_labels(plot_series: DataSeries[]): {
|
|
15
14
|
y1: string;
|