matterviz 0.3.0 → 0.3.2

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 (286) hide show
  1. package/dist/FilePicker.svelte +37 -20
  2. package/dist/Icon.svelte +2 -2
  3. package/dist/MillerIndexInput.svelte +60 -0
  4. package/dist/MillerIndexInput.svelte.d.ts +7 -0
  5. package/dist/app.css +38 -2
  6. package/dist/brillouin/BrillouinZone.svelte +20 -62
  7. package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
  8. package/dist/brillouin/BrillouinZoneExportPane.svelte +12 -20
  9. package/dist/brillouin/BrillouinZoneScene.svelte +2 -2
  10. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
  11. package/dist/chempot-diagram/ChemPotDiagram.svelte +192 -0
  12. package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +13 -0
  13. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +677 -0
  14. package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +16 -0
  15. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +2688 -0
  16. package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +16 -0
  17. package/dist/chempot-diagram/ChemPotScene3D.svelte +8 -0
  18. package/dist/chempot-diagram/ChemPotScene3D.svelte.d.ts +7 -0
  19. package/dist/chempot-diagram/color.d.ts +10 -0
  20. package/dist/chempot-diagram/color.js +33 -0
  21. package/dist/chempot-diagram/compute.d.ts +38 -0
  22. package/dist/chempot-diagram/compute.js +650 -0
  23. package/dist/chempot-diagram/index.d.ts +5 -0
  24. package/dist/chempot-diagram/index.js +5 -0
  25. package/dist/chempot-diagram/pointer.d.ts +16 -0
  26. package/dist/chempot-diagram/pointer.js +40 -0
  27. package/dist/chempot-diagram/temperature.d.ts +15 -0
  28. package/dist/chempot-diagram/temperature.js +37 -0
  29. package/dist/chempot-diagram/types.d.ts +83 -0
  30. package/dist/chempot-diagram/types.js +27 -0
  31. package/dist/colors/index.d.ts +3 -1
  32. package/dist/colors/index.js +4 -0
  33. package/dist/composition/BarChart.svelte +13 -22
  34. package/dist/composition/BubbleChart.svelte +5 -3
  35. package/dist/composition/FormulaFilter.svelte +770 -90
  36. package/dist/composition/FormulaFilter.svelte.d.ts +37 -1
  37. package/dist/composition/PieChart.svelte +43 -18
  38. package/dist/composition/PieChart.svelte.d.ts +1 -1
  39. package/dist/constants.d.ts +1 -0
  40. package/dist/constants.js +2 -0
  41. package/dist/convex-hull/ConvexHull.svelte +14 -1
  42. package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -1
  43. package/dist/convex-hull/ConvexHull2D.svelte +14 -45
  44. package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
  45. package/dist/convex-hull/ConvexHull3D.svelte +396 -134
  46. package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
  47. package/dist/convex-hull/ConvexHull4D.svelte +93 -42
  48. package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
  49. package/dist/convex-hull/ConvexHullControls.svelte +94 -31
  50. package/dist/convex-hull/ConvexHullControls.svelte.d.ts +4 -2
  51. package/dist/convex-hull/ConvexHullStats.svelte +697 -128
  52. package/dist/convex-hull/ConvexHullStats.svelte.d.ts +6 -1
  53. package/dist/convex-hull/ConvexHullTooltip.svelte +1 -0
  54. package/dist/convex-hull/GasPressureControls.svelte +72 -38
  55. package/dist/convex-hull/GasPressureControls.svelte.d.ts +2 -1
  56. package/dist/convex-hull/TemperatureSlider.svelte +46 -19
  57. package/dist/convex-hull/TemperatureSlider.svelte.d.ts +2 -1
  58. package/dist/convex-hull/demo-temperature.d.ts +6 -0
  59. package/dist/convex-hull/demo-temperature.js +36 -0
  60. package/dist/convex-hull/gas-thermodynamics.js +16 -5
  61. package/dist/convex-hull/helpers.d.ts +7 -1
  62. package/dist/convex-hull/helpers.js +45 -15
  63. package/dist/convex-hull/index.d.ts +15 -1
  64. package/dist/convex-hull/index.js +1 -0
  65. package/dist/convex-hull/thermodynamics.d.ts +8 -21
  66. package/dist/convex-hull/thermodynamics.js +106 -17
  67. package/dist/convex-hull/types.d.ts +7 -0
  68. package/dist/convex-hull/types.js +11 -0
  69. package/dist/coordination/CoordinationBarPlot.svelte +29 -46
  70. package/dist/element/BohrAtom.svelte +1 -1
  71. package/dist/element/data.js +2 -14
  72. package/dist/element/data.json.gz +0 -0
  73. package/dist/element/index.d.ts +1 -1
  74. package/dist/element/index.js +1 -0
  75. package/dist/element/types.d.ts +1 -0
  76. package/dist/fermi-surface/FermiSurface.svelte +21 -65
  77. package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
  78. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
  79. package/dist/fermi-surface/FermiSurfaceScene.svelte +1 -1
  80. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
  81. package/dist/fermi-surface/compute.js +1 -21
  82. package/dist/fermi-surface/marching-cubes.d.ts +2 -13
  83. package/dist/fermi-surface/marching-cubes.js +2 -519
  84. package/dist/fermi-surface/parse.js +17 -23
  85. package/dist/heatmap-matrix/HeatmapMatrix.svelte +1273 -0
  86. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +110 -0
  87. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +171 -0
  88. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +31 -0
  89. package/dist/heatmap-matrix/index.d.ts +53 -0
  90. package/dist/heatmap-matrix/index.js +100 -0
  91. package/dist/heatmap-matrix/shared.d.ts +2 -0
  92. package/dist/heatmap-matrix/shared.js +4 -0
  93. package/dist/icons.d.ts +119 -0
  94. package/dist/icons.js +119 -0
  95. package/dist/index.d.ts +6 -1
  96. package/dist/index.js +6 -1
  97. package/dist/io/export.js +15 -3
  98. package/dist/io/file-drop.d.ts +7 -0
  99. package/dist/io/file-drop.js +43 -0
  100. package/dist/io/index.d.ts +2 -2
  101. package/dist/io/index.js +2 -112
  102. package/dist/io/types.d.ts +1 -0
  103. package/dist/io/url-drop.d.ts +2 -0
  104. package/dist/io/url-drop.js +118 -0
  105. package/dist/isosurface/Isosurface.svelte +231 -0
  106. package/dist/isosurface/Isosurface.svelte.d.ts +8 -0
  107. package/dist/isosurface/IsosurfaceControls.svelte +273 -0
  108. package/dist/isosurface/IsosurfaceControls.svelte.d.ts +9 -0
  109. package/dist/isosurface/index.d.ts +5 -0
  110. package/dist/isosurface/index.js +6 -0
  111. package/dist/isosurface/parse.d.ts +6 -0
  112. package/dist/isosurface/parse.js +548 -0
  113. package/dist/isosurface/slice.d.ts +11 -0
  114. package/dist/isosurface/slice.js +145 -0
  115. package/dist/isosurface/types.d.ts +55 -0
  116. package/dist/isosurface/types.js +178 -0
  117. package/dist/labels.d.ts +2 -1
  118. package/dist/labels.js +1 -0
  119. package/dist/layout/InfoTag.svelte +62 -62
  120. package/dist/layout/SubpageGrid.svelte +74 -0
  121. package/dist/layout/SubpageGrid.svelte.d.ts +14 -0
  122. package/dist/layout/index.d.ts +1 -0
  123. package/dist/layout/index.js +1 -0
  124. package/dist/layout/json-tree/JsonNode.svelte +226 -53
  125. package/dist/layout/json-tree/JsonTree.svelte +425 -51
  126. package/dist/layout/json-tree/JsonTree.svelte.d.ts +1 -1
  127. package/dist/layout/json-tree/JsonValue.svelte +218 -97
  128. package/dist/layout/json-tree/types.d.ts +27 -2
  129. package/dist/layout/json-tree/utils.d.ts +14 -1
  130. package/dist/layout/json-tree/utils.js +254 -0
  131. package/dist/marching-cubes.d.ts +14 -0
  132. package/dist/marching-cubes.js +519 -0
  133. package/dist/math.d.ts +8 -0
  134. package/dist/math.js +374 -7
  135. package/dist/overlays/ContextMenu.svelte +3 -2
  136. package/dist/overlays/DraggablePane.svelte +163 -58
  137. package/dist/overlays/DraggablePane.svelte.d.ts +2 -0
  138. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +232 -77
  139. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -2
  140. package/dist/phase-diagram/PhaseDiagramControls.svelte +32 -11
  141. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +3 -2
  142. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +103 -0
  143. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +15 -0
  144. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +102 -95
  145. package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +7 -0
  146. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +100 -26
  147. package/dist/phase-diagram/PhaseDiagramTooltip.svelte.d.ts +6 -3
  148. package/dist/phase-diagram/index.d.ts +2 -0
  149. package/dist/phase-diagram/index.js +2 -0
  150. package/dist/phase-diagram/svg-to-diagram.d.ts +2 -0
  151. package/dist/phase-diagram/svg-to-diagram.js +865 -0
  152. package/dist/phase-diagram/types.d.ts +10 -0
  153. package/dist/phase-diagram/utils.d.ts +7 -4
  154. package/dist/phase-diagram/utils.js +149 -59
  155. package/dist/plot/AxisLabel.svelte +26 -0
  156. package/dist/plot/AxisLabel.svelte.d.ts +16 -0
  157. package/dist/plot/BarPlot.svelte +473 -228
  158. package/dist/plot/BarPlot.svelte.d.ts +3 -3
  159. package/dist/plot/BarPlotControls.svelte +3 -2
  160. package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
  161. package/dist/plot/ColorBar.svelte +54 -54
  162. package/dist/plot/ColorBar.svelte.d.ts +1 -1
  163. package/dist/plot/ElementScatter.svelte +4 -3
  164. package/dist/plot/FillArea.svelte +4 -1
  165. package/dist/plot/Histogram.svelte +320 -230
  166. package/dist/plot/Histogram.svelte.d.ts +2 -2
  167. package/dist/plot/HistogramControls.svelte +29 -10
  168. package/dist/plot/HistogramControls.svelte.d.ts +6 -2
  169. package/dist/plot/InteractiveAxisLabel.svelte.d.ts +2 -2
  170. package/dist/plot/PlotControls.svelte +109 -27
  171. package/dist/plot/PlotControls.svelte.d.ts +1 -1
  172. package/dist/plot/PlotLegend.svelte +1 -1
  173. package/dist/plot/PortalSelect.svelte +2 -1
  174. package/dist/plot/ReferenceLine.svelte +2 -1
  175. package/dist/plot/ReferenceLine.svelte.d.ts +1 -0
  176. package/dist/plot/ReferencePlane.svelte +1 -3
  177. package/dist/plot/ScatterPlot.svelte +343 -209
  178. package/dist/plot/ScatterPlot.svelte.d.ts +3 -3
  179. package/dist/plot/ScatterPlot3D.svelte.d.ts +2 -2
  180. package/dist/plot/ScatterPlot3DControls.svelte +203 -250
  181. package/dist/plot/ScatterPlot3DScene.svelte +4 -7
  182. package/dist/plot/ScatterPlot3DScene.svelte.d.ts +2 -2
  183. package/dist/plot/ScatterPlotControls.svelte +95 -55
  184. package/dist/plot/ScatterPlotControls.svelte.d.ts +1 -1
  185. package/dist/plot/ZeroLines.svelte +44 -0
  186. package/dist/plot/ZeroLines.svelte.d.ts +32 -0
  187. package/dist/plot/ZoomRect.svelte +21 -0
  188. package/dist/plot/ZoomRect.svelte.d.ts +8 -0
  189. package/dist/plot/axis-utils.d.ts +1 -1
  190. package/dist/plot/data-cleaning.js +1 -5
  191. package/dist/plot/index.d.ts +6 -2
  192. package/dist/plot/index.js +6 -2
  193. package/dist/plot/interactions.d.ts +8 -10
  194. package/dist/plot/interactions.js +10 -19
  195. package/dist/plot/layout.d.ts +7 -1
  196. package/dist/plot/layout.js +12 -4
  197. package/dist/plot/reference-line.d.ts +4 -21
  198. package/dist/plot/reference-line.js +7 -81
  199. package/dist/plot/types.d.ts +42 -17
  200. package/dist/plot/types.js +10 -0
  201. package/dist/plot/utils/label-placement.js +14 -11
  202. package/dist/plot/utils.d.ts +1 -0
  203. package/dist/plot/utils.js +14 -0
  204. package/dist/rdf/RdfPlot.svelte +55 -66
  205. package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
  206. package/dist/rdf/index.d.ts +1 -1
  207. package/dist/rdf/index.js +1 -1
  208. package/dist/settings.d.ts +5 -0
  209. package/dist/settings.js +37 -3
  210. package/dist/spectral/Bands.svelte +515 -143
  211. package/dist/spectral/Bands.svelte.d.ts +22 -2
  212. package/dist/spectral/helpers.d.ts +23 -1
  213. package/dist/spectral/helpers.js +65 -9
  214. package/dist/spectral/types.d.ts +2 -0
  215. package/dist/structure/AtomLegend.svelte +31 -10
  216. package/dist/structure/AtomLegend.svelte.d.ts +1 -1
  217. package/dist/structure/CellSelect.svelte +92 -22
  218. package/dist/structure/Lattice.svelte +2 -0
  219. package/dist/structure/Structure.svelte +716 -173
  220. package/dist/structure/Structure.svelte.d.ts +7 -2
  221. package/dist/structure/StructureControls.svelte +26 -14
  222. package/dist/structure/StructureControls.svelte.d.ts +5 -1
  223. package/dist/structure/StructureInfoPane.svelte +7 -1
  224. package/dist/structure/StructureScene.svelte +386 -95
  225. package/dist/structure/StructureScene.svelte.d.ts +15 -4
  226. package/dist/structure/atom-properties.d.ts +6 -2
  227. package/dist/structure/atom-properties.js +38 -25
  228. package/dist/structure/export.js +10 -7
  229. package/dist/structure/ferrox-wasm-types.d.ts +3 -2
  230. package/dist/structure/ferrox-wasm-types.js +0 -3
  231. package/dist/structure/ferrox-wasm.d.ts +3 -2
  232. package/dist/structure/ferrox-wasm.js +1 -2
  233. package/dist/structure/index.d.ts +7 -0
  234. package/dist/structure/index.js +22 -0
  235. package/dist/structure/parse.js +19 -16
  236. package/dist/structure/partial-occupancy.d.ts +25 -0
  237. package/dist/structure/partial-occupancy.js +102 -0
  238. package/dist/structure/validation.js +6 -3
  239. package/dist/symmetry/SymmetryStats.svelte +18 -4
  240. package/dist/symmetry/WyckoffTable.svelte +18 -10
  241. package/dist/symmetry/index.d.ts +7 -4
  242. package/dist/symmetry/index.js +83 -18
  243. package/dist/table/HeatmapTable.svelte +468 -69
  244. package/dist/table/HeatmapTable.svelte.d.ts +13 -1
  245. package/dist/table/ToggleMenu.svelte +291 -44
  246. package/dist/table/ToggleMenu.svelte.d.ts +4 -1
  247. package/dist/table/index.d.ts +3 -0
  248. package/dist/tooltip/index.d.ts +1 -1
  249. package/dist/tooltip/index.js +1 -0
  250. package/dist/trajectory/Trajectory.svelte +147 -145
  251. package/dist/trajectory/TrajectoryExportPane.svelte +13 -9
  252. package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +1 -1
  253. package/dist/trajectory/constants.d.ts +6 -0
  254. package/dist/trajectory/constants.js +7 -0
  255. package/dist/trajectory/extract.js +3 -5
  256. package/dist/trajectory/format-detect.d.ts +9 -0
  257. package/dist/trajectory/format-detect.js +76 -0
  258. package/dist/trajectory/frame-reader.d.ts +17 -0
  259. package/dist/trajectory/frame-reader.js +339 -0
  260. package/dist/trajectory/helpers.d.ts +15 -0
  261. package/dist/trajectory/helpers.js +187 -0
  262. package/dist/trajectory/index.d.ts +1 -0
  263. package/dist/trajectory/index.js +11 -4
  264. package/dist/trajectory/parse/ase.d.ts +2 -0
  265. package/dist/trajectory/parse/ase.js +76 -0
  266. package/dist/trajectory/parse/hdf5.d.ts +2 -0
  267. package/dist/trajectory/parse/hdf5.js +121 -0
  268. package/dist/trajectory/parse/index.d.ts +12 -0
  269. package/dist/trajectory/parse/index.js +304 -0
  270. package/dist/trajectory/parse/lammps.d.ts +5 -0
  271. package/dist/trajectory/parse/lammps.js +169 -0
  272. package/dist/trajectory/parse/vasp.d.ts +2 -0
  273. package/dist/trajectory/parse/vasp.js +65 -0
  274. package/dist/trajectory/parse/xyz.d.ts +2 -0
  275. package/dist/trajectory/parse/xyz.js +109 -0
  276. package/dist/trajectory/types.d.ts +11 -0
  277. package/dist/trajectory/types.js +1 -0
  278. package/dist/utils.d.ts +2 -0
  279. package/dist/utils.js +4 -0
  280. package/dist/xrd/XrdPlot.svelte +6 -4
  281. package/dist/xrd/calc-xrd.js +0 -1
  282. package/package.json +33 -23
  283. package/readme.md +4 -4
  284. package/dist/trajectory/parse.d.ts +0 -42
  285. package/dist/trajectory/parse.js +0 -1267
  286. /package/dist/element/{data.json.d.ts → data.json.gz.d.ts} +0 -0
@@ -1,31 +1,18 @@
1
1
  import type { ElementSymbol } from '../element';
2
- import type { ConvexHullTriangle, PhaseData, Point2D, Point3D, ProcessedPhaseData } from './types';
2
+ import type { ConvexHullEntry, ConvexHullTriangle, PhaseData, PhaseStats, Point2D, Point3D, ProcessedPhaseData } from './types';
3
3
  export declare function normalize_hull_composition_keys(composition: Record<string, number>): Partial<Record<ElementSymbol, number>>;
4
4
  export declare function process_hull_entries(entries: PhaseData[]): ProcessedPhaseData;
5
5
  export declare function compute_e_form_per_atom(entry: PhaseData, el_refs: Record<string, PhaseData>): number | null;
6
6
  export declare function find_lowest_energy_unary_refs(entries: PhaseData[]): Record<string, PhaseData>;
7
7
  export declare function calculate_e_above_hull(entry: PhaseData, reference_entries: PhaseData[]): number;
8
8
  export declare function calculate_e_above_hull(entries: PhaseData[], reference_entries: PhaseData[]): Record<string, number>;
9
- export declare function get_convex_hull_stats(processed_entries: PhaseData[], elements: ElementSymbol[], max_arity: 3 | 4): {
10
- total: number;
11
- unary: number;
12
- binary: number;
13
- ternary: number;
14
- quaternary: number;
15
- stable: number;
16
- unstable: number;
17
- energy_range: {
18
- min: number;
19
- max: number;
20
- avg: number;
21
- };
22
- hull_distance: {
23
- max: number;
24
- avg: number;
25
- };
26
- elements: number;
27
- chemical_system: string;
28
- } | null;
9
+ export declare function get_convex_hull_stats(processed_entries: PhaseData[], elements: ElementSymbol[], max_arity?: number): PhaseStats | null;
10
+ export interface HighDimHullResult {
11
+ stable_entries: ConvexHullEntry[];
12
+ unstable_entries: ConvexHullEntry[];
13
+ phase_stats: PhaseStats | null;
14
+ }
15
+ export declare function process_hull_for_stats(entries: PhaseData[], elements?: ElementSymbol[]): HighDimHullResult | null;
29
16
  export declare function compute_lower_hull_2d(points: Point2D[]): Point2D[];
30
17
  export declare function interpolate_hull_2d(hull: Point2D[], x: number): number | null;
31
18
  export declare function compute_quickhull_triangles(points: Point3D[]): ConvexHullTriangle[];
@@ -1,7 +1,7 @@
1
1
  import { count_atoms_in_composition, extract_formula_elements, sort_by_electronegativity, } from '../composition';
2
2
  import * as math from '../math';
3
3
  import { barycentric_to_ternary_xyz, barycentric_to_tetrahedral, composition_to_barycentric_3d, composition_to_barycentric_4d, composition_to_barycentric_nd, } from './barycentric-coords';
4
- import { is_unary_entry } from './types';
4
+ import { get_arity, HULL_STABILITY_TOL, is_on_hull, is_unary_entry } from './types';
5
5
  // Track warned keys to avoid log spam on large datasets with repeated invalid keys
6
6
  const warned_keys = new Set();
7
7
  // Normalize convex hull composition keys by stripping oxidation states (e.g. "V4+" -> "V")
@@ -365,32 +365,57 @@ export function calculate_e_above_hull(input, reference_entries) {
365
365
  }
366
366
  return results;
367
367
  }
368
- export function get_convex_hull_stats(processed_entries, elements, max_arity) {
369
- if (!processed_entries || processed_entries.length === 0)
368
+ export function get_convex_hull_stats(processed_entries, elements, max_arity = 4) {
369
+ if (processed_entries.length === 0)
370
370
  return null;
371
- const composition_counts = (max_arity === 4 ? [1, 2, 3, 4] : [1, 2, 3]).map((target) => processed_entries.filter((entry) => Object.keys(entry.composition).filter((el) => (entry.composition[el] ?? 0) > 0).length === target).length);
372
- const [unary, binary, ternary, quaternaryMaybe] = composition_counts;
373
- const quaternary = max_arity === 4 ? (quaternaryMaybe ?? 0) : 0;
374
- const stable_count = processed_entries.filter((e) => e.is_stable === true ||
375
- (typeof e.e_above_hull === `number` && e.e_above_hull < 1e-6)).length;
371
+ max_arity = Math.max(1, max_arity);
372
+ let unary = 0;
373
+ let binary = 0;
374
+ let ternary = 0;
375
+ let quaternary = 0;
376
+ let quinary_plus = 0;
377
+ for (const entry of processed_entries) {
378
+ const arity = get_arity(entry);
379
+ if (arity === 1)
380
+ unary++;
381
+ else if (arity === 2)
382
+ binary++;
383
+ else if (arity === 3)
384
+ ternary++;
385
+ else if (arity === 4)
386
+ quaternary++;
387
+ else if (arity >= 5)
388
+ quinary_plus++;
389
+ }
390
+ // Zero out counts beyond system dimensionality for cleaner display
391
+ // quinary_plus is intentionally not zeroed — it's a catch-all bucket that
392
+ // is naturally 0 for systems with fewer than 5 elements
393
+ if (max_arity < 4)
394
+ quaternary = 0;
395
+ if (max_arity < 3)
396
+ ternary = 0;
397
+ if (max_arity < 2)
398
+ binary = 0;
399
+ const stable_count = processed_entries.filter((entry) => is_on_hull(entry)).length;
376
400
  const unstable_count = processed_entries.length - stable_count;
377
401
  const energies = processed_entries
378
- .map((e) => e.e_form_per_atom ?? e.energy_per_atom)
379
- .filter((v) => typeof v === `number` && Number.isFinite(v));
402
+ .map((entry) => entry.e_form_per_atom ?? entry.energy_per_atom ?? get_energy_per_atom(entry))
403
+ .filter(Number.isFinite);
404
+ // Use reduce instead of Math.min/max(...arr) to avoid stack overflow on large datasets
380
405
  const energy_range = energies.length > 0
381
406
  ? {
382
- min: Math.min(...energies),
383
- max: Math.max(...energies),
384
- avg: energies.reduce((a, b) => a + b, 0) / energies.length,
407
+ min: energies.reduce((min, val) => val < min ? val : min, Infinity),
408
+ max: energies.reduce((max, val) => val > max ? val : max, -Infinity),
409
+ avg: energies.reduce((sum, val) => sum + val, 0) / energies.length,
385
410
  }
386
411
  : { min: 0, max: 0, avg: 0 };
387
412
  const hull_distances = processed_entries
388
- .map((e) => e.e_above_hull)
389
- .filter((v) => typeof v === `number` && v >= 0);
413
+ .map((entry) => entry.e_above_hull)
414
+ .filter((val) => typeof val === `number` && val >= 0);
390
415
  const hull_distance = hull_distances.length > 0
391
416
  ? {
392
- max: Math.max(...hull_distances),
393
- avg: hull_distances.reduce((a, b) => a + b, 0) / hull_distances.length,
417
+ max: hull_distances.reduce((max, val) => val > max ? val : max, -Infinity),
418
+ avg: hull_distances.reduce((sum, val) => sum + val, 0) / hull_distances.length,
394
419
  }
395
420
  : { max: 0, avg: 0 };
396
421
  return {
@@ -399,12 +424,76 @@ export function get_convex_hull_stats(processed_entries, elements, max_arity) {
399
424
  binary,
400
425
  ternary,
401
426
  quaternary,
427
+ quinary_plus,
402
428
  stable: stable_count,
403
429
  unstable: unstable_count,
404
430
  energy_range,
405
431
  hull_distance,
406
432
  elements: elements.length,
407
433
  chemical_system: sort_by_electronegativity([...elements]).join(`-`),
434
+ max_arity,
435
+ };
436
+ }
437
+ // Convert a PhaseData entry to a ConvexHullEntry with default visual fields.
438
+ // x/y/z default to 0 since high-dim systems aren't visually plotted.
439
+ function to_hull_entry(entry) {
440
+ return {
441
+ ...entry,
442
+ visible: true,
443
+ is_element: get_arity(entry) === 1,
444
+ x: 0,
445
+ y: 0,
446
+ z: 0,
447
+ };
448
+ }
449
+ // Process raw hull entries for high-dimensional systems (5+ elements) where the
450
+ // ConvexHull visual component can't render. Computes formation energies, hull distances,
451
+ // stable/unstable classification, and phase stats. Returns null on failure.
452
+ // Optionally accepts `elements` to scope the chemical system; if omitted, elements
453
+ // are derived from the entries' compositions.
454
+ export function process_hull_for_stats(entries, elements) {
455
+ if (!entries.length)
456
+ return null;
457
+ const processed = process_hull_entries(entries);
458
+ if (!processed.entries.length)
459
+ return null;
460
+ const hull_elements = elements ?? processed.elements;
461
+ // Compute formation energies
462
+ const el_refs = find_lowest_energy_unary_refs(processed.entries);
463
+ for (const entry of processed.entries) {
464
+ if (entry.e_form_per_atom === undefined) {
465
+ const e_form = compute_e_form_per_atom(entry, el_refs);
466
+ if (e_form !== null)
467
+ entry.e_form_per_atom = e_form;
468
+ }
469
+ }
470
+ // Compute hull distances. Note: entries without entry_id are keyed by
471
+ // JSON.stringify(composition), so polymorphs at the same composition
472
+ // collide — the last-processed entry's distance wins for all of them.
473
+ try {
474
+ const hull_distances = calculate_e_above_hull(processed.entries, processed.entries);
475
+ for (const entry of processed.entries) {
476
+ const dist = hull_distances[entry.entry_id ?? JSON.stringify(entry.composition)];
477
+ if (typeof dist === `number` && Number.isFinite(dist)) {
478
+ entry.e_above_hull = dist;
479
+ entry.is_stable = dist < HULL_STABILITY_TOL;
480
+ }
481
+ else {
482
+ // Clear stale hull metadata so previous values don't persist
483
+ entry.e_above_hull = undefined;
484
+ entry.is_stable = undefined;
485
+ }
486
+ }
487
+ }
488
+ catch (err) {
489
+ console.warn(`Failed to compute high-dim hull:`, err);
490
+ return null;
491
+ }
492
+ const hull_entries = processed.entries.map(to_hull_entry);
493
+ return {
494
+ stable_entries: hull_entries.filter((entry) => is_on_hull(entry)),
495
+ unstable_entries: hull_entries.filter((entry) => !is_on_hull(entry)),
496
+ phase_stats: get_convex_hull_stats(processed.entries, hull_elements, hull_elements.length),
408
497
  };
409
498
  }
410
499
  // --- 2D Convex Hull (Binary Phase Diagrams) ---
@@ -39,6 +39,8 @@ export interface Point3D extends Point2D {
39
39
  z: number;
40
40
  }
41
41
  export type MarkerSymbol = `circle` | `star` | `triangle` | `cross` | `diamond` | `square` | `wye`;
42
+ export type HullFaceColorMode = `uniform` | `formation_energy` | `dominant_element` | `facet_index`;
43
+ export declare const HULL_FACE_COLOR_MODES: readonly HullFaceColorMode[];
42
44
  export interface ConvexHullEntry extends PhaseData, Point3D {
43
45
  is_element: boolean;
44
46
  size?: number;
@@ -104,6 +106,7 @@ export interface PhaseStats {
104
106
  binary: number;
105
107
  ternary: number;
106
108
  quaternary: number;
109
+ quinary_plus: number;
107
110
  stable: number;
108
111
  unstable: number;
109
112
  energy_range: {
@@ -117,7 +120,11 @@ export interface PhaseStats {
117
120
  };
118
121
  elements: number;
119
122
  chemical_system: string;
123
+ max_arity: number;
120
124
  }
125
+ export type PhaseArityField = Extract<keyof PhaseStats, `unary` | `binary` | `ternary` | `quaternary` | `quinary_plus`>;
126
+ export declare const HULL_STABILITY_TOL = 0.000001;
127
+ export declare const is_on_hull: (entry: PhaseData, tol?: number) => boolean;
121
128
  export declare const get_arity: (entry: PhaseData) => number;
122
129
  export declare const is_unary_entry: (entry: PhaseData) => boolean;
123
130
  export declare const is_binary_entry: (entry: PhaseData) => boolean;
@@ -1,3 +1,14 @@
1
+ export const HULL_FACE_COLOR_MODES = [
2
+ `uniform`,
3
+ `formation_energy`,
4
+ `dominant_element`,
5
+ `facet_index`,
6
+ ];
7
+ // Tolerance for classifying a phase as on the convex hull (eV/atom)
8
+ export const HULL_STABILITY_TOL = 1e-6;
9
+ // Check if entry is on the convex hull (stable or e_above_hull ≈ 0)
10
+ export const is_on_hull = (entry, tol = HULL_STABILITY_TOL) => entry.is_stable === true ||
11
+ (typeof entry.e_above_hull === `number` && entry.e_above_hull < tol);
1
12
  // Arity helpers (inlined from former arity.ts)
2
13
  export const get_arity = (entry) => Object.values(entry.composition).filter((count) => count > 0).length;
3
14
  export const is_unary_entry = (entry) => get_arity(entry) === 1;
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">import { PLOT_COLORS } from '../colors';
2
2
  import { StatusMessage } from '../feedback';
3
- import { decompress_file, handle_url_drop } from '../io';
3
+ import { create_file_drop_handler } from '../io';
4
4
  import { format_value } from '../labels';
5
5
  import { BarPlot } from '../plot';
6
6
  import { parse_any_structure } from '../structure/parse';
@@ -135,55 +135,38 @@ const bar_series = $derived.by(() => {
135
135
  ];
136
136
  }
137
137
  });
138
- async function handle_file_drop(event) {
139
- event.preventDefault();
140
- dragover = false;
141
- if (!allow_file_drop)
142
- return;
143
- loading = true;
144
- error_msg = undefined;
145
- const compute_and_add = (content, filename) => {
146
- try {
147
- const text_content = content instanceof ArrayBuffer
148
- ? new TextDecoder().decode(content)
149
- : content;
150
- const parsed_structure = parse_any_structure(text_content, filename);
151
- if (is_crystal(parsed_structure)) {
152
- dropped_entries = [{
153
- label: filename || `Dropped structure`,
154
- structure: parsed_structure,
155
- }, ...dropped_entries];
156
- }
157
- else {
158
- error_msg = `Structure has no lattice or sites; cannot compute coordination`;
159
- }
160
- }
161
- catch (exc) {
162
- error_msg = `Failed to process structure: ${exc instanceof Error ? exc.message : String(exc)}`;
163
- }
164
- };
138
+ const compute_and_add = (content, filename) => {
165
139
  try {
166
- // Handle URL-based drops
167
- const handled = await handle_url_drop(event, on_file_drop || compute_and_add)
168
- .catch(() => false);
169
- if (handled)
170
- return;
171
- const file = event.dataTransfer?.files?.[0];
172
- if (file) {
173
- try {
174
- const { content, filename } = await decompress_file(file);
175
- if (content)
176
- (on_file_drop || compute_and_add)(content, filename);
177
- }
178
- catch (exc) {
179
- error_msg = `Failed to load file ${file.name}: ${exc instanceof Error ? exc.message : String(exc)}`;
180
- }
140
+ const text_content = content instanceof ArrayBuffer
141
+ ? new TextDecoder().decode(content)
142
+ : content;
143
+ const parsed_structure = parse_any_structure(text_content, filename);
144
+ if (is_crystal(parsed_structure)) {
145
+ dropped_entries = [{
146
+ label: filename || `Dropped structure`,
147
+ structure: parsed_structure,
148
+ }, ...dropped_entries];
149
+ }
150
+ else {
151
+ error_msg = `Structure has no lattice or sites; cannot compute coordination`;
181
152
  }
182
153
  }
183
- finally {
184
- loading = false;
154
+ catch (exc) {
155
+ error_msg = `Failed to process structure: ${exc instanceof Error ? exc.message : String(exc)}`;
185
156
  }
186
- }
157
+ };
158
+ const handle_file_drop = create_file_drop_handler({
159
+ allow: () => allow_file_drop,
160
+ on_drop: (content, filename) => (on_file_drop || compute_and_add)(content, filename),
161
+ on_error: (msg) => {
162
+ error_msg = msg;
163
+ },
164
+ set_loading: (val) => {
165
+ loading = val;
166
+ if (val)
167
+ [error_msg, dragover] = [undefined, false];
168
+ },
169
+ });
187
170
  let display = $state({ x_zero_line: false, y_zero_line: false });
188
171
  // Update display when orientation changes
189
172
  $effect(() => {
@@ -42,7 +42,7 @@ export {};
42
42
  {/if}
43
43
 
44
44
  <!-- electron orbitals -->
45
- {#each shells as electrons, shell_idx ([electrons, shell_idx])}
45
+ {#each shells as electrons, shell_idx (`${shell_idx}-${electrons}`)}
46
46
  {@const n = shell_idx + 1}
47
47
  {@const shell_radius = _nucleus_props.r + n * shell_width}
48
48
  {@const active = n === highlight_shell}