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