matterviz 0.3.4 → 0.3.6

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 (852) hide show
  1. package/.vscode/launch.json +13 -0
  2. package/.vscodeignore +7 -0
  3. package/dist/assets/STLExporter-BpTH3YHE.js +8 -0
  4. package/dist/assets/browser-DdDecX_W.js +1 -0
  5. package/dist/assets/export-qgn-H9y6.js +2 -0
  6. package/dist/assets/main-DiKYzti2.css +1 -0
  7. package/dist/assets/moyo_wasm_bg-0ocwg7xY.wasm +0 -0
  8. package/dist/extension.js +31293 -0
  9. package/dist/src/lib/FilePicker.svelte +360 -0
  10. package/dist/src/lib/MillerIndexInput.svelte +66 -0
  11. package/dist/src/lib/api/mp.ts +26 -0
  12. package/dist/src/lib/api/optimade.ts +204 -0
  13. package/dist/src/lib/app.css +247 -0
  14. package/dist/src/lib/brillouin/BrillouinZone.svelte +549 -0
  15. package/dist/src/lib/brillouin/BrillouinZoneControls.svelte +144 -0
  16. package/dist/src/lib/brillouin/BrillouinZoneExportPane.svelte +146 -0
  17. package/dist/src/lib/brillouin/BrillouinZoneInfoPane.svelte +146 -0
  18. package/dist/src/lib/brillouin/BrillouinZoneScene.svelte +476 -0
  19. package/dist/src/lib/brillouin/BrillouinZoneTooltip.svelte +92 -0
  20. package/dist/src/lib/brillouin/compute.ts +529 -0
  21. package/dist/src/lib/brillouin/index.ts +8 -0
  22. package/dist/src/lib/brillouin/types.ts +51 -0
  23. package/dist/src/lib/chempot-diagram/ChemPotDiagram.svelte +327 -0
  24. package/dist/src/lib/chempot-diagram/ChemPotDiagram2D.svelte +846 -0
  25. package/dist/src/lib/chempot-diagram/ChemPotDiagram3D.svelte +3193 -0
  26. package/dist/src/lib/chempot-diagram/async-compute.svelte.ts +94 -0
  27. package/dist/src/lib/chempot-diagram/chempot-worker.ts +11 -0
  28. package/dist/src/lib/chempot-diagram/color.ts +42 -0
  29. package/dist/src/lib/chempot-diagram/compute.ts +1014 -0
  30. package/dist/src/lib/chempot-diagram/index.ts +6 -0
  31. package/dist/src/lib/chempot-diagram/pointer.ts +56 -0
  32. package/dist/src/lib/chempot-diagram/temperature.ts +77 -0
  33. package/dist/src/lib/chempot-diagram/types.ts +130 -0
  34. package/dist/src/lib/colors/index.ts +249 -0
  35. package/dist/src/lib/composition/BarChart.svelte +297 -0
  36. package/dist/src/lib/composition/BubbleChart.svelte +218 -0
  37. package/dist/src/lib/composition/Composition.svelte +165 -0
  38. package/dist/src/lib/composition/Formula.svelte +268 -0
  39. package/dist/src/lib/composition/FormulaFilter.svelte +1257 -0
  40. package/dist/src/lib/composition/PieChart.svelte +323 -0
  41. package/dist/src/lib/composition/format.ts +155 -0
  42. package/dist/src/lib/composition/index.ts +37 -0
  43. package/dist/src/lib/composition/parse.ts +605 -0
  44. package/dist/src/lib/constants.ts +134 -0
  45. package/dist/src/lib/controls.ts +42 -0
  46. package/dist/src/lib/convex-hull/ConvexHull.svelte +157 -0
  47. package/dist/src/lib/convex-hull/ConvexHull2D.svelte +825 -0
  48. package/dist/src/lib/convex-hull/ConvexHull3D.svelte +1801 -0
  49. package/dist/src/lib/convex-hull/ConvexHull4D.svelte +1398 -0
  50. package/dist/src/lib/convex-hull/ConvexHullControls.svelte +535 -0
  51. package/dist/src/lib/convex-hull/ConvexHullInfoPane.svelte +125 -0
  52. package/dist/src/lib/convex-hull/ConvexHullStats.svelte +929 -0
  53. package/dist/src/lib/convex-hull/ConvexHullTooltip.svelte +131 -0
  54. package/dist/src/lib/convex-hull/GasPressureControls.svelte +247 -0
  55. package/dist/src/lib/convex-hull/StructurePopup.svelte +151 -0
  56. package/dist/src/lib/convex-hull/TemperatureSlider.svelte +140 -0
  57. package/dist/src/lib/convex-hull/barycentric-coords.ts +246 -0
  58. package/dist/src/lib/convex-hull/demo-temperature.ts +63 -0
  59. package/dist/src/lib/convex-hull/gas-thermodynamics.ts +405 -0
  60. package/dist/src/lib/convex-hull/helpers.ts +932 -0
  61. package/dist/src/lib/convex-hull/index.ts +202 -0
  62. package/dist/src/lib/convex-hull/thermodynamics.ts +2192 -0
  63. package/dist/src/lib/convex-hull/types.ts +267 -0
  64. package/dist/src/lib/coordination/CoordinationBarPlot.svelte +311 -0
  65. package/dist/src/lib/coordination/calc-coordination.ts +93 -0
  66. package/dist/src/lib/coordination/index.ts +9 -0
  67. package/dist/src/lib/effects.svelte.ts +48 -0
  68. package/dist/src/lib/element/BohrAtom.svelte +147 -0
  69. package/dist/src/lib/element/ElementHeading.svelte +26 -0
  70. package/dist/src/lib/element/ElementPhoto.svelte +57 -0
  71. package/dist/src/lib/element/ElementStats.svelte +80 -0
  72. package/dist/src/lib/element/ElementTile.svelte +484 -0
  73. package/dist/src/lib/element/data.json.gz.d.ts +4 -0
  74. package/dist/src/lib/element/data.ts +14 -0
  75. package/dist/src/lib/element/index.ts +8 -0
  76. package/dist/src/lib/element/types.ts +62 -0
  77. package/dist/src/lib/feedback/ClickFeedback.svelte +58 -0
  78. package/dist/src/lib/feedback/DragOverlay.svelte +42 -0
  79. package/dist/src/lib/feedback/index.ts +4 -0
  80. package/dist/src/lib/fermi-surface/FermiSlice.svelte +189 -0
  81. package/dist/src/lib/fermi-surface/FermiSurface.svelte +600 -0
  82. package/dist/src/lib/fermi-surface/FermiSurfaceControls.svelte +448 -0
  83. package/dist/src/lib/fermi-surface/FermiSurfaceScene.svelte +794 -0
  84. package/dist/src/lib/fermi-surface/FermiSurfaceTooltip.svelte +111 -0
  85. package/dist/src/lib/fermi-surface/compute.ts +728 -0
  86. package/dist/src/lib/fermi-surface/constants.ts +32 -0
  87. package/dist/src/lib/fermi-surface/export.ts +64 -0
  88. package/dist/src/lib/fermi-surface/index.ts +14 -0
  89. package/dist/src/lib/fermi-surface/marching-cubes.ts +3 -0
  90. package/dist/src/lib/fermi-surface/parse.ts +574 -0
  91. package/dist/src/lib/fermi-surface/symmetry.ts +56 -0
  92. package/dist/src/lib/fermi-surface/types.ts +159 -0
  93. package/dist/src/lib/heatmap-matrix/HeatmapMatrix.svelte +1545 -0
  94. package/dist/src/lib/heatmap-matrix/HeatmapMatrixControls.svelte +225 -0
  95. package/dist/src/lib/heatmap-matrix/index.ts +167 -0
  96. package/dist/src/lib/heatmap-matrix/shared.ts +7 -0
  97. package/dist/src/lib/icons.ts +650 -0
  98. package/dist/src/lib/index.ts +61 -0
  99. package/dist/src/lib/io/decompress.ts +92 -0
  100. package/dist/src/lib/io/export.ts +385 -0
  101. package/dist/src/lib/io/fetch.ts +46 -0
  102. package/dist/src/lib/io/file-drop.ts +51 -0
  103. package/dist/src/lib/io/index.ts +7 -0
  104. package/dist/src/lib/io/is-binary.ts +24 -0
  105. package/dist/src/lib/io/types.ts +8 -0
  106. package/dist/src/lib/io/url-drop.ts +141 -0
  107. package/dist/src/lib/isosurface/Isosurface.svelte +285 -0
  108. package/dist/src/lib/isosurface/IsosurfaceControls.svelte +277 -0
  109. package/dist/src/lib/isosurface/index.ts +7 -0
  110. package/dist/src/lib/isosurface/parse.ts +656 -0
  111. package/dist/src/lib/isosurface/slice.ts +175 -0
  112. package/dist/src/lib/isosurface/types.ts +309 -0
  113. package/dist/src/lib/labels.ts +320 -0
  114. package/dist/src/lib/layout/FullscreenToggle.svelte +50 -0
  115. package/dist/src/lib/layout/InfoCard.svelte +120 -0
  116. package/dist/src/lib/layout/InfoTag.svelte +185 -0
  117. package/dist/src/lib/layout/PropertyFilter.svelte +246 -0
  118. package/dist/src/lib/layout/SettingsSection.svelte +148 -0
  119. package/dist/src/lib/layout/SubpageGrid.svelte +82 -0
  120. package/dist/src/lib/layout/fullscreen.ts +65 -0
  121. package/dist/src/lib/layout/index.ts +11 -0
  122. package/dist/src/lib/layout/json-tree/JsonNode.svelte +548 -0
  123. package/dist/src/lib/layout/json-tree/JsonTree.svelte +1230 -0
  124. package/dist/src/lib/layout/json-tree/JsonValue.svelte +334 -0
  125. package/dist/src/lib/layout/json-tree/index.ts +3 -0
  126. package/dist/src/lib/layout/json-tree/types.ts +126 -0
  127. package/dist/src/lib/layout/json-tree/utils.ts +682 -0
  128. package/dist/src/lib/marching-cubes.ts +614 -0
  129. package/dist/src/lib/math.ts +1081 -0
  130. package/dist/src/lib/overlays/ContextMenu.svelte +162 -0
  131. package/dist/src/lib/overlays/CopyButton.svelte +45 -0
  132. package/dist/src/lib/overlays/DragControlTab.svelte +98 -0
  133. package/dist/src/lib/overlays/DraggablePane.svelte +487 -0
  134. package/dist/src/lib/overlays/InfoPaneCards.svelte +149 -0
  135. package/dist/src/lib/overlays/index.ts +3 -0
  136. package/dist/src/lib/periodic-table/PeriodicTable.svelte +469 -0
  137. package/dist/src/lib/periodic-table/PeriodicTableControls.svelte +557 -0
  138. package/dist/src/lib/periodic-table/PropertySelect.svelte +37 -0
  139. package/dist/src/lib/periodic-table/index.ts +12 -0
  140. package/dist/src/lib/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +1086 -0
  141. package/dist/src/lib/phase-diagram/PhaseDiagramControls.svelte +444 -0
  142. package/dist/src/lib/phase-diagram/PhaseDiagramEditorPane.svelte +126 -0
  143. package/dist/src/lib/phase-diagram/PhaseDiagramExportPane.svelte +184 -0
  144. package/dist/src/lib/phase-diagram/PhaseDiagramTooltip.svelte +391 -0
  145. package/dist/src/lib/phase-diagram/TdbInfoPanel.svelte +203 -0
  146. package/dist/src/lib/phase-diagram/build-diagram.ts +186 -0
  147. package/dist/src/lib/phase-diagram/colors.ts +58 -0
  148. package/dist/src/lib/phase-diagram/diagram-input.ts +40 -0
  149. package/dist/src/lib/phase-diagram/index.ts +13 -0
  150. package/dist/src/lib/phase-diagram/parse.ts +348 -0
  151. package/dist/src/lib/phase-diagram/svg-to-diagram.ts +1023 -0
  152. package/dist/src/lib/phase-diagram/types.ts +144 -0
  153. package/dist/src/lib/phase-diagram/utils.ts +775 -0
  154. package/dist/src/lib/plot/AxisLabel.svelte +51 -0
  155. package/dist/src/lib/plot/BarPlot.svelte +2113 -0
  156. package/dist/src/lib/plot/BarPlotControls.svelte +66 -0
  157. package/dist/src/lib/plot/BinnedScatterPlot.svelte +1114 -0
  158. package/dist/src/lib/plot/ColorBar.svelte +721 -0
  159. package/dist/src/lib/plot/ColorScaleSelect.svelte +54 -0
  160. package/dist/src/lib/plot/ElementScatter.svelte +63 -0
  161. package/dist/src/lib/plot/FillArea.svelte +223 -0
  162. package/dist/src/lib/plot/Histogram.svelte +1558 -0
  163. package/dist/src/lib/plot/HistogramControls.svelte +212 -0
  164. package/dist/src/lib/plot/InteractiveAxisLabel.svelte +96 -0
  165. package/dist/src/lib/plot/Line.svelte +84 -0
  166. package/dist/src/lib/plot/PlotAxis.svelte +169 -0
  167. package/dist/src/lib/plot/PlotControls.svelte +537 -0
  168. package/dist/src/lib/plot/PlotLegend.svelte +569 -0
  169. package/dist/src/lib/plot/PlotTooltip.svelte +67 -0
  170. package/dist/src/lib/plot/PortalSelect.svelte +253 -0
  171. package/dist/src/lib/plot/ReferenceLine3D.svelte +156 -0
  172. package/dist/src/lib/plot/ReferencePlane.svelte +175 -0
  173. package/dist/src/lib/plot/ScatterPlot.svelte +2778 -0
  174. package/dist/src/lib/plot/ScatterPlot3D.svelte +529 -0
  175. package/dist/src/lib/plot/ScatterPlot3DControls.svelte +437 -0
  176. package/dist/src/lib/plot/ScatterPlot3DScene.svelte +912 -0
  177. package/dist/src/lib/plot/ScatterPlotControls.svelte +306 -0
  178. package/dist/src/lib/plot/ScatterPoint.svelte +182 -0
  179. package/dist/src/lib/plot/SpacegroupBarPlot.svelte +293 -0
  180. package/dist/src/lib/plot/Surface3D.svelte +197 -0
  181. package/dist/src/lib/plot/ZeroLines.svelte +97 -0
  182. package/dist/src/lib/plot/ZoomRect.svelte +23 -0
  183. package/dist/src/lib/plot/adaptive-density.ts +316 -0
  184. package/dist/src/lib/plot/auto-place.ts +184 -0
  185. package/dist/src/lib/plot/axis-utils.ts +122 -0
  186. package/dist/src/lib/plot/binned-scatter-types.ts +83 -0
  187. package/dist/src/lib/plot/data-cleaning.ts +1069 -0
  188. package/dist/src/lib/plot/data-transform.ts +69 -0
  189. package/dist/src/lib/plot/defaults.ts +9 -0
  190. package/dist/src/lib/plot/fill-utils.ts +494 -0
  191. package/dist/src/lib/plot/hover-lock.svelte.ts +60 -0
  192. package/dist/src/lib/plot/index.ts +53 -0
  193. package/dist/src/lib/plot/interactions.ts +119 -0
  194. package/dist/src/lib/plot/layout.ts +425 -0
  195. package/dist/src/lib/plot/reference-line.ts +426 -0
  196. package/dist/src/lib/plot/scales.ts +654 -0
  197. package/dist/src/lib/plot/svg.ts +23 -0
  198. package/dist/src/lib/plot/types.ts +1144 -0
  199. package/dist/src/lib/plot/utils/label-placement.ts +541 -0
  200. package/dist/src/lib/plot/utils/series-visibility.ts +140 -0
  201. package/dist/src/lib/plot/utils.ts +11 -0
  202. package/dist/src/lib/rdf/RdfPlot.svelte +247 -0
  203. package/dist/src/lib/rdf/calc-rdf.ts +167 -0
  204. package/dist/src/lib/rdf/index.ts +27 -0
  205. package/dist/src/lib/sanitize.ts +126 -0
  206. package/dist/src/lib/settings.ts +1479 -0
  207. package/dist/src/lib/spectral/Bands.svelte +1040 -0
  208. package/dist/src/lib/spectral/BandsAndDos.svelte +134 -0
  209. package/dist/src/lib/spectral/BrillouinBandsDos.svelte +252 -0
  210. package/dist/src/lib/spectral/Dos.svelte +697 -0
  211. package/dist/src/lib/spectral/helpers.ts +1381 -0
  212. package/dist/src/lib/spectral/index.ts +8 -0
  213. package/dist/src/lib/spectral/types.ts +112 -0
  214. package/dist/src/lib/state.svelte.ts +64 -0
  215. package/dist/src/lib/structure/Arrow.svelte +72 -0
  216. package/dist/src/lib/structure/AtomLegend.svelte +815 -0
  217. package/dist/src/lib/structure/Bond.svelte +140 -0
  218. package/dist/src/lib/structure/CanvasTooltip.svelte +33 -0
  219. package/dist/src/lib/structure/CellSelect.svelte +349 -0
  220. package/dist/src/lib/structure/Cylinder.svelte +45 -0
  221. package/dist/src/lib/structure/Lattice.svelte +196 -0
  222. package/dist/src/lib/structure/Structure.svelte +2248 -0
  223. package/dist/src/lib/structure/StructureControls.svelte +1273 -0
  224. package/dist/src/lib/structure/StructureExportPane.svelte +252 -0
  225. package/dist/src/lib/structure/StructureInfoPane.svelte +737 -0
  226. package/dist/src/lib/structure/StructureScene.svelte +2255 -0
  227. package/dist/src/lib/structure/atom-properties.ts +316 -0
  228. package/dist/src/lib/structure/bond-order-perception.ts +447 -0
  229. package/dist/src/lib/structure/bonding.ts +944 -0
  230. package/dist/src/lib/structure/export.ts +861 -0
  231. package/dist/src/lib/structure/index.ts +291 -0
  232. package/dist/src/lib/structure/label-placement.ts +130 -0
  233. package/dist/src/lib/structure/measure.ts +45 -0
  234. package/dist/src/lib/structure/parse.ts +1705 -0
  235. package/dist/src/lib/structure/partial-occupancy.ts +183 -0
  236. package/dist/src/lib/structure/pbc.ts +164 -0
  237. package/dist/src/lib/structure/supercell.ts +226 -0
  238. package/dist/src/lib/structure/validation.ts +11 -0
  239. package/dist/src/lib/symmetry/SymmetryStats.svelte +226 -0
  240. package/dist/src/lib/symmetry/WyckoffTable.svelte +120 -0
  241. package/dist/src/lib/symmetry/cell-transform.ts +118 -0
  242. package/dist/src/lib/symmetry/index.ts +348 -0
  243. package/dist/src/lib/symmetry/spacegroups.ts +404 -0
  244. package/dist/src/lib/table/HeatmapTable.svelte +1833 -0
  245. package/dist/src/lib/table/ToggleMenu.svelte +385 -0
  246. package/dist/src/lib/table/index.ts +139 -0
  247. package/dist/src/lib/theme/ThemeControl.svelte +53 -0
  248. package/dist/src/lib/theme/index.ts +107 -0
  249. package/dist/src/lib/theme/themes.mjs +297 -0
  250. package/dist/src/lib/time.ts +71 -0
  251. package/dist/src/lib/tooltip/TooltipContent.svelte +58 -0
  252. package/dist/src/lib/tooltip/index.ts +2 -0
  253. package/dist/src/lib/tooltip/types.ts +13 -0
  254. package/dist/src/lib/trajectory/Trajectory.svelte +1545 -0
  255. package/dist/src/lib/trajectory/TrajectoryError.svelte +128 -0
  256. package/dist/src/lib/trajectory/TrajectoryExportPane.svelte +357 -0
  257. package/dist/src/lib/trajectory/TrajectoryInfoPane.svelte +313 -0
  258. package/dist/src/lib/trajectory/constants.ts +7 -0
  259. package/dist/src/lib/trajectory/extract.ts +196 -0
  260. package/dist/src/lib/trajectory/format-detect.ts +96 -0
  261. package/dist/src/lib/trajectory/frame-reader.ts +456 -0
  262. package/dist/src/lib/trajectory/helpers.ts +217 -0
  263. package/dist/src/lib/trajectory/index.ts +218 -0
  264. package/dist/src/lib/trajectory/parse/ase.ts +109 -0
  265. package/dist/src/lib/trajectory/parse/hdf5.ts +173 -0
  266. package/dist/src/lib/trajectory/parse/index.ts +411 -0
  267. package/dist/src/lib/trajectory/parse/lammps.ts +215 -0
  268. package/dist/src/lib/trajectory/parse/vasp.ts +102 -0
  269. package/dist/src/lib/trajectory/parse/xyz.ts +143 -0
  270. package/dist/src/lib/trajectory/plotting.ts +599 -0
  271. package/dist/src/lib/trajectory/types.ts +13 -0
  272. package/dist/src/lib/utils.ts +56 -0
  273. package/dist/src/lib/xrd/XrdPlot.svelte +615 -0
  274. package/dist/src/lib/xrd/broadening.ts +130 -0
  275. package/dist/src/lib/xrd/calc-xrd.ts +397 -0
  276. package/dist/src/lib/xrd/index.ts +38 -0
  277. package/dist/src/lib/xrd/parse.ts +858 -0
  278. package/dist/webview.js +29421 -0
  279. package/icon.png +0 -0
  280. package/license +1 -1
  281. package/matterviz-0.3.2.vsix +0 -0
  282. package/matterviz-0.3.4.vsix +0 -0
  283. package/matterviz-0.3.5.vsix +0 -0
  284. package/package.json +1461 -231
  285. package/readme.md +171 -98
  286. package/scripts/sync-config.ts +101 -0
  287. package/src/declarations.d.ts +2 -0
  288. package/src/extension.ts +972 -0
  289. package/src/node-io.ts +65 -0
  290. package/src/types.ts +17 -0
  291. package/src/webview/JsonBrowser.svelte +1079 -0
  292. package/src/webview/PlotPanel.svelte +346 -0
  293. package/src/webview/detect.ts +444 -0
  294. package/src/webview/main.ts +764 -0
  295. package/src/webview/plot-utils.ts +250 -0
  296. package/test-fixtures/all-viz-types.json.gz +0 -0
  297. package/test-fixtures/plot-demo-data.json.gz +0 -0
  298. package/tests/detect.test.ts +604 -0
  299. package/tests/extension.test.ts +2041 -0
  300. package/tests/node-io.test.ts +39 -0
  301. package/tests/plot-utils.test.ts +302 -0
  302. package/tests/vite-plugin-json-gz.test.ts +114 -0
  303. package/tests/vscode-mock.ts +18 -0
  304. package/tests/webview.test.ts +231 -0
  305. package/tsconfig.json +20 -0
  306. package/vite-plugin-json-gz.ts +29 -0
  307. package/vite.config.ts +34 -0
  308. package/vite.extension.config.ts +34 -0
  309. package/dist/EmptyState.svelte.d.ts +0 -9
  310. package/dist/FilePicker.svelte +0 -360
  311. package/dist/FilePicker.svelte.d.ts +0 -17
  312. package/dist/Icon.svelte.d.ts +0 -13
  313. package/dist/MillerIndexInput.svelte +0 -66
  314. package/dist/MillerIndexInput.svelte.d.ts +0 -7
  315. package/dist/api/mp.d.ts +0 -6
  316. package/dist/api/mp.js +0 -22
  317. package/dist/api/optimade.d.ts +0 -45
  318. package/dist/api/optimade.js +0 -135
  319. package/dist/app.css +0 -240
  320. package/dist/brillouin/BrillouinZone.svelte +0 -543
  321. package/dist/brillouin/BrillouinZone.svelte.d.ts +0 -83
  322. package/dist/brillouin/BrillouinZoneControls.svelte +0 -144
  323. package/dist/brillouin/BrillouinZoneControls.svelte.d.ts +0 -17
  324. package/dist/brillouin/BrillouinZoneExportPane.svelte +0 -148
  325. package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +0 -15
  326. package/dist/brillouin/BrillouinZoneInfoPane.svelte +0 -146
  327. package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +0 -13
  328. package/dist/brillouin/BrillouinZoneScene.svelte +0 -476
  329. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +0 -48
  330. package/dist/brillouin/BrillouinZoneTooltip.svelte +0 -92
  331. package/dist/brillouin/BrillouinZoneTooltip.svelte.d.ts +0 -8
  332. package/dist/brillouin/compute.d.ts +0 -17
  333. package/dist/brillouin/compute.js +0 -422
  334. package/dist/brillouin/index.d.ts +0 -8
  335. package/dist/brillouin/index.js +0 -8
  336. package/dist/brillouin/types.d.ts +0 -48
  337. package/dist/brillouin/types.js +0 -1
  338. package/dist/chempot-diagram/ChemPotDiagram.svelte +0 -327
  339. package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +0 -13
  340. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +0 -847
  341. package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +0 -16
  342. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +0 -3194
  343. package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +0 -16
  344. package/dist/chempot-diagram/ChemPotScene3D.svelte.d.ts +0 -7
  345. package/dist/chempot-diagram/async-compute.svelte.d.ts +0 -3
  346. package/dist/chempot-diagram/async-compute.svelte.js +0 -77
  347. package/dist/chempot-diagram/chempot-worker.d.ts +0 -1
  348. package/dist/chempot-diagram/chempot-worker.js +0 -11
  349. package/dist/chempot-diagram/color.d.ts +0 -10
  350. package/dist/chempot-diagram/color.js +0 -32
  351. package/dist/chempot-diagram/compute.d.ts +0 -48
  352. package/dist/chempot-diagram/compute.js +0 -812
  353. package/dist/chempot-diagram/index.d.ts +0 -6
  354. package/dist/chempot-diagram/index.js +0 -6
  355. package/dist/chempot-diagram/pointer.d.ts +0 -16
  356. package/dist/chempot-diagram/pointer.js +0 -40
  357. package/dist/chempot-diagram/temperature.d.ts +0 -15
  358. package/dist/chempot-diagram/temperature.js +0 -36
  359. package/dist/chempot-diagram/types.d.ts +0 -86
  360. package/dist/chempot-diagram/types.js +0 -28
  361. package/dist/colors/index.d.ts +0 -47
  362. package/dist/colors/index.js +0 -203
  363. package/dist/composition/BarChart.svelte +0 -297
  364. package/dist/composition/BarChart.svelte.d.ts +0 -39
  365. package/dist/composition/BubbleChart.svelte +0 -218
  366. package/dist/composition/BubbleChart.svelte.d.ts +0 -28
  367. package/dist/composition/Composition.svelte +0 -164
  368. package/dist/composition/Composition.svelte.d.ts +0 -15
  369. package/dist/composition/Formula.svelte +0 -265
  370. package/dist/composition/Formula.svelte.d.ts +0 -19
  371. package/dist/composition/FormulaFilter.svelte +0 -1259
  372. package/dist/composition/FormulaFilter.svelte.d.ts +0 -51
  373. package/dist/composition/PieChart.svelte +0 -323
  374. package/dist/composition/PieChart.svelte.d.ts +0 -37
  375. package/dist/composition/format.d.ts +0 -15
  376. package/dist/composition/format.js +0 -109
  377. package/dist/composition/index.d.ts +0 -20
  378. package/dist/composition/index.js +0 -14
  379. package/dist/composition/parse.d.ts +0 -55
  380. package/dist/composition/parse.js +0 -459
  381. package/dist/constants.d.ts +0 -29
  382. package/dist/constants.js +0 -105
  383. package/dist/controls.d.ts +0 -14
  384. package/dist/controls.js +0 -30
  385. package/dist/convex-hull/ConvexHull.svelte +0 -157
  386. package/dist/convex-hull/ConvexHull.svelte.d.ts +0 -13
  387. package/dist/convex-hull/ConvexHull2D.svelte +0 -813
  388. package/dist/convex-hull/ConvexHull2D.svelte.d.ts +0 -11
  389. package/dist/convex-hull/ConvexHull3D.svelte +0 -1788
  390. package/dist/convex-hull/ConvexHull3D.svelte.d.ts +0 -8
  391. package/dist/convex-hull/ConvexHull4D.svelte +0 -1374
  392. package/dist/convex-hull/ConvexHull4D.svelte.d.ts +0 -8
  393. package/dist/convex-hull/ConvexHullControls.svelte +0 -546
  394. package/dist/convex-hull/ConvexHullControls.svelte.d.ts +0 -48
  395. package/dist/convex-hull/ConvexHullInfoPane.svelte +0 -115
  396. package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +0 -18
  397. package/dist/convex-hull/ConvexHullStats.svelte +0 -905
  398. package/dist/convex-hull/ConvexHullStats.svelte.d.ts +0 -15
  399. package/dist/convex-hull/ConvexHullTooltip.svelte +0 -131
  400. package/dist/convex-hull/ConvexHullTooltip.svelte.d.ts +0 -33
  401. package/dist/convex-hull/GasPressureControls.svelte +0 -247
  402. package/dist/convex-hull/GasPressureControls.svelte.d.ts +0 -11
  403. package/dist/convex-hull/StructurePopup.svelte +0 -116
  404. package/dist/convex-hull/StructurePopup.svelte.d.ts +0 -18
  405. package/dist/convex-hull/TemperatureSlider.svelte +0 -137
  406. package/dist/convex-hull/TemperatureSlider.svelte.d.ts +0 -8
  407. package/dist/convex-hull/barycentric-coords.d.ts +0 -18
  408. package/dist/convex-hull/barycentric-coords.js +0 -182
  409. package/dist/convex-hull/demo-temperature.d.ts +0 -6
  410. package/dist/convex-hull/demo-temperature.js +0 -40
  411. package/dist/convex-hull/gas-thermodynamics.d.ts +0 -16
  412. package/dist/convex-hull/gas-thermodynamics.js +0 -316
  413. package/dist/convex-hull/helpers.d.ts +0 -103
  414. package/dist/convex-hull/helpers.js +0 -671
  415. package/dist/convex-hull/index.d.ts +0 -118
  416. package/dist/convex-hull/index.js +0 -57
  417. package/dist/convex-hull/thermodynamics.d.ts +0 -66
  418. package/dist/convex-hull/thermodynamics.js +0 -1752
  419. package/dist/convex-hull/types.d.ts +0 -162
  420. package/dist/convex-hull/types.js +0 -36
  421. package/dist/coordination/CoordinationBarPlot.svelte +0 -311
  422. package/dist/coordination/CoordinationBarPlot.svelte.d.ts +0 -30
  423. package/dist/coordination/calc-coordination.d.ts +0 -15
  424. package/dist/coordination/calc-coordination.js +0 -63
  425. package/dist/coordination/index.d.ts +0 -8
  426. package/dist/coordination/index.js +0 -7
  427. package/dist/element/BohrAtom.svelte +0 -149
  428. package/dist/element/BohrAtom.svelte.d.ts +0 -20
  429. package/dist/element/ElementHeading.svelte +0 -26
  430. package/dist/element/ElementHeading.svelte.d.ts +0 -8
  431. package/dist/element/ElementPhoto.svelte +0 -57
  432. package/dist/element/ElementPhoto.svelte.d.ts +0 -9
  433. package/dist/element/ElementStats.svelte +0 -80
  434. package/dist/element/ElementStats.svelte.d.ts +0 -8
  435. package/dist/element/ElementTile.svelte +0 -484
  436. package/dist/element/ElementTile.svelte.d.ts +0 -29
  437. package/dist/element/Nucleus.svelte.d.ts +0 -17
  438. package/dist/element/data.d.ts +0 -3
  439. package/dist/element/data.js +0 -2
  440. package/dist/element/data.json.gz.d.ts +0 -2
  441. package/dist/element/index.d.ts +0 -8
  442. package/dist/element/index.js +0 -8
  443. package/dist/element/types.d.ts +0 -57
  444. package/dist/element/types.js +0 -1
  445. package/dist/feedback/ClickFeedback.svelte +0 -58
  446. package/dist/feedback/ClickFeedback.svelte.d.ts +0 -12
  447. package/dist/feedback/DragOverlay.svelte +0 -42
  448. package/dist/feedback/DragOverlay.svelte.d.ts +0 -7
  449. package/dist/feedback/Spinner.svelte.d.ts +0 -7
  450. package/dist/feedback/StatusMessage.svelte.d.ts +0 -9
  451. package/dist/feedback/index.d.ts +0 -4
  452. package/dist/feedback/index.js +0 -4
  453. package/dist/fermi-surface/FermiSlice.svelte +0 -189
  454. package/dist/fermi-surface/FermiSlice.svelte.d.ts +0 -24
  455. package/dist/fermi-surface/FermiSurface.svelte +0 -597
  456. package/dist/fermi-surface/FermiSurface.svelte.d.ts +0 -83
  457. package/dist/fermi-surface/FermiSurfaceControls.svelte +0 -452
  458. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +0 -35
  459. package/dist/fermi-surface/FermiSurfaceScene.svelte +0 -792
  460. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +0 -50
  461. package/dist/fermi-surface/FermiSurfaceTooltip.svelte +0 -111
  462. package/dist/fermi-surface/FermiSurfaceTooltip.svelte.d.ts +0 -8
  463. package/dist/fermi-surface/compute.d.ts +0 -5
  464. package/dist/fermi-surface/compute.js +0 -538
  465. package/dist/fermi-surface/constants.d.ts +0 -9
  466. package/dist/fermi-surface/constants.js +0 -27
  467. package/dist/fermi-surface/export.d.ts +0 -5
  468. package/dist/fermi-surface/export.js +0 -63
  469. package/dist/fermi-surface/index.d.ts +0 -12
  470. package/dist/fermi-surface/index.js +0 -13
  471. package/dist/fermi-surface/marching-cubes.d.ts +0 -2
  472. package/dist/fermi-surface/marching-cubes.js +0 -2
  473. package/dist/fermi-surface/parse.d.ts +0 -2
  474. package/dist/fermi-surface/parse.js +0 -495
  475. package/dist/fermi-surface/symmetry.d.ts +0 -3
  476. package/dist/fermi-surface/symmetry.js +0 -46
  477. package/dist/fermi-surface/types.d.ts +0 -113
  478. package/dist/fermi-surface/types.js +0 -4
  479. package/dist/heatmap-matrix/HeatmapMatrix.svelte +0 -1527
  480. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +0 -110
  481. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +0 -225
  482. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +0 -30
  483. package/dist/heatmap-matrix/index.d.ts +0 -53
  484. package/dist/heatmap-matrix/index.js +0 -100
  485. package/dist/heatmap-matrix/shared.d.ts +0 -2
  486. package/dist/heatmap-matrix/shared.js +0 -4
  487. package/dist/icons.d.ts +0 -569
  488. package/dist/icons.js +0 -648
  489. package/dist/index.d.ts +0 -39
  490. package/dist/index.js +0 -39
  491. package/dist/io/decompress.d.ts +0 -10
  492. package/dist/io/decompress.js +0 -69
  493. package/dist/io/export.d.ts +0 -16
  494. package/dist/io/export.js +0 -312
  495. package/dist/io/fetch.d.ts +0 -5
  496. package/dist/io/fetch.js +0 -39
  497. package/dist/io/file-drop.d.ts +0 -7
  498. package/dist/io/file-drop.js +0 -43
  499. package/dist/io/index.d.ts +0 -7
  500. package/dist/io/index.js +0 -7
  501. package/dist/io/is-binary.d.ts +0 -1
  502. package/dist/io/is-binary.js +0 -5
  503. package/dist/io/types.d.ts +0 -8
  504. package/dist/io/types.js +0 -1
  505. package/dist/io/url-drop.d.ts +0 -2
  506. package/dist/io/url-drop.js +0 -117
  507. package/dist/isosurface/Isosurface.svelte +0 -285
  508. package/dist/isosurface/Isosurface.svelte.d.ts +0 -8
  509. package/dist/isosurface/IsosurfaceControls.svelte +0 -291
  510. package/dist/isosurface/IsosurfaceControls.svelte.d.ts +0 -9
  511. package/dist/isosurface/index.d.ts +0 -5
  512. package/dist/isosurface/index.js +0 -6
  513. package/dist/isosurface/parse.d.ts +0 -6
  514. package/dist/isosurface/parse.js +0 -553
  515. package/dist/isosurface/slice.d.ts +0 -11
  516. package/dist/isosurface/slice.js +0 -140
  517. package/dist/isosurface/types.d.ts +0 -56
  518. package/dist/isosurface/types.js +0 -227
  519. package/dist/labels.d.ts +0 -53
  520. package/dist/labels.js +0 -274
  521. package/dist/layout/FullscreenToggle.svelte +0 -50
  522. package/dist/layout/FullscreenToggle.svelte.d.ts +0 -7
  523. package/dist/layout/InfoCard.svelte +0 -120
  524. package/dist/layout/InfoCard.svelte.d.ts +0 -21
  525. package/dist/layout/InfoTag.svelte +0 -183
  526. package/dist/layout/InfoTag.svelte.d.ts +0 -19
  527. package/dist/layout/PropertyFilter.svelte +0 -244
  528. package/dist/layout/PropertyFilter.svelte.d.ts +0 -24
  529. package/dist/layout/SettingsSection.svelte +0 -148
  530. package/dist/layout/SettingsSection.svelte.d.ts +0 -17
  531. package/dist/layout/SubpageGrid.svelte +0 -82
  532. package/dist/layout/SubpageGrid.svelte.d.ts +0 -14
  533. package/dist/layout/fullscreen.d.ts +0 -9
  534. package/dist/layout/fullscreen.js +0 -53
  535. package/dist/layout/index.d.ts +0 -10
  536. package/dist/layout/index.js +0 -8
  537. package/dist/layout/json-tree/JsonNode.svelte +0 -547
  538. package/dist/layout/json-tree/JsonNode.svelte.d.ts +0 -11
  539. package/dist/layout/json-tree/JsonTree.svelte +0 -1222
  540. package/dist/layout/json-tree/JsonTree.svelte.d.ts +0 -6
  541. package/dist/layout/json-tree/JsonValue.svelte +0 -334
  542. package/dist/layout/json-tree/JsonValue.svelte.d.ts +0 -9
  543. package/dist/layout/json-tree/index.d.ts +0 -3
  544. package/dist/layout/json-tree/index.js +0 -3
  545. package/dist/layout/json-tree/types.d.ts +0 -73
  546. package/dist/layout/json-tree/types.js +0 -3
  547. package/dist/layout/json-tree/utils.d.ts +0 -29
  548. package/dist/layout/json-tree/utils.js +0 -648
  549. package/dist/marching-cubes.d.ts +0 -14
  550. package/dist/marching-cubes.js +0 -542
  551. package/dist/math.d.ts +0 -91
  552. package/dist/math.js +0 -896
  553. package/dist/overlays/ContextMenu.svelte +0 -162
  554. package/dist/overlays/ContextMenu.svelte.d.ts +0 -25
  555. package/dist/overlays/DraggablePane.svelte +0 -564
  556. package/dist/overlays/DraggablePane.svelte.d.ts +0 -36
  557. package/dist/overlays/index.d.ts +0 -2
  558. package/dist/overlays/index.js +0 -2
  559. package/dist/periodic-table/PeriodicTable.svelte +0 -469
  560. package/dist/periodic-table/PeriodicTable.svelte.d.ts +0 -55
  561. package/dist/periodic-table/PeriodicTableControls.svelte +0 -557
  562. package/dist/periodic-table/PeriodicTableControls.svelte.d.ts +0 -24
  563. package/dist/periodic-table/PropertySelect.svelte +0 -37
  564. package/dist/periodic-table/PropertySelect.svelte.d.ts +0 -13
  565. package/dist/periodic-table/TableInset.svelte.d.ts +0 -9
  566. package/dist/periodic-table/index.d.ts +0 -10
  567. package/dist/periodic-table/index.js +0 -4
  568. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +0 -1086
  569. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +0 -44
  570. package/dist/phase-diagram/PhaseDiagramControls.svelte +0 -451
  571. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +0 -30
  572. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +0 -126
  573. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +0 -15
  574. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +0 -192
  575. package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +0 -19
  576. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +0 -392
  577. package/dist/phase-diagram/PhaseDiagramTooltip.svelte.d.ts +0 -16
  578. package/dist/phase-diagram/TdbInfoPanel.svelte +0 -203
  579. package/dist/phase-diagram/TdbInfoPanel.svelte.d.ts +0 -12
  580. package/dist/phase-diagram/build-diagram.d.ts +0 -11
  581. package/dist/phase-diagram/build-diagram.js +0 -167
  582. package/dist/phase-diagram/colors.d.ts +0 -35
  583. package/dist/phase-diagram/colors.js +0 -51
  584. package/dist/phase-diagram/diagram-input.d.ts +0 -33
  585. package/dist/phase-diagram/diagram-input.js +0 -3
  586. package/dist/phase-diagram/index.d.ts +0 -13
  587. package/dist/phase-diagram/index.js +0 -13
  588. package/dist/phase-diagram/parse.d.ts +0 -55
  589. package/dist/phase-diagram/parse.js +0 -276
  590. package/dist/phase-diagram/svg-to-diagram.d.ts +0 -2
  591. package/dist/phase-diagram/svg-to-diagram.js +0 -869
  592. package/dist/phase-diagram/types.d.ts +0 -99
  593. package/dist/phase-diagram/types.js +0 -1
  594. package/dist/phase-diagram/utils.d.ts +0 -118
  595. package/dist/phase-diagram/utils.js +0 -606
  596. package/dist/plot/AxisLabel.svelte +0 -51
  597. package/dist/plot/AxisLabel.svelte.d.ts +0 -16
  598. package/dist/plot/BarPlot.svelte +0 -2256
  599. package/dist/plot/BarPlot.svelte.d.ts +0 -82
  600. package/dist/plot/BarPlotControls.svelte +0 -66
  601. package/dist/plot/BarPlotControls.svelte.d.ts +0 -18
  602. package/dist/plot/ColorBar.svelte +0 -719
  603. package/dist/plot/ColorBar.svelte.d.ts +0 -31
  604. package/dist/plot/ColorScaleSelect.svelte +0 -54
  605. package/dist/plot/ColorScaleSelect.svelte.d.ts +0 -15
  606. package/dist/plot/ElementScatter.svelte +0 -63
  607. package/dist/plot/ElementScatter.svelte.d.ts +0 -14
  608. package/dist/plot/FillArea.svelte +0 -226
  609. package/dist/plot/FillArea.svelte.d.ts +0 -20
  610. package/dist/plot/Histogram.svelte +0 -1654
  611. package/dist/plot/Histogram.svelte.d.ts +0 -50
  612. package/dist/plot/HistogramControls.svelte +0 -212
  613. package/dist/plot/HistogramControls.svelte.d.ts +0 -22
  614. package/dist/plot/InteractiveAxisLabel.svelte +0 -94
  615. package/dist/plot/InteractiveAxisLabel.svelte.d.ts +0 -14
  616. package/dist/plot/Line.svelte +0 -85
  617. package/dist/plot/Line.svelte.d.ts +0 -15
  618. package/dist/plot/PlotControls.svelte +0 -537
  619. package/dist/plot/PlotControls.svelte.d.ts +0 -4
  620. package/dist/plot/PlotLegend.svelte +0 -498
  621. package/dist/plot/PlotLegend.svelte.d.ts +0 -25
  622. package/dist/plot/PlotTooltip.svelte +0 -67
  623. package/dist/plot/PlotTooltip.svelte.d.ts +0 -17
  624. package/dist/plot/PortalSelect.svelte +0 -253
  625. package/dist/plot/PortalSelect.svelte.d.ts +0 -16
  626. package/dist/plot/ReferenceLine.svelte.d.ts +0 -20
  627. package/dist/plot/ReferenceLine3D.svelte +0 -154
  628. package/dist/plot/ReferenceLine3D.svelte.d.ts +0 -14
  629. package/dist/plot/ReferencePlane.svelte +0 -178
  630. package/dist/plot/ReferencePlane.svelte.d.ts +0 -14
  631. package/dist/plot/ScatterPlot.svelte +0 -2831
  632. package/dist/plot/ScatterPlot.svelte.d.ts +0 -92
  633. package/dist/plot/ScatterPlot3D.svelte +0 -499
  634. package/dist/plot/ScatterPlot3D.svelte.d.ts +0 -94
  635. package/dist/plot/ScatterPlot3DControls.svelte +0 -437
  636. package/dist/plot/ScatterPlot3DControls.svelte.d.ts +0 -20
  637. package/dist/plot/ScatterPlot3DScene.svelte +0 -912
  638. package/dist/plot/ScatterPlot3DScene.svelte.d.ts +0 -74
  639. package/dist/plot/ScatterPlotControls.svelte +0 -307
  640. package/dist/plot/ScatterPlotControls.svelte.d.ts +0 -17
  641. package/dist/plot/ScatterPoint.svelte +0 -185
  642. package/dist/plot/ScatterPoint.svelte.d.ts +0 -19
  643. package/dist/plot/SpacegroupBarPlot.svelte +0 -292
  644. package/dist/plot/SpacegroupBarPlot.svelte.d.ts +0 -9
  645. package/dist/plot/Surface3D.svelte +0 -200
  646. package/dist/plot/Surface3D.svelte.d.ts +0 -13
  647. package/dist/plot/ZeroLines.svelte +0 -96
  648. package/dist/plot/ZeroLines.svelte.d.ts +0 -32
  649. package/dist/plot/ZoomRect.svelte +0 -23
  650. package/dist/plot/ZoomRect.svelte.d.ts +0 -8
  651. package/dist/plot/axis-utils.d.ts +0 -19
  652. package/dist/plot/axis-utils.js +0 -80
  653. package/dist/plot/data-cleaning.d.ts +0 -37
  654. package/dist/plot/data-cleaning.js +0 -855
  655. package/dist/plot/data-transform.d.ts +0 -16
  656. package/dist/plot/data-transform.js +0 -45
  657. package/dist/plot/defaults.d.ts +0 -19
  658. package/dist/plot/defaults.js +0 -9
  659. package/dist/plot/fill-utils.d.ts +0 -51
  660. package/dist/plot/fill-utils.js +0 -337
  661. package/dist/plot/hover-lock.svelte.d.ts +0 -14
  662. package/dist/plot/hover-lock.svelte.js +0 -46
  663. package/dist/plot/index.d.ts +0 -43
  664. package/dist/plot/index.js +0 -37
  665. package/dist/plot/interactions.d.ts +0 -12
  666. package/dist/plot/interactions.js +0 -100
  667. package/dist/plot/layout.d.ts +0 -60
  668. package/dist/plot/layout.js +0 -230
  669. package/dist/plot/reference-line.d.ts +0 -60
  670. package/dist/plot/reference-line.js +0 -316
  671. package/dist/plot/scales.d.ts +0 -48
  672. package/dist/plot/scales.js +0 -484
  673. package/dist/plot/svg.d.ts +0 -1
  674. package/dist/plot/svg.js +0 -11
  675. package/dist/plot/types.d.ts +0 -863
  676. package/dist/plot/types.js +0 -103
  677. package/dist/plot/utils/label-placement.d.ts +0 -47
  678. package/dist/plot/utils/label-placement.js +0 -256
  679. package/dist/plot/utils/series-visibility.d.ts +0 -9
  680. package/dist/plot/utils/series-visibility.js +0 -67
  681. package/dist/plot/utils.d.ts +0 -1
  682. package/dist/plot/utils.js +0 -14
  683. package/dist/rdf/RdfPlot.svelte +0 -247
  684. package/dist/rdf/RdfPlot.svelte.d.ts +0 -27
  685. package/dist/rdf/calc-rdf.d.ts +0 -4
  686. package/dist/rdf/calc-rdf.js +0 -111
  687. package/dist/rdf/index.d.ts +0 -23
  688. package/dist/rdf/index.js +0 -2
  689. package/dist/sanitize.d.ts +0 -4
  690. package/dist/sanitize.js +0 -107
  691. package/dist/settings.d.ts +0 -253
  692. package/dist/settings.js +0 -1123
  693. package/dist/spectral/Bands.svelte +0 -1040
  694. package/dist/spectral/Bands.svelte.d.ts +0 -40
  695. package/dist/spectral/BandsAndDos.svelte +0 -128
  696. package/dist/spectral/BandsAndDos.svelte.d.ts +0 -18
  697. package/dist/spectral/BrillouinBandsDos.svelte +0 -248
  698. package/dist/spectral/BrillouinBandsDos.svelte.d.ts +0 -20
  699. package/dist/spectral/Dos.svelte +0 -697
  700. package/dist/spectral/Dos.svelte.d.ts +0 -29
  701. package/dist/spectral/helpers.d.ts +0 -117
  702. package/dist/spectral/helpers.js +0 -1023
  703. package/dist/spectral/index.d.ts +0 -6
  704. package/dist/spectral/index.js +0 -7
  705. package/dist/spectral/types.d.ts +0 -84
  706. package/dist/spectral/types.js +0 -2
  707. package/dist/state.svelte.d.ts +0 -25
  708. package/dist/state.svelte.js +0 -45
  709. package/dist/structure/Arrow.svelte +0 -72
  710. package/dist/structure/Arrow.svelte.d.ts +0 -15
  711. package/dist/structure/AtomLegend.svelte +0 -798
  712. package/dist/structure/AtomLegend.svelte.d.ts +0 -34
  713. package/dist/structure/Bond.svelte +0 -140
  714. package/dist/structure/Bond.svelte.d.ts +0 -9
  715. package/dist/structure/CanvasTooltip.svelte +0 -33
  716. package/dist/structure/CanvasTooltip.svelte.d.ts +0 -12
  717. package/dist/structure/CellSelect.svelte +0 -351
  718. package/dist/structure/CellSelect.svelte.d.ts +0 -13
  719. package/dist/structure/Cylinder.svelte +0 -45
  720. package/dist/structure/Cylinder.svelte.d.ts +0 -10
  721. package/dist/structure/Lattice.svelte +0 -196
  722. package/dist/structure/Lattice.svelte.d.ts +0 -17
  723. package/dist/structure/Structure.svelte +0 -1857
  724. package/dist/structure/Structure.svelte.d.ts +0 -83
  725. package/dist/structure/StructureControls.svelte +0 -1184
  726. package/dist/structure/StructureControls.svelte.d.ts +0 -31
  727. package/dist/structure/StructureExportPane.svelte +0 -251
  728. package/dist/structure/StructureExportPane.svelte.d.ts +0 -17
  729. package/dist/structure/StructureInfoPane.svelte +0 -434
  730. package/dist/structure/StructureInfoPane.svelte.d.ts +0 -18
  731. package/dist/structure/StructureScene.svelte +0 -1574
  732. package/dist/structure/StructureScene.svelte.d.ts +0 -104
  733. package/dist/structure/atom-properties.d.ts +0 -37
  734. package/dist/structure/atom-properties.js +0 -198
  735. package/dist/structure/bonding.d.ts +0 -33
  736. package/dist/structure/bonding.js +0 -304
  737. package/dist/structure/export.d.ts +0 -20
  738. package/dist/structure/export.js +0 -725
  739. package/dist/structure/ferrox-wasm-types.d.ts +0 -46
  740. package/dist/structure/ferrox-wasm-types.js +0 -18
  741. package/dist/structure/ferrox-wasm.d.ts +0 -94
  742. package/dist/structure/ferrox-wasm.js +0 -249
  743. package/dist/structure/index.d.ts +0 -110
  744. package/dist/structure/index.js +0 -168
  745. package/dist/structure/measure.d.ts +0 -6
  746. package/dist/structure/measure.js +0 -29
  747. package/dist/structure/parse.d.ts +0 -65
  748. package/dist/structure/parse.js +0 -1374
  749. package/dist/structure/partial-occupancy.d.ts +0 -25
  750. package/dist/structure/partial-occupancy.js +0 -99
  751. package/dist/structure/pbc.d.ts +0 -9
  752. package/dist/structure/pbc.js +0 -123
  753. package/dist/structure/supercell.d.ts +0 -8
  754. package/dist/structure/supercell.js +0 -137
  755. package/dist/structure/validation.d.ts +0 -2
  756. package/dist/structure/validation.js +0 -10
  757. package/dist/symmetry/SymmetryStats.svelte +0 -226
  758. package/dist/symmetry/SymmetryStats.svelte.d.ts +0 -21
  759. package/dist/symmetry/WyckoffTable.svelte +0 -113
  760. package/dist/symmetry/WyckoffTable.svelte.d.ts +0 -11
  761. package/dist/symmetry/cell-transform.d.ts +0 -12
  762. package/dist/symmetry/cell-transform.js +0 -77
  763. package/dist/symmetry/index.d.ts +0 -43
  764. package/dist/symmetry/index.js +0 -229
  765. package/dist/symmetry/spacegroups.d.ts +0 -9
  766. package/dist/symmetry/spacegroups.js +0 -394
  767. package/dist/table/HeatmapTable.svelte +0 -1854
  768. package/dist/table/HeatmapTable.svelte.d.ts +0 -49
  769. package/dist/table/ToggleMenu.svelte +0 -376
  770. package/dist/table/ToggleMenu.svelte.d.ts +0 -11
  771. package/dist/table/index.d.ts +0 -74
  772. package/dist/table/index.js +0 -38
  773. package/dist/theme/ThemeControl.svelte +0 -53
  774. package/dist/theme/ThemeControl.svelte.d.ts +0 -9
  775. package/dist/theme/index.d.ts +0 -29
  776. package/dist/theme/index.js +0 -79
  777. package/dist/theme/themes.mjs +0 -285
  778. package/dist/time.d.ts +0 -4
  779. package/dist/time.js +0 -70
  780. package/dist/tooltip/TooltipContent.svelte +0 -58
  781. package/dist/tooltip/TooltipContent.svelte.d.ts +0 -31
  782. package/dist/tooltip/index.d.ts +0 -2
  783. package/dist/tooltip/index.js +0 -2
  784. package/dist/tooltip/types.d.ts +0 -8
  785. package/dist/tooltip/types.js +0 -1
  786. package/dist/trajectory/Trajectory.svelte +0 -1517
  787. package/dist/trajectory/Trajectory.svelte.d.ts +0 -77
  788. package/dist/trajectory/TrajectoryError.svelte +0 -128
  789. package/dist/trajectory/TrajectoryError.svelte.d.ts +0 -13
  790. package/dist/trajectory/TrajectoryExportPane.svelte +0 -357
  791. package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +0 -17
  792. package/dist/trajectory/TrajectoryInfoPane.svelte +0 -387
  793. package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +0 -17
  794. package/dist/trajectory/constants.d.ts +0 -6
  795. package/dist/trajectory/constants.js +0 -7
  796. package/dist/trajectory/extract.d.ts +0 -5
  797. package/dist/trajectory/extract.js +0 -162
  798. package/dist/trajectory/format-detect.d.ts +0 -9
  799. package/dist/trajectory/format-detect.js +0 -76
  800. package/dist/trajectory/frame-reader.d.ts +0 -17
  801. package/dist/trajectory/frame-reader.js +0 -332
  802. package/dist/trajectory/helpers.d.ts +0 -14
  803. package/dist/trajectory/helpers.js +0 -172
  804. package/dist/trajectory/index.d.ts +0 -63
  805. package/dist/trajectory/index.js +0 -126
  806. package/dist/trajectory/parse/ase.d.ts +0 -2
  807. package/dist/trajectory/parse/ase.js +0 -77
  808. package/dist/trajectory/parse/hdf5.d.ts +0 -2
  809. package/dist/trajectory/parse/hdf5.js +0 -129
  810. package/dist/trajectory/parse/index.d.ts +0 -12
  811. package/dist/trajectory/parse/index.js +0 -299
  812. package/dist/trajectory/parse/lammps.d.ts +0 -5
  813. package/dist/trajectory/parse/lammps.js +0 -179
  814. package/dist/trajectory/parse/vasp.d.ts +0 -2
  815. package/dist/trajectory/parse/vasp.js +0 -68
  816. package/dist/trajectory/parse/xyz.d.ts +0 -2
  817. package/dist/trajectory/parse/xyz.js +0 -110
  818. package/dist/trajectory/plotting.d.ts +0 -28
  819. package/dist/trajectory/plotting.js +0 -423
  820. package/dist/trajectory/types.d.ts +0 -11
  821. package/dist/trajectory/types.js +0 -1
  822. package/dist/utils.d.ts +0 -5
  823. package/dist/utils.js +0 -36
  824. package/dist/xrd/XrdPlot.svelte +0 -615
  825. package/dist/xrd/XrdPlot.svelte.d.ts +0 -28
  826. package/dist/xrd/broadening.d.ts +0 -20
  827. package/dist/xrd/broadening.js +0 -97
  828. package/dist/xrd/calc-xrd.d.ts +0 -37
  829. package/dist/xrd/calc-xrd.js +0 -337
  830. package/dist/xrd/index.d.ts +0 -37
  831. package/dist/xrd/index.js +0 -4
  832. package/dist/xrd/parse.d.ts +0 -13
  833. package/dist/xrd/parse.js +0 -749
  834. /package/dist/{EmptyState.svelte → src/lib/EmptyState.svelte} +0 -0
  835. /package/dist/{Icon.svelte → src/lib/Icon.svelte} +0 -0
  836. /package/dist/{chempot-diagram → src/lib/chempot-diagram}/ChemPotScene3D.svelte +0 -0
  837. /package/dist/{colors → src/lib/colors}/alloy-colors.json +0 -0
  838. /package/dist/{colors → src/lib/colors}/dark-mode-colors.json +0 -0
  839. /package/dist/{colors → src/lib/colors}/jmol-colors.json +0 -0
  840. /package/dist/{colors → src/lib/colors}/muted-colors.json +0 -0
  841. /package/dist/{colors → src/lib/colors}/pastel-colors.json +0 -0
  842. /package/dist/{colors → src/lib/colors}/vesta-colors.json +0 -0
  843. /package/dist/{element → src/lib/element}/Nucleus.svelte +0 -0
  844. /package/dist/{element → src/lib/element}/data.json +0 -0
  845. /package/dist/{element → src/lib/element}/data.json.gz +0 -0
  846. /package/dist/{element → src/lib/element}/data.schema.json +0 -0
  847. /package/dist/{element-image-urls.json → src/lib/element-image-urls.json} +0 -0
  848. /package/dist/{feedback → src/lib/feedback}/Spinner.svelte +0 -0
  849. /package/dist/{feedback → src/lib/feedback}/StatusMessage.svelte +0 -0
  850. /package/dist/{periodic-table → src/lib/periodic-table}/TableInset.svelte +0 -0
  851. /package/dist/{plot → src/lib/plot}/ReferenceLine.svelte +0 -0
  852. /package/dist/{xrd → src/lib/xrd}/atomic_scattering_params.json +0 -0
@@ -0,0 +1,1381 @@
1
+ // Helper utilities for band structure and DOS data processing
2
+ import { SUBSCRIPT_MAP } from '$lib/labels'
3
+ import { centered_frac, euclidean_dist } from '$lib/math'
4
+ import type { Matrix3x3, Vec2, Vec3 } from '$lib/math'
5
+ import type { AxisConfig } from '$lib/plot/types'
6
+ import type * as types from './types'
7
+ import type { RibbonConfig } from './types'
8
+
9
+ const is_subscript_key = (key: string): key is keyof typeof SUBSCRIPT_MAP =>
10
+ key in SUBSCRIPT_MAP
11
+
12
+ // Check if range is a valid [min, max] tuple (strict 2-element array of finite numbers)
13
+ export const is_valid_range = (range: unknown): range is Vec2 =>
14
+ Array.isArray(range) &&
15
+ range.length === 2 &&
16
+ Number.isFinite(range[0]) &&
17
+ Number.isFinite(range[1])
18
+
19
+ // Check if two ranges are approximately equal (within tolerance)
20
+ // Returns false if either range is invalid (null, undefined, or fails is_valid_range)
21
+ // Negative tol is clamped to 0; tol=0 checks exact equality
22
+ export const ranges_equal = (
23
+ a: Vec2 | undefined | null,
24
+ b: Vec2 | undefined | null,
25
+ tol = 0.001,
26
+ ): boolean => {
27
+ const safe_tol = Math.max(0, tol)
28
+ return (
29
+ is_valid_range(a) &&
30
+ is_valid_range(b) &&
31
+ Math.abs(a[0] - b[0]) <= safe_tol &&
32
+ Math.abs(a[1] - b[1]) <= safe_tol
33
+ )
34
+ }
35
+
36
+ export const axis_with_range = (
37
+ axis: AxisConfig | undefined,
38
+ range: Vec2 | undefined,
39
+ label?: string,
40
+ ): AxisConfig => ({
41
+ ...axis,
42
+ ...(label !== undefined && { label }),
43
+ ...(is_valid_range(range) && { range }),
44
+ })
45
+
46
+ // Detect which plot triggered a zoom change and return the new synced range.
47
+ // Returns null to reset to shared range, undefined for no change, or Vec2 for new zoom.
48
+ export function detect_zoom_change(
49
+ bands_range: unknown,
50
+ dos_range: unknown,
51
+ shared_range: Vec2,
52
+ current_synced: Vec2 | null,
53
+ dos_enabled = true,
54
+ ): Vec2 | null | undefined {
55
+ const bands_valid = is_valid_range(bands_range)
56
+ const dos_valid = dos_enabled && is_valid_range(dos_range)
57
+
58
+ // Reset if either becomes invalid (auto-range reset) or returns to shared range
59
+ if (current_synced !== null) {
60
+ const bands_at_shared = bands_valid && ranges_equal(bands_range, shared_range)
61
+ const dos_at_shared = dos_valid && ranges_equal(dos_range, shared_range)
62
+ if (bands_at_shared || dos_at_shared || !bands_valid || (dos_enabled && !dos_valid)) {
63
+ return null
64
+ }
65
+ }
66
+
67
+ // Check for new zoom from either plot
68
+ const bands_is_new =
69
+ bands_valid &&
70
+ !ranges_equal(bands_range, shared_range) &&
71
+ !ranges_equal(bands_range, current_synced)
72
+ const dos_is_new =
73
+ dos_valid &&
74
+ !ranges_equal(dos_range, shared_range) &&
75
+ !ranges_equal(dos_range, current_synced)
76
+
77
+ if (bands_is_new && !dos_is_new) return bands_range
78
+ if (dos_is_new && !bands_is_new) return dos_range
79
+ return undefined // no change
80
+ }
81
+
82
+ // Physical constants for unit conversions (SI units)
83
+ const PLANCK = 6.62607015e-34 // J⋅s
84
+ const EV_TO_J = 1.602176634e-19 // J
85
+ const C_LIGHT = 299792458 // m/s
86
+ const THz_TO_HZ = 1e12
87
+ const THz_TO_EV = (PLANCK * THz_TO_HZ) / EV_TO_J
88
+ const THz_TO_MEV = THz_TO_EV * 1000
89
+ const THz_TO_HA = THz_TO_EV / 27.211386245988 // Hartree
90
+ const THz_TO_CM = THz_TO_HZ / (C_LIGHT * 100) // cm^-1 (c in cm/s)
91
+
92
+ // Band structure constants
93
+ export const IMAGINARY_MODE_NOISE_THRESHOLD = 0.005 // Clamp negatives < 0.5% as noise
94
+
95
+ // Convert symmetry point symbols to pretty-printed versions.
96
+ // Handles Greek letters (both plain and LaTeX backslash-prefixed) and subscripts.
97
+ export function pretty_sym_point(symbol: string): string {
98
+ if (!symbol) return ``
99
+
100
+ // Remove underscores (htmlify maps S0 → S<sub>0</sub> but leaves S_0 as is)
101
+ // Replace common symmetry point names with Greek letters
102
+ // Handle both plain names (GAMMA) and LaTeX notation (\Gamma) from pymatgen
103
+ // Handle subscripts: convert S0 to S₀, K1 to K₁, Γ1 to Γ₁, etc.
104
+ // Use \p{L} to match any Unicode letter (not just ASCII A-Z)
105
+ return symbol
106
+ .replace(/_/g, ``)
107
+ .replace(/\\?GAMMA/gi, `Γ`)
108
+ .replace(/\\?DELTA/gi, `Δ`)
109
+ .replace(/\\?SIGMA/gi, `Σ`)
110
+ .replace(/\\?LAMBDA/gi, `Λ`)
111
+ .replace(
112
+ /(\p{L})(\d+)/gu,
113
+ (_, letter, num) =>
114
+ letter +
115
+ num
116
+ .split(``)
117
+ .map((digit: string) => (is_subscript_key(digit) ? SUBSCRIPT_MAP[digit] : digit))
118
+ .join(``),
119
+ )
120
+ }
121
+
122
+ // Create segment key from start and end labels
123
+ export const get_segment_key = (start_label?: string, end_label?: string) =>
124
+ `${start_label ?? `null`}_${end_label ?? `null`}`
125
+
126
+ // Get ordered segment keys from a band structure, preserving physical path order.
127
+ export const get_ordered_segments = (
128
+ band_struct: types.BaseBandStructure | null,
129
+ segments: Set<string>,
130
+ ) => {
131
+ if (!band_struct) return Array.from(segments)
132
+
133
+ const ordered = band_struct.branches.map((branch) =>
134
+ get_segment_key(
135
+ band_struct.qpoints[branch.start_index]?.label ?? undefined,
136
+ band_struct.qpoints[branch.end_index]?.label ?? undefined,
137
+ ),
138
+ )
139
+ const remaining = Array.from(segments).filter((seg) => !ordered.includes(seg))
140
+ return [...ordered, ...remaining]
141
+ }
142
+
143
+ // Scale segment distances to a target x-axis range [x_start, x_end].
144
+ // Used by both band line series and fat band ribbons for consistent x-axis positioning.
145
+ export function scale_segment_distances(
146
+ segment_distances: number[],
147
+ x_start: number,
148
+ x_end: number,
149
+ ): number[] {
150
+ if (segment_distances.length === 0) return []
151
+
152
+ const dist_min = segment_distances[0]
153
+ const dist_range = (segment_distances.at(-1) ?? dist_min) - dist_min
154
+
155
+ if (dist_range === 0) {
156
+ // All points at same distance - place at midpoint
157
+ return segment_distances.map(() => (x_start + x_end) / 2)
158
+ }
159
+
160
+ return segment_distances.map(
161
+ (dist) => x_start + ((dist - dist_min) / dist_range) * (x_end - x_start),
162
+ )
163
+ }
164
+
165
+ // Get ribbon config for a specific band structure label.
166
+ // Supports both single global config (with primitive keys like opacity, max_width, scale, color)
167
+ // and per-structure config (keyed by structure label).
168
+ // Distinguishes between a global config and a per-structure config by checking if any
169
+ // primitive-typed keys (opacity, max_width, scale, color) exist at the top level.
170
+ export function get_ribbon_config(
171
+ ribbon_config: RibbonConfig | Record<string, RibbonConfig>,
172
+ label: string,
173
+ ): RibbonConfig {
174
+ const defaults: RibbonConfig = { opacity: 0.3, max_width: 6, scale: 1 }
175
+ const config_record = ribbon_config as Record<string, unknown>
176
+
177
+ // Check for primitive config values (not objects) to distinguish single vs per-structure config
178
+ const has_primitive = [`opacity`, `max_width`, `scale`, `color`].some((key) => {
179
+ const value = config_record[key]
180
+ return value !== undefined && typeof value !== `object`
181
+ })
182
+
183
+ if (has_primitive) {
184
+ // Single global config with primitive values - apply to all structures
185
+ return { ...defaults, ...ribbon_config }
186
+ }
187
+
188
+ // Otherwise, treat as Record<string, RibbonConfig> and look up by label
189
+ // Empty label skips lookup and uses defaults only
190
+ const label_config = label ? config_record[label] : undefined
191
+ return {
192
+ ...defaults,
193
+ ...(label_config && typeof label_config === `object` ? label_config : {}),
194
+ }
195
+ }
196
+
197
+ // Extract tick positions and labels for a band structure plot.
198
+ export function get_band_xaxis_ticks(
199
+ band_struct: types.BaseBandStructure,
200
+ branches: string[] | Set<string> = [],
201
+ ): [number[], string[]] {
202
+ const ticks_x_pos: number[] = []
203
+ const tick_labels: string[] = []
204
+ let prev_label = band_struct.qpoints[0]?.label || null
205
+ let prev_branch = band_struct.branches[0]?.name || null
206
+
207
+ // Convert branches to Set for consistent handling
208
+ const branches_set = Array.isArray(branches) ? new Set(branches) : branches
209
+
210
+ for (let idx = 0; idx < band_struct.qpoints.length; idx++) {
211
+ const point = band_struct.qpoints[idx]
212
+ if (point.label === null) continue
213
+
214
+ // Find which branch this point belongs to
215
+ const branch_names = band_struct.branches
216
+ .filter((branch) => branch.start_index <= idx && idx <= branch.end_index)
217
+ .map((branch) => branch.name)
218
+ const this_branch = branch_names[0] || null
219
+
220
+ if (point.label !== prev_label && prev_branch !== this_branch) {
221
+ // Branch transition - combine labels
222
+ tick_labels[tick_labels.length - 1] = `${prev_label || ``}|${point.label}`
223
+ ticks_x_pos[ticks_x_pos.length - 1] = band_struct.distance[idx]
224
+ } else if (branches_set.size === 0 || (this_branch && branches_set.has(this_branch))) {
225
+ tick_labels.push(point.label)
226
+ ticks_x_pos.push(band_struct.distance[idx])
227
+ }
228
+
229
+ prev_label = point.label
230
+ prev_branch = this_branch
231
+ }
232
+
233
+ return [ticks_x_pos, tick_labels.map(pretty_sym_point)]
234
+ }
235
+
236
+ // Convert frequencies from THz to specified units.
237
+ export function convert_frequencies(
238
+ frequencies: number[],
239
+ unit: types.FrequencyUnit = `THz`,
240
+ ): number[] {
241
+ const conversion_factors: Record<types.FrequencyUnit, number> = {
242
+ THz: 1,
243
+ eV: THz_TO_EV,
244
+ meV: THz_TO_MEV,
245
+ Ha: THz_TO_HA,
246
+ 'cm-1': THz_TO_CM,
247
+ }
248
+
249
+ const factor = conversion_factors[unit]
250
+ if (!factor) {
251
+ const valid_units = Object.keys(conversion_factors).join(`, `)
252
+ throw new Error(`Invalid unit: ${unit}. Must be one of ${valid_units}`)
253
+ }
254
+
255
+ return frequencies.map((freq) => freq * factor)
256
+ }
257
+
258
+ // Normalize DOS densities according to specified mode.
259
+ export function normalize_densities(
260
+ densities: number[],
261
+ freqs_or_energies: number[],
262
+ mode: types.NormalizationMode,
263
+ ): number[] {
264
+ if (!mode) return densities
265
+
266
+ const normalized = [...densities]
267
+
268
+ if (mode === `max`) {
269
+ const max_val = Math.max(...normalized)
270
+ if (max_val === 0) return normalized
271
+ return normalized.map((dens) => dens / max_val)
272
+ } else if (mode === `sum`) {
273
+ const sum = normalized.reduce((acc, d) => acc + d, 0)
274
+ if (sum === 0) return normalized
275
+ return normalized.map((dens) => dens / sum)
276
+ } else if (mode === `integral`) {
277
+ if (freqs_or_energies.length < 2) return normalized
278
+ const bin_width = freqs_or_energies[1] - freqs_or_energies[0]
279
+ if (bin_width === 0) return normalized
280
+ const sum = normalized.reduce((acc, d) => acc + d, 0)
281
+ if (sum === 0) return normalized
282
+ return normalized.map((dens) => dens / (sum * bin_width))
283
+ }
284
+
285
+ return normalized
286
+ }
287
+
288
+ // Simple LRU cache for Gaussian smearing results
289
+ // Key: hash of (frequencies, densities, sigma), Value: smeared densities
290
+ const SMEARING_CACHE_MAX_SIZE = 10
291
+ const smearing_cache = new Map<string, number[]>()
292
+
293
+ // FNV-1a hash for number arrays (fast, good distribution, O(n))
294
+ function fnv1a_hash(arr: number[]): number {
295
+ let hash = 2166136261 // FNV offset basis
296
+ for (const val of arr) {
297
+ // Convert float to int32 bits for consistent hashing
298
+ const bits = new Float64Array([val])
299
+ const int_view = new Uint32Array(bits.buffer)
300
+ hash ^= int_view[0]
301
+ hash = Math.imul(hash, 16777619) // FNV prime
302
+ hash ^= int_view[1]
303
+ hash = Math.imul(hash, 16777619)
304
+ }
305
+ return hash >>> 0 // Ensure unsigned
306
+ }
307
+
308
+ // Generate cache key using FNV-1a hash over full arrays (O(n), low collision risk)
309
+ function generate_smearing_cache_key(
310
+ freqs_or_energies: number[],
311
+ densities: number[],
312
+ sigma: number,
313
+ ): string {
314
+ const len = freqs_or_energies.length
315
+ if (len === 0) return `0:${sigma.toFixed(6)}:0:0`
316
+ return `${len}:${sigma.toFixed(6)}:${fnv1a_hash(freqs_or_energies).toString(16)}:${fnv1a_hash(
317
+ densities,
318
+ ).toString(16)}`
319
+ }
320
+
321
+ // Core Gaussian smearing computation (unmemoized)
322
+ function apply_gaussian_smearing_core(
323
+ freqs_or_energies: number[],
324
+ densities: number[],
325
+ sigma: number,
326
+ ): number[] {
327
+ const orig_sum = densities.reduce((acc, d) => acc + d, 0)
328
+ if (sigma <= 0 || orig_sum === 0) return densities
329
+
330
+ const smeared = Array(densities.length).fill(0)
331
+ const truncation_width = 4 // Truncate Gaussian at ±4σ (contribution < 0.01%)
332
+
333
+ for (let idx = 0; idx < freqs_or_energies.length; idx++) {
334
+ const energy = freqs_or_energies[idx]
335
+ const cutoff = truncation_width * sigma
336
+
337
+ for (let jdx = 0; jdx < freqs_or_energies.length; jdx++) {
338
+ const e_j = freqs_or_energies[jdx]
339
+ const delta = Math.abs(energy - e_j)
340
+
341
+ // Skip points beyond truncation width
342
+ if (delta > cutoff) continue
343
+
344
+ const gaussian = Math.exp(-((energy - e_j) ** 2) / (2 * sigma ** 2))
345
+ smeared[idx] += densities[jdx] * gaussian
346
+ }
347
+ }
348
+
349
+ // Normalize to preserve integral
350
+ const smeared_sum = smeared.reduce((acc, d) => acc + d, 0)
351
+ if (smeared_sum === 0) return densities
352
+ const normalization = orig_sum / smeared_sum
353
+ return smeared.map((dens) => dens * normalization)
354
+ }
355
+
356
+ // Apply Gaussian smearing to DOS densities with memoization.
357
+ // Uses truncated Gaussian (±4σ) for O(n·w) complexity instead of O(n²).
358
+ // Results are cached using an LRU cache to avoid recomputation on reactive updates.
359
+ export function apply_gaussian_smearing(
360
+ freqs_or_energies: number[],
361
+ densities: number[],
362
+ sigma: number,
363
+ ): number[] {
364
+ // Fast path: no smearing needed
365
+ if (sigma <= 0) return densities
366
+
367
+ const cache_key = generate_smearing_cache_key(freqs_or_energies, densities, sigma)
368
+
369
+ // Check cache
370
+ const cached = smearing_cache.get(cache_key)
371
+ if (cached) {
372
+ // Move to end (LRU behavior: most recently used last)
373
+ smearing_cache.delete(cache_key)
374
+ smearing_cache.set(cache_key, cached)
375
+ return cached
376
+ }
377
+
378
+ // Compute and cache
379
+ const result = apply_gaussian_smearing_core(freqs_or_energies, densities, sigma)
380
+
381
+ // Evict oldest entry if cache is full (LRU: first entry is oldest)
382
+ if (smearing_cache.size >= SMEARING_CACHE_MAX_SIZE) {
383
+ const oldest_key = smearing_cache.keys().next().value
384
+ if (oldest_key !== undefined) smearing_cache.delete(oldest_key)
385
+ }
386
+
387
+ smearing_cache.set(cache_key, result)
388
+ return result
389
+ }
390
+
391
+ // Clear the smearing cache (useful for testing or memory management)
392
+ export function clear_smearing_cache(): void {
393
+ smearing_cache.clear()
394
+ }
395
+
396
+ // Type guards for pymatgen qpoint formats
397
+ const is_vec3 = (val: unknown): val is Vec3 =>
398
+ Array.isArray(val) && val.length >= 3 && val.slice(0, 3).every(Number.isFinite)
399
+
400
+ interface PymatgenKpoint {
401
+ frac_coords: Vec3
402
+ label?: string | null
403
+ }
404
+ const is_kpoint = (val: unknown): val is PymatgenKpoint =>
405
+ !!val && typeof val === `object` && `frac_coords` in val && is_vec3(val.frac_coords)
406
+
407
+ const is_pymatgen_format = (obj: Record<string, unknown>): boolean => {
408
+ // Check for explicit pymatgen markers
409
+ if (typeof obj[`@class`] === `string` || typeof obj[`@module`] === `string`) {
410
+ return true
411
+ }
412
+ // Check for pymatgen-style qpoints (phonon) or kpoints (electronic) without branches
413
+ const points = obj.qpoints ?? obj.kpoints
414
+ if (Array.isArray(points) && points.length > 0 && !Array.isArray(obj.branches)) {
415
+ return is_vec3(points[0]) || is_kpoint(points[0])
416
+ }
417
+ return false
418
+ }
419
+
420
+ // Extract frac_coords/label from pymatgen qpoint, matching label from labels_dict if needed
421
+ const parse_qpoint = (
422
+ qpt: unknown,
423
+ labels_dict?: Record<string, Vec3>,
424
+ ): types.QPoint | null => {
425
+ const frac_coords = is_vec3(qpt)
426
+ ? ([qpt[0], qpt[1], qpt[2]] as Vec3)
427
+ : is_kpoint(qpt)
428
+ ? qpt.frac_coords
429
+ : null
430
+ if (!frac_coords) return null
431
+
432
+ const label =
433
+ (is_kpoint(qpt) && typeof qpt.label === `string` && qpt.label) ||
434
+ Object.entries(labels_dict ?? {}).find(
435
+ ([, c]) => euclidean_dist(frac_coords, c) < 1e-4,
436
+ )?.[0] ||
437
+ null
438
+ return { label, frac_coords }
439
+ }
440
+
441
+ // Inverse conversion factors (derived from THz_TO_* for consistency)
442
+ const EV_TO_THZ = 1 / THz_TO_EV
443
+ const CM_TO_THZ = 1 / THz_TO_CM
444
+
445
+ // Spin key constants for pymatgen spin-polarized data
446
+ const SPIN_UP_KEYS = [`1`, `Spin.up`]
447
+ const SPIN_DOWN_KEYS = [`-1`, `Spin.down`]
448
+
449
+ // Extract both spin channels from pymatgen spin-keyed data.
450
+ // Returns { up: T, down: T | null } where down is null for non-spin-polarized data.
451
+ export function extract_spin_channels<T>(data: unknown): { up: T; down: T | null } | null {
452
+ if (Array.isArray(data)) return { up: data as T, down: null }
453
+ if (data && typeof data === `object`) {
454
+ const record = data as Record<string, T>
455
+ let spin_up: T | null = null
456
+ let spin_down: T | null = null
457
+
458
+ // Extract spin-up channel
459
+ for (const key of SPIN_UP_KEYS) {
460
+ if (key in record) {
461
+ spin_up = record[key]
462
+ break
463
+ }
464
+ }
465
+ // Extract spin-down channel
466
+ for (const key of SPIN_DOWN_KEYS) {
467
+ if (key in record) {
468
+ spin_down = record[key]
469
+ break
470
+ }
471
+ }
472
+
473
+ // Fall back to first key if no spin-up key found
474
+ if (spin_up === null) {
475
+ const keys = Object.keys(record)
476
+ if (keys.length > 0) spin_up = record[keys[0]]
477
+ }
478
+
479
+ if (spin_up === null) return null
480
+ return { up: spin_up, down: spin_down }
481
+ }
482
+ return null
483
+ }
484
+
485
+ // Convert pymatgen PhononBandStructureSymmLine or BandStructure to matterviz format
486
+ function convert_pymatgen_band_structure(
487
+ pmg: Record<string, unknown>,
488
+ ): types.BaseBandStructure | null {
489
+ // Support both qpoints (phonon) and kpoints (electronic)
490
+ const raw_qpts = (pmg.qpoints ?? pmg.kpoints) as unknown[] | undefined
491
+
492
+ // Handle bands in multiple formats:
493
+ // 1. Standard pymatgen: bands as dict with spin keys {1: [[...], ...]}
494
+ // 2. Custom phonon format: frequencies_cm as 2D array [[...], ...]
495
+ // 3. Already normalized: bands as 2D array [[...], ...]
496
+ const spin_channels = extract_spin_channels<number[][]>(pmg.bands)
497
+ let raw_bands = spin_channels?.up ?? null
498
+ let raw_spin_down_bands = spin_channels?.down ?? null
499
+ const has_frequencies_cm = Array.isArray(pmg.frequencies_cm)
500
+ if (!raw_bands && has_frequencies_cm) {
501
+ // Phonon format: frequencies_cm is [n_qpoints x n_branches] - needs transpose
502
+ const freqs = pmg.frequencies_cm as number[][]
503
+ if (freqs.length > 0 && Array.isArray(freqs[0])) {
504
+ // Transpose: [n_qpoints x n_branches] -> [n_branches x n_qpoints]
505
+ raw_bands = Array.from({ length: freqs[0].length }, (_, band_idx) =>
506
+ freqs.map((qpt_freqs) => qpt_freqs[band_idx]),
507
+ )
508
+ raw_spin_down_bands = null
509
+ }
510
+ }
511
+
512
+ const labels_dict = pmg.labels_dict as Record<string, Vec3> | undefined
513
+ const lattice_rec = pmg.lattice_rec as { matrix?: Matrix3x3 } | undefined
514
+ // Determine unit: cm-1 if frequencies_cm present, else check explicit unit or default to THz
515
+ const unit =
516
+ (pmg.unit as string | undefined)?.toLowerCase() ?? (has_frequencies_cm ? `cm-1` : `thz`)
517
+
518
+ if (
519
+ !Array.isArray(raw_qpts) ||
520
+ !Array.isArray(raw_bands) ||
521
+ !raw_qpts.length ||
522
+ !raw_bands.length
523
+ )
524
+ return null
525
+
526
+ const qpoints = raw_qpts
527
+ .map((qpoint) => parse_qpoint(qpoint, labels_dict))
528
+ .filter((qpoint): qpoint is types.QPoint => qpoint !== null)
529
+ if (!qpoints.length) return null
530
+
531
+ // Step distances and discontinuity detection (5x median threshold)
532
+ const steps = qpoints
533
+ .slice(1)
534
+ .map((qpoint, idx) => euclidean_dist(qpoints[idx].frac_coords, qpoint.frac_coords))
535
+ const sorted = steps.slice().sort((a, b) => a - b)
536
+ const threshold = (sorted[Math.floor(sorted.length / 2)] ?? 0) * 5
537
+ const disc_set = new Set(
538
+ steps
539
+ .map((step, idx) => (step > threshold ? idx + 1 : -1))
540
+ .filter((disc_idx) => disc_idx >= 0),
541
+ )
542
+
543
+ // Cumulative distance (skip discontinuities)
544
+ const distance = steps.reduce(
545
+ (acc, step, idx) => [...acc, disc_set.has(idx + 1) ? acc[idx] : acc[idx] + step],
546
+ [0],
547
+ )
548
+
549
+ // Use pymatgen's branches if available - they correctly handle discontinuities
550
+ // Otherwise, infer branches from discontinuities (robust fallback covering all qpoints)
551
+ const pmg_branches = pmg.branches as types.Branch[] | undefined
552
+ let branches: types.Branch[] = []
553
+
554
+ if (Array.isArray(pmg_branches) && pmg_branches.length > 0) {
555
+ // Validate and use pymatgen branches directly
556
+ branches = pmg_branches.filter(
557
+ (branch) =>
558
+ typeof branch.start_index === `number` &&
559
+ typeof branch.end_index === `number` &&
560
+ branch.start_index >= 0 &&
561
+ branch.end_index < qpoints.length &&
562
+ branch.start_index <= branch.end_index,
563
+ )
564
+ }
565
+
566
+ // Fallback: infer branches from discontinuities when none provided or all invalid
567
+ if (branches.length === 0) {
568
+ console.warn(
569
+ `Band structure missing 'branches' field - inferring from path discontinuities`,
570
+ )
571
+ // Discontinuity indices mark points where the path jumps (disc before that index)
572
+ // Create continuous segments between discontinuities
573
+ const disc_indices = [...disc_set].sort((a, b) => a - b)
574
+ // Segment boundaries: [0, first_disc), [first_disc, second_disc), ..., [last_disc, end]
575
+ const segment_starts = [0, ...disc_indices]
576
+ const segment_ends = [...disc_indices.map((idx) => idx - 1), qpoints.length - 1]
577
+
578
+ branches = segment_starts
579
+ .map((start, idx) => {
580
+ const end = segment_ends[idx]
581
+ const start_label = qpoints[start]?.label ?? `?`
582
+ const end_label = qpoints[end]?.label ?? `?`
583
+ return {
584
+ start_index: start,
585
+ end_index: end,
586
+ name: `${start_label}-${end_label}`,
587
+ }
588
+ })
589
+ .filter((branch) => branch.start_index <= branch.end_index)
590
+ }
591
+
592
+ if (!branches.length) {
593
+ branches.push({ start_index: 0, end_index: qpoints.length - 1, name: `path` })
594
+ }
595
+
596
+ // Convert bands to THz based on input unit
597
+ const convert_to_thz = (val: number): number => {
598
+ if (unit === `ev`) return val * EV_TO_THZ
599
+ if (unit === `cm-1`) return val * CM_TO_THZ
600
+ return val // THz (default) - no conversion
601
+ }
602
+
603
+ const converted_bands = raw_bands.map((band) => band.map(convert_to_thz))
604
+ const valid_spin_down_bands =
605
+ Array.isArray(raw_spin_down_bands) &&
606
+ raw_spin_down_bands.length === raw_bands.length &&
607
+ raw_spin_down_bands.every(
608
+ (band, band_idx) => Array.isArray(band) && band.length === raw_bands[band_idx]?.length,
609
+ )
610
+ ? raw_spin_down_bands
611
+ : null
612
+ const converted_spin_down_bands = valid_spin_down_bands?.map((band) =>
613
+ band.map(convert_to_thz),
614
+ )
615
+
616
+ return {
617
+ qpoints,
618
+ branches,
619
+ distance,
620
+ bands: converted_bands,
621
+ spin_down_bands: converted_spin_down_bands,
622
+ nb_bands: raw_bands.length,
623
+ labels_dict: labels_dict ?? {},
624
+ recip_lattice: {
625
+ matrix: lattice_rec?.matrix ?? [
626
+ [1, 0, 0],
627
+ [0, 1, 0],
628
+ [0, 0, 1],
629
+ ],
630
+ },
631
+ }
632
+ }
633
+
634
+ export function normalize_band_structure(bs: unknown): types.BaseBandStructure | null {
635
+ if (!bs || typeof bs !== `object`) return null
636
+
637
+ const band_struct = bs as Record<string, unknown>
638
+
639
+ // Check if this is pymatgen format and convert if so
640
+ if (is_pymatgen_format(band_struct)) {
641
+ return convert_pymatgen_band_structure(band_struct)
642
+ }
643
+
644
+ // Standard matterviz format validation
645
+ const { qpoints, branches, bands, distance } =
646
+ band_struct as Partial<types.BaseBandStructure>
647
+ if (
648
+ !Array.isArray(qpoints) ||
649
+ !Array.isArray(branches) ||
650
+ !Array.isArray(bands) ||
651
+ !Array.isArray(distance)
652
+ )
653
+ return null
654
+
655
+ // Validate array lengths and branch indices
656
+ const n_qpts = qpoints.length
657
+ if (
658
+ distance.length !== n_qpts ||
659
+ bands.some((band) => !Array.isArray(band) || band.length !== n_qpts) ||
660
+ branches.some(
661
+ (branch) =>
662
+ typeof branch.start_index !== `number` ||
663
+ typeof branch.end_index !== `number` ||
664
+ branch.start_index < 0 ||
665
+ branch.end_index >= n_qpts ||
666
+ branch.start_index > branch.end_index,
667
+ )
668
+ )
669
+ return null
670
+
671
+ return band_struct as unknown as types.BaseBandStructure
672
+ }
673
+
674
+ // Validate and normalize a DOS object.
675
+ // Supports both matterviz and pymatgen formats.
676
+ // Also auto-detects and converts cm⁻¹ to THz for legacy data (disable with auto_convert_units: false).
677
+ export function normalize_dos(
678
+ dos: unknown,
679
+ options: { auto_convert_units?: boolean } = {},
680
+ ): types.DosData | null {
681
+ const { auto_convert_units = true } = options
682
+ if (!dos || typeof dos !== `object`) return null
683
+
684
+ const dos_obj = dos as Record<string, unknown>
685
+
686
+ // Check for pymatgen format (has @class or @module)
687
+ const is_pymatgen =
688
+ typeof dos_obj[`@class`] === `string` || typeof dos_obj[`@module`] === `string`
689
+
690
+ const { frequencies, energies, spin_polarized } = dos_obj
691
+
692
+ // Handle densities as either array or dict with spin keys (pymatgen format)
693
+ // Pymatgen stores densities as {1: [...], -1: [...]} or {"Spin.up": [...], ...}
694
+ const spin_channels = extract_spin_channels<number[]>(dos_obj.densities)
695
+ if (!spin_channels) return null
696
+
697
+ const densities = spin_channels.up
698
+ // Use extracted spin-down or fallback to explicit field (for already-normalized DosData)
699
+ const spin_down_densities =
700
+ spin_channels.down ?? (dos_obj.spin_down_densities as number[] | undefined) ?? null
701
+
702
+ if (!Array.isArray(densities)) return null
703
+
704
+ // Phonon DOS: has frequencies
705
+ if (Array.isArray(frequencies)) {
706
+ if (frequencies.length !== densities.length) return null
707
+
708
+ // Auto-detect if frequencies are in cm⁻¹ instead of THz (unless disabled)
709
+ // Typical phonon frequencies are < 50 THz for most materials
710
+ // If max frequency > 100, it's almost certainly in cm⁻¹
711
+ const max_freq = Math.max(...(frequencies as number[]))
712
+ let final_frequencies = frequencies as number[]
713
+
714
+ if (auto_convert_units && max_freq > 100) {
715
+ // Likely in cm⁻¹, convert to THz
716
+ final_frequencies = (frequencies as number[]).map((frequency) => frequency * CM_TO_THZ)
717
+ console.warn(
718
+ `Phonon DOS frequencies appear to be in cm⁻¹ (max: ${max_freq.toFixed(1)}). ` +
719
+ `Converting to THz (max: ${(max_freq * CM_TO_THZ).toFixed(1)} THz).`,
720
+ )
721
+ }
722
+
723
+ return { type: `phonon`, frequencies: final_frequencies, densities }
724
+ }
725
+
726
+ // Electronic DOS: has energies
727
+ if (Array.isArray(energies)) {
728
+ if (energies.length !== densities.length) return null
729
+ // Detect spin-polarized from data if not explicitly set
730
+ const is_spin_polarized =
731
+ (spin_polarized as boolean | undefined) ??
732
+ (spin_down_densities !== null && spin_down_densities.length === densities.length)
733
+ return {
734
+ type: `electronic`,
735
+ energies,
736
+ densities,
737
+ spin_down_densities: is_spin_polarized ? (spin_down_densities ?? undefined) : undefined,
738
+ spin_polarized: is_spin_polarized,
739
+ }
740
+ }
741
+
742
+ // For pymatgen format, log a helpful message if format wasn't recognized
743
+ if (is_pymatgen) {
744
+ console.warn(
745
+ `Pymatgen DOS format detected but missing required fields. ` +
746
+ `Expected 'frequencies' (phonon) or 'energies' (electronic) arrays.`,
747
+ )
748
+ }
749
+
750
+ return null
751
+ }
752
+
753
+ // Extract k-path points from band structure and convert to reciprocal space coordinates
754
+ // Accepts a reciprocal lattice matrix (should include 2π factor for consistency with BZ)
755
+ // Handles both matterviz format (qpoints as objects) and normalized pymatgen format
756
+ // Optionally wraps fractional coordinates to first BZ (default: true)
757
+ export function extract_k_path_points(
758
+ band_struct: types.BaseBandStructure,
759
+ recip_lattice_matrix: Matrix3x3,
760
+ options: { wrap_to_bz?: boolean } = {},
761
+ ): Vec3[] {
762
+ const { wrap_to_bz = true } = options
763
+ if (!band_struct?.qpoints || !recip_lattice_matrix) return []
764
+
765
+ if (
766
+ recip_lattice_matrix.length !== 3 ||
767
+ recip_lattice_matrix.some((row) => row?.length !== 3)
768
+ )
769
+ throw new Error(`reciprocal_lattice_matrix must be a 3×3 matrix`)
770
+
771
+ const [[m00, m01, m02], [m10, m11, m12], [m20, m21, m22]] = recip_lattice_matrix
772
+
773
+ return band_struct.qpoints.map((qpoint): Vec3 => {
774
+ let [x, y, z] = qpoint.frac_coords
775
+ // Wrap to first BZ if enabled (handles [0,1] vs [-0.5,0.5] convention difference)
776
+ if (wrap_to_bz) {
777
+ x = centered_frac(x)
778
+ y = centered_frac(y)
779
+ z = centered_frac(z)
780
+ }
781
+ const kx = x * m00 + y * m10 + z * m20
782
+ const ky = x * m01 + y * m11 + z * m21
783
+ const kz = x * m02 + y * m12 + z * m22
784
+ return [kx, ky, kz]
785
+ })
786
+ }
787
+
788
+ // Find the q-point index closest to a given distance along the band structure path
789
+ export function find_qpoint_at_distance(
790
+ band_struct: types.BaseBandStructure,
791
+ target: number,
792
+ ): number | null {
793
+ const { distance } = band_struct
794
+ if (!distance?.length) return null
795
+
796
+ return distance.reduce(
797
+ (closest: number, dist: number, idx: number) =>
798
+ Math.abs(dist - target) < Math.abs(distance[closest] - target) ? idx : closest,
799
+ 0,
800
+ )
801
+ }
802
+
803
+ // Find q-point index from rescaled x-coordinate (used in band structure plots)
804
+ // This handles the case where the plot uses custom x-axis scaling per segment
805
+ export function find_qpoint_at_rescaled_x(
806
+ band_struct: types.BaseBandStructure,
807
+ rescaled_x: number,
808
+ x_positions: Record<string, [number, number]>,
809
+ ): number | null {
810
+ if (!band_struct?.branches?.length || !x_positions) return null
811
+
812
+ // Find which segment contains this x coordinate
813
+ for (const branch of band_struct.branches) {
814
+ const start_idx = branch.start_index
815
+ const end_idx = branch.end_index
816
+ const start_label = band_struct.qpoints[start_idx]?.label ?? undefined
817
+ const end_label = band_struct.qpoints[end_idx]?.label ?? undefined
818
+ const segment_key = get_segment_key(start_label, end_label)
819
+
820
+ const segment_range = x_positions[segment_key]
821
+ if (!segment_range) continue
822
+
823
+ const [x_start, x_end] = segment_range
824
+
825
+ // Check if discontinuity (zero-length segment)
826
+ const is_discontinuity = Math.abs(x_end - x_start) < 1e-6
827
+ if (is_discontinuity) {
828
+ // For discontinuities, check if x is exactly at this point
829
+ if (Math.abs(rescaled_x - x_start) < 1e-6) {
830
+ return start_idx
831
+ }
832
+ continue
833
+ }
834
+
835
+ // Check if x is within this segment (with small tolerance for edges)
836
+ if (rescaled_x >= x_start - 1e-6 && rescaled_x <= x_end + 1e-6) {
837
+ // Map from rescaled x back to original distance
838
+ const segment_distances = band_struct.distance.slice(start_idx, end_idx + 1)
839
+ const dist_min = segment_distances[0]
840
+ const dist_max = segment_distances.at(-1) ?? dist_min
841
+ const dist_range = dist_max - dist_min
842
+
843
+ // Handle zero-length segments
844
+ if (dist_range === 0) {
845
+ return start_idx
846
+ }
847
+
848
+ // Inverse of the scaling: x = x_start + ((dist - dist_min) / dist_range) * (x_end - x_start)
849
+ // Solving for dist: dist = dist_min + ((x - x_start) / (x_end - x_start)) * dist_range
850
+ const normalized_x = (rescaled_x - x_start) / (x_end - x_start)
851
+ const target_dist = dist_min + normalized_x * dist_range
852
+
853
+ // Find closest qpoint in this branch to the target distance
854
+ let closest_idx = start_idx
855
+ let min_diff = Math.abs(band_struct.distance[start_idx] - target_dist)
856
+
857
+ for (let idx = start_idx; idx <= end_idx; idx++) {
858
+ const diff = Math.abs(band_struct.distance[idx] - target_dist)
859
+ if (diff < min_diff) {
860
+ min_diff = diff
861
+ closest_idx = idx
862
+ }
863
+ }
864
+
865
+ return closest_idx
866
+ }
867
+ }
868
+
869
+ // Fallback: find closest labeled point
870
+ let closest_idx = 0
871
+ let min_dist = Infinity
872
+
873
+ for (const branch of band_struct.branches) {
874
+ const start_idx = branch.start_index
875
+ const end_idx = branch.end_index
876
+ const start_label = band_struct.qpoints[start_idx]?.label ?? undefined
877
+ const end_label = band_struct.qpoints[end_idx]?.label ?? undefined
878
+ const segment_key = get_segment_key(start_label, end_label)
879
+ const segment_range = x_positions[segment_key]
880
+
881
+ if (!segment_range) continue
882
+
883
+ const [x_start, x_end] = segment_range
884
+
885
+ for (const [x_pos, idx] of [
886
+ [x_start, start_idx],
887
+ [x_end, end_idx],
888
+ ] as const) {
889
+ const dist = Math.abs(rescaled_x - x_pos)
890
+ if (dist < min_dist) {
891
+ min_dist = dist
892
+ closest_idx = idx
893
+ }
894
+ }
895
+ }
896
+
897
+ return closest_idx
898
+ }
899
+
900
+ // Type definitions for pymatgen DOS formats
901
+ // Densities can be spin-keyed: {1: number[], -1: number[]} or {"Spin.up": number[], ...}
902
+ type SpinDensities = Record<string, number[]>
903
+
904
+ // Pymatgen Dos base class format
905
+ export interface PymatgenDos {
906
+ '@class': string
907
+ '@module': string
908
+ energies: number[]
909
+ densities: SpinDensities | number[]
910
+ efermi: number
911
+ }
912
+
913
+ // Pymatgen CompleteDos format (includes projected DOS)
914
+ export interface PymatgenCompleteDos extends PymatgenDos {
915
+ '@class': `CompleteDos` | `LobsterCompleteDos`
916
+ structure?: Record<string, unknown>
917
+ pdos?: Record<string, SpinDensities>[]
918
+ atom_dos?: Record<string, PymatgenDos>
919
+ spd_dos?: Record<string, PymatgenDos>
920
+ }
921
+
922
+ // Extract projected DOS from pymatgen CompleteDos format.
923
+ // Returns a dict of label → DosData for each atom or orbital.
924
+ // filter_keys: optional list of keys to include (e.g., ["Fe", "O"] for atoms or ["s", "p", "d"] for orbitals)
925
+ export function extract_pdos(
926
+ dos: unknown,
927
+ pdos_type: types.PdosType,
928
+ filter_keys?: string[],
929
+ ): Record<string, types.ElectronicDos> | null {
930
+ if (!dos || typeof dos !== `object`) return null
931
+
932
+ const dos_obj = dos as Record<string, unknown>
933
+
934
+ // Get the appropriate projected DOS dict
935
+ const pdos_dict =
936
+ pdos_type === `atom`
937
+ ? (dos_obj.atom_dos as Record<string, PymatgenDos> | undefined)
938
+ : (dos_obj.spd_dos as Record<string, PymatgenDos> | undefined)
939
+
940
+ if (!pdos_dict || typeof pdos_dict !== `object`) return null
941
+
942
+ const result: Record<string, types.ElectronicDos> = {}
943
+
944
+ for (const [key, nested_dos] of Object.entries(pdos_dict)) {
945
+ // Apply filter if provided
946
+ if (filter_keys && filter_keys.length > 0 && !filter_keys.includes(key)) continue
947
+
948
+ if (!nested_dos || typeof nested_dos !== `object`) continue
949
+
950
+ const energies = nested_dos.energies
951
+ const spin_channels = extract_spin_channels<number[]>(nested_dos.densities)
952
+
953
+ if (!Array.isArray(energies) || !spin_channels) continue
954
+
955
+ const densities = spin_channels.up
956
+ if (!Array.isArray(densities) || energies.length !== densities.length) continue
957
+
958
+ const is_spin_polarized =
959
+ spin_channels.down !== null && spin_channels.down.length === densities.length
960
+
961
+ result[key] = {
962
+ type: `electronic`,
963
+ energies,
964
+ densities,
965
+ spin_down_densities: is_spin_polarized ? (spin_channels.down ?? undefined) : undefined,
966
+ spin_polarized: is_spin_polarized,
967
+ efermi: nested_dos.efermi,
968
+ }
969
+ }
970
+
971
+ return Object.keys(result).length > 0 ? result : null
972
+ }
973
+
974
+ // Shift a single DOS object's energies by the given amount
975
+ const shift_dos_energies = <T extends PymatgenDos>(dos: T, shift: number): T => ({
976
+ ...dos,
977
+ efermi: dos.efermi - shift,
978
+ energies: dos.energies.map((energy) => energy - shift),
979
+ })
980
+
981
+ // Shift DOS energies relative to Fermi energy so E_F = 0
982
+ // Recursively shifts nested DOS in atom_dos and spd_dos for consistency
983
+ export function shift_to_fermi(dos: PymatgenCompleteDos): PymatgenCompleteDos {
984
+ const shift = dos.efermi
985
+
986
+ // Shift root DOS energies using the shared helper
987
+ const shifted_root = shift_dos_energies(dos, shift)
988
+
989
+ // Shift nested atom_dos if present
990
+ const atom_dos = dos.atom_dos
991
+ ? Object.fromEntries(
992
+ Object.entries(dos.atom_dos).map(([key, nested_dos]) => [
993
+ key,
994
+ shift_dos_energies(nested_dos, shift),
995
+ ]),
996
+ )
997
+ : undefined
998
+
999
+ // Shift nested spd_dos if present
1000
+ const spd_dos = dos.spd_dos
1001
+ ? Object.fromEntries(
1002
+ Object.entries(dos.spd_dos).map(([key, nested_dos]) => [
1003
+ key,
1004
+ shift_dos_energies(nested_dos, shift),
1005
+ ]),
1006
+ )
1007
+ : undefined
1008
+
1009
+ return {
1010
+ ...shifted_root,
1011
+ efermi: 0, // Explicitly set to 0 (shift_dos_energies would give efermi - shift)
1012
+ ...(atom_dos && { atom_dos }),
1013
+ ...(spd_dos && { spd_dos }),
1014
+ }
1015
+ }
1016
+
1017
+ // Generate an SVG path for a fat band ribbon.
1018
+ // Creates a closed polygon by tracing the upper edge (y - half_width) forward,
1019
+ // then tracing the lower edge (y + half_width) backward.
1020
+ // Non-finite or non-positive widths are clamped to 0.
1021
+ export function generate_ribbon_path(
1022
+ x_values: number[],
1023
+ y_values: number[],
1024
+ width_values: number[],
1025
+ x_scale_fn: (x: number) => number,
1026
+ y_scale_fn: (y: number) => number,
1027
+ max_width_px: number,
1028
+ scale: number = 1,
1029
+ ): string {
1030
+ const len = x_values.length
1031
+ if (len < 2 || len !== y_values.length || len !== width_values.length) return ``
1032
+
1033
+ // Normalize width values to [0, 1] range based on the max positive finite value
1034
+ const finite_positive_widths = width_values.filter(
1035
+ (width) => Number.isFinite(width) && width > 0,
1036
+ )
1037
+ if (finite_positive_widths.length === 0) return ``
1038
+ const max_width_val = Math.max(...finite_positive_widths)
1039
+
1040
+ // Build upper edge path (forward direction)
1041
+ const upper_points: string[] = []
1042
+ const lower_points: string[] = []
1043
+
1044
+ for (let idx = 0; idx < x_values.length; idx++) {
1045
+ const x_px = x_scale_fn(x_values[idx])
1046
+ const y_data = y_values[idx]
1047
+ const raw_width = width_values[idx] ?? 0
1048
+ const width_normalized =
1049
+ Number.isFinite(raw_width) && raw_width > 0 ? raw_width / max_width_val : 0
1050
+ const half_width_px = width_normalized * max_width_px * scale
1051
+
1052
+ // In SVG, y increases downward, so upper edge has smaller y value
1053
+ const y_upper_px = y_scale_fn(y_data) - half_width_px
1054
+ const y_lower_px = y_scale_fn(y_data) + half_width_px
1055
+
1056
+ upper_points.push(`${x_px.toFixed(2)},${y_upper_px.toFixed(2)}`)
1057
+ lower_points.push(`${x_px.toFixed(2)},${y_lower_px.toFixed(2)}`)
1058
+ }
1059
+
1060
+ // Combine: upper edge forward, lower edge backward, close path
1061
+ const path_parts = [
1062
+ `M${upper_points[0]}`,
1063
+ ...upper_points.slice(1).map((pt) => `L${pt}`),
1064
+ ...lower_points.toReversed().map((pt) => `L${pt}`),
1065
+ `Z`,
1066
+ ]
1067
+
1068
+ return path_parts.join(` `)
1069
+ }
1070
+
1071
+ // Extract efermi from a data source (band structure or DOS).
1072
+ // Handles both single objects with an efermi field and dicts of objects.
1073
+ // Returns undefined if no valid efermi is found or if the source is empty.
1074
+ export function extract_efermi(data: unknown): number | undefined {
1075
+ if (!data || typeof data !== `object`) return undefined
1076
+ const obj = data as Record<string, unknown>
1077
+
1078
+ // Direct efermi field on the object
1079
+ if (`efermi` in obj && typeof obj.efermi === `number`) return obj.efermi
1080
+
1081
+ // Dict of objects - try to get efermi from first value
1082
+ const values = Object.values(obj)
1083
+ if (values.length === 0) return undefined
1084
+
1085
+ const first_val = values[0]
1086
+ if (first_val && typeof first_val === `object`) {
1087
+ const efermi = (first_val as Record<string, unknown>).efermi
1088
+ if (typeof efermi === `number`) return efermi
1089
+ }
1090
+
1091
+ return undefined
1092
+ }
1093
+
1094
+ // Calculate fraction of |values| that are negative. Used to detect imaginary phonon modes.
1095
+ export function negative_fraction(values: number[]): number {
1096
+ let [neg, total] = [0, 0]
1097
+ for (const val of values) {
1098
+ if (!Number.isFinite(val)) continue
1099
+ const abs_val = Math.abs(val)
1100
+ total += abs_val
1101
+ if (val < 0) neg += abs_val
1102
+ }
1103
+ return total > 0 ? neg / total : 0
1104
+ }
1105
+
1106
+ // Check if raw band structure input has electronic markers (efermi, kpoints, or electronic @class).
1107
+ // Must be called on raw input before normalization since these fields aren't preserved.
1108
+ function is_electronic_band_struct(bs: unknown): boolean {
1109
+ if (!bs || typeof bs !== `object`) return false
1110
+ const obj = bs as Record<string, unknown>
1111
+ // Electronic band structures have efermi field
1112
+ if (`efermi` in obj && typeof obj.efermi === `number`) return true
1113
+ // Pymatgen electronic format uses kpoints (not qpoints)
1114
+ if (`kpoints` in obj && Array.isArray(obj.kpoints) && obj.kpoints.length > 0) {
1115
+ return true
1116
+ }
1117
+ // Pymatgen @class: BandStructure* but not Phonon*
1118
+ const raw_class = obj[`@class`]
1119
+ const py_class_name = typeof raw_class === `string` ? raw_class : ``
1120
+ if (py_class_name.startsWith(`BandStructure`) && !py_class_name.includes(`Phonon`)) {
1121
+ return true
1122
+ }
1123
+ return false
1124
+ }
1125
+
1126
+ // Compute frequency/energy range from bands and DOS. Clamps phonon min to 0 if noise < 0.5%.
1127
+ export function compute_frequency_range(
1128
+ band_structs: unknown,
1129
+ doses: unknown,
1130
+ padding_factor = 0.02,
1131
+ ): [number, number] | undefined {
1132
+ let [min_val, max_val, is_phonon] = [Infinity, -Infinity, false]
1133
+ const all_freqs: number[] = []
1134
+
1135
+ // Check raw band_structs for electronic markers before normalization
1136
+ // (normalized structures always have qpoints, so we can't detect from them)
1137
+ let has_electronic_bs = false
1138
+ // Support both qpoints (phonon) and kpoints (electronic) to detect single vs dict
1139
+ const is_single_bs =
1140
+ band_structs &&
1141
+ typeof band_structs === `object` &&
1142
+ (`qpoints` in band_structs || `kpoints` in band_structs)
1143
+ if (band_structs && typeof band_structs === `object`) {
1144
+ // Single structure check
1145
+ if (is_electronic_band_struct(band_structs)) {
1146
+ has_electronic_bs = true
1147
+ } else if (!is_single_bs) {
1148
+ // Dict of band structures - check each value
1149
+ for (const bs_val of Object.values(band_structs)) {
1150
+ if (is_electronic_band_struct(bs_val)) {
1151
+ has_electronic_bs = true
1152
+ break
1153
+ }
1154
+ }
1155
+ }
1156
+ }
1157
+
1158
+ const bs_list = band_structs
1159
+ ? is_single_bs
1160
+ ? [normalize_band_structure(band_structs)]
1161
+ : Object.values(band_structs as object).map(normalize_band_structure)
1162
+ : []
1163
+
1164
+ // If band structures exist and aren't electronic, mark as phonon
1165
+ const has_band_structs = bs_list.some(Boolean)
1166
+ if (has_band_structs && !has_electronic_bs) is_phonon = true
1167
+
1168
+ for (const bs of bs_list) {
1169
+ if (!bs) continue
1170
+ for (const band of bs.bands) {
1171
+ for (const val of band) {
1172
+ if (!Number.isFinite(val)) continue
1173
+ all_freqs.push(val)
1174
+ min_val = Math.min(min_val, val)
1175
+ max_val = Math.max(max_val, val)
1176
+ }
1177
+ }
1178
+ }
1179
+
1180
+ const dos_list = doses
1181
+ ? `densities` in (doses as object)
1182
+ ? [normalize_dos(doses)]
1183
+ : Object.values(doses as object).map((dos) => normalize_dos(dos))
1184
+ : []
1185
+ for (const dos of dos_list) {
1186
+ if (!dos) continue
1187
+ // DOS type detection: explicit type field is authoritative
1188
+ if (dos.type === `phonon`) is_phonon = true
1189
+ if (dos.type === `electronic`) is_phonon = false
1190
+ for (const val of dos.type === `phonon` ? dos.frequencies : dos.energies) {
1191
+ if (!Number.isFinite(val)) continue
1192
+ all_freqs.push(val)
1193
+ min_val = Math.min(min_val, val)
1194
+ max_val = Math.max(max_val, val)
1195
+ }
1196
+ }
1197
+
1198
+ if (!Number.isFinite(min_val) || !Number.isFinite(max_val)) return undefined
1199
+ const clamp_min =
1200
+ is_phonon &&
1201
+ min_val < 0 && // clamp phonon noise to 0
1202
+ negative_fraction(all_freqs) < IMAGINARY_MODE_NOISE_THRESHOLD
1203
+ if (clamp_min) min_val = 0
1204
+ // Calculate padding from (possibly clamped) range for consistency with Bands.svelte
1205
+ const padding = (max_val - min_val) * padding_factor
1206
+ return [min_val === 0 ? 0 : min_val - padding, max_val + padding]
1207
+ }
1208
+
1209
+ // Parse axis label: "Frequency (THz)" → { name: "Frequency", unit: "THz" }
1210
+ function parse_axis_label(label: string): { name: string; unit?: string } {
1211
+ const match = /^(.+?)\s*\(([^)]+)\)$/.exec(label)
1212
+ return match ? { name: match[1], unit: match[2] } : { name: label }
1213
+ }
1214
+
1215
+ const format_tooltip_line = (name: string, value: string, unit?: string) =>
1216
+ `${name}: ${value}${unit ? ` ${unit}` : ``}`
1217
+
1218
+ // Format DOS tooltip content from axis labels and values
1219
+ export function format_dos_tooltip(
1220
+ x_formatted: string,
1221
+ y_formatted: string,
1222
+ label: string | null,
1223
+ is_horizontal: boolean,
1224
+ is_phonon: boolean,
1225
+ units: types.FrequencyUnit,
1226
+ x_axis_label: string,
1227
+ y_axis_label: string,
1228
+ num_series: number,
1229
+ ): { title?: string; lines: string[] } {
1230
+ const x_parsed = parse_axis_label(x_axis_label)
1231
+ const y_parsed = parse_axis_label(y_axis_label)
1232
+ const freq_defaults = {
1233
+ name: is_phonon ? `Frequency` : `Energy`,
1234
+ unit: is_phonon ? units : `eV`,
1235
+ }
1236
+
1237
+ const lines = is_horizontal
1238
+ ? [
1239
+ format_tooltip_line(
1240
+ y_parsed.name || freq_defaults.name,
1241
+ y_formatted,
1242
+ y_parsed.unit || freq_defaults.unit,
1243
+ ),
1244
+ format_tooltip_line(x_parsed.name || `Density`, x_formatted),
1245
+ ]
1246
+ : [
1247
+ format_tooltip_line(y_parsed.name || `Density`, y_formatted),
1248
+ format_tooltip_line(
1249
+ x_parsed.name || freq_defaults.name,
1250
+ x_formatted,
1251
+ x_parsed.unit || freq_defaults.unit,
1252
+ ),
1253
+ ]
1254
+
1255
+ return { title: num_series > 1 && label ? label : undefined, lines }
1256
+ }
1257
+
1258
+ // Spin mode options for DOS visualization
1259
+ export const SPIN_MODES = [
1260
+ { value: `mirror`, label: `↕`, title: `Mirror: spin-up above, spin-down below zero` },
1261
+ { value: `overlay`, label: `≡`, title: `Overlay: both spins on same axis` },
1262
+ { value: `up_only`, label: `↑`, title: `Show spin-up only` },
1263
+ { value: `down_only`, label: `↓`, title: `Show spin-down only` },
1264
+ ] as const satisfies readonly { value: types.SpinMode; label: string; title: string }[]
1265
+
1266
+ // Normalization mode options
1267
+ export const NORMALIZATION_MODES = [
1268
+ { value: null, label: `None` },
1269
+ { value: `max`, label: `Max=1` },
1270
+ { value: `sum`, label: `Sum=1` },
1271
+ { value: `integral`, label: `∫=1` },
1272
+ ] as const satisfies readonly { value: types.NormalizationMode; label: string }[]
1273
+
1274
+ // Available frequency units for phonon DOS
1275
+ export const FREQUENCY_UNITS: types.FrequencyUnit[] = [`THz`, `eV`, `meV`, `cm-1`, `Ha`]
1276
+
1277
+ // Default values for DOS controls
1278
+ export const DEFAULT_SPIN_MODE: types.SpinMode = `mirror`
1279
+ export const DEFAULT_SIGMA = 0
1280
+ export const DEFAULT_NORMALIZE: types.NormalizationMode = null
1281
+ export const DEFAULT_UNITS: types.FrequencyUnit = `THz`
1282
+
1283
+ // Format sigma with adaptive precision: 0→"0", <0.01→exp, <1→3dp, else→2dp
1284
+ export function format_sigma(val: number): string {
1285
+ if (val === 0) return `0`
1286
+ if (val < 0.01) return val.toExponential(1)
1287
+ return val.toFixed(val < 1 ? 3 : 2)
1288
+ }
1289
+
1290
+ // Validate sigma_range: ensures min < max, returns [0, 1] if invalid
1291
+ export const validate_sigma_range = ([min, max]: [number, number]): [number, number] =>
1292
+ Number.isFinite(min) && Number.isFinite(max) && min < max ? [min, max] : [0, 1]
1293
+
1294
+ // Calculate slider step: 1/100th of range, or 0.01 fallback
1295
+ export function calculate_sigma_step(range: [number, number]): number {
1296
+ const [min, max] = validate_sigma_range(range)
1297
+ return (max - min) / 100 || 0.01
1298
+ }
1299
+
1300
+ // === Band Tooltip Helpers ===
1301
+
1302
+ // Per-point metadata for band tooltip display
1303
+ export interface BandPointMeta extends Record<string, unknown> {
1304
+ band_idx: number
1305
+ spin: `up` | `down`
1306
+ is_acoustic: boolean | null
1307
+ nb_bands: number
1308
+ frac_coords: Vec3 | null
1309
+ qpoint_label: string | null
1310
+ band_width: number | null
1311
+ slope: number | null
1312
+ }
1313
+
1314
+ // Central difference for local slope (dω/dk or dE/dk).
1315
+ // Uses forward/backward difference at endpoints, central difference for interior points.
1316
+ export function compute_slope(x_vals: number[], y_vals: number[], idx: number): number | null {
1317
+ const len = Math.min(x_vals.length, y_vals.length)
1318
+ if (len < 2 || idx < 0 || idx >= len) return null
1319
+ const lo = idx === 0 ? 0 : idx - 1
1320
+ const hi = idx >= len - 1 ? len - 1 : idx + 1
1321
+ const dx = x_vals[hi] - x_vals[lo]
1322
+ return dx ? (y_vals[hi] - y_vals[lo]) / dx : null
1323
+ }
1324
+
1325
+ // Find Gamma-point indices (q ≈ integer lattice point) in a band structure.
1326
+ // Returns indices of q-points whose fractional coordinates are all within 0.01 of integers.
1327
+ export function find_gamma_indices(bs: types.BaseBandStructure): number[] {
1328
+ const indices: number[] = []
1329
+ for (let q_idx = 0; q_idx < bs.qpoints.length; q_idx++) {
1330
+ const coords = bs.qpoints[q_idx]?.frac_coords
1331
+ if (coords?.every((coord) => Math.abs(coord - Math.round(coord)) < 0.01)) {
1332
+ indices.push(q_idx)
1333
+ }
1334
+ }
1335
+ return indices
1336
+ }
1337
+
1338
+ // Threshold below which a band's frequency at Gamma is considered acoustic (THz).
1339
+ // Assumes bands are stored in THz (normalize_band_structure converts to THz).
1340
+ export const ACOUSTIC_FREQ_THRESHOLD = 0.5
1341
+
1342
+ // Classify a band as acoustic based on near-zero frequency at Gamma points.
1343
+ // Returns true (acoustic), false (optical), or null (no Gamma points → can't determine).
1344
+ export function classify_acoustic(
1345
+ bs: types.BaseBandStructure,
1346
+ band_idx: number,
1347
+ gamma_indices: number[],
1348
+ threshold = ACOUSTIC_FREQ_THRESHOLD,
1349
+ ): boolean | null {
1350
+ if (gamma_indices.length === 0) return null
1351
+ return gamma_indices.some(
1352
+ (gamma_idx) => Math.abs(bs.bands[band_idx]?.[gamma_idx] ?? Infinity) < threshold,
1353
+ )
1354
+ }
1355
+
1356
+ // Build per-point metadata array for a band series in the tooltip.
1357
+ export function build_point_metadata(opts: {
1358
+ x_vals: number[]
1359
+ y_vals: number[]
1360
+ band_idx: number
1361
+ spin: `up` | `down`
1362
+ is_acoustic: boolean | null
1363
+ bs: types.BaseBandStructure
1364
+ start_idx: number
1365
+ }): BandPointMeta[] {
1366
+ const { x_vals, y_vals, band_idx, spin, is_acoustic, bs, start_idx } = opts
1367
+ return x_vals.map((_, pt_idx) => {
1368
+ const global_idx = start_idx + pt_idx
1369
+ const qpoint = bs.qpoints[global_idx]
1370
+ return {
1371
+ band_idx,
1372
+ spin,
1373
+ is_acoustic,
1374
+ nb_bands: bs.nb_bands,
1375
+ frac_coords: qpoint?.frac_coords ?? null,
1376
+ qpoint_label: qpoint?.label ?? null,
1377
+ band_width: bs.band_widths?.[band_idx]?.[global_idx] ?? null,
1378
+ slope: compute_slope(x_vals, y_vals, pt_idx),
1379
+ }
1380
+ })
1381
+ }