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
@@ -1,11 +1,10 @@
1
1
  // Parsers for volumetric data file formats (VASP CHGCAR, Gaussian .cube)
2
- import { VASP_VOLUMETRIC_REGEX } from '../constants';
2
+ import { COMPRESSION_EXTENSIONS_REGEX, VASP_VOLUMETRIC_REGEX } from '../constants';
3
3
  import { ELEM_SYMBOLS } from '../labels';
4
4
  import * as math from '../math';
5
+ import { wrap_to_unit_cell } from '../structure/pbc';
5
6
  // Bohr radius in Angstroms (for Gaussian .cube unit conversion)
6
7
  const BOHR_TO_ANGSTROM = 0.529177249;
7
- // Wrap a value to [0, 1) range for fractional coordinates
8
- const wrap_frac = (val) => val - Math.floor(val);
9
8
  // === Fast number parsing utilities ===
10
9
  // Parse whitespace-separated numbers directly from a string, starting at `pos`.
11
10
  // Writes into a pre-allocated Float64Array and returns { count, end_pos }.
@@ -87,13 +86,9 @@ function read_lines(text, pos, count) {
87
86
  }
88
87
  return { lines: result, next: pos };
89
88
  }
90
- // Build 3D grid directly from Float64Array, computing data_range in the same pass.
91
- function build_grid(data, nx, ny, nz, divisor = 1) {
89
+ function build_grid({ data, nx, ny, nz, divisor = 1, data_order = `z_fastest`, }) {
92
90
  const grid = new Array(nx);
93
- let min_val = Infinity;
94
- let max_val = -Infinity;
95
- let sum = 0;
96
- const ny_nz = ny * nz;
91
+ let [min_val, max_val, sum] = [Infinity, -Infinity, 0];
97
92
  const total = nx * ny * nz;
98
93
  const data_len = Math.min(data.length, total);
99
94
  if (data_len === 0) {
@@ -106,39 +101,68 @@ function build_grid(data, nx, ny, nz, divisor = 1) {
106
101
  }
107
102
  return { grid, data_range: { min: 0, max: 0, abs_max: 0, mean: 0 } };
108
103
  }
109
- for (let ix = 0; ix < nx; ix++) {
110
- const plane = new Array(ny);
111
- for (let iy = 0; iy < ny; iy++) {
112
- const row = new Array(nz).fill(0);
113
- const base = ix * ny_nz + iy * nz;
114
- const row_end = Math.min(base + nz, data_len);
115
- for (let flat_idx = base; flat_idx < row_end; flat_idx++) {
116
- const val = data[flat_idx] / divisor;
117
- row[flat_idx - base] = val;
118
- if (val < min_val)
119
- min_val = val;
120
- if (val > max_val)
121
- max_val = val;
122
- sum += val;
104
+ if (data_order === `z_fastest`) {
105
+ // .cube convention: z varies fastest, then y, then x.
106
+ const ny_nz = ny * nz;
107
+ for (let ix = 0; ix < nx; ix++) {
108
+ const plane = new Array(ny);
109
+ for (let iy = 0; iy < ny; iy++) {
110
+ const row = new Array(nz).fill(0);
111
+ const base = ix * ny_nz + iy * nz;
112
+ const row_end = Math.min(base + nz, data_len);
113
+ for (let flat_idx = base; flat_idx < row_end; flat_idx++) {
114
+ const val = data[flat_idx] / divisor;
115
+ row[flat_idx - base] = val;
116
+ if (val < min_val)
117
+ min_val = val;
118
+ if (val > max_val)
119
+ max_val = val;
120
+ sum += val;
121
+ }
122
+ plane[iy] = row;
123
123
  }
124
- plane[iy] = row;
124
+ grid[ix] = plane;
125
+ }
126
+ }
127
+ else {
128
+ // VASP CHGCAR/ELFCAR/LOCPOT convention: x varies fastest, then y, then z.
129
+ for (let ix = 0; ix < nx; ix++) {
130
+ const plane = new Array(ny);
131
+ for (let iy = 0; iy < ny; iy++)
132
+ plane[iy] = new Array(nz).fill(0);
133
+ grid[ix] = plane;
134
+ }
135
+ let [flat_idx, data_exhausted] = [0, false];
136
+ for (let iz = 0; iz < nz; iz++) {
137
+ for (let iy = 0; iy < ny; iy++) {
138
+ for (let ix = 0; ix < nx; ix++) {
139
+ if (flat_idx >= data_len) {
140
+ data_exhausted = true;
141
+ break;
142
+ }
143
+ const val = data[flat_idx] / divisor;
144
+ grid[ix][iy][iz] = val;
145
+ if (val < min_val)
146
+ min_val = val;
147
+ if (val > max_val)
148
+ max_val = val;
149
+ sum += val;
150
+ flat_idx++;
151
+ }
152
+ if (data_exhausted)
153
+ break;
154
+ }
155
+ if (data_exhausted)
156
+ break;
125
157
  }
126
- grid[ix] = plane;
127
158
  }
128
159
  const abs_max = Math.max(Math.abs(min_val), Math.abs(max_val));
129
- return {
130
- grid,
131
- data_range: {
132
- min: min_val,
133
- max: max_val,
134
- abs_max,
135
- mean: sum / data_len,
136
- },
137
- };
160
+ const data_range = { min: min_val, max: max_val, abs_max, mean: sum / data_len };
161
+ return { grid, data_range };
138
162
  }
139
163
  // === CHGCAR Parser ===
140
- // Parse VASP CHGCAR/AECCAR/ELFCAR/LOCPOT file format.
141
- // CHGCAR consists of a POSCAR header followed by volumetric data on a 3D grid.
164
+ // Parse VASP CHGCAR/AECCAR/ELFCAR/LOCPOT/PARCHG file format.
165
+ // CHGCAR/PARCHG consists of a POSCAR header followed by volumetric data on a 3D grid.
142
166
  // Spin-polarized files contain two data blocks (total charge + magnetization).
143
167
  export function parse_chgcar(content) {
144
168
  // Strip leading whitespace
@@ -212,8 +236,16 @@ export function parse_chgcar(content) {
212
236
  const is_direct = cur.line.trim().toUpperCase().startsWith(`D`);
213
237
  pos = cur.next;
214
238
  // Parse atomic positions
215
- const lattice_transposed = math.transpose_3x3_matrix(lattice);
216
- const lattice_inv = math.matrix_inverse_3x3(lattice_transposed);
239
+ let cart_to_frac;
240
+ let frac_to_cart;
241
+ try {
242
+ ;
243
+ ({ cart_to_frac, frac_to_cart } = math.create_lattice_converters(lattice));
244
+ }
245
+ catch {
246
+ console.error(`CHGCAR: lattice matrix is singular; cannot convert coordinates`);
247
+ return null;
248
+ }
217
249
  const sites = [];
218
250
  let atom_idx = 0;
219
251
  for (let elem_idx = 0; elem_idx < element_symbols.length; elem_idx++) {
@@ -231,13 +263,13 @@ export function parse_chgcar(content) {
231
263
  let abc;
232
264
  let xyz;
233
265
  if (is_direct) {
234
- abc = [wrap_frac(coords[0]), wrap_frac(coords[1]), wrap_frac(coords[2])];
235
- xyz = math.mat3x3_vec3_multiply(lattice_transposed, abc);
266
+ abc = wrap_to_unit_cell(coords);
267
+ xyz = frac_to_cart(abc);
236
268
  }
237
269
  else {
238
270
  xyz = math.scale(coords, scale_factor);
239
- const raw = math.mat3x3_vec3_multiply(lattice_inv, xyz);
240
- abc = [wrap_frac(raw[0]), wrap_frac(raw[1]), wrap_frac(raw[2])];
271
+ const raw = cart_to_frac(xyz);
272
+ abc = wrap_to_unit_cell(raw);
241
273
  }
242
274
  sites.push({
243
275
  species: [{ element, occu: 1, oxidation_state: 0 }],
@@ -289,13 +321,21 @@ export function parse_chgcar(content) {
289
321
  // Use Math.abs to guard against negative determinant (left-handed lattice).
290
322
  const cell_volume = Math.abs(lattice_params.volume);
291
323
  const divisor = cell_volume > 1e-30 ? cell_volume : 1;
292
- const { grid, data_range } = build_grid(data.subarray(0, parsed_count), ngx, ngy, ngz, divisor);
324
+ const { grid, data_range } = build_grid({
325
+ data: data.subarray(0, parsed_count),
326
+ nx: ngx,
327
+ ny: ngy,
328
+ nz: ngz,
329
+ divisor,
330
+ data_order: `x_fastest`,
331
+ });
293
332
  volumes.push({
294
333
  grid,
295
334
  grid_dims: [ngx, ngy, ngz],
296
335
  lattice,
297
336
  origin: [0, 0, 0],
298
337
  data_range,
338
+ data_order: `x_fastest`,
299
339
  periodic: true, // VASP grids span [0,1) with N points, wrapping at boundaries
300
340
  label: volume_labels[vol_idx],
301
341
  });
@@ -378,21 +418,22 @@ export function parse_cube(content, options = {}) {
378
418
  const is_periodic = options.periodic ?? Math.hypot(...origin) < 1e-6;
379
419
  // Parse atomic positions
380
420
  const sites = [];
381
- const lattice_transposed = math.transpose_3x3_matrix(lattice);
382
- let lattice_inv;
421
+ let cube_cart_to_frac;
383
422
  try {
384
- lattice_inv = math.matrix_inverse_3x3(lattice_transposed);
423
+ cube_cart_to_frac = math.create_cart_to_frac(lattice);
385
424
  }
386
425
  catch {
387
426
  // Non-periodic system (molecule), use identity
388
- lattice_inv = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];
427
+ cube_cart_to_frac = (v) => [v[0], v[1], v[2]];
389
428
  }
390
429
  for (let atom_idx = 0; atom_idx < n_atoms; atom_idx++) {
391
430
  const cur = read_line(content, pos);
392
431
  const atom_line = cur.line.trim().split(/\s+/).map(Number);
393
432
  pos = cur.next;
394
433
  // Validate: need atomic_number, charge, x, y, z (5 tokens, indices 2-4 finite)
395
- if (atom_line.length < 5 || !isFinite(atom_line[2]) || !isFinite(atom_line[3]) ||
434
+ if (atom_line.length < 5 ||
435
+ !isFinite(atom_line[2]) ||
436
+ !isFinite(atom_line[3]) ||
396
437
  !isFinite(atom_line[4])) {
397
438
  console.warn(`.cube atom ${atom_idx}: malformed line "${cur.line.trim()}", skipping`);
398
439
  continue;
@@ -402,7 +443,7 @@ export function parse_cube(content, options = {}) {
402
443
  // Convert Cartesian to fractional, accounting for origin offset.
403
444
  // Store lattice-frame xyz (shifted) so abc and xyz stay consistent.
404
445
  const xyz = math.subtract(raw_xyz, origin);
405
- const abc = math.mat3x3_vec3_multiply(lattice_inv, xyz);
446
+ const abc = cube_cart_to_frac(xyz);
406
447
  const element = atomic_number_to_symbol(atom_line[0]);
407
448
  sites.push({
408
449
  species: [{ element, occu: 1, oxidation_state: 0 }],
@@ -438,30 +479,37 @@ export function parse_cube(content, options = {}) {
438
479
  return null;
439
480
  }
440
481
  }
441
- const { grid, data_range } = build_grid(data.subarray(0, parsed_count), n_grid[0], n_grid[1], n_grid[2]);
442
- const volumes = [{
482
+ const { grid, data_range } = build_grid({
483
+ data: data.subarray(0, parsed_count),
484
+ nx: n_grid[0],
485
+ ny: n_grid[1],
486
+ nz: n_grid[2],
487
+ data_order: `z_fastest`,
488
+ });
489
+ const volumes = [
490
+ {
443
491
  grid,
444
492
  grid_dims: n_grid,
445
493
  lattice,
446
494
  origin,
447
495
  data_range,
496
+ data_order: `z_fastest`,
448
497
  periodic: is_periodic, // periodic systems wrap; molecular .cube files include both endpoints
449
498
  label: `volumetric data`,
450
- }];
499
+ },
500
+ ];
451
501
  return { structure, volumes };
452
502
  }
453
503
  // Convert atomic number to element symbol using ELEM_SYMBOLS (1-indexed: H=1, He=2, ...)
454
504
  function atomic_number_to_symbol(atomic_number) {
455
505
  // ELEM_SYMBOLS is 0-indexed (H at index 0), atomic numbers are 1-indexed
456
506
  const idx = atomic_number - 1;
457
- return (idx >= 0 && idx < ELEM_SYMBOLS.length
458
- ? ELEM_SYMBOLS[idx]
459
- : `H`);
507
+ return (idx >= 0 && idx < ELEM_SYMBOLS.length ? ELEM_SYMBOLS[idx] : `H`);
460
508
  }
461
509
  // Auto-detect and parse volumetric file format based on filename and content
462
510
  export function parse_volumetric_file(content, filename) {
463
511
  // Strip compression suffixes so "CHGCAR.gz" and "molecule.cube.bz2" match correctly
464
- const lower_name = (filename ?? ``).toLowerCase().replace(/\.(gz|bz2|xz|zst)$/, ``);
512
+ const lower_name = (filename ?? ``).toLowerCase().replace(COMPRESSION_EXTENSIONS_REGEX, ``);
465
513
  // Extension-based detection
466
514
  if (lower_name.endsWith(`.cube`))
467
515
  return parse_cube(content);
@@ -1,3 +1,4 @@
1
+ import type { Vec3 } from '../math';
1
2
  import type { VolumetricData } from './types';
2
3
  export interface SliceResult {
3
4
  data: Float64Array;
@@ -7,4 +8,4 @@ export interface SliceResult {
7
8
  max: number;
8
9
  }
9
10
  export declare function trilinear_interpolate(grid: number[][][], fx: number, fy: number, fz: number, periodic: boolean): number;
10
- export declare function sample_hkl_slice(volume: VolumetricData, miller_indices: [number, number, number], distance: number): SliceResult | null;
11
+ export declare function sample_hkl_slice(volume: VolumetricData, miller_indices: Vec3, distance: number, n_points?: number): SliceResult | null;
@@ -56,7 +56,7 @@ export function trilinear_interpolate(grid, fx, fy, fz, periodic) {
56
56
  // `miller_indices` [h,k,l] defines the plane normal in reciprocal space.
57
57
  // `distance` is fractional [0,1] along the normal direction within the cell.
58
58
  // Returns null if indices are all zero.
59
- export function sample_hkl_slice(volume, miller_indices, distance) {
59
+ export function sample_hkl_slice(volume, miller_indices, distance, n_points) {
60
60
  const [h_idx, k_idx, l_idx] = miller_indices;
61
61
  if (h_idx === 0 && k_idx === 0 && l_idx === 0)
62
62
  return null;
@@ -74,9 +74,7 @@ export function sample_hkl_slice(volume, miller_indices, distance) {
74
74
  const unit_normal = math.normalize_vec3(plane_normal);
75
75
  // In-plane basis vectors
76
76
  const [u_vec, v_vec] = math.compute_in_plane_basis(unit_normal);
77
- // Compute lattice inverse for Cartesian → fractional conversion.
78
- // lattice rows are vectors [a, b, c], so cart = lattice^T * frac → frac = inv(lattice^T) * cart
79
- const lattice_inv = math.matrix_inverse_3x3(math.transpose_3x3_matrix(lattice));
77
+ const cart_to_frac = math.create_cart_to_frac(lattice);
80
78
  // Project all 8 unit cell corners onto the (u, v) plane to find sampling bounds.
81
79
  // Corners are at fractional coords (0 or 1) for each axis.
82
80
  let u_min = Infinity;
@@ -86,9 +84,9 @@ export function sample_hkl_slice(volume, miller_indices, distance) {
86
84
  let normal_min = Infinity;
87
85
  let normal_max = -Infinity;
88
86
  for (let ci = 0; ci < 8; ci++) {
89
- const fi = (ci & 1) ? 1 : 0;
90
- const fj = (ci & 2) ? 1 : 0;
91
- const fk = (ci & 4) ? 1 : 0;
87
+ const fi = ci & 1 ? 1 : 0;
88
+ const fj = ci & 2 ? 1 : 0;
89
+ const fk = ci & 4 ? 1 : 0;
92
90
  // Corner in Cartesian: frac * lattice
93
91
  const corner = [
94
92
  fi * lattice[0][0] + fj * lattice[1][0] + fk * lattice[2][0],
@@ -113,8 +111,8 @@ export function sample_hkl_slice(volume, miller_indices, distance) {
113
111
  }
114
112
  // Plane position: fractional distance [0,1] along the normal extent
115
113
  const d_cartesian = normal_min + distance * (normal_max - normal_min);
116
- // Sampling resolution: square grid using max dimension
117
- const width = Math.max(nx, ny, nz);
114
+ // Sampling resolution: caller-specified or default to max grid dimension
115
+ const width = n_points ?? Math.max(nx, ny, nz);
118
116
  const height = width;
119
117
  const data = new Float64Array(width * height);
120
118
  let data_min = Infinity;
@@ -129,10 +127,7 @@ export function sample_hkl_slice(volume, miller_indices, distance) {
129
127
  const px = d_cartesian * unit_normal[0] + u_val * u_vec[0] + v_val * v_vec[0];
130
128
  const py = d_cartesian * unit_normal[1] + u_val * u_vec[1] + v_val * v_vec[1];
131
129
  const pz = d_cartesian * unit_normal[2] + u_val * u_vec[2] + v_val * v_vec[2];
132
- // Convert to fractional coordinates: frac = lattice_inv * p
133
- const fx = lattice_inv[0][0] * px + lattice_inv[0][1] * py + lattice_inv[0][2] * pz;
134
- const fy = lattice_inv[1][0] * px + lattice_inv[1][1] * py + lattice_inv[1][2] * pz;
135
- const fz = lattice_inv[2][0] * px + lattice_inv[2][1] * py + lattice_inv[2][2] * pz;
130
+ const [fx, fy, fz] = cart_to_frac([px, py, pz]);
136
131
  const val = trilinear_interpolate(grid, fx, fy, fz, periodic);
137
132
  data[row * width + col] = val;
138
133
  if (val < data_min)
@@ -8,10 +8,11 @@ export interface DataRange {
8
8
  }
9
9
  export interface VolumetricData {
10
10
  grid: number[][][];
11
- grid_dims: [number, number, number];
11
+ grid_dims: Vec3;
12
12
  lattice: Matrix3x3;
13
13
  origin: Vec3;
14
14
  data_range: DataRange;
15
+ data_order?: `x_fastest` | `z_fastest`;
15
16
  periodic: boolean;
16
17
  label?: string;
17
18
  }
@@ -34,10 +35,22 @@ export interface IsosurfaceSettings {
34
35
  negative_color: string;
35
36
  show_negative: boolean;
36
37
  wireframe: boolean;
38
+ halo: number;
37
39
  layers?: IsosurfaceLayer[];
38
40
  }
39
41
  export declare const LAYER_COLORS: readonly ["#3b82f6", "#ef4444", "#22c55e", "#a855f7", "#f97316", "#06b6d4", "#eab308", "#ec4899"];
40
42
  export declare function grid_data_range(grid: number[][][]): DataRange;
43
+ export declare function pad_periodic_grid(grid: number[][][], dims: Vec3, pad_fraction: number): {
44
+ grid: number[][][];
45
+ dims: Vec3;
46
+ offset: Vec3;
47
+ };
48
+ export declare function downsample_grid(grid: number[][][], dims: Vec3, max_points?: number): {
49
+ grid: number[][][];
50
+ dims: Vec3;
51
+ factor: number;
52
+ };
41
53
  export declare const DEFAULT_ISOSURFACE_SETTINGS: IsosurfaceSettings;
42
54
  export declare function auto_isosurface_settings(data_range: DataRange): IsosurfaceSettings;
43
55
  export declare function generate_layers(data_range: DataRange, n_layers: number): IsosurfaceLayer[];
56
+ export declare function tile_volumetric_data(volume: VolumetricData, scaling: Vec3): VolumetricData;
@@ -1,3 +1,4 @@
1
+ import { scale_lattice_matrix } from '../math';
1
2
  // Categorical palette for auto-coloring isosurface layers (Tailwind-inspired)
2
3
  export const LAYER_COLORS = [
3
4
  `#3b82f6`, // blue
@@ -15,8 +16,7 @@ export function grid_data_range(grid) {
15
16
  if (!grid.length || !grid[0]?.length || !grid[0][0]?.length) {
16
17
  return { min: 0, max: 0, abs_max: 0, mean: 0 };
17
18
  }
18
- let min_val = Infinity;
19
- let max_val = -Infinity;
19
+ let [min_val, max_val] = [Infinity, -Infinity];
20
20
  let sum = 0;
21
21
  let count = 0;
22
22
  for (const plane of grid) {
@@ -34,6 +34,109 @@ export function grid_data_range(grid) {
34
34
  const abs_max = Math.max(Math.abs(min_val), Math.abs(max_val));
35
35
  return { min: min_val, max: max_val, abs_max, mean: count > 0 ? sum / count : 0 };
36
36
  }
37
+ // Pad a periodic 3D grid with halo cells from the opposite face so isosurfaces
38
+ // extend beyond the unit cell and close into complete enclosed shapes.
39
+ // Returns a larger grid with dims [nx+2*pad, ny+2*pad, nz+2*pad] and the
40
+ // fractional offset that the padded grid's origin has shifted by.
41
+ export function pad_periodic_grid(grid, dims, pad_fraction) {
42
+ const [nx, ny, nz] = dims;
43
+ const frac = Math.max(0, pad_fraction);
44
+ const px = Math.min(Math.ceil(nx * frac), Math.floor(nx / 2));
45
+ const py = Math.min(Math.ceil(ny * frac), Math.floor(ny / 2));
46
+ const pz = Math.min(Math.ceil(nz * frac), Math.floor(nz / 2));
47
+ if (px === 0 && py === 0 && pz === 0)
48
+ return { grid, dims, offset: [0, 0, 0] };
49
+ const out_nx = nx + 2 * px;
50
+ const out_ny = ny + 2 * py;
51
+ const out_nz = nz + 2 * pz;
52
+ const wrap = (val, size) => ((val % size) + size) % size;
53
+ const out = new Array(out_nx);
54
+ for (let ix = 0; ix < out_nx; ix++) {
55
+ const plane = new Array(out_ny);
56
+ const src_x = wrap(ix - px, nx);
57
+ for (let iy = 0; iy < out_ny; iy++) {
58
+ const row = new Array(out_nz);
59
+ const src_y = wrap(iy - py, ny);
60
+ for (let iz = 0; iz < out_nz; iz++) {
61
+ row[iz] = grid[src_x][src_y][wrap(iz - pz, nz)];
62
+ }
63
+ plane[iy] = row;
64
+ }
65
+ out[ix] = plane;
66
+ }
67
+ // Fractional offset: the padded grid starts at -pad/n in each axis
68
+ const offset = [-px / nx, -py / ny, -pz / nz];
69
+ return { grid: out, dims: [out_nx, out_ny, out_nz], offset };
70
+ }
71
+ // Max total grid points before downsampling is applied for isosurface extraction.
72
+ // 500K balances visual quality with interactive performance (<200ms marching cubes).
73
+ const MAX_GRID_POINTS = 500_000;
74
+ // Downsample a 3D volumetric grid to keep total point count under a budget.
75
+ // Uses block averaging to preserve data fidelity while reducing grid dimensions.
76
+ // Returns original grid/dims if already within budget.
77
+ export function downsample_grid(grid, dims, max_points = MAX_GRID_POINTS) {
78
+ const [nx, ny, nz] = dims;
79
+ const total = nx * ny * nz;
80
+ if (total <= max_points)
81
+ return { grid, dims, factor: 1 };
82
+ // Floor at 1 to avoid Infinity in cbrt(total/0)
83
+ max_points = Math.max(1, max_points);
84
+ // Increase factor until the clamped output fits within budget.
85
+ // A single cbrt step can overshoot for anisotropic grids where max(2,...)
86
+ // clamping prevents a small axis from shrinking below 2.
87
+ // clamp_dim: returns 1 for single-cell axes, otherwise clamps to [2, src]
88
+ const clamp_dim = (src, fac) => Math.min(src, Math.max(2, Math.ceil(src / fac)));
89
+ let factor = Math.ceil(Math.cbrt(total / max_points));
90
+ let new_nx = clamp_dim(nx, factor);
91
+ let new_ny = clamp_dim(ny, factor);
92
+ let new_nz = clamp_dim(nz, factor);
93
+ while (new_nx * new_ny * new_nz > max_points) {
94
+ factor++;
95
+ const prev_total = new_nx * new_ny * new_nz;
96
+ new_nx = clamp_dim(nx, factor);
97
+ new_ny = clamp_dim(ny, factor);
98
+ new_nz = clamp_dim(nz, factor);
99
+ // dims hit their floor (2 per axis or 1 for single-cell) — stop to avoid infinite loop
100
+ if (new_nx * new_ny * new_nz === prev_total)
101
+ break;
102
+ }
103
+ // Proportional partitioning: evenly divides [0, n) into new_n non-empty blocks.
104
+ // Unlike fixed-stride (ix * factor), this is safe when max(2,...) clamping
105
+ // produces more output cells than ceil(n/factor) would — no empty blocks.
106
+ const partition = (n_out, n_src) => Array.from({ length: n_out }, (_, idx) => [
107
+ Math.round((idx * n_src) / n_out),
108
+ Math.round(((idx + 1) * n_src) / n_out),
109
+ ]);
110
+ const x_ranges = partition(new_nx, nx);
111
+ const y_ranges = partition(new_ny, ny);
112
+ const z_ranges = partition(new_nz, nz);
113
+ const out = new Array(new_nx);
114
+ for (let ix = 0; ix < new_nx; ix++) {
115
+ const plane = new Array(new_ny);
116
+ const [sx_start, sx_end] = x_ranges[ix];
117
+ for (let iy = 0; iy < new_ny; iy++) {
118
+ const row = new Array(new_nz);
119
+ const [sy_start, sy_end] = y_ranges[iy];
120
+ for (let iz = 0; iz < new_nz; iz++) {
121
+ let sum = 0;
122
+ const [sz_start, sz_end] = z_ranges[iz];
123
+ for (let sx = sx_start; sx < sx_end; sx++) {
124
+ const src_plane = grid[sx];
125
+ for (let sy = sy_start; sy < sy_end; sy++) {
126
+ const src_row = src_plane[sy];
127
+ for (let sz = sz_start; sz < sz_end; sz++) {
128
+ sum += src_row[sz];
129
+ }
130
+ }
131
+ }
132
+ row[iz] = sum / ((sx_end - sx_start) * (sy_end - sy_start) * (sz_end - sz_start));
133
+ }
134
+ plane[iy] = row;
135
+ }
136
+ out[ix] = plane;
137
+ }
138
+ return { grid: out, dims: [new_nx, new_ny, new_nz], factor };
139
+ }
37
140
  // Default isosurface rendering settings
38
141
  export const DEFAULT_ISOSURFACE_SETTINGS = {
39
142
  isovalue: 0.05,
@@ -42,6 +145,7 @@ export const DEFAULT_ISOSURFACE_SETTINGS = {
42
145
  negative_color: `#ef4444`, // red
43
146
  show_negative: false,
44
147
  wireframe: false,
148
+ halo: 0,
45
149
  };
46
150
  // Compute reasonable isosurface settings from a volume's data range.
47
151
  // Sets isovalue to 20% of abs_max and enables negative lobe when data has
@@ -51,9 +155,7 @@ export function auto_isosurface_settings(data_range) {
51
155
  return {
52
156
  ...DEFAULT_ISOSURFACE_SETTINGS,
53
157
  // Fall back to default isovalue for all-zero grids to keep controls usable
54
- isovalue: data_range.abs_max > 0
55
- ? data_range.abs_max * 0.2
56
- : DEFAULT_ISOSURFACE_SETTINGS.isovalue,
158
+ isovalue: data_range.abs_max > 0 ? data_range.abs_max * 0.2 : DEFAULT_ISOSURFACE_SETTINGS.isovalue,
57
159
  show_negative: has_negatives,
58
160
  };
59
161
  }
@@ -78,3 +180,48 @@ export function generate_layers(data_range, n_layers) {
78
180
  };
79
181
  });
80
182
  }
183
+ // Tile (repeat) volumetric data to fill a supercell.
184
+ // Pre-downsamples the source grid when the tiled result would exceed MAX_GRID_POINTS
185
+ // to avoid large temporary allocations. Returns the original volume unchanged for
186
+ // [1,1,1] scaling.
187
+ export function tile_volumetric_data(volume, scaling) {
188
+ const [sx, sy, sz] = scaling;
189
+ if (sx === 1 && sy === 1 && sz === 1)
190
+ return volume;
191
+ const total_cells = sx * sy * sz;
192
+ let src_grid = volume.grid;
193
+ let [nx, ny, nz] = volume.grid_dims;
194
+ // Pre-downsample source grid so the tiled result stays within budget.
195
+ // Clamp budget to 8 (minimum downsample output = 2^3) to prevent infinite
196
+ // loops in downsample_grid when total_cells is very large.
197
+ if (nx * ny * nz * total_cells > MAX_GRID_POINTS) {
198
+ const budget = Math.max(8, Math.floor(MAX_GRID_POINTS / total_cells));
199
+ const ds = downsample_grid(src_grid, [nx, ny, nz], budget);
200
+ src_grid = ds.grid;
201
+ [nx, ny, nz] = ds.dims;
202
+ }
203
+ const new_nx = nx * sx;
204
+ const new_ny = ny * sy;
205
+ const new_nz = nz * sz;
206
+ const new_grid = new Array(new_nx);
207
+ for (let ix = 0; ix < new_nx; ix++) {
208
+ const plane = new Array(new_ny);
209
+ const src_x = ix % nx;
210
+ for (let iy = 0; iy < new_ny; iy++) {
211
+ const row = new Array(new_nz);
212
+ const src_y = iy % ny;
213
+ const src_row = src_grid[src_x][src_y];
214
+ for (let iz = 0; iz < new_nz; iz++) {
215
+ row[iz] = src_row[iz % nz];
216
+ }
217
+ plane[iy] = row;
218
+ }
219
+ new_grid[ix] = plane;
220
+ }
221
+ return {
222
+ ...volume,
223
+ grid: new_grid,
224
+ grid_dims: [new_nx, new_ny, new_nz],
225
+ lattice: scale_lattice_matrix(volume.lattice, scaling),
226
+ };
227
+ }
package/dist/labels.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { ChemicalElement, ElementCategory } from './element/types';
2
+ import type { Vec3 } from './math';
2
3
  import type { SymbolType } from 'd3-shape';
3
4
  import * as d3_symbols from 'd3-shape';
4
5
  export type D3Symbol = keyof typeof d3_symbols & `symbol${Capitalize<string>}`;
@@ -12,7 +13,7 @@ export declare const ELEM_HEATMAP_LABELS: Partial<Record<string, keyof ChemicalE
12
13
  export declare const DEFAULT_FMT: [string, string];
13
14
  export declare const FRACTION_GLYPHS: ReadonlyArray<readonly [number, string]>;
14
15
  export declare const format_num: (num: number, fmt?: string | number) => string;
15
- export declare const format_vec3: (vec: readonly [number, number, number], fmt_spec?: string) => string;
16
+ export declare const format_vec3: (vec: Readonly<Vec3>, fmt_spec?: string) => string;
16
17
  export declare const format_bytes: (bytes?: number) => string;
17
18
  export declare function format_fractional(value: number): string;
18
19
  export declare function parse_si_float<T extends string | number | null | undefined>(value: T): T | number | string;
package/dist/labels.js CHANGED
@@ -10,9 +10,13 @@ function name_for_symbol(sym) {
10
10
  }
11
11
  return null;
12
12
  }
13
- export const symbol_names = ([...new Set([...d3_symbols.symbolsFill, ...d3_symbols.symbolsStroke])]
14
- .map(name_for_symbol).filter((n) => n !== null));
15
- export const symbol_map = Object.fromEntries(// Symbol lookup from d3-shape
13
+ export const symbol_names = [
14
+ ...new Set([...d3_symbols.symbolsFill, ...d3_symbols.symbolsStroke]),
15
+ ]
16
+ .map(name_for_symbol)
17
+ .filter((n) => n !== null);
18
+ export const symbol_map = Object.fromEntries(
19
+ // Symbol lookup from d3-shape
16
20
  symbol_names.map((name) => [name, d3_symbols[`symbol${name}`]]));
17
21
  // Format a value for display with optional time formatting
18
22
  export function format_value(value, formatter) {
@@ -56,6 +60,7 @@ export const ELEM_PROPERTY_LABELS = {
56
60
  electronegativity: [`Electronegativity`, null],
57
61
  first_ionization: [`First Ionization Energy`, `eV`],
58
62
  melting_point: [`Melting Point`, `K`],
63
+ mendeleev_number: [`Mendeleev Number`, null],
59
64
  // molar_heat: [`Molar Heat`, `J/(mol·K)`],
60
65
  n_shells: [`Number of Shells`, null],
61
66
  n_valence: [`Electron Valency`, null],
@@ -73,8 +78,7 @@ export const ELEM_HEATMAP_KEYS = [
73
78
  `melting_point`,
74
79
  `first_ionization`,
75
80
  ];
76
- export const ELEM_HEATMAP_LABELS = Object
77
- .fromEntries(ELEM_HEATMAP_KEYS.map((key) => {
81
+ export const ELEM_HEATMAP_LABELS = Object.fromEntries(ELEM_HEATMAP_KEYS.map((key) => {
78
82
  const [label, unit] = ELEM_PROPERTY_LABELS[key] ?? [];
79
83
  if (!label)
80
84
  throw `Unexpected missing label ${label}`;
@@ -141,7 +145,7 @@ export function format_fractional(value) {
141
145
  return glyph;
142
146
  }
143
147
  for (const [target, glyph] of FRACTION_GLYPHS) {
144
- if (target !== 0 && Math.abs((1 - x) - target) < eps)
148
+ if (target !== 0 && Math.abs(1 - x - target) < eps)
145
149
  return glyph;
146
150
  }
147
151
  return format_num(value, `.4~`);
@@ -153,7 +157,7 @@ export function parse_si_float(value) {
153
157
  // Remove whitespace and commas
154
158
  const cleaned = value.trim().replace(/(\d),(\d)/g, `$1$2`);
155
159
  // Check if the value is a SI-formatted number (e.g. "1.23k", "4.56M", "789µ", "12n")
156
- const match = cleaned.match(/^([-+]?\d*\.?\d+)\s*([yzafpnµmkMGTPEZY])?$/i);
160
+ const match = /^([-+]?\d*\.?\d+)\s*([yzafpnµmkMGTPEZY])?$/i.exec(cleaned);
157
161
  if (match) {
158
162
  const [, num_part, suffix] = match;
159
163
  let multiplier = 1;
@@ -196,7 +200,7 @@ export const ELEMENT_CATEGORIES = [
196
200
  `post-transition metal`,
197
201
  `transition metal`,
198
202
  ];
199
- // deno-fmt-ignore-next-line
203
+ // oxfmt-ignore
200
204
  export const ELEM_SYMBOLS = [`H`, `He`, `Li`, `Be`, `B`, `C`, `N`, `O`, `F`, `Ne`, `Na`, `Mg`, `Al`, `Si`, `P`, `S`, `Cl`, `Ar`, `K`, `Ca`, `Sc`, `Ti`, `V`, `Cr`, `Mn`, `Fe`, `Co`, `Ni`, `Cu`, `Zn`, `Ga`, `Ge`, `As`, `Se`, `Br`, `Kr`, `Rb`, `Sr`, `Y`, `Zr`, `Nb`, `Mo`, `Tc`, `Ru`, `Rh`, `Pd`, `Ag`, `Cd`, `In`, `Sn`, `Sb`, `Te`, `I`, `Xe`, `Cs`, `Ba`, `La`, `Ce`, `Pr`, `Nd`, `Pm`, `Sm`, `Eu`, `Gd`, `Tb`, `Dy`, `Ho`, `Er`, `Tm`, `Yb`, `Lu`, `Hf`, `Ta`, `W`, `Re`, `Os`, `Ir`, `Pt`, `Au`, `Hg`, `Tl`, `Pb`, `Bi`, `Po`, `At`, `Rn`, `Fr`, `Ra`, `Ac`, `Th`, `Pa`, `U`, `Np`, `Pu`, `Am`, `Cm`, `Bk`, `Cf`, `Es`, `Fm`, `Md`, `No`, `Lr`, `Rf`, `Db`, `Sg`, `Bh`, `Hs`, `Mt`, `Ds`, `Rg`, `Cn`, `Nh`, `Fl`, `Mc`, `Lv`, `Ts`, `Og`];
201
205
  export const SUPERSCRIPT_MAP = {
202
206
  '0': `⁰`,
@@ -1,5 +1,14 @@
1
- <script lang="ts">import Icon from '../Icon.svelte';
2
- let { fullscreen = $bindable(false), class: className, ...rest } = $props();
1
+ <script lang="ts">
2
+ import Icon from '../Icon.svelte'
3
+ import type { HTMLButtonAttributes } from 'svelte/elements'
4
+
5
+ let {
6
+ fullscreen = $bindable(false),
7
+ class: className,
8
+ ...rest
9
+ }: HTMLButtonAttributes & {
10
+ fullscreen?: boolean
11
+ } = $props()
3
12
  </script>
4
13
 
5
14
  <button