matterviz 0.3.1 → 0.3.3

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 (358) hide show
  1. package/dist/EmptyState.svelte +10 -2
  2. package/dist/FilePicker.svelte +154 -96
  3. package/dist/Icon.svelte +20 -14
  4. package/dist/MillerIndexInput.svelte +27 -21
  5. package/dist/api/optimade.js +6 -6
  6. package/dist/app.css +216 -178
  7. package/dist/brillouin/BrillouinZone.svelte +299 -198
  8. package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
  9. package/dist/brillouin/BrillouinZoneControls.svelte +32 -5
  10. package/dist/brillouin/BrillouinZoneExportPane.svelte +74 -55
  11. package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +1 -1
  12. package/dist/brillouin/BrillouinZoneInfoPane.svelte +99 -68
  13. package/dist/brillouin/BrillouinZoneScene.svelte +277 -165
  14. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
  15. package/dist/brillouin/BrillouinZoneTooltip.svelte +17 -7
  16. package/dist/brillouin/compute.js +11 -6
  17. package/dist/chempot-diagram/ChemPotDiagram.svelte +327 -0
  18. package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +13 -0
  19. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +847 -0
  20. package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +16 -0
  21. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +3194 -0
  22. package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +16 -0
  23. package/dist/chempot-diagram/ChemPotScene3D.svelte +11 -0
  24. package/dist/chempot-diagram/ChemPotScene3D.svelte.d.ts +7 -0
  25. package/dist/chempot-diagram/async-compute.svelte.d.ts +3 -0
  26. package/dist/chempot-diagram/async-compute.svelte.js +77 -0
  27. package/dist/chempot-diagram/chempot-worker.d.ts +1 -0
  28. package/dist/chempot-diagram/chempot-worker.js +11 -0
  29. package/dist/chempot-diagram/color.d.ts +10 -0
  30. package/dist/chempot-diagram/color.js +32 -0
  31. package/dist/chempot-diagram/compute.d.ts +48 -0
  32. package/dist/chempot-diagram/compute.js +812 -0
  33. package/dist/chempot-diagram/index.d.ts +6 -0
  34. package/dist/chempot-diagram/index.js +6 -0
  35. package/dist/chempot-diagram/pointer.d.ts +16 -0
  36. package/dist/chempot-diagram/pointer.js +40 -0
  37. package/dist/chempot-diagram/temperature.d.ts +15 -0
  38. package/dist/chempot-diagram/temperature.js +36 -0
  39. package/dist/chempot-diagram/types.d.ts +86 -0
  40. package/dist/chempot-diagram/types.js +28 -0
  41. package/dist/colors/index.d.ts +3 -1
  42. package/dist/colors/index.js +9 -3
  43. package/dist/composition/BarChart.svelte +141 -77
  44. package/dist/composition/BubbleChart.svelte +107 -52
  45. package/dist/composition/Composition.svelte +100 -79
  46. package/dist/composition/Formula.svelte +108 -62
  47. package/dist/composition/FormulaFilter.svelte +973 -353
  48. package/dist/composition/FormulaFilter.svelte.d.ts +35 -1
  49. package/dist/composition/PieChart.svelte +199 -99
  50. package/dist/composition/PieChart.svelte.d.ts +1 -1
  51. package/dist/composition/format.d.ts +5 -0
  52. package/dist/composition/format.js +20 -3
  53. package/dist/composition/parse.js +14 -9
  54. package/dist/convex-hull/ConvexHull.svelte +93 -38
  55. package/dist/convex-hull/ConvexHull2D.svelte +551 -393
  56. package/dist/convex-hull/ConvexHull3D.svelte +1303 -825
  57. package/dist/convex-hull/ConvexHull4D.svelte +1012 -686
  58. package/dist/convex-hull/ConvexHullControls.svelte +115 -28
  59. package/dist/convex-hull/ConvexHullInfoPane.svelte +29 -3
  60. package/dist/convex-hull/ConvexHullStats.svelte +821 -249
  61. package/dist/convex-hull/ConvexHullStats.svelte.d.ts +6 -1
  62. package/dist/convex-hull/ConvexHullTooltip.svelte +41 -16
  63. package/dist/convex-hull/GasPressureControls.svelte +104 -61
  64. package/dist/convex-hull/StructurePopup.svelte +25 -4
  65. package/dist/convex-hull/TemperatureSlider.svelte +45 -25
  66. package/dist/convex-hull/barycentric-coords.js +13 -7
  67. package/dist/convex-hull/demo-temperature.d.ts +6 -0
  68. package/dist/convex-hull/demo-temperature.js +40 -0
  69. package/dist/convex-hull/gas-thermodynamics.js +17 -12
  70. package/dist/convex-hull/helpers.d.ts +10 -1
  71. package/dist/convex-hull/helpers.js +79 -38
  72. package/dist/convex-hull/index.d.ts +1 -0
  73. package/dist/convex-hull/index.js +1 -0
  74. package/dist/convex-hull/thermodynamics.d.ts +8 -21
  75. package/dist/convex-hull/thermodynamics.js +163 -69
  76. package/dist/convex-hull/types.d.ts +12 -12
  77. package/dist/convex-hull/types.js +0 -12
  78. package/dist/coordination/CoordinationBarPlot.svelte +232 -176
  79. package/dist/element/BohrAtom.svelte +56 -13
  80. package/dist/element/ElementHeading.svelte +7 -2
  81. package/dist/element/ElementPhoto.svelte +15 -9
  82. package/dist/element/ElementStats.svelte +10 -4
  83. package/dist/element/ElementTile.svelte +137 -73
  84. package/dist/element/Nucleus.svelte +39 -11
  85. package/dist/element/data.js +2 -14
  86. package/dist/element/data.json.gz +0 -0
  87. package/dist/element/types.d.ts +1 -0
  88. package/dist/feedback/ClickFeedback.svelte +16 -5
  89. package/dist/feedback/DragOverlay.svelte +10 -2
  90. package/dist/feedback/Spinner.svelte +4 -2
  91. package/dist/feedback/StatusMessage.svelte +8 -2
  92. package/dist/fermi-surface/FermiSlice.svelte +118 -88
  93. package/dist/fermi-surface/FermiSurface.svelte +336 -239
  94. package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
  95. package/dist/fermi-surface/FermiSurfaceControls.svelte +113 -46
  96. package/dist/fermi-surface/FermiSurfaceScene.svelte +536 -343
  97. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
  98. package/dist/fermi-surface/FermiSurfaceTooltip.svelte +14 -5
  99. package/dist/fermi-surface/compute.js +16 -20
  100. package/dist/fermi-surface/parse.js +37 -33
  101. package/dist/fermi-surface/symmetry.js +2 -7
  102. package/dist/fermi-surface/types.d.ts +3 -5
  103. package/dist/heatmap-matrix/HeatmapMatrix.svelte +1527 -0
  104. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +110 -0
  105. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +225 -0
  106. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +30 -0
  107. package/dist/heatmap-matrix/index.d.ts +53 -0
  108. package/dist/heatmap-matrix/index.js +100 -0
  109. package/dist/heatmap-matrix/shared.d.ts +2 -0
  110. package/dist/heatmap-matrix/shared.js +4 -0
  111. package/dist/icons.d.ts +111 -0
  112. package/dist/icons.js +158 -0
  113. package/dist/index.d.ts +5 -2
  114. package/dist/index.js +5 -2
  115. package/dist/io/decompress.js +1 -1
  116. package/dist/io/export.d.ts +3 -0
  117. package/dist/io/export.js +138 -140
  118. package/dist/io/file-drop.d.ts +7 -0
  119. package/dist/io/file-drop.js +43 -0
  120. package/dist/io/index.d.ts +2 -2
  121. package/dist/io/index.js +2 -112
  122. package/dist/io/is-binary.js +2 -3
  123. package/dist/io/types.d.ts +1 -0
  124. package/dist/io/url-drop.d.ts +2 -0
  125. package/dist/io/url-drop.js +117 -0
  126. package/dist/isosurface/Isosurface.svelte +220 -110
  127. package/dist/isosurface/IsosurfaceControls.svelte +65 -28
  128. package/dist/isosurface/parse.js +104 -56
  129. package/dist/isosurface/slice.d.ts +2 -1
  130. package/dist/isosurface/slice.js +8 -13
  131. package/dist/isosurface/types.d.ts +14 -1
  132. package/dist/isosurface/types.js +152 -5
  133. package/dist/labels.d.ts +2 -1
  134. package/dist/labels.js +12 -8
  135. package/dist/layout/FullscreenToggle.svelte +11 -2
  136. package/dist/layout/InfoCard.svelte +38 -6
  137. package/dist/layout/InfoTag.svelte +125 -94
  138. package/dist/layout/PropertyFilter.svelte +82 -37
  139. package/dist/layout/SettingsSection.svelte +85 -55
  140. package/dist/layout/SubpageGrid.svelte +82 -0
  141. package/dist/layout/SubpageGrid.svelte.d.ts +14 -0
  142. package/dist/layout/index.d.ts +1 -0
  143. package/dist/layout/index.js +1 -0
  144. package/dist/layout/json-tree/JsonNode.svelte +266 -223
  145. package/dist/layout/json-tree/JsonTree.svelte +516 -429
  146. package/dist/layout/json-tree/JsonTree.svelte.d.ts +1 -1
  147. package/dist/layout/json-tree/JsonValue.svelte +281 -173
  148. package/dist/layout/json-tree/types.d.ts +10 -2
  149. package/dist/layout/json-tree/utils.d.ts +2 -0
  150. package/dist/layout/json-tree/utils.js +37 -2
  151. package/dist/marching-cubes.js +25 -2
  152. package/dist/math.d.ts +20 -17
  153. package/dist/math.js +474 -57
  154. package/dist/overlays/ContextMenu.svelte +66 -40
  155. package/dist/overlays/DraggablePane.svelte +331 -154
  156. package/dist/overlays/DraggablePane.svelte.d.ts +2 -0
  157. package/dist/periodic-table/PeriodicTable.svelte +278 -145
  158. package/dist/periodic-table/PeriodicTableControls.svelte +178 -128
  159. package/dist/periodic-table/PropertySelect.svelte +25 -7
  160. package/dist/periodic-table/TableInset.svelte +8 -3
  161. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +559 -267
  162. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -2
  163. package/dist/phase-diagram/PhaseDiagramControls.svelte +131 -51
  164. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +3 -2
  165. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +126 -0
  166. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +15 -0
  167. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +160 -110
  168. package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +8 -1
  169. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +217 -86
  170. package/dist/phase-diagram/PhaseDiagramTooltip.svelte.d.ts +6 -3
  171. package/dist/phase-diagram/TdbInfoPanel.svelte +28 -4
  172. package/dist/phase-diagram/build-diagram.js +9 -9
  173. package/dist/phase-diagram/colors.js +1 -3
  174. package/dist/phase-diagram/index.d.ts +2 -0
  175. package/dist/phase-diagram/index.js +2 -0
  176. package/dist/phase-diagram/parse.js +10 -9
  177. package/dist/phase-diagram/svg-to-diagram.d.ts +2 -0
  178. package/dist/phase-diagram/svg-to-diagram.js +869 -0
  179. package/dist/phase-diagram/types.d.ts +10 -0
  180. package/dist/phase-diagram/utils.d.ts +8 -4
  181. package/dist/phase-diagram/utils.js +219 -74
  182. package/dist/plot/AxisLabel.svelte +51 -0
  183. package/dist/plot/AxisLabel.svelte.d.ts +16 -0
  184. package/dist/plot/BarPlot.svelte +1461 -768
  185. package/dist/plot/BarPlot.svelte.d.ts +3 -3
  186. package/dist/plot/BarPlotControls.svelte +33 -6
  187. package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
  188. package/dist/plot/ColorBar.svelte +533 -383
  189. package/dist/plot/ColorBar.svelte.d.ts +1 -1
  190. package/dist/plot/ColorScaleSelect.svelte +28 -7
  191. package/dist/plot/ElementScatter.svelte +38 -16
  192. package/dist/plot/FillArea.svelte +152 -92
  193. package/dist/plot/Histogram.svelte +1162 -709
  194. package/dist/plot/Histogram.svelte.d.ts +1 -1
  195. package/dist/plot/HistogramControls.svelte +81 -18
  196. package/dist/plot/HistogramControls.svelte.d.ts +6 -2
  197. package/dist/plot/InteractiveAxisLabel.svelte +34 -11
  198. package/dist/plot/InteractiveAxisLabel.svelte.d.ts +1 -1
  199. package/dist/plot/Line.svelte +63 -28
  200. package/dist/plot/PlotControls.svelte +221 -96
  201. package/dist/plot/PlotControls.svelte.d.ts +1 -1
  202. package/dist/plot/PlotLegend.svelte +174 -91
  203. package/dist/plot/PlotTooltip.svelte +45 -6
  204. package/dist/plot/PortalSelect.svelte +175 -146
  205. package/dist/plot/ReferenceLine.svelte +77 -22
  206. package/dist/plot/ReferenceLine.svelte.d.ts +1 -0
  207. package/dist/plot/ReferenceLine3D.svelte +132 -107
  208. package/dist/plot/ReferencePlane.svelte +146 -123
  209. package/dist/plot/ScatterPlot.svelte +1880 -1156
  210. package/dist/plot/ScatterPlot.svelte.d.ts +3 -3
  211. package/dist/plot/ScatterPlot3D.svelte +256 -131
  212. package/dist/plot/ScatterPlot3D.svelte.d.ts +2 -2
  213. package/dist/plot/ScatterPlot3DControls.svelte +300 -297
  214. package/dist/plot/ScatterPlot3DControls.svelte.d.ts +2 -1
  215. package/dist/plot/ScatterPlot3DScene.svelte +608 -406
  216. package/dist/plot/ScatterPlot3DScene.svelte.d.ts +2 -2
  217. package/dist/plot/ScatterPlotControls.svelte +150 -70
  218. package/dist/plot/ScatterPlotControls.svelte.d.ts +1 -1
  219. package/dist/plot/ScatterPoint.svelte +98 -26
  220. package/dist/plot/ScatterPoint.svelte.d.ts +1 -0
  221. package/dist/plot/SpacegroupBarPlot.svelte +142 -85
  222. package/dist/plot/Surface3D.svelte +159 -108
  223. package/dist/plot/ZeroLines.svelte +96 -0
  224. package/dist/plot/ZeroLines.svelte.d.ts +32 -0
  225. package/dist/plot/ZoomRect.svelte +23 -0
  226. package/dist/plot/ZoomRect.svelte.d.ts +8 -0
  227. package/dist/plot/axis-utils.d.ts +1 -1
  228. package/dist/plot/axis-utils.js +1 -3
  229. package/dist/plot/data-cleaning.js +12 -28
  230. package/dist/plot/data-transform.js +2 -1
  231. package/dist/plot/fill-utils.js +2 -0
  232. package/dist/plot/index.d.ts +6 -2
  233. package/dist/plot/index.js +6 -2
  234. package/dist/plot/interactions.d.ts +8 -10
  235. package/dist/plot/interactions.js +2 -3
  236. package/dist/plot/layout.d.ts +11 -2
  237. package/dist/plot/layout.js +44 -17
  238. package/dist/plot/reference-line.d.ts +5 -22
  239. package/dist/plot/reference-line.js +12 -84
  240. package/dist/plot/scales.js +24 -36
  241. package/dist/plot/types.d.ts +53 -40
  242. package/dist/plot/types.js +12 -7
  243. package/dist/plot/utils/label-placement.d.ts +32 -15
  244. package/dist/plot/utils/label-placement.js +227 -63
  245. package/dist/plot/utils/series-visibility.js +2 -3
  246. package/dist/plot/utils.d.ts +1 -0
  247. package/dist/plot/utils.js +14 -0
  248. package/dist/rdf/RdfPlot.svelte +173 -132
  249. package/dist/rdf/calc-rdf.js +4 -5
  250. package/dist/sanitize.d.ts +4 -0
  251. package/dist/sanitize.js +107 -0
  252. package/dist/settings.d.ts +21 -6
  253. package/dist/settings.js +63 -19
  254. package/dist/spectral/Bands.svelte +963 -412
  255. package/dist/spectral/Bands.svelte.d.ts +22 -2
  256. package/dist/spectral/BandsAndDos.svelte +90 -49
  257. package/dist/spectral/BrillouinBandsDos.svelte +151 -93
  258. package/dist/spectral/Dos.svelte +389 -258
  259. package/dist/spectral/helpers.d.ts +23 -1
  260. package/dist/spectral/helpers.js +119 -51
  261. package/dist/spectral/types.d.ts +2 -0
  262. package/dist/state.svelte.d.ts +1 -1
  263. package/dist/state.svelte.js +3 -2
  264. package/dist/structure/Arrow.svelte +59 -20
  265. package/dist/structure/AtomLegend.svelte +231 -129
  266. package/dist/structure/AtomLegend.svelte.d.ts +1 -1
  267. package/dist/structure/Bond.svelte +73 -47
  268. package/dist/structure/CanvasTooltip.svelte +10 -2
  269. package/dist/structure/CellSelect.svelte +148 -51
  270. package/dist/structure/Cylinder.svelte +33 -17
  271. package/dist/structure/Lattice.svelte +88 -33
  272. package/dist/structure/Structure.svelte +1077 -821
  273. package/dist/structure/Structure.svelte.d.ts +1 -1
  274. package/dist/structure/StructureControls.svelte +373 -139
  275. package/dist/structure/StructureControls.svelte.d.ts +1 -1
  276. package/dist/structure/StructureExportPane.svelte +124 -89
  277. package/dist/structure/StructureExportPane.svelte.d.ts +1 -1
  278. package/dist/structure/StructureInfoPane.svelte +304 -231
  279. package/dist/structure/StructureScene.svelte +919 -445
  280. package/dist/structure/StructureScene.svelte.d.ts +16 -7
  281. package/dist/structure/atom-properties.d.ts +6 -2
  282. package/dist/structure/atom-properties.js +42 -29
  283. package/dist/structure/bonding.js +6 -7
  284. package/dist/structure/export.js +22 -34
  285. package/dist/structure/ferrox-wasm-types.d.ts +3 -2
  286. package/dist/structure/ferrox-wasm-types.js +0 -3
  287. package/dist/structure/ferrox-wasm.d.ts +3 -2
  288. package/dist/structure/ferrox-wasm.js +2 -3
  289. package/dist/structure/index.d.ts +16 -0
  290. package/dist/structure/index.js +88 -6
  291. package/dist/structure/measure.d.ts +2 -2
  292. package/dist/structure/measure.js +4 -44
  293. package/dist/structure/parse.js +130 -155
  294. package/dist/structure/partial-occupancy.d.ts +25 -0
  295. package/dist/structure/partial-occupancy.js +99 -0
  296. package/dist/structure/pbc.d.ts +1 -0
  297. package/dist/structure/pbc.js +16 -6
  298. package/dist/structure/supercell.d.ts +2 -2
  299. package/dist/structure/supercell.js +12 -22
  300. package/dist/structure/validation.js +5 -3
  301. package/dist/symmetry/SymmetryStats.svelte +94 -37
  302. package/dist/symmetry/WyckoffTable.svelte +42 -14
  303. package/dist/symmetry/cell-transform.js +5 -3
  304. package/dist/symmetry/index.d.ts +7 -4
  305. package/dist/symmetry/index.js +87 -21
  306. package/dist/symmetry/spacegroups.js +148 -148
  307. package/dist/table/HeatmapTable.svelte +1112 -516
  308. package/dist/table/HeatmapTable.svelte.d.ts +12 -1
  309. package/dist/table/ToggleMenu.svelte +125 -90
  310. package/dist/table/index.d.ts +2 -0
  311. package/dist/table/index.js +2 -4
  312. package/dist/theme/ThemeControl.svelte +21 -12
  313. package/dist/time.js +4 -1
  314. package/dist/tooltip/TooltipContent.svelte +33 -8
  315. package/dist/trajectory/Trajectory.svelte +889 -687
  316. package/dist/trajectory/TrajectoryError.svelte +14 -3
  317. package/dist/trajectory/TrajectoryExportPane.svelte +148 -90
  318. package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +1 -1
  319. package/dist/trajectory/TrajectoryInfoPane.svelte +272 -143
  320. package/dist/trajectory/constants.d.ts +6 -0
  321. package/dist/trajectory/constants.js +7 -0
  322. package/dist/trajectory/extract.js +13 -31
  323. package/dist/trajectory/format-detect.d.ts +9 -0
  324. package/dist/trajectory/format-detect.js +76 -0
  325. package/dist/trajectory/frame-reader.d.ts +17 -0
  326. package/dist/trajectory/frame-reader.js +332 -0
  327. package/dist/trajectory/helpers.d.ts +14 -0
  328. package/dist/trajectory/helpers.js +172 -0
  329. package/dist/trajectory/index.d.ts +1 -0
  330. package/dist/trajectory/index.js +23 -14
  331. package/dist/trajectory/parse/ase.d.ts +2 -0
  332. package/dist/trajectory/parse/ase.js +77 -0
  333. package/dist/trajectory/parse/hdf5.d.ts +2 -0
  334. package/dist/trajectory/parse/hdf5.js +129 -0
  335. package/dist/trajectory/parse/index.d.ts +12 -0
  336. package/dist/trajectory/parse/index.js +299 -0
  337. package/dist/trajectory/parse/lammps.d.ts +5 -0
  338. package/dist/trajectory/parse/lammps.js +179 -0
  339. package/dist/trajectory/parse/vasp.d.ts +2 -0
  340. package/dist/trajectory/parse/vasp.js +68 -0
  341. package/dist/trajectory/parse/xyz.d.ts +2 -0
  342. package/dist/trajectory/parse/xyz.js +110 -0
  343. package/dist/trajectory/plotting.js +13 -8
  344. package/dist/trajectory/types.d.ts +11 -0
  345. package/dist/trajectory/types.js +1 -0
  346. package/dist/utils.d.ts +3 -0
  347. package/dist/utils.js +17 -0
  348. package/dist/xrd/XrdPlot.svelte +337 -245
  349. package/dist/xrd/broadening.js +14 -9
  350. package/dist/xrd/calc-xrd.js +12 -19
  351. package/dist/xrd/parse.d.ts +1 -1
  352. package/dist/xrd/parse.js +17 -17
  353. package/package.json +103 -101
  354. package/readme.md +4 -4
  355. package/dist/trajectory/parse.d.ts +0 -42
  356. package/dist/trajectory/parse.js +0 -1267
  357. /package/dist/element/{data.json.d.ts → data.json.gz.d.ts} +0 -0
  358. /package/dist/theme/{themes.js → themes.mjs} +0 -0
@@ -0,0 +1,76 @@
1
+ // Format detection for trajectory files
2
+ import { COMPRESSION_EXTENSIONS_REGEX, CONFIG_DIRS_REGEX, MD_SIM_EXCLUDE_REGEX, TRAJ_EXTENSIONS_REGEX, TRAJ_FALLBACK_EXTENSIONS_REGEX, TRAJ_KEYWORDS_SIMPLE_REGEX, XDATCAR_REGEX, } from '../constants';
3
+ import { count_xyz_frames } from './helpers';
4
+ export function strip_compression_extensions(filename) {
5
+ let base_name = filename.toLowerCase();
6
+ while (COMPRESSION_EXTENSIONS_REGEX.test(base_name)) {
7
+ base_name = base_name.replace(COMPRESSION_EXTENSIONS_REGEX, ``);
8
+ }
9
+ return base_name;
10
+ }
11
+ // Unified format detection
12
+ export const FORMAT_PATTERNS = {
13
+ ase: (data, filename) => {
14
+ const base_name = filename ? strip_compression_extensions(filename) : undefined;
15
+ if (!base_name?.endsWith(`.traj`) || !(data instanceof ArrayBuffer)) {
16
+ return false;
17
+ }
18
+ const view = new Uint8Array(data.slice(0, 24));
19
+ return [0x2d, 0x20, 0x6f, 0x66, 0x20, 0x55, 0x6c, 0x6d].every((byte, idx) => view[idx] === byte);
20
+ },
21
+ hdf5: (data, filename) => {
22
+ const base_name = filename ? strip_compression_extensions(filename) : undefined;
23
+ const has_ext = base_name?.match(/\.(h5|hdf5)$/);
24
+ if (!has_ext || !(data instanceof ArrayBuffer) || data.byteLength < 8)
25
+ return false;
26
+ const signature = new Uint8Array(data.slice(0, 8));
27
+ return [0x89, 0x48, 0x44, 0x46, 0x0d, 0x0a, 0x1a, 0x0a].every((b, idx) => signature[idx] === b);
28
+ },
29
+ vasp: (data, filename) => {
30
+ const basename = filename?.toLowerCase().split(`/`).pop() || ``;
31
+ if (basename === `xdatcar` || basename.startsWith(`xdatcar`))
32
+ return true;
33
+ const lines = data.trim().split(/\r?\n/);
34
+ return (lines.length >= 10 &&
35
+ lines.some((line) => line.includes(`Direct configuration=`)) &&
36
+ !isNaN(parseFloat(lines[1])) &&
37
+ lines.slice(2, 5).every((line) => line.trim().split(/\s+/).length === 3));
38
+ },
39
+ xyz_multi: (data, filename) => {
40
+ const base = filename ? strip_compression_extensions(filename) : ``;
41
+ if (!/\.(xyz|extxyz)$/.test(base))
42
+ return false;
43
+ return count_xyz_frames(data) >= 2;
44
+ },
45
+ lammpstrj: (data, filename) => {
46
+ const base = filename ? strip_compression_extensions(filename) : ``;
47
+ if (!base.endsWith(`.lammpstrj`))
48
+ return false;
49
+ return data.includes(`ITEM: TIMESTEP`) && data.includes(`ITEM: ATOMS`);
50
+ },
51
+ };
52
+ // Check if file is a trajectory (supports both filename-only and content-based detection)
53
+ export function is_trajectory_file(filename, content) {
54
+ if (CONFIG_DIRS_REGEX.test(filename))
55
+ return false;
56
+ const base_name = strip_compression_extensions(filename);
57
+ // For xyz/extxyz files, use content-based detection if available
58
+ if (/\.(xyz|extxyz)$/i.test(base_name)) {
59
+ if (content)
60
+ return count_xyz_frames(content) >= 2;
61
+ return TRAJ_KEYWORDS_SIMPLE_REGEX.test(base_name);
62
+ }
63
+ // Always detect these specific trajectory formats
64
+ if (TRAJ_EXTENSIONS_REGEX.test(base_name) || XDATCAR_REGEX.test(base_name))
65
+ return true;
66
+ // Special exclusion for generic md_simulation pattern with certain extensions
67
+ if (MD_SIM_EXCLUDE_REGEX.test(base_name))
68
+ return false;
69
+ // For .h5/.hdf5 files, require trajectory keywords
70
+ if (/\.(h5|hdf5)$/i.test(base_name)) {
71
+ return TRAJ_KEYWORDS_SIMPLE_REGEX.test(base_name);
72
+ }
73
+ // For other extensions, require both keywords and specific extensions
74
+ return (TRAJ_KEYWORDS_SIMPLE_REGEX.test(base_name) &&
75
+ TRAJ_FALLBACK_EXTENSIONS_REGEX.test(base_name));
76
+ }
@@ -0,0 +1,17 @@
1
+ import type { FrameIndex, FrameLoader, ParseProgress, TrajectoryFrame, TrajectoryMetadata } from './index';
2
+ export declare class TrajFrameReader implements FrameLoader {
3
+ private readonly format;
4
+ private global_numbers?;
5
+ constructor(filename: string);
6
+ get_total_frames(data: string | ArrayBuffer): Promise<number>;
7
+ build_frame_index(data: string | ArrayBuffer, sample_rate: number, on_progress?: (progress: ParseProgress) => void): Promise<FrameIndex[]>;
8
+ load_frame(data: string | ArrayBuffer, frame_number: number): Promise<TrajectoryFrame | null>;
9
+ extract_plot_metadata(data: string | ArrayBuffer, options?: {
10
+ sample_rate?: number;
11
+ properties?: string[];
12
+ }, on_progress?: (progress: ParseProgress) => void): Promise<TrajectoryMetadata[]>;
13
+ private load_xyz_frame;
14
+ private load_ase_frame;
15
+ private parse_xyz_metadata;
16
+ private parse_ase_metadata;
17
+ }
@@ -0,0 +1,332 @@
1
+ import * as math from '../math';
2
+ import { MAX_METADATA_SIZE } from './constants';
3
+ import { coerce_element_symbol, convert_atomic_numbers, count_xyz_frames, create_trajectory_frame, read_ndarray_from_view, validate_3x3_matrix, } from './helpers';
4
+ import { strip_compression_extensions } from './format-detect';
5
+ export class TrajFrameReader {
6
+ format;
7
+ global_numbers;
8
+ constructor(filename) {
9
+ const base_filename = strip_compression_extensions(filename);
10
+ this.format = base_filename.endsWith(`.traj`) ? `ase` : `xyz`;
11
+ }
12
+ async get_total_frames(data) {
13
+ if (this.format === `xyz`) {
14
+ if (data instanceof ArrayBuffer)
15
+ throw new Error(`XYZ loader requires text data`);
16
+ return count_xyz_frames(data);
17
+ }
18
+ if (!(data instanceof ArrayBuffer))
19
+ throw new Error(`ASE loader requires binary data`);
20
+ const view = new DataView(data);
21
+ return Number(view.getBigInt64(32, true));
22
+ }
23
+ async build_frame_index(data, sample_rate, on_progress) {
24
+ const total_frames = await this.get_total_frames(data);
25
+ const frame_index = [];
26
+ if (this.format === `xyz`) {
27
+ const data_str = data;
28
+ const lines = data_str.trim().split(/\r?\n/);
29
+ const encoder = new TextEncoder();
30
+ const newline_sequence = data_str.includes(`\r\n`) ? `\r\n` : `\n`;
31
+ const newline_byte_len = encoder.encode(newline_sequence).length;
32
+ let [current_frame, line_idx, byte_offset] = [0, 0, 0];
33
+ while (line_idx < lines.length && current_frame < total_frames) {
34
+ if (!lines[line_idx]?.trim()) {
35
+ byte_offset += encoder.encode(lines[line_idx]).length + newline_byte_len;
36
+ line_idx++;
37
+ continue;
38
+ }
39
+ const num_atoms = parseInt(lines[line_idx].trim(), 10);
40
+ if (isNaN(num_atoms) || num_atoms <= 0 || line_idx + num_atoms + 1 >= lines.length) {
41
+ byte_offset += encoder.encode(lines[line_idx]).length + newline_byte_len;
42
+ line_idx++;
43
+ continue;
44
+ }
45
+ if (current_frame % sample_rate === 0) {
46
+ frame_index.push({
47
+ frame_number: current_frame,
48
+ byte_offset,
49
+ estimated_size: 0,
50
+ });
51
+ }
52
+ const frame_start = line_idx;
53
+ line_idx += 2 + num_atoms;
54
+ let frame_size = 0;
55
+ for (let idx = frame_start; idx < line_idx; idx++) {
56
+ frame_size += encoder.encode(lines[idx]).length + newline_byte_len;
57
+ }
58
+ if (current_frame % sample_rate === 0) {
59
+ frame_index[frame_index.length - 1].estimated_size = frame_size;
60
+ }
61
+ byte_offset += frame_size;
62
+ current_frame++;
63
+ if (on_progress && current_frame % 1000 === 0) {
64
+ on_progress({
65
+ current: (current_frame / total_frames) * 100,
66
+ total: 100,
67
+ stage: `Indexing: ${current_frame}`,
68
+ });
69
+ }
70
+ }
71
+ }
72
+ else {
73
+ const view = new DataView(data);
74
+ const offsets_pos = Number(view.getBigInt64(40, true));
75
+ for (let idx = 0; idx < total_frames; idx += sample_rate) {
76
+ const frame_offset = Number(view.getBigInt64(offsets_pos + idx * 8, true));
77
+ frame_index.push({
78
+ frame_number: idx,
79
+ byte_offset: frame_offset,
80
+ estimated_size: 0,
81
+ });
82
+ if (on_progress && idx % 10000 === 0) {
83
+ on_progress({
84
+ current: (idx / total_frames) * 100,
85
+ total: 100,
86
+ stage: `Indexing ASE: ${idx}`,
87
+ });
88
+ }
89
+ }
90
+ }
91
+ return frame_index;
92
+ }
93
+ async load_frame(data, frame_number) {
94
+ const actual_data_type = data instanceof ArrayBuffer ? `ArrayBuffer` : typeof data;
95
+ if (this.format === `xyz`) {
96
+ if (typeof data !== `string`) {
97
+ throw new TypeError(`load_frame expected string data for xyz format, received ${actual_data_type}`);
98
+ }
99
+ return this.load_xyz_frame(data, frame_number);
100
+ }
101
+ if (!(data instanceof ArrayBuffer)) {
102
+ throw new TypeError(`load_frame expected ArrayBuffer data for ase format, received ${actual_data_type}`);
103
+ }
104
+ return this.load_ase_frame(data, frame_number);
105
+ }
106
+ async extract_plot_metadata(data, options, on_progress) {
107
+ const { sample_rate = 1, properties } = options || {};
108
+ const metadata_list = [];
109
+ const total_frames = await this.get_total_frames(data);
110
+ if (this.format === `xyz`) {
111
+ const lines = data.trim().split(/\r?\n/);
112
+ let [current_frame, line_idx] = [0, 0];
113
+ while (line_idx < lines.length && current_frame < total_frames) {
114
+ if (!lines[line_idx]?.trim()) {
115
+ line_idx++;
116
+ continue;
117
+ }
118
+ const num_atoms = parseInt(lines[line_idx].trim(), 10);
119
+ if (isNaN(num_atoms) || num_atoms <= 0 || line_idx + num_atoms + 1 >= lines.length) {
120
+ line_idx++;
121
+ continue;
122
+ }
123
+ if (current_frame % sample_rate === 0) {
124
+ const comment = lines[line_idx + 1] || ``;
125
+ let frame_metadata = null;
126
+ try {
127
+ frame_metadata = this.parse_xyz_metadata(comment, current_frame);
128
+ }
129
+ catch (error) {
130
+ console.warn(`Failed to parse XYZ metadata for frame ${current_frame} at line ${line_idx + 1}:`, error);
131
+ }
132
+ if (frame_metadata && properties) {
133
+ const filtered = Object.fromEntries(Object.entries(frame_metadata.properties).filter(([key]) => properties.includes(key)));
134
+ frame_metadata.properties = filtered;
135
+ }
136
+ if (frame_metadata)
137
+ metadata_list.push(frame_metadata);
138
+ }
139
+ line_idx += 2 + num_atoms;
140
+ current_frame++;
141
+ if (on_progress && current_frame % 5000 === 0) {
142
+ on_progress({
143
+ current: (current_frame / total_frames) * 100,
144
+ total: 100,
145
+ stage: `Extracting: ${current_frame}`,
146
+ });
147
+ }
148
+ }
149
+ }
150
+ else if (this.format === `ase`) {
151
+ const view = new DataView(data);
152
+ const n_items = Number(view.getBigInt64(32, true));
153
+ const offsets_pos = Number(view.getBigInt64(40, true));
154
+ for (let idx = 0; idx < n_items; idx += sample_rate) {
155
+ try {
156
+ const frame_offset = Number(view.getBigInt64(offsets_pos + idx * 8, true));
157
+ const json_length = Number(view.getBigInt64(frame_offset, true));
158
+ if (json_length > MAX_METADATA_SIZE) {
159
+ console.warn(`Skipping large frame ${idx}: ${Math.round(json_length / 1024 / 1024)}MB`);
160
+ continue;
161
+ }
162
+ const frame_data = JSON.parse(new TextDecoder().decode(new Uint8Array(data, frame_offset + 8, json_length)));
163
+ const frame_metadata = this.parse_ase_metadata(frame_data, idx);
164
+ if (properties) {
165
+ const filtered = Object.fromEntries(Object.entries(frame_metadata.properties).filter(([key]) => properties.includes(key)));
166
+ frame_metadata.properties = filtered;
167
+ }
168
+ metadata_list.push(frame_metadata);
169
+ if (on_progress && idx % 5000 === 0) {
170
+ on_progress({
171
+ current: (idx / n_items) * 100,
172
+ total: 100,
173
+ stage: `Extracting ASE: ${idx}/${n_items}`,
174
+ });
175
+ }
176
+ }
177
+ catch (error) {
178
+ console.warn(`Failed to extract metadata from ASE frame ${idx}:`, error);
179
+ }
180
+ }
181
+ }
182
+ return metadata_list;
183
+ }
184
+ load_xyz_frame(data, frame_number) {
185
+ const lines = data.trim().split(/\r?\n/);
186
+ let [current_frame, line_idx] = [0, 0];
187
+ while (line_idx < lines.length && current_frame < frame_number) {
188
+ if (!lines[line_idx]?.trim()) {
189
+ line_idx++;
190
+ continue;
191
+ }
192
+ const num_atoms = parseInt(lines[line_idx].trim(), 10);
193
+ if (isNaN(num_atoms) || num_atoms <= 0) {
194
+ line_idx++;
195
+ continue;
196
+ }
197
+ line_idx += 2 + num_atoms;
198
+ current_frame++;
199
+ }
200
+ if (line_idx >= lines.length)
201
+ return null;
202
+ const num_atoms = parseInt(lines[line_idx].trim(), 10);
203
+ if (isNaN(num_atoms) || line_idx + num_atoms + 1 >= lines.length)
204
+ return null;
205
+ const comment = lines[line_idx + 1] || ``;
206
+ const positions = [];
207
+ const elements = [];
208
+ for (let idx = 0; idx < num_atoms; idx++) {
209
+ const parts = lines[line_idx + 2 + idx]?.trim().split(/\s+/);
210
+ if (parts?.length >= 4) {
211
+ const x_coord = parseFloat(parts[1]);
212
+ const y_coord = parseFloat(parts[2]);
213
+ const z_coord = parseFloat(parts[3]);
214
+ if (!Number.isFinite(x_coord) ||
215
+ !Number.isFinite(y_coord) ||
216
+ !Number.isFinite(z_coord)) {
217
+ console.warn(`Skipping XYZ atom with invalid coordinates in indexed frame ${frame_number} at line ${line_idx + 2 + idx}`);
218
+ continue;
219
+ }
220
+ const raw_symbol = parts[0];
221
+ const element_symbol = coerce_element_symbol(raw_symbol);
222
+ if (!element_symbol) {
223
+ console.warn(`Skipping XYZ atom with unknown element symbol "${raw_symbol}" in indexed frame ${frame_number}`);
224
+ continue;
225
+ }
226
+ elements.push(element_symbol);
227
+ positions.push([x_coord, y_coord, z_coord]);
228
+ }
229
+ }
230
+ const metadata = this.parse_xyz_metadata(comment, frame_number);
231
+ return create_trajectory_frame(positions, elements, undefined, undefined, metadata.step, metadata.properties);
232
+ }
233
+ load_ase_frame(data, frame_number) {
234
+ try {
235
+ const view = new DataView(data);
236
+ const n_items = Number(view.getBigInt64(32, true));
237
+ const offsets_pos = Number(view.getBigInt64(40, true));
238
+ if (frame_number >= n_items)
239
+ return null;
240
+ const frame_offset = Number(view.getBigInt64(offsets_pos + frame_number * 8, true));
241
+ const json_length = Number(view.getBigInt64(frame_offset, true));
242
+ const frame_data = JSON.parse(new TextDecoder().decode(new Uint8Array(data, frame_offset + 8, json_length)));
243
+ const positions_ref = frame_data[`positions.`] || frame_data.positions;
244
+ const positions = positions_ref?.ndarray
245
+ ? read_ndarray_from_view(view, positions_ref)
246
+ : positions_ref;
247
+ const numbers_ref = frame_data[`numbers.`] || frame_data.numbers || this.global_numbers;
248
+ const numbers = numbers_ref?.ndarray
249
+ ? read_ndarray_from_view(view, numbers_ref).flat()
250
+ : numbers_ref;
251
+ if (numbers)
252
+ this.global_numbers = numbers;
253
+ if (!numbers || !positions)
254
+ throw new Error(`Missing atomic numbers or positions`);
255
+ const cell = frame_data.cell ? validate_3x3_matrix(frame_data.cell) : undefined;
256
+ const metadata = {
257
+ step: frame_number,
258
+ ...(frame_data.calculator || {}),
259
+ ...(frame_data.info || {}),
260
+ };
261
+ if (cell) {
262
+ try {
263
+ metadata.volume = Math.abs(math.det_3x3(cell));
264
+ }
265
+ catch (error) {
266
+ console.warn(`Failed to calculate volume for frame ${frame_number}:`, error);
267
+ }
268
+ }
269
+ return create_trajectory_frame(positions, convert_atomic_numbers(numbers), cell, frame_data.pbc || [true, true, true], frame_number, metadata);
270
+ }
271
+ catch (error) {
272
+ console.warn(`Failed to load ASE frame ${frame_number}:`, error);
273
+ return null;
274
+ }
275
+ }
276
+ parse_xyz_metadata(comment, frame_number) {
277
+ const properties = {};
278
+ const patterns = {
279
+ energy: /(?:energy|E|etot)\s*[=:]?\s*([-+]?\d*\.?\d+(?:[eE][-+]?\d+)?)/i,
280
+ volume: /(?:volume|vol|V)\s*[=:]?\s*([-+]?\d*\.?\d+(?:[eE][-+]?\d+)?)/i,
281
+ pressure: /(?:pressure|press|P)\s*[=:]?\s*([-+]?\d*\.?\d+(?:[eE][-+]?\d+)?)/i,
282
+ force_max: /(?:max_force|fmax)\s*[=:]?\s*([-+]?\d*\.?\d+(?:[eE][-+]?\d+)?)/i,
283
+ };
284
+ Object.entries(patterns).forEach(([key, pattern]) => {
285
+ const match = pattern.exec(comment);
286
+ if (match)
287
+ properties[key] = parseFloat(match[1]);
288
+ });
289
+ const step_match = /(?:step|frame)\s*[=:]?\s*(\d+)/i.exec(comment);
290
+ const step = step_match ? parseInt(step_match[1]) : frame_number;
291
+ return { frame_number, step, properties };
292
+ }
293
+ parse_ase_metadata(frame_data, frame_number) {
294
+ const properties = {};
295
+ const step = frame_number;
296
+ if (frame_data.calculator && typeof frame_data.calculator === `object`) {
297
+ const calculator = frame_data.calculator;
298
+ const calc_properties = [`energy`, `potential_energy`, `kinetic_energy`, `total_energy`];
299
+ for (const prop of calc_properties) {
300
+ if (prop in calculator && typeof calculator[prop] === `number`) {
301
+ properties[prop] = calculator[prop];
302
+ }
303
+ }
304
+ }
305
+ if (frame_data.info && typeof frame_data.info === `object`) {
306
+ const info = frame_data.info;
307
+ const info_properties = [
308
+ `force_max`,
309
+ `force_norm`,
310
+ `stress_max`,
311
+ `stress_frobenius`,
312
+ `pressure`,
313
+ `temperature`,
314
+ ];
315
+ for (const prop of info_properties) {
316
+ if (prop in info && typeof info[prop] === `number`) {
317
+ properties[prop] = info[prop];
318
+ }
319
+ }
320
+ }
321
+ if (frame_data.cell && Array.isArray(frame_data.cell)) {
322
+ try {
323
+ const validated_cell = validate_3x3_matrix(frame_data.cell);
324
+ properties.volume = Math.abs(math.det_3x3(validated_cell));
325
+ }
326
+ catch (error) {
327
+ console.warn(`Failed to calculate volume for ASE frame ${frame_number}:`, error);
328
+ }
329
+ }
330
+ return { frame_number, step, properties };
331
+ }
332
+ }
@@ -0,0 +1,14 @@
1
+ import type { ElementSymbol } from '../element';
2
+ import * as math from '../math';
3
+ import type { AnyStructure, Pbc } from '../structure';
4
+ import type { TrajectoryFrame } from './index';
5
+ export declare function is_valid_element_symbol(symbol: string): symbol is ElementSymbol;
6
+ export declare function coerce_element_symbol(symbol: string): ElementSymbol | undefined;
7
+ export declare function validate_3x3_matrix(data: unknown): math.Matrix3x3;
8
+ export declare const convert_atomic_numbers: (numbers: number[]) => ElementSymbol[];
9
+ export declare const create_structure: (positions: number[][], elements: ElementSymbol[], lattice_matrix?: math.Matrix3x3, pbc?: Pbc, force_data?: number[][]) => AnyStructure;
10
+ export declare const create_trajectory_frame: (positions: number[][], elements: ElementSymbol[], lattice_matrix: math.Matrix3x3 | undefined, pbc: Pbc | undefined, step: number, metadata?: Record<string, unknown>) => TrajectoryFrame;
11
+ export declare const read_ndarray_from_view: (view: DataView, ref: {
12
+ ndarray: unknown[];
13
+ }) => number[][];
14
+ export declare function count_xyz_frames(data: string): number;
@@ -0,0 +1,172 @@
1
+ // Shared utilities for trajectory parsing
2
+ import { ATOMIC_NUMBER_TO_SYMBOL } from '../composition/parse';
3
+ import { ELEM_SYMBOLS } from '../labels';
4
+ import * as math from '../math';
5
+ const element_symbol_set = new Set(ELEM_SYMBOLS);
6
+ export function is_valid_element_symbol(symbol) {
7
+ return element_symbol_set.has(symbol);
8
+ }
9
+ export function coerce_element_symbol(symbol) {
10
+ return is_valid_element_symbol(symbol) ? symbol : undefined;
11
+ }
12
+ // Validate that data is a proper 3x3 matrix
13
+ // Accepts both regular arrays and typed arrays (Float32Array, Float64Array, etc.)
14
+ export function validate_3x3_matrix(data) {
15
+ if (!Array.isArray(data) || data.length !== 3) {
16
+ throw new Error(`Expected 3x3 matrix, got array of length ${Array.isArray(data) ? data.length : `non-array`}`);
17
+ }
18
+ const is_valid_row = (row) => {
19
+ if (Array.isArray(row))
20
+ return row.length === 3;
21
+ if (!ArrayBuffer.isView(row))
22
+ return false;
23
+ return `length` in row && typeof row.length === `number` && row.length === 3;
24
+ };
25
+ if (!data.every(is_valid_row)) {
26
+ throw new Error(`Invalid 3x3 matrix structure`);
27
+ }
28
+ return data;
29
+ }
30
+ export const convert_atomic_numbers = (numbers) => numbers.map((num) => {
31
+ const symbol = ATOMIC_NUMBER_TO_SYMBOL[num];
32
+ if (!symbol || !is_valid_element_symbol(symbol)) {
33
+ throw new Error(`Unknown atomic number in trajectory data: ${num}`);
34
+ }
35
+ return symbol;
36
+ });
37
+ export const create_structure = (positions, elements, lattice_matrix, pbc, force_data) => {
38
+ if (positions.length !== elements.length) {
39
+ throw new Error(`create_structure requires matching positions and elements lengths, got positions=${positions.length}, elements=${elements.length}`);
40
+ }
41
+ const cart_to_frac = lattice_matrix ? math.create_cart_to_frac(lattice_matrix) : null;
42
+ const is_valid_vec3 = (coords) => Array.isArray(coords) &&
43
+ coords.length === 3 &&
44
+ coords.every((value) => typeof value === `number` && Number.isFinite(value));
45
+ const sites = positions.map((pos, idx) => {
46
+ if (!is_valid_vec3(pos)) {
47
+ throw new Error(`Invalid position at index ${idx}: expected 3 finite coordinates`);
48
+ }
49
+ const xyz = pos;
50
+ const abc = cart_to_frac ? cart_to_frac(xyz) : [0, 0, 0];
51
+ const force = force_data?.[idx];
52
+ const properties = is_valid_vec3(force) ? { force } : {};
53
+ return {
54
+ species: [{ element: elements[idx], occu: 1, oxidation_state: 0 }],
55
+ abc,
56
+ xyz,
57
+ label: `${elements[idx]}${idx + 1}`,
58
+ properties,
59
+ };
60
+ });
61
+ return lattice_matrix
62
+ ? {
63
+ sites,
64
+ lattice: {
65
+ matrix: lattice_matrix,
66
+ ...math.calc_lattice_params(lattice_matrix),
67
+ pbc: pbc || [true, true, true],
68
+ },
69
+ }
70
+ : { sites };
71
+ };
72
+ export const create_trajectory_frame = (positions, elements, lattice_matrix, pbc, step, metadata = {}) => ({
73
+ structure: create_structure(positions, elements, lattice_matrix, pbc),
74
+ step,
75
+ metadata,
76
+ });
77
+ // Shared utility to read ndarray data from binary format
78
+ export const read_ndarray_from_view = (view, ref) => {
79
+ const [shape, dtype, array_offset] = ref.ndarray;
80
+ const total = shape.reduce((product, dim_size) => product * dim_size, 1);
81
+ const data = [];
82
+ let pos = array_offset;
83
+ const readers = {
84
+ int64: {
85
+ bytes_per_element: 8,
86
+ read: () => {
87
+ const value = Number(view.getBigInt64(pos, true));
88
+ pos += 8;
89
+ return value;
90
+ },
91
+ },
92
+ int32: {
93
+ bytes_per_element: 4,
94
+ read: () => {
95
+ const value = view.getInt32(pos, true);
96
+ pos += 4;
97
+ return value;
98
+ },
99
+ },
100
+ float64: {
101
+ bytes_per_element: 8,
102
+ read: () => {
103
+ const value = view.getFloat64(pos, true);
104
+ pos += 8;
105
+ return value;
106
+ },
107
+ },
108
+ float32: {
109
+ bytes_per_element: 4,
110
+ read: () => {
111
+ const value = view.getFloat32(pos, true);
112
+ pos += 4;
113
+ return value;
114
+ },
115
+ },
116
+ };
117
+ const reader_config = readers[dtype];
118
+ if (!reader_config)
119
+ throw new Error(`Unsupported dtype: ${dtype}`);
120
+ if (!Number.isInteger(array_offset) || array_offset < 0) {
121
+ throw new Error(`Invalid array_offset: expected non-negative integer, got ${array_offset}`);
122
+ }
123
+ const bytes_needed = total * reader_config.bytes_per_element;
124
+ if (array_offset + bytes_needed > view.byteLength) {
125
+ throw new Error(`Out-of-bounds read: array_offset + bytesNeeded exceeds view.byteLength`);
126
+ }
127
+ for (let idx = 0; idx < total; idx++)
128
+ data.push(reader_config.read());
129
+ return shape.length === 1
130
+ ? [data]
131
+ : shape.length === 2
132
+ ? Array.from({ length: shape[0] }, (_, idx) => data.slice(idx * shape[1], (idx + 1) * shape[1]))
133
+ : (() => {
134
+ throw new Error(`Unsupported shape`);
135
+ })();
136
+ };
137
+ // Unified frame counting for XYZ
138
+ export function count_xyz_frames(data) {
139
+ if (!data || typeof data !== `string`)
140
+ return 0;
141
+ const lines = data.trim().split(/\r?\n/);
142
+ let frame_count = 0;
143
+ let line_idx = 0;
144
+ while (line_idx < lines.length) {
145
+ if (!lines[line_idx]?.trim()) {
146
+ line_idx++;
147
+ continue;
148
+ }
149
+ const num_atoms = parseInt(lines[line_idx].trim(), 10);
150
+ if (isNaN(num_atoms) || num_atoms <= 0 || line_idx + num_atoms + 2 > lines.length) {
151
+ line_idx++;
152
+ continue;
153
+ }
154
+ // Quick validation of first few atom lines
155
+ let valid_coords = 0;
156
+ for (let idx = 0; idx < Math.min(num_atoms, 3); idx++) {
157
+ const parts = lines[line_idx + 2 + idx]?.trim().split(/\s+/);
158
+ if (parts?.length >= 4 && isNaN(parseInt(parts[0])) && parts[0].length <= 3) {
159
+ if (parts.slice(1, 4).every((coord) => !isNaN(parseFloat(coord))))
160
+ valid_coords++;
161
+ }
162
+ }
163
+ if (valid_coords >= Math.min(num_atoms, 3)) {
164
+ frame_count++;
165
+ line_idx += 2 + num_atoms;
166
+ }
167
+ else {
168
+ line_idx++;
169
+ }
170
+ }
171
+ return frame_count;
172
+ }
@@ -6,6 +6,7 @@ export { default as TrajectoryError } from './TrajectoryError.svelte';
6
6
  export { default as TrajectoryExportPane } from './TrajectoryExportPane.svelte';
7
7
  export { default as TrajectoryInfoPane } from './TrajectoryInfoPane.svelte';
8
8
  export type TrajectoryFormat = `hdf5` | `json` | `xyz` | `xdatcar` | `traj` | `unknown`;
9
+ export type { AtomTypeMapping } from './types';
9
10
  export interface ParseProgress {
10
11
  current: number;
11
12
  total: number;