matterviz 0.3.7 → 0.4.1
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/Icon.svelte +7 -4
- package/dist/MillerIndexInput.svelte +1 -1
- package/dist/api/optimade.js +32 -26
- package/dist/app.css +0 -3
- package/dist/brillouin/BrillouinZone.svelte +76 -148
- package/dist/brillouin/BrillouinZone.svelte.d.ts +6 -14
- package/dist/brillouin/BrillouinZoneExportPane.svelte +43 -96
- package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +1 -1
- package/dist/brillouin/BrillouinZoneInfoPane.svelte +9 -32
- package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +2 -3
- package/dist/brillouin/BrillouinZoneScene.svelte +97 -205
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +4 -23
- package/dist/brillouin/BrillouinZoneTooltip.svelte +16 -25
- package/dist/brillouin/ReciprocalVectors.svelte +39 -0
- package/dist/brillouin/ReciprocalVectors.svelte.d.ts +9 -0
- package/dist/brillouin/compute.d.ts +2 -0
- package/dist/brillouin/compute.js +89 -90
- package/dist/brillouin/geometry.d.ts +8 -0
- package/dist/brillouin/geometry.js +57 -0
- package/dist/brillouin/index.d.ts +2 -0
- package/dist/brillouin/index.js +2 -0
- package/dist/brillouin/types.d.ts +2 -2
- package/dist/chempot-diagram/ChemPotDiagram.svelte +14 -13
- package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +1 -1
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +109 -203
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +4 -1
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +180 -470
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +7 -1
- package/dist/chempot-diagram/async-compute.svelte.js +3 -1
- package/dist/chempot-diagram/chempot-worker.js +2 -1
- package/dist/chempot-diagram/color.d.ts +3 -6
- package/dist/chempot-diagram/color.js +5 -5
- package/dist/chempot-diagram/compute.d.ts +4 -4
- package/dist/chempot-diagram/compute.js +20 -20
- package/dist/chempot-diagram/controls-state.svelte.d.ts +10 -0
- package/dist/chempot-diagram/controls-state.svelte.js +42 -0
- package/dist/chempot-diagram/export.d.ts +47 -0
- package/dist/chempot-diagram/export.js +133 -0
- package/dist/chempot-diagram/index.d.ts +1 -0
- package/dist/chempot-diagram/index.js +1 -0
- package/dist/chempot-diagram/pointer.d.ts +0 -10
- package/dist/chempot-diagram/pointer.js +4 -4
- package/dist/chempot-diagram/types.d.ts +3 -3
- package/dist/colors/index.js +8 -7
- package/dist/composition/FormulaFilter.svelte +18 -11
- package/dist/composition/PieChart.svelte +11 -10
- package/dist/composition/chem-sys.d.ts +8 -0
- package/dist/composition/chem-sys.js +86 -0
- package/dist/composition/format.js +7 -4
- package/dist/composition/index.d.ts +1 -0
- package/dist/composition/index.js +1 -0
- package/dist/composition/parse.d.ts +0 -1
- package/dist/composition/parse.js +41 -31
- package/dist/controls.d.ts +1 -0
- package/dist/controls.js +0 -1
- package/dist/convex-hull/ConvexHull.svelte +8 -10
- package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -4
- package/dist/convex-hull/ConvexHull2D.svelte +106 -185
- package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull3D.svelte +179 -683
- package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull4D.svelte +183 -687
- package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHullChrome.svelte +268 -0
- package/dist/convex-hull/ConvexHullChrome.svelte.d.ts +30 -0
- package/dist/convex-hull/ConvexHullControls.svelte +88 -7
- package/dist/convex-hull/ConvexHullControls.svelte.d.ts +7 -6
- package/dist/convex-hull/ConvexHullInfoPane.svelte +18 -5
- package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +6 -5
- package/dist/convex-hull/ConvexHullStats.svelte +36 -175
- package/dist/convex-hull/ConvexHullStats.svelte.d.ts +3 -1
- package/dist/convex-hull/ConvexHullTooltip.svelte +11 -2
- package/dist/convex-hull/ConvexHullTooltip.svelte.d.ts +2 -1
- package/dist/convex-hull/GasPressureControls.svelte +4 -4
- package/dist/convex-hull/TemperatureSlider.svelte +2 -2
- package/dist/convex-hull/barycentric-coords.d.ts +2 -4
- package/dist/convex-hull/barycentric-coords.js +6 -33
- package/dist/convex-hull/canvas-interactions.svelte.d.ts +79 -0
- package/dist/convex-hull/canvas-interactions.svelte.js +278 -0
- package/dist/convex-hull/demo-temperature.d.ts +1 -1
- package/dist/convex-hull/demo-temperature.js +20 -22
- package/dist/convex-hull/gas-thermodynamics.d.ts +2 -2
- package/dist/convex-hull/gas-thermodynamics.js +22 -30
- package/dist/convex-hull/helpers.d.ts +42 -7
- package/dist/convex-hull/helpers.js +171 -78
- package/dist/convex-hull/hull-state.svelte.d.ts +44 -0
- package/dist/convex-hull/hull-state.svelte.js +124 -0
- package/dist/convex-hull/index.d.ts +10 -8
- package/dist/convex-hull/index.js +7 -2
- package/dist/convex-hull/thermodynamics.js +136 -960
- package/dist/convex-hull/types.d.ts +13 -5
- package/dist/convex-hull/types.js +12 -0
- package/dist/coordination/CoordinationBarPlot.svelte +27 -34
- package/dist/coordination/CoordinationBarPlot.svelte.d.ts +1 -1
- package/dist/element/BohrAtom.svelte +2 -1
- package/dist/element/index.d.ts +4 -0
- package/dist/element/index.js +18 -0
- package/dist/feedback/DragOverlay.svelte +3 -1
- package/dist/feedback/DragOverlay.svelte.d.ts +1 -0
- package/dist/feedback/StatusMessage.svelte +13 -3
- package/dist/fermi-surface/FermiSlice.svelte +13 -5
- package/dist/fermi-surface/FermiSurface.svelte +78 -151
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +5 -14
- package/dist/fermi-surface/FermiSurfaceControls.svelte +1 -1
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte +72 -221
- package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +3 -23
- package/dist/fermi-surface/FermiSurfaceTooltip.svelte +8 -34
- package/dist/fermi-surface/compute.js +67 -66
- package/dist/fermi-surface/export.js +6 -16
- package/dist/fermi-surface/index.d.ts +0 -1
- package/dist/fermi-surface/index.js +0 -1
- package/dist/fermi-surface/parse.d.ts +1 -1
- package/dist/fermi-surface/parse.js +71 -79
- package/dist/fermi-surface/types.d.ts +3 -2
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +69 -52
- package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +4 -3
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +3 -2
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +5 -5
- package/dist/heatmap-matrix/index.d.ts +3 -2
- package/dist/heatmap-matrix/index.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/io/ExportPane.svelte +166 -0
- package/dist/io/ExportPane.svelte.d.ts +17 -0
- package/dist/io/decompress.js +5 -4
- package/dist/io/export.d.ts +9 -5
- package/dist/io/export.js +77 -51
- package/dist/io/fetch.d.ts +2 -1
- package/dist/io/fetch.js +5 -1
- package/dist/io/file-drop.d.ts +8 -1
- package/dist/io/file-drop.js +48 -36
- package/dist/io/index.d.ts +2 -0
- package/dist/io/index.js +10 -0
- package/dist/io/types.d.ts +13 -0
- package/dist/io/url-drop.js +64 -33
- package/dist/isosurface/parse.js +52 -51
- package/dist/isosurface/slice.js +5 -4
- package/dist/isosurface/types.js +1 -1
- package/dist/keyboard.d.ts +3 -0
- package/dist/keyboard.js +23 -0
- package/dist/labels.d.ts +1 -1
- package/dist/labels.js +9 -8
- package/dist/layout/FullscreenButton.svelte +33 -0
- package/dist/layout/FullscreenButton.svelte.d.ts +10 -0
- package/dist/layout/FullscreenToggle.svelte +8 -14
- package/dist/layout/PropertyFilter.svelte +3 -2
- package/dist/layout/SettingsSection.svelte +1 -1
- package/dist/layout/ViewerChrome.svelte +116 -0
- package/dist/layout/ViewerChrome.svelte.d.ts +17 -0
- package/dist/layout/fullscreen.d.ts +4 -0
- package/dist/layout/fullscreen.svelte.d.ts +8 -0
- package/dist/layout/fullscreen.svelte.js +37 -0
- package/dist/layout/index.d.ts +3 -0
- package/dist/layout/index.js +3 -0
- package/dist/layout/json-tree/JsonNode.svelte +1 -1
- package/dist/layout/json-tree/JsonTree.svelte +2 -2
- package/dist/layout/json-tree/utils.js +5 -4
- package/dist/marching-cubes.js +8 -13
- package/dist/math.d.ts +12 -4
- package/dist/math.js +42 -30
- package/dist/overlays/DraggablePane.svelte +4 -4
- package/dist/overlays/index.d.ts +4 -0
- package/dist/periodic-table/PeriodicTable.svelte +27 -15
- package/dist/periodic-table/PropertySelect.svelte +1 -0
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +9 -3
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramControls.svelte +3 -2
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +4 -3
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +4 -2
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +2 -3
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +47 -132
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +3 -4
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte +1 -1
- package/dist/phase-diagram/build-diagram.js +2 -2
- package/dist/phase-diagram/colors.js +1 -1
- package/dist/phase-diagram/parse.d.ts +2 -1
- package/dist/phase-diagram/parse.js +6 -5
- package/dist/phase-diagram/types.d.ts +1 -1
- package/dist/phase-diagram/utils.d.ts +3 -3
- package/dist/phase-diagram/utils.js +8 -12
- package/dist/plot/{BarPlot.svelte → bar/BarPlot.svelte} +246 -841
- package/dist/plot/{BarPlot.svelte.d.ts → bar/BarPlot.svelte.d.ts} +8 -16
- package/dist/plot/{BarPlotControls.svelte → bar/BarPlotControls.svelte} +6 -5
- package/dist/plot/{BarPlotControls.svelte.d.ts → bar/BarPlotControls.svelte.d.ts} +3 -3
- package/dist/plot/{SpacegroupBarPlot.svelte → bar/SpacegroupBarPlot.svelte} +8 -7
- package/dist/plot/{SpacegroupBarPlot.svelte.d.ts → bar/SpacegroupBarPlot.svelte.d.ts} +1 -1
- package/dist/plot/bar/data.d.ts +40 -0
- package/dist/plot/bar/data.js +154 -0
- package/dist/plot/bar/geometry.d.ts +39 -0
- package/dist/plot/bar/geometry.js +60 -0
- package/dist/plot/bar/index.d.ts +3 -0
- package/dist/plot/bar/index.js +3 -0
- package/dist/plot/box/BoxPlot.svelte +1292 -0
- package/dist/plot/box/BoxPlot.svelte.d.ts +95 -0
- package/dist/plot/box/BoxPlotControls.svelte +109 -0
- package/dist/plot/box/BoxPlotControls.svelte.d.ts +19 -0
- package/dist/plot/box/Violin.svelte +14 -0
- package/dist/plot/box/Violin.svelte.d.ts +70 -0
- package/dist/plot/box/box-plot.d.ts +56 -0
- package/dist/plot/box/box-plot.js +129 -0
- package/dist/plot/box/index.d.ts +5 -0
- package/dist/plot/box/index.js +5 -0
- package/dist/plot/box/kde.d.ts +17 -0
- package/dist/plot/box/kde.js +160 -0
- package/dist/plot/box/quantile.d.ts +3 -0
- package/dist/plot/box/quantile.js +53 -0
- package/dist/plot/{auto-place.d.ts → core/auto-place.d.ts} +1 -1
- package/dist/plot/{auto-place.js → core/auto-place.js} +6 -3
- package/dist/plot/core/axis-utils.d.ts +46 -0
- package/dist/plot/core/axis-utils.js +110 -0
- package/dist/plot/{AxisLabel.svelte → core/components/AxisLabel.svelte} +2 -2
- package/dist/plot/{AxisLabel.svelte.d.ts → core/components/AxisLabel.svelte.d.ts} +1 -1
- package/dist/plot/{ColorBar.svelte → core/components/ColorBar.svelte} +41 -38
- package/dist/plot/{ColorBar.svelte.d.ts → core/components/ColorBar.svelte.d.ts} +7 -6
- package/dist/plot/{ColorScaleSelect.svelte → core/components/ColorScaleSelect.svelte} +4 -3
- package/dist/plot/{ColorScaleSelect.svelte.d.ts → core/components/ColorScaleSelect.svelte.d.ts} +2 -2
- package/dist/plot/core/components/ControlPane.svelte +46 -0
- package/dist/plot/core/components/ControlPane.svelte.d.ts +13 -0
- package/dist/plot/{FillArea.svelte → core/components/FillArea.svelte} +17 -6
- package/dist/plot/{FillArea.svelte.d.ts → core/components/FillArea.svelte.d.ts} +1 -1
- package/dist/plot/{InteractiveAxisLabel.svelte → core/components/InteractiveAxisLabel.svelte} +3 -3
- package/dist/plot/{InteractiveAxisLabel.svelte.d.ts → core/components/InteractiveAxisLabel.svelte.d.ts} +2 -2
- package/dist/plot/{Line.svelte → core/components/Line.svelte} +33 -15
- package/dist/plot/{Line.svelte.d.ts → core/components/Line.svelte.d.ts} +3 -2
- package/dist/plot/{PlotAxis.svelte → core/components/PlotAxis.svelte} +9 -6
- package/dist/plot/{PlotAxis.svelte.d.ts → core/components/PlotAxis.svelte.d.ts} +5 -3
- package/dist/plot/{PlotControls.svelte → core/components/PlotControls.svelte} +17 -29
- package/dist/plot/core/components/PlotControls.svelte.d.ts +4 -0
- package/dist/plot/{PlotLegend.svelte → core/components/PlotLegend.svelte} +21 -10
- package/dist/plot/{PlotLegend.svelte.d.ts → core/components/PlotLegend.svelte.d.ts} +3 -2
- package/dist/plot/{PlotTooltip.svelte → core/components/PlotTooltip.svelte} +17 -1
- package/dist/plot/{PlotTooltip.svelte.d.ts → core/components/PlotTooltip.svelte.d.ts} +8 -0
- package/dist/plot/{PortalSelect.svelte → core/components/PortalSelect.svelte} +11 -7
- package/dist/plot/{ReferenceLine.svelte → core/components/ReferenceLine.svelte} +3 -3
- package/dist/plot/{ReferenceLine.svelte.d.ts → core/components/ReferenceLine.svelte.d.ts} +1 -1
- package/dist/plot/{ReferenceLine3D.svelte → core/components/ReferenceLine3D.svelte} +5 -5
- package/dist/plot/{ReferenceLine3D.svelte.d.ts → core/components/ReferenceLine3D.svelte.d.ts} +5 -5
- package/dist/plot/{ReferencePlane.svelte → core/components/ReferencePlane.svelte} +8 -8
- package/dist/plot/{ReferencePlane.svelte.d.ts → core/components/ReferencePlane.svelte.d.ts} +5 -5
- package/dist/plot/{ZeroLines.svelte → core/components/ZeroLines.svelte} +3 -3
- package/dist/plot/{ZeroLines.svelte.d.ts → core/components/ZeroLines.svelte.d.ts} +3 -3
- package/dist/plot/{ZoomRect.svelte → core/components/ZoomRect.svelte} +1 -1
- package/dist/plot/{ZoomRect.svelte.d.ts → core/components/ZoomRect.svelte.d.ts} +1 -1
- package/dist/plot/core/components/index.d.ts +17 -0
- package/dist/plot/core/components/index.js +17 -0
- package/dist/plot/{data-cleaning.d.ts → core/data-cleaning.d.ts} +71 -1
- package/dist/plot/{data-cleaning.js → core/data-cleaning.js} +21 -23
- package/dist/plot/{data-transform.d.ts → core/data-transform.d.ts} +2 -2
- package/dist/plot/{data-transform.js → core/data-transform.js} +3 -3
- package/dist/plot/core/fill-utils.d.ts +34 -0
- package/dist/plot/core/fill-utils.js +391 -0
- package/dist/plot/core/index.d.ts +10 -0
- package/dist/plot/core/index.js +11 -0
- package/dist/plot/core/interactions.d.ts +39 -0
- package/dist/plot/core/interactions.js +209 -0
- package/dist/plot/{layout.d.ts → core/layout.d.ts} +1 -0
- package/dist/plot/{layout.js → core/layout.js} +16 -8
- package/dist/plot/core/pan-zoom.svelte.d.ts +35 -0
- package/dist/plot/core/pan-zoom.svelte.js +221 -0
- package/dist/plot/core/placed-tween.svelte.d.ts +21 -0
- package/dist/plot/core/placed-tween.svelte.js +68 -0
- package/dist/plot/{reference-line.d.ts → core/reference-line.d.ts} +11 -11
- package/dist/plot/{reference-line.js → core/reference-line.js} +29 -42
- package/dist/plot/core/scales.d.ts +40 -0
- package/dist/plot/{scales.js → core/scales.js} +94 -93
- package/dist/plot/core/svg.d.ts +3 -0
- package/dist/plot/core/svg.js +41 -0
- package/dist/plot/{types.d.ts → core/types.d.ts} +36 -85
- package/dist/plot/{types.js → core/types.js} +1 -1
- package/dist/plot/{utils → core/utils}/label-placement.d.ts +3 -3
- package/dist/plot/{utils → core/utils}/label-placement.js +3 -3
- package/dist/plot/core/utils/series-visibility.d.ts +26 -0
- package/dist/plot/{utils → core/utils}/series-visibility.js +29 -2
- package/dist/plot/core/utils.d.ts +12 -0
- package/dist/plot/core/utils.js +27 -0
- package/dist/plot/{Histogram.svelte → histogram/Histogram.svelte} +174 -551
- package/dist/plot/{Histogram.svelte.d.ts → histogram/Histogram.svelte.d.ts} +2 -2
- package/dist/plot/{HistogramControls.svelte → histogram/HistogramControls.svelte} +6 -6
- package/dist/plot/{HistogramControls.svelte.d.ts → histogram/HistogramControls.svelte.d.ts} +4 -4
- package/dist/plot/histogram/index.d.ts +2 -0
- package/dist/plot/histogram/index.js +2 -0
- package/dist/plot/index.d.ts +8 -41
- package/dist/plot/index.js +10 -39
- package/dist/plot/sankey/Sankey.svelte +697 -0
- package/dist/plot/sankey/Sankey.svelte.d.ts +74 -0
- package/dist/plot/sankey/SankeyControls.svelte +98 -0
- package/dist/plot/sankey/SankeyControls.svelte.d.ts +19 -0
- package/dist/plot/sankey/index.d.ts +4 -0
- package/dist/plot/sankey/index.js +3 -0
- package/dist/plot/sankey/sankey-types.d.ts +42 -0
- package/dist/plot/sankey/sankey-types.js +4 -0
- package/dist/plot/sankey/sankey.d.ts +52 -0
- package/dist/plot/sankey/sankey.js +189 -0
- package/dist/plot/{BinnedScatterPlot.svelte → scatter/BinnedScatterPlot.svelte} +64 -64
- package/dist/plot/{BinnedScatterPlot.svelte.d.ts → scatter/BinnedScatterPlot.svelte.d.ts} +6 -6
- package/dist/plot/{ElementScatter.svelte → scatter/ElementScatter.svelte} +6 -6
- package/dist/plot/{ElementScatter.svelte.d.ts → scatter/ElementScatter.svelte.d.ts} +2 -2
- package/dist/plot/{ScatterPlot.svelte → scatter/ScatterPlot.svelte} +297 -1008
- package/dist/plot/{ScatterPlot.svelte.d.ts → scatter/ScatterPlot.svelte.d.ts} +10 -18
- package/dist/plot/{ScatterPlotControls.svelte → scatter/ScatterPlotControls.svelte} +6 -5
- package/dist/plot/{ScatterPlotControls.svelte.d.ts → scatter/ScatterPlotControls.svelte.d.ts} +2 -2
- package/dist/plot/{ScatterPoint.svelte → scatter/ScatterPoint.svelte} +7 -7
- package/dist/plot/{ScatterPoint.svelte.d.ts → scatter/ScatterPoint.svelte.d.ts} +3 -3
- package/dist/plot/{adaptive-density.d.ts → scatter/adaptive-density.d.ts} +14 -4
- package/dist/plot/{adaptive-density.js → scatter/adaptive-density.js} +46 -20
- package/dist/plot/{binned-scatter-types.d.ts → scatter/binned-scatter-types.d.ts} +5 -12
- package/dist/plot/scatter/index.d.ts +7 -0
- package/dist/plot/scatter/index.js +5 -0
- package/dist/plot/scatter/scatter-data.d.ts +19 -0
- package/dist/plot/scatter/scatter-data.js +212 -0
- package/dist/plot/{ScatterPlot3D.svelte → scatter-3d/ScatterPlot3D.svelte} +25 -34
- package/dist/plot/{ScatterPlot3D.svelte.d.ts → scatter-3d/ScatterPlot3D.svelte.d.ts} +9 -17
- package/dist/plot/{ScatterPlot3DControls.svelte → scatter-3d/ScatterPlot3DControls.svelte} +14 -14
- package/dist/plot/{ScatterPlot3DControls.svelte.d.ts → scatter-3d/ScatterPlot3DControls.svelte.d.ts} +6 -6
- package/dist/plot/{ScatterPlot3DScene.svelte → scatter-3d/ScatterPlot3DScene.svelte} +129 -128
- package/dist/plot/{ScatterPlot3DScene.svelte.d.ts → scatter-3d/ScatterPlot3DScene.svelte.d.ts} +6 -15
- package/dist/plot/{Surface3D.svelte → scatter-3d/Surface3D.svelte} +7 -6
- package/dist/plot/{Surface3D.svelte.d.ts → scatter-3d/Surface3D.svelte.d.ts} +5 -4
- package/dist/plot/scatter-3d/index.d.ts +4 -0
- package/dist/plot/scatter-3d/index.js +4 -0
- package/dist/plot/sunburst/Sunburst.svelte +1041 -0
- package/dist/plot/sunburst/Sunburst.svelte.d.ts +97 -0
- package/dist/plot/sunburst/SunburstControls.svelte +200 -0
- package/dist/plot/sunburst/SunburstControls.svelte.d.ts +26 -0
- package/dist/plot/sunburst/index.d.ts +4 -0
- package/dist/plot/sunburst/index.js +4 -0
- package/dist/plot/sunburst/render.d.ts +34 -0
- package/dist/plot/sunburst/render.js +122 -0
- package/dist/plot/sunburst/sunburst.d.ts +62 -0
- package/dist/plot/sunburst/sunburst.js +269 -0
- package/dist/rdf/RdfPlot.svelte +2 -1
- package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
- package/dist/rdf/calc-rdf.js +11 -24
- package/dist/sanitize.js +14 -3
- package/dist/scene/SceneCamera.svelte +62 -0
- package/dist/scene/SceneCamera.svelte.d.ts +19 -0
- package/dist/scene/bind-renderer.svelte.d.ts +2 -0
- package/dist/scene/bind-renderer.svelte.js +14 -0
- package/dist/scene/index.d.ts +4 -0
- package/dist/scene/index.js +5 -0
- package/dist/scene/props.js +52 -0
- package/dist/scene/types.d.ts +26 -0
- package/dist/scene/types.js +1 -0
- package/dist/settings.d.ts +79 -3
- package/dist/settings.js +321 -1
- package/dist/spectral/Bands.svelte +47 -36
- package/dist/spectral/Bands.svelte.d.ts +6 -6
- package/dist/spectral/BandsAndDos.svelte +23 -25
- package/dist/spectral/BrillouinBandsDos.svelte +42 -30
- package/dist/spectral/Dos.svelte +15 -23
- package/dist/spectral/Dos.svelte.d.ts +4 -3
- package/dist/spectral/helpers.d.ts +8 -6
- package/dist/spectral/helpers.js +137 -65
- package/dist/state.svelte.d.ts +0 -7
- package/dist/state.svelte.js +0 -6
- package/dist/structure/Arrow.svelte +2 -4
- package/dist/structure/AtomLegend.svelte +8 -9
- package/dist/structure/AtomLegend.svelte.d.ts +1 -1
- package/dist/structure/CanvasTooltip.svelte +1 -0
- package/dist/structure/CellSelect.svelte +12 -5
- package/dist/structure/CellSelect.svelte.d.ts +2 -1
- package/dist/structure/Cylinder.svelte +12 -8
- package/dist/structure/Cylinder.svelte.d.ts +4 -1
- package/dist/structure/Lattice.svelte +2 -2
- package/dist/structure/Structure.svelte +365 -423
- package/dist/structure/Structure.svelte.d.ts +5 -15
- package/dist/structure/StructureControls.svelte +217 -2
- package/dist/structure/StructureControls.svelte.d.ts +5 -3
- package/dist/structure/StructureExportPane.svelte +54 -156
- package/dist/structure/StructureExportPane.svelte.d.ts +4 -5
- package/dist/structure/StructureInfoPane.svelte +10 -9
- package/dist/structure/StructureInfoPane.svelte.d.ts +5 -5
- package/dist/structure/StructureScene.svelte +376 -208
- package/dist/structure/StructureScene.svelte.d.ts +22 -20
- package/dist/structure/{label-placement.d.ts → atom-label-placement.d.ts} +3 -3
- package/dist/structure/{label-placement.js → atom-label-placement.js} +15 -5
- package/dist/structure/atom-properties.d.ts +1 -1
- package/dist/structure/atom-properties.js +17 -22
- package/dist/structure/bond-order-perception.js +3 -5
- package/dist/structure/bonding.d.ts +4 -0
- package/dist/structure/bonding.js +134 -63
- package/dist/structure/export.d.ts +24 -4
- package/dist/structure/export.js +89 -143
- package/dist/structure/index.d.ts +4 -4
- package/dist/structure/index.js +3 -3
- package/dist/structure/measure.d.ts +3 -2
- package/dist/structure/measure.js +6 -5
- package/dist/structure/parse.d.ts +3 -2
- package/dist/structure/parse.js +419 -438
- package/dist/structure/partial-occupancy.d.ts +0 -1
- package/dist/structure/partial-occupancy.js +1 -1
- package/dist/structure/pbc.d.ts +1 -1
- package/dist/structure/pbc.js +190 -13
- package/dist/structure/polyhedra.d.ts +41 -0
- package/dist/structure/polyhedra.js +602 -0
- package/dist/structure/site.d.ts +4 -0
- package/dist/structure/site.js +1 -0
- package/dist/structure/supercell.js +3 -2
- package/dist/structure/validation.js +5 -6
- package/dist/symmetry/SymmetryElementControls.svelte +69 -0
- package/dist/symmetry/SymmetryElementControls.svelte.d.ts +9 -0
- package/dist/symmetry/SymmetryElements.svelte +354 -0
- package/dist/symmetry/SymmetryElements.svelte.d.ts +24 -0
- package/dist/symmetry/SymmetryStats.svelte +113 -8
- package/dist/symmetry/WyckoffTable.svelte +68 -7
- package/dist/symmetry/WyckoffTable.svelte.d.ts +3 -0
- package/dist/symmetry/cell-transform.js +7 -14
- package/dist/symmetry/index.d.ts +14 -4
- package/dist/symmetry/index.js +291 -72
- package/dist/symmetry/spacegroups.d.ts +12 -1
- package/dist/symmetry/spacegroups.js +63 -14
- package/dist/symmetry/symmetry-elements.d.ts +33 -0
- package/dist/symmetry/symmetry-elements.js +521 -0
- package/dist/symmetry/wyckoff-db.d.ts +9 -0
- package/dist/symmetry/wyckoff-db.js +87 -0
- package/dist/table/HeatmapTable.svelte +66 -25
- package/dist/table/HeatmapTable.svelte.d.ts +1 -1
- package/dist/table/index.d.ts +1 -3
- package/dist/table/index.js +1 -1
- package/dist/theme/index.js +8 -8
- package/dist/tooltip/KCoords.svelte +45 -0
- package/dist/tooltip/KCoords.svelte.d.ts +8 -0
- package/dist/tooltip/index.d.ts +1 -0
- package/dist/tooltip/index.js +1 -0
- package/dist/trajectory/Trajectory.svelte +123 -100
- package/dist/trajectory/Trajectory.svelte.d.ts +11 -22
- package/dist/trajectory/TrajectoryExportPane.svelte +17 -25
- package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +4 -5
- package/dist/trajectory/TrajectoryInfoPane.svelte +5 -3
- package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +3 -2
- package/dist/trajectory/constants.js +6 -2
- package/dist/trajectory/extract.js +17 -37
- package/dist/trajectory/format-detect.d.ts +1 -1
- package/dist/trajectory/format-detect.js +27 -19
- package/dist/trajectory/frame-reader.d.ts +0 -1
- package/dist/trajectory/frame-reader.js +63 -162
- package/dist/trajectory/helpers.d.ts +10 -2
- package/dist/trajectory/helpers.js +56 -36
- package/dist/trajectory/index.js +1 -1
- package/dist/trajectory/parse/ase.d.ts +9 -1
- package/dist/trajectory/parse/ase.js +47 -32
- package/dist/trajectory/parse/diagnostics.d.ts +3 -0
- package/dist/trajectory/parse/diagnostics.js +14 -0
- package/dist/trajectory/parse/hdf5.js +1 -1
- package/dist/trajectory/parse/index.d.ts +1 -1
- package/dist/trajectory/parse/index.js +65 -105
- package/dist/trajectory/parse/lammps.d.ts +0 -2
- package/dist/trajectory/parse/lammps.js +8 -6
- package/dist/trajectory/parse/pymatgen.d.ts +2 -0
- package/dist/trajectory/parse/pymatgen.js +74 -0
- package/dist/trajectory/parse/vasp.js +38 -18
- package/dist/trajectory/parse/xyz.d.ts +13 -1
- package/dist/trajectory/parse/xyz.js +102 -94
- package/dist/trajectory/plotting.d.ts +1 -2
- package/dist/trajectory/plotting.js +16 -113
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +7 -5
- package/dist/xrd/XrdPlot.svelte +16 -30
- package/dist/xrd/broadening.d.ts +2 -1
- package/dist/xrd/calc-xrd.js +18 -20
- package/dist/xrd/index.d.ts +2 -2
- package/dist/xrd/parse.js +2 -2
- package/package.json +43 -26
- package/dist/element/data.json +0 -11864
- package/dist/fermi-surface/marching-cubes.d.ts +0 -2
- package/dist/fermi-surface/marching-cubes.js +0 -2
- package/dist/plot/PlotControls.svelte.d.ts +0 -4
- package/dist/plot/axis-utils.d.ts +0 -19
- package/dist/plot/axis-utils.js +0 -78
- package/dist/plot/defaults.d.ts +0 -19
- package/dist/plot/defaults.js +0 -9
- package/dist/plot/fill-utils.d.ts +0 -46
- package/dist/plot/fill-utils.js +0 -322
- package/dist/plot/hover-lock.svelte.d.ts +0 -14
- package/dist/plot/hover-lock.svelte.js +0 -46
- package/dist/plot/interactions.d.ts +0 -12
- package/dist/plot/interactions.js +0 -101
- package/dist/plot/scales.d.ts +0 -48
- package/dist/plot/svg.d.ts +0 -1
- package/dist/plot/svg.js +0 -11
- package/dist/plot/utils/series-visibility.d.ts +0 -15
- package/dist/plot/utils.d.ts +0 -1
- package/dist/plot/utils.js +0 -14
- /package/dist/plot/{PortalSelect.svelte.d.ts → core/components/PortalSelect.svelte.d.ts} +0 -0
- /package/dist/plot/{binned-scatter-types.js → scatter/binned-scatter-types.js} +0 -0
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
import * as math from '../math';
|
|
2
|
+
// All element kinds in display order (axes first, then planes, then point elements).
|
|
3
|
+
// Single source of truth for ordering — both the controls legend and the element list
|
|
4
|
+
// returned by symmetry_elements_from_ops follow this sequence.
|
|
5
|
+
export const SYM_ELEM_KINDS = [
|
|
6
|
+
`rotation`,
|
|
7
|
+
`screw`,
|
|
8
|
+
`rotoinversion`,
|
|
9
|
+
`mirror`,
|
|
10
|
+
`glide`,
|
|
11
|
+
`inversion`,
|
|
12
|
+
];
|
|
13
|
+
// Default overlay visibility: a SINGLE kind (proper rotation axes). High-symmetry
|
|
14
|
+
// structures easily have 100+ distinct elements which, drawn all at once, bury the
|
|
15
|
+
// structure entirely. Users opt into additional kinds individually via
|
|
16
|
+
// SymmetryElementControls (or the show_kinds prop).
|
|
17
|
+
export const DEFAULT_SHOW_SYM_KINDS = { rotation: true };
|
|
18
|
+
// Human-readable labels + representative legend colors per kind. mirror/glide/
|
|
19
|
+
// rotoinversion/inversion match the SymmetryElements.svelte render colors exactly;
|
|
20
|
+
// rotation/screw axes are colored by rotation order in-scene, so their swatch uses the
|
|
21
|
+
// 2-fold color as representative.
|
|
22
|
+
export const SYM_ELEM_KIND_INFO = {
|
|
23
|
+
rotation: { label: `rotation axes`, color: `#e63946` },
|
|
24
|
+
screw: { label: `screw axes`, color: `#e76f51` },
|
|
25
|
+
mirror: { label: `mirror planes`, color: `#ffb703` },
|
|
26
|
+
glide: { label: `glide planes`, color: `#8ecae6` },
|
|
27
|
+
rotoinversion: { label: `rotoinversion axes`, color: `#9c27b0` },
|
|
28
|
+
inversion: { label: `inversion centers`, color: `#555555` },
|
|
29
|
+
};
|
|
30
|
+
// Tally elements per kind (for legend labels like "mirror planes (9)")
|
|
31
|
+
export function count_symmetry_elements(elements) {
|
|
32
|
+
const counts = {};
|
|
33
|
+
for (const elem of elements)
|
|
34
|
+
counts[elem.kind] = (counts[elem.kind] ?? 0) + 1;
|
|
35
|
+
return counts;
|
|
36
|
+
}
|
|
37
|
+
// Whether the overlay would actually draw something: at least one PRESENT element whose
|
|
38
|
+
// kind is ENABLED in show_kinds. Used to gate declutter so callers don't hide polyhedra /
|
|
39
|
+
// shrink atoms when the enabled kinds match no present element (e.g. the rotation-only
|
|
40
|
+
// default on an inversion-only P-1 cell).
|
|
41
|
+
export const has_visible_symmetry_overlay = (elements, show_kinds = DEFAULT_SHOW_SYM_KINDS) => elements.some((elem) => show_kinds[elem.kind] ?? false);
|
|
42
|
+
const ELEM_TOL = 1e-6;
|
|
43
|
+
// The 12 edges of the unit cube [0,1]³ (corner pairs differing in exactly one coord)
|
|
44
|
+
const UNIT_CUBE_EDGES = (() => {
|
|
45
|
+
const corners = [];
|
|
46
|
+
for (let x = 0; x <= 1; x++) {
|
|
47
|
+
for (let y = 0; y <= 1; y++)
|
|
48
|
+
for (let z = 0; z <= 1; z++)
|
|
49
|
+
corners.push([x, y, z]);
|
|
50
|
+
}
|
|
51
|
+
const edges = [];
|
|
52
|
+
for (let idx_a = 0; idx_a < corners.length; idx_a++) {
|
|
53
|
+
for (let idx_b = idx_a + 1; idx_b < corners.length; idx_b++) {
|
|
54
|
+
const manhattan = corners[idx_a].reduce((sum, val, dim) => sum + Math.abs(val - corners[idx_b][dim]), 0);
|
|
55
|
+
if (manhattan === 1)
|
|
56
|
+
edges.push([corners[idx_a], corners[idx_b]]);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return edges;
|
|
60
|
+
})();
|
|
61
|
+
// moyo-wasm serializes nalgebra matrices as flat 9-arrays in COLUMN-major order
|
|
62
|
+
export const mat3_from_flat_col_major = (flat) => [
|
|
63
|
+
[flat[0], flat[3], flat[6]],
|
|
64
|
+
[flat[1], flat[4], flat[7]],
|
|
65
|
+
[flat[2], flat[5], flat[8]],
|
|
66
|
+
];
|
|
67
|
+
const mat_round = (mat) => mat.map((row) => row.map((val) => Math.round(val)));
|
|
68
|
+
const mat_add = (mat_a, mat_b) => mat_a.map((row, idx) => row.map((val, jdx) => val + mat_b[idx][jdx]));
|
|
69
|
+
const mat_scale = (mat, factor) => mat.map((row) => row.map((val) => val * factor));
|
|
70
|
+
const mat_negate = (mat) => mat_scale(mat, -1);
|
|
71
|
+
const IDENTITY = [
|
|
72
|
+
[1, 0, 0],
|
|
73
|
+
[0, 1, 0],
|
|
74
|
+
[0, 0, 1],
|
|
75
|
+
];
|
|
76
|
+
const is_identity = (mat) => mat.every((row, idx) => row.every((val, jdx) => val === (idx === jdx ? 1 : 0)));
|
|
77
|
+
const trace = (mat) => mat[0][0] + mat[1][1] + mat[2][2];
|
|
78
|
+
// Projection onto the invariant (+1 eigenvalue) subspace P = (1/n) Σₖ Wᵏ, plus the
|
|
79
|
+
// matrix order n (crystallographic: 1, 2, 3, 4 or 6)
|
|
80
|
+
function invariant_projector(mat) {
|
|
81
|
+
let sum = IDENTITY;
|
|
82
|
+
let power = mat;
|
|
83
|
+
for (let order = 1; order <= 6; order++) {
|
|
84
|
+
if (is_identity(power))
|
|
85
|
+
return { proj: mat_scale(sum, 1 / order), order };
|
|
86
|
+
sum = mat_add(sum, power);
|
|
87
|
+
power = mat_round(math.dot(power, mat));
|
|
88
|
+
}
|
|
89
|
+
throw new Error(`Matrix is not of finite crystallographic order`);
|
|
90
|
+
}
|
|
91
|
+
const gcd = (val_a, val_b) => val_b === 0 ? val_a : gcd(val_b, val_a % val_b);
|
|
92
|
+
// Extract the (1D) invariant axis of a proper rotation as a reduced integer vector with
|
|
93
|
+
// canonical sign (first nonzero component positive). proj must have rank 1.
|
|
94
|
+
function axis_from_projector(proj, order) {
|
|
95
|
+
// n·P is an integer matrix whose nonzero columns all span the axis
|
|
96
|
+
const int_proj = mat_round(mat_scale(proj, order));
|
|
97
|
+
let best = null;
|
|
98
|
+
let best_norm = 0;
|
|
99
|
+
for (let col = 0; col < 3; col++) {
|
|
100
|
+
const vec = [int_proj[0][col], int_proj[1][col], int_proj[2][col]];
|
|
101
|
+
const norm = Math.abs(vec[0]) + Math.abs(vec[1]) + Math.abs(vec[2]);
|
|
102
|
+
if (norm > best_norm) {
|
|
103
|
+
best = vec;
|
|
104
|
+
best_norm = norm;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (!best)
|
|
108
|
+
return null;
|
|
109
|
+
const divisor = best.reduce((acc, val) => gcd(acc, Math.abs(val)), 0);
|
|
110
|
+
let axis = best.map((val) => val / divisor);
|
|
111
|
+
const first_nonzero = axis.find((val) => val !== 0) ?? 1;
|
|
112
|
+
// normalize -0 to 0 when flipping to canonical sign (first nonzero positive)
|
|
113
|
+
if (first_nonzero < 0)
|
|
114
|
+
axis = axis.map((val) => (val === 0 ? 0 : -val));
|
|
115
|
+
return axis;
|
|
116
|
+
}
|
|
117
|
+
// Fixed point of the affine map x ↦ W·x + w_loc as the orbit average of the origin.
|
|
118
|
+
// Exact whenever w_loc has no component in the invariant subspace (P·w_loc = 0).
|
|
119
|
+
function fixed_point(mat, w_loc, order) {
|
|
120
|
+
let current = [0, 0, 0];
|
|
121
|
+
const sum = [0, 0, 0];
|
|
122
|
+
for (let iter = 0; iter < order; iter++) {
|
|
123
|
+
if (iter > 0)
|
|
124
|
+
current = math.add(math.mat3x3_vec3_multiply(mat, current), w_loc);
|
|
125
|
+
sum[0] += current[0];
|
|
126
|
+
sum[1] += current[1];
|
|
127
|
+
sum[2] += current[2];
|
|
128
|
+
}
|
|
129
|
+
return sum.map((val) => val / order);
|
|
130
|
+
}
|
|
131
|
+
// NOTE on epsilon: 1e-8 is the loosest of three intentionally different wrap
|
|
132
|
+
// helpers (vs wrap_frac_coord @1e-10 [[src/lib/structure/pbc.ts:26]] for parsed
|
|
133
|
+
// coords and wrap_frac @1e-9 [[src/lib/symmetry/index.ts:80]] for standardized
|
|
134
|
+
// Wyckoff positions). Inputs here are fixed points / intercepts obtained by
|
|
135
|
+
// solving linear systems and averaging over operation order, so float error is
|
|
136
|
+
// largest; the result feeds toFixed()-based dedup keys for symmetry elements,
|
|
137
|
+
// which need both near-0 and near-1 snapped onto exactly 0 to stay stable near
|
|
138
|
+
// cell boundaries. Do not unify: tightening this epsilon breaks element dedup.
|
|
139
|
+
const wrap_point = (pos) => pos.map((coord) => {
|
|
140
|
+
const wrapped = coord - Math.floor(coord); // always in [0, 1)
|
|
141
|
+
// snap near-0 and near-1 (which wraps to near-0) onto exactly 0
|
|
142
|
+
return wrapped < 1e-8 || wrapped > 1 - 1e-8 ? 0 : wrapped;
|
|
143
|
+
});
|
|
144
|
+
// Enumerate lattice translations invariant under W (lying along the axis / in the
|
|
145
|
+
// plane), including centering vectors of non-primitive cells (I/F/A/B/C/R): without
|
|
146
|
+
// them, e.g. the body-centering (1/2,1/2,1/2) period along ⟨111⟩ axes is missed and
|
|
147
|
+
// centering-composed mirrors get mislabeled as glides. Candidates r + c with
|
|
148
|
+
// r ∈ {-1,0,1}³ cover all cases for moyo translations, which lie in [0,1)³.
|
|
149
|
+
function invariant_translations(mat, centerings) {
|
|
150
|
+
const result = [];
|
|
151
|
+
for (let dx = -1; dx <= 1; dx++) {
|
|
152
|
+
for (let dy = -1; dy <= 1; dy++) {
|
|
153
|
+
for (let dz = -1; dz <= 1; dz++) {
|
|
154
|
+
for (const centering of [[0, 0, 0], ...centerings]) {
|
|
155
|
+
const cand = [dx + centering[0], dy + centering[1], dz + centering[2]];
|
|
156
|
+
if (cand.every((val) => Math.abs(val) < ELEM_TOL))
|
|
157
|
+
continue;
|
|
158
|
+
const mapped = math.mat3x3_vec3_multiply(mat, cand);
|
|
159
|
+
if (mapped.some((val, idx) => Math.abs(val - cand[idx]) > ELEM_TOL))
|
|
160
|
+
continue;
|
|
161
|
+
result.push(cand);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
// Reduce an intrinsic (in-plane glide) translation modulo invariant lattice translations
|
|
169
|
+
function reduce_intrinsic_translation(w_intrinsic, candidates) {
|
|
170
|
+
let best = w_intrinsic;
|
|
171
|
+
let best_sq = math.dot(w_intrinsic, w_intrinsic);
|
|
172
|
+
for (const cand of candidates) {
|
|
173
|
+
const reduced = math.subtract(w_intrinsic, cand);
|
|
174
|
+
const sq = math.dot(reduced, reduced);
|
|
175
|
+
if (sq < best_sq - ELEM_TOL) {
|
|
176
|
+
best = reduced;
|
|
177
|
+
best_sq = sq;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return best;
|
|
181
|
+
}
|
|
182
|
+
const is_zero_vec = (vec) => vec.every((val) => Math.abs(val) < ELEM_TOL);
|
|
183
|
+
// Glide letter from the reduced glide vector: a/b/c (half along one cell axis),
|
|
184
|
+
// n (half along a face/body diagonal), d (quarter diagonal), g otherwise
|
|
185
|
+
function glide_letter(glide_vec) {
|
|
186
|
+
const doubled = glide_vec.map((val) => val * 2);
|
|
187
|
+
const is_int = (vals) => vals.every((val) => Math.abs(val - Math.round(val)) < 1e-4);
|
|
188
|
+
if (is_int(doubled)) {
|
|
189
|
+
const nonzero = doubled.map((val) => Math.round(val)).filter((val) => val !== 0);
|
|
190
|
+
if (nonzero.length === 1)
|
|
191
|
+
return [`a`, `b`, `c`][doubled.findIndex((val) => Math.round(val) !== 0)];
|
|
192
|
+
return `n`;
|
|
193
|
+
}
|
|
194
|
+
if (is_int(glide_vec.map((val) => val * 4)))
|
|
195
|
+
return `d`;
|
|
196
|
+
return `g`;
|
|
197
|
+
}
|
|
198
|
+
// Translation-independent analysis of a rotation matrix. Returns null for the identity
|
|
199
|
+
// (pure translations define no geometric element).
|
|
200
|
+
function build_rotation_info(rotation, centerings) {
|
|
201
|
+
const mat = mat_round(mat3_from_flat_col_major(rotation));
|
|
202
|
+
const det = Math.round(math.det_3x3(mat));
|
|
203
|
+
const tr = Math.round(trace(mat));
|
|
204
|
+
if (det === 1 && tr === 3)
|
|
205
|
+
return null; // identity or pure translation
|
|
206
|
+
const { proj, order: mat_order } = invariant_projector(mat);
|
|
207
|
+
if (det === -1 && tr === -3) {
|
|
208
|
+
return {
|
|
209
|
+
mat,
|
|
210
|
+
proj,
|
|
211
|
+
mat_order,
|
|
212
|
+
kind: `inversion`,
|
|
213
|
+
order: 1,
|
|
214
|
+
axis: null,
|
|
215
|
+
axis_sq: 0,
|
|
216
|
+
period: 1,
|
|
217
|
+
invariant_candidates: [],
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
if (det === 1) {
|
|
221
|
+
// proper rotation (order from trace: −1→2, 0→3, 1→4, 2→6)
|
|
222
|
+
const proper_order_by_trace = { [-1]: 2, 0: 3, 1: 4, 2: 6 };
|
|
223
|
+
const order = proper_order_by_trace[tr];
|
|
224
|
+
if (!order)
|
|
225
|
+
throw new Error(`Invalid proper rotation trace ${tr}`);
|
|
226
|
+
const axis = axis_from_projector(proj, mat_order);
|
|
227
|
+
if (!axis)
|
|
228
|
+
throw new Error(`Failed to extract rotation axis`);
|
|
229
|
+
// shortest lattice period along the axis (1 for primitive lattices; can be 1/2 via
|
|
230
|
+
// centering vectors, e.g. (1/2,1/2,1/2) along ⟨111⟩ in body-centered cells)
|
|
231
|
+
const axis_sq = math.dot(axis, axis);
|
|
232
|
+
let period = 1;
|
|
233
|
+
for (const cand of invariant_translations(mat, centerings)) {
|
|
234
|
+
const lambda_cand = math.dot(cand, axis) / axis_sq;
|
|
235
|
+
// candidate must be parallel to the axis and shorter than the current period
|
|
236
|
+
const is_parallel = cand.every((val, idx) => Math.abs(val - lambda_cand * axis[idx]) < ELEM_TOL);
|
|
237
|
+
if (is_parallel && lambda_cand > ELEM_TOL && lambda_cand < period) {
|
|
238
|
+
period = lambda_cand;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return {
|
|
242
|
+
mat,
|
|
243
|
+
proj,
|
|
244
|
+
mat_order,
|
|
245
|
+
kind: `proper`,
|
|
246
|
+
order,
|
|
247
|
+
axis,
|
|
248
|
+
axis_sq,
|
|
249
|
+
period,
|
|
250
|
+
invariant_candidates: [],
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
// Improper: mirror/glide (trace 1) or rotoinversion −3/−4/−6. The proper part −W is a
|
|
254
|
+
// rotation about the same axis (the plane normal for mirrors).
|
|
255
|
+
const proper_part = mat_negate(mat);
|
|
256
|
+
const { proj: proper_proj, order: proper_order } = invariant_projector(proper_part);
|
|
257
|
+
const axis = axis_from_projector(proper_proj, proper_order);
|
|
258
|
+
if (!axis)
|
|
259
|
+
throw new Error(`Failed to extract improper-operation axis`);
|
|
260
|
+
if (tr === 1) {
|
|
261
|
+
return {
|
|
262
|
+
mat,
|
|
263
|
+
proj,
|
|
264
|
+
mat_order,
|
|
265
|
+
kind: `mirror`,
|
|
266
|
+
order: 2,
|
|
267
|
+
axis,
|
|
268
|
+
axis_sq: math.dot(axis, axis),
|
|
269
|
+
period: 1,
|
|
270
|
+
invariant_candidates: invariant_translations(mat, centerings),
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
const rotoinv_order_by_trace = { 0: 3, [-1]: 4, [-2]: 6 };
|
|
274
|
+
const order = rotoinv_order_by_trace[tr];
|
|
275
|
+
if (!order)
|
|
276
|
+
throw new Error(`Invalid improper rotation trace ${tr}`);
|
|
277
|
+
return {
|
|
278
|
+
mat,
|
|
279
|
+
proj,
|
|
280
|
+
mat_order,
|
|
281
|
+
kind: `rotoinversion`,
|
|
282
|
+
order,
|
|
283
|
+
axis,
|
|
284
|
+
axis_sq: math.dot(axis, axis),
|
|
285
|
+
period: 1,
|
|
286
|
+
invariant_candidates: [],
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
// Classify the operation (info.mat, w) given precomputed rotation-dependent data
|
|
290
|
+
function classify_with_rotation_info(info, w) {
|
|
291
|
+
const { mat, proj, mat_order, kind, order, axis } = info;
|
|
292
|
+
const w_intrinsic = math.mat3x3_vec3_multiply(proj, w);
|
|
293
|
+
const w_loc = math.subtract(w, w_intrinsic);
|
|
294
|
+
const point = wrap_point(fixed_point(mat, w_loc, mat_order));
|
|
295
|
+
if (kind === `inversion`) {
|
|
296
|
+
return { kind, order: 1, label: `-1`, axis: null, point, translation: null };
|
|
297
|
+
}
|
|
298
|
+
if (kind === `proper`) {
|
|
299
|
+
// Screw component: w_i = λ·axis, reduced modulo the lattice period along the axis
|
|
300
|
+
const { axis_sq, period } = info;
|
|
301
|
+
const lambda_raw = math.dot(w_intrinsic, axis) / axis_sq;
|
|
302
|
+
let lambda = lambda_raw - period * Math.floor(lambda_raw / period + ELEM_TOL);
|
|
303
|
+
if (Math.abs(lambda) < ELEM_TOL)
|
|
304
|
+
lambda = 0;
|
|
305
|
+
const is_screw = lambda > ELEM_TOL;
|
|
306
|
+
const screw_part = Math.round((order * lambda) / period) % order;
|
|
307
|
+
return {
|
|
308
|
+
kind: is_screw ? `screw` : `rotation`,
|
|
309
|
+
order,
|
|
310
|
+
label: is_screw ? `${order}_${screw_part}` : `${order}`,
|
|
311
|
+
axis,
|
|
312
|
+
point,
|
|
313
|
+
translation: is_screw ? axis.map((val) => val * lambda) : null,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
if (kind === `mirror`) {
|
|
317
|
+
const glide_vec = reduce_intrinsic_translation(w_intrinsic, info.invariant_candidates);
|
|
318
|
+
const is_glide = !is_zero_vec(glide_vec);
|
|
319
|
+
return {
|
|
320
|
+
kind: is_glide ? `glide` : `mirror`,
|
|
321
|
+
order: 2,
|
|
322
|
+
label: is_glide ? glide_letter(glide_vec) : `m`,
|
|
323
|
+
axis,
|
|
324
|
+
point,
|
|
325
|
+
translation: is_glide ? glide_vec : null,
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
// Rotoinversion −3/−4/−6 (no intrinsic translation: P = 0, so w_i = 0)
|
|
329
|
+
return { kind, order, label: `-${order}`, axis, point, translation: null };
|
|
330
|
+
}
|
|
331
|
+
// Classify a single operation (rotation as flat column-major 9-array, translation
|
|
332
|
+
// vector, both fractional). Returns null for the identity and pure (centering)
|
|
333
|
+
// translations, which define no geometric element. For non-primitive (centered) cells,
|
|
334
|
+
// pass the centering vectors so intrinsic screw/glide translations are reduced modulo
|
|
335
|
+
// the TRUE lattice — e.g. along a ⟨111⟩ axis of a body-centered cell the lattice period
|
|
336
|
+
// is (1/2)(1,1,1), and a C-centering-composed mirror is still a mirror, not an n-glide.
|
|
337
|
+
export function classify_symmetry_op(rotation, translation, centerings = []) {
|
|
338
|
+
const info = build_rotation_info(rotation, centerings);
|
|
339
|
+
return info ? classify_with_rotation_info(info, translation) : null;
|
|
340
|
+
}
|
|
341
|
+
// Canonical dedup key for the geometric locus of an element. Elements are identified
|
|
342
|
+
// modulo lattice translations:
|
|
343
|
+
// - inversion centers: the wrapped center
|
|
344
|
+
// - planes: (normal, offset s = x₀·normal mod 1) — lattice translations change s by an
|
|
345
|
+
// integer since the normal is an integer vector
|
|
346
|
+
// - axis lines: (direction, line intercept x₀ − λ·u wrapped mod 1) — wrapping merges
|
|
347
|
+
// lattice-equivalent parallel lines
|
|
348
|
+
function element_locus_key(elem) {
|
|
349
|
+
const fmt = (val) => (Math.abs(val) < 1e-4 ? 0 : val).toFixed(4);
|
|
350
|
+
if (elem.axis === null)
|
|
351
|
+
return `center|${elem.point.map(fmt).join(`,`)}`;
|
|
352
|
+
const axis_key = elem.axis.join(`,`);
|
|
353
|
+
if (elem.kind === `mirror` || elem.kind === `glide`) {
|
|
354
|
+
const offset = math.dot(elem.point, elem.axis);
|
|
355
|
+
const wrapped = offset - Math.floor(offset + 1e-6);
|
|
356
|
+
return `plane|${axis_key}|${fmt(wrapped >= 1 - 1e-4 ? 0 : wrapped)}`;
|
|
357
|
+
}
|
|
358
|
+
const lambda = math.dot(elem.point, elem.axis) / math.dot(elem.axis, elem.axis);
|
|
359
|
+
const intercept = wrap_point(math.subtract(elem.point, elem.axis.map((val) => val * lambda)));
|
|
360
|
+
return `line|${axis_key}|${intercept.map(fmt).join(`,`)}`;
|
|
361
|
+
}
|
|
362
|
+
// Derive all distinct symmetry elements (modulo lattice translations) from a list of
|
|
363
|
+
// space-group operations. Each operation is classified, then re-anchored with the 8
|
|
364
|
+
// lattice offsets t ∈ {0,1}³ to enumerate the distinct in-cell instances of its element
|
|
365
|
+
// family (e.g. the inversion centers of P-1 sit at all 8 half-lattice points; 2-fold
|
|
366
|
+
// axes recur at quarter positions). Elements sharing the same geometric locus but
|
|
367
|
+
// different symbols (e.g. a 2-fold axis inside a 4-fold axis) are kept as separate
|
|
368
|
+
// entries — filter by `order`/`label` downstream if desired.
|
|
369
|
+
export function symmetry_elements_from_ops(operations) {
|
|
370
|
+
// Centering vectors are the pure-translation operations (identity rotation, w ∉ ℤ³).
|
|
371
|
+
// They define the true lattice for screw/glide reduction in centered cells.
|
|
372
|
+
// Deduplicated since supercell inputs repeat sublattice translations.
|
|
373
|
+
const centering_keys = new Set();
|
|
374
|
+
const centerings = [];
|
|
375
|
+
for (const { rotation, translation } of operations) {
|
|
376
|
+
if (!is_identity(mat_round(mat3_from_flat_col_major(rotation))))
|
|
377
|
+
continue;
|
|
378
|
+
const wrapped = wrap_point(translation);
|
|
379
|
+
if (is_zero_vec(wrapped))
|
|
380
|
+
continue;
|
|
381
|
+
const key = wrapped.map((val) => val.toFixed(6)).join(`,`);
|
|
382
|
+
if (centering_keys.has(key))
|
|
383
|
+
continue;
|
|
384
|
+
centering_keys.add(key);
|
|
385
|
+
centerings.push(wrapped);
|
|
386
|
+
}
|
|
387
|
+
// Cache rotation-dependent analysis: supercell inputs can have thousands of ops but
|
|
388
|
+
// share at most 48 distinct rotation matrices
|
|
389
|
+
const info_cache = new Map();
|
|
390
|
+
const seen = new Map();
|
|
391
|
+
for (const { rotation, translation } of operations) {
|
|
392
|
+
const rot_key = rotation.join(`,`);
|
|
393
|
+
let info = info_cache.get(rot_key);
|
|
394
|
+
if (info === undefined) {
|
|
395
|
+
info = build_rotation_info(rotation, centerings);
|
|
396
|
+
info_cache.set(rot_key, info);
|
|
397
|
+
}
|
|
398
|
+
if (info === null)
|
|
399
|
+
continue; // identity / pure translation
|
|
400
|
+
for (let dx = 0; dx <= 1; dx++) {
|
|
401
|
+
for (let dy = 0; dy <= 1; dy++) {
|
|
402
|
+
for (let dz = 0; dz <= 1; dz++) {
|
|
403
|
+
const shifted = [translation[0] + dx, translation[1] + dy, translation[2] + dz];
|
|
404
|
+
const elem = classify_with_rotation_info(info, shifted);
|
|
405
|
+
const key = `${elem.kind}|${elem.label}|${element_locus_key(elem)}`;
|
|
406
|
+
if (!seen.has(key))
|
|
407
|
+
seen.set(key, elem);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
// Stable order: by kind (SYM_ELEM_KINDS sequence), then descending order, label, point
|
|
413
|
+
return [...seen.values()].sort((el1, el2) => SYM_ELEM_KINDS.indexOf(el1.kind) - SYM_ELEM_KINDS.indexOf(el2.kind) ||
|
|
414
|
+
el2.order - el1.order ||
|
|
415
|
+
el1.label.localeCompare(el2.label) ||
|
|
416
|
+
el1.point.join(`,`).localeCompare(el2.point.join(`,`)));
|
|
417
|
+
}
|
|
418
|
+
// Evenly-spaced dash layout along a segment of given length (Å): returns dash centers
|
|
419
|
+
// (distance from the segment start) and lengths. Dashes touch both segment ends so
|
|
420
|
+
// dashed axes still visually span the full cell; the gap stretches as needed. Used to
|
|
421
|
+
// render screw axes dashed (vs solid pure rotations) — translation-carrying elements
|
|
422
|
+
// are dashed, echoing the ITA plane-group convention.
|
|
423
|
+
export function dash_segments(length, dash, gap) {
|
|
424
|
+
if (!(length > 0) || !(dash > 0) || gap < 0)
|
|
425
|
+
return [];
|
|
426
|
+
if (length <= dash)
|
|
427
|
+
return [{ center: length / 2, length }];
|
|
428
|
+
const count = Math.floor((length + gap) / (dash + gap));
|
|
429
|
+
if (count <= 1)
|
|
430
|
+
return [{ center: length / 2, length: dash }];
|
|
431
|
+
// count·dash + (count−1)·gap_actual = length, with gap_actual ≥ gap by construction
|
|
432
|
+
const gap_actual = (length - count * dash) / (count - 1);
|
|
433
|
+
return Array.from({ length: count }, (_, idx) => ({
|
|
434
|
+
center: idx * (dash + gap_actual) + dash / 2,
|
|
435
|
+
length: dash,
|
|
436
|
+
}));
|
|
437
|
+
}
|
|
438
|
+
// Convert a fractional direction or point to Cartesian coordinates (lattice rows are
|
|
439
|
+
// basis vectors). Valid for axis directions AND plane normals (eigenvectors of the
|
|
440
|
+
// fractional operator map to eigenvectors of the orthogonal Cartesian operator).
|
|
441
|
+
export const frac_to_cart_direction = (frac, lattice) => math.create_frac_to_cart(lattice)(frac);
|
|
442
|
+
// Clip the line (point + t·direction, fractional) to the unit cell [0,1]³ using the
|
|
443
|
+
// slab method, returning the Cartesian segment endpoints (or null if the line misses
|
|
444
|
+
// the cell). Used to draw rotation/screw axes spanning the rendered cell.
|
|
445
|
+
export function clip_line_to_cell(point, direction, lattice, eps = 1e-9) {
|
|
446
|
+
let t_min = -Infinity;
|
|
447
|
+
let t_max = Infinity;
|
|
448
|
+
for (let dim = 0; dim < 3; dim++) {
|
|
449
|
+
if (Math.abs(direction[dim]) < eps) {
|
|
450
|
+
if (point[dim] < -eps || point[dim] > 1 + eps)
|
|
451
|
+
return null; // parallel, outside slab
|
|
452
|
+
continue;
|
|
453
|
+
}
|
|
454
|
+
const t_0 = (0 - point[dim]) / direction[dim];
|
|
455
|
+
const t_1 = (1 - point[dim]) / direction[dim];
|
|
456
|
+
t_min = Math.max(t_min, Math.min(t_0, t_1));
|
|
457
|
+
t_max = Math.min(t_max, Math.max(t_0, t_1));
|
|
458
|
+
}
|
|
459
|
+
if (t_min >= t_max - eps || !Number.isFinite(t_min) || !Number.isFinite(t_max)) {
|
|
460
|
+
return null;
|
|
461
|
+
}
|
|
462
|
+
const endpoint = (t_param) => frac_to_cart_direction(point.map((coord, idx) => coord + t_param * direction[idx]), lattice);
|
|
463
|
+
return [endpoint(t_min), endpoint(t_max)];
|
|
464
|
+
}
|
|
465
|
+
// Clip the plane through `point` with fractional-direct-space normal `normal_frac` to
|
|
466
|
+
// the unit cell, returning the Cartesian polygon vertices in winding order (empty if
|
|
467
|
+
// the plane misses the cell). The plane equation in fractional coordinates uses the
|
|
468
|
+
// pullback n_eq[i] = lattice[i]·N_cart of the Cartesian normal, which is exact for
|
|
469
|
+
// arbitrary (non-orthogonal) cells.
|
|
470
|
+
export function clip_plane_to_cell(point, normal_frac, lattice) {
|
|
471
|
+
const normal_cart = frac_to_cart_direction(normal_frac, lattice);
|
|
472
|
+
const n_eq = [
|
|
473
|
+
math.dot(lattice[0], normal_cart),
|
|
474
|
+
math.dot(lattice[1], normal_cart),
|
|
475
|
+
math.dot(lattice[2], normal_cart),
|
|
476
|
+
];
|
|
477
|
+
const signed_dist = (frac) => n_eq[0] * (frac[0] - point[0]) +
|
|
478
|
+
n_eq[1] * (frac[1] - point[1]) +
|
|
479
|
+
n_eq[2] * (frac[2] - point[2]);
|
|
480
|
+
const frac_points = [];
|
|
481
|
+
const tol = 1e-7;
|
|
482
|
+
// Intersect the plane with the 12 unit-cube edges (corners on the plane included)
|
|
483
|
+
for (const [edge_a, edge_b] of UNIT_CUBE_EDGES) {
|
|
484
|
+
const dist_a = signed_dist(edge_a);
|
|
485
|
+
const dist_b = signed_dist(edge_b);
|
|
486
|
+
if (Math.abs(dist_a) < tol)
|
|
487
|
+
frac_points.push(edge_a);
|
|
488
|
+
if (Math.abs(dist_b) < tol)
|
|
489
|
+
frac_points.push(edge_b);
|
|
490
|
+
if (dist_a * dist_b < -tol * tol) {
|
|
491
|
+
const frac_t = dist_a / (dist_a - dist_b);
|
|
492
|
+
frac_points.push(edge_a.map((val, dim) => val + frac_t * (edge_b[dim] - val)));
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
// Dedup and convert to Cartesian
|
|
496
|
+
const seen = new Set();
|
|
497
|
+
const cart_points = [];
|
|
498
|
+
for (const frac of frac_points) {
|
|
499
|
+
const key = frac.map((val) => val.toFixed(6)).join(`,`);
|
|
500
|
+
if (seen.has(key))
|
|
501
|
+
continue;
|
|
502
|
+
seen.add(key);
|
|
503
|
+
cart_points.push(frac_to_cart_direction(frac, lattice));
|
|
504
|
+
}
|
|
505
|
+
if (cart_points.length < 3)
|
|
506
|
+
return [];
|
|
507
|
+
// Order vertices by angle around the centroid within the plane
|
|
508
|
+
const centroid = cart_points
|
|
509
|
+
.reduce((acc, vert) => math.add(acc, vert), [0, 0, 0])
|
|
510
|
+
.map((val) => val / cart_points.length);
|
|
511
|
+
const normal_unit = math.normalize_vec(normal_cart);
|
|
512
|
+
const ref_vec = math.normalize_vec(math.subtract(cart_points[0], centroid));
|
|
513
|
+
const cross_ref = math.cross_3d(normal_unit, ref_vec);
|
|
514
|
+
return cart_points
|
|
515
|
+
.map((vert) => {
|
|
516
|
+
const rel = math.subtract(vert, centroid);
|
|
517
|
+
return { vert, angle: Math.atan2(math.dot(rel, cross_ref), math.dot(rel, ref_vec)) };
|
|
518
|
+
})
|
|
519
|
+
.sort((pt_a, pt_b) => pt_a.angle - pt_b.angle)
|
|
520
|
+
.map(({ vert }) => vert);
|
|
521
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { MoyoHallSymbolEntry, MoyoWyckoffPosition } from '@spglib/moyo-wasm';
|
|
2
|
+
import type { WyckoffPos } from './index';
|
|
3
|
+
export declare function spacegroup_wyckoff_positions(hall_number: number): MoyoWyckoffPosition[];
|
|
4
|
+
export declare function spacegroup_settings(spacegroup_number: number): MoyoHallSymbolEntry[];
|
|
5
|
+
export declare const wyckoff_letter: (wyckoff: string) => string;
|
|
6
|
+
export declare const count_free_params: (coordinates: string) => number;
|
|
7
|
+
export declare function enrich_wyckoff_rows(rows: WyckoffPos[], db_positions: MoyoWyckoffPosition[]): WyckoffPos[];
|
|
8
|
+
export declare function wyckoff_sequence(rows: WyckoffPos[]): string;
|
|
9
|
+
export declare function count_structure_free_params(rows: WyckoffPos[]): number | null;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Helpers around moyo's space-group database functions (new in moyo-wasm 0.11):
|
|
2
|
+
// - wyckoff_positions(hall_number): ALL Wyckoff positions of a space-group setting
|
|
3
|
+
// (multiplicity, letter, site symmetry, representative coordinate triplet)
|
|
4
|
+
// - hall_symbol_entries_from_number(number): all settings (origin choices, unique
|
|
5
|
+
// axes, cell choices) of an ITA space group
|
|
6
|
+
// Plus pure helpers to join that database against the occupied Wyckoff orbits of an
|
|
7
|
+
// analyzed structure (Wyckoff sequence, internal degrees of freedom, ITA coords).
|
|
8
|
+
import { superscript_digits } from '../labels';
|
|
9
|
+
import { hall_symbol_entries_from_number, wyckoff_positions } from '@spglib/moyo-wasm';
|
|
10
|
+
// All Wyckoff positions of the space-group setting given by hall_number (1-530),
|
|
11
|
+
// ordered general-position-first. moyo returns [] for out-of-range hall numbers.
|
|
12
|
+
// Returns [] when the moyo WASM module is not initialized (SSR, unit tests) — callers
|
|
13
|
+
// treat the database as an optional enrichment, never a hard requirement.
|
|
14
|
+
export function spacegroup_wyckoff_positions(hall_number) {
|
|
15
|
+
try {
|
|
16
|
+
return wyckoff_positions(hall_number);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
// All Hall-symbol entries (settings) of the ITA space group `spacegroup_number`
|
|
23
|
+
// (1-230), ordered by Hall number. Returns [] when the WASM module is not initialized.
|
|
24
|
+
export function spacegroup_settings(spacegroup_number) {
|
|
25
|
+
try {
|
|
26
|
+
return hall_symbol_entries_from_number(spacegroup_number);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Wyckoff letter from a `4a`-style multiplicity+letter label. Uppercase `A` is moyo's
|
|
33
|
+
// encoding of ITA's 27th letter alpha (general position of Pmmm-like groups).
|
|
34
|
+
export const wyckoff_letter = (wyckoff) => /[a-zA-Z]+$/.exec(wyckoff)?.[0] ?? ``;
|
|
35
|
+
// Number of free coordinate parameters in an ITA representative triplet: distinct
|
|
36
|
+
// x/y/z variables, e.g. `x,y,z` → 3, `1/4,1/4,z` → 1, `x,2x,1/2` → 1, `x,-x,z` → 2
|
|
37
|
+
export const count_free_params = (coordinates) => new Set(coordinates.match(/[xyz]/g)).size;
|
|
38
|
+
// Attach the space-group database entry (ITA representative coordinates, site-symmetry
|
|
39
|
+
// fallback) to each occupied Wyckoff row, matched by letter. Rows whose letter has no
|
|
40
|
+
// database entry (or an empty database) pass through unchanged.
|
|
41
|
+
export function enrich_wyckoff_rows(rows, db_positions) {
|
|
42
|
+
if (db_positions.length === 0)
|
|
43
|
+
return rows;
|
|
44
|
+
const db_by_letter = new Map(db_positions.map((pos) => [pos.letter, pos]));
|
|
45
|
+
return rows.map((row) => {
|
|
46
|
+
const entry = db_by_letter.get(wyckoff_letter(row.wyckoff));
|
|
47
|
+
if (!entry)
|
|
48
|
+
return row;
|
|
49
|
+
return {
|
|
50
|
+
...row,
|
|
51
|
+
coordinates: entry.coordinates,
|
|
52
|
+
site_symmetry: row.site_symmetry ?? entry.site_symmetry,
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
// Rank `A` (ITA's alpha, the letter AFTER z) above all lowercase letters
|
|
57
|
+
const letter_rank = (letter) => letter.charCodeAt(0) + (letter < `a` ? 64 : 0);
|
|
58
|
+
// Wyckoff sequence of the occupied orbits: letters in descending alphabetical order
|
|
59
|
+
// (general position first, ICSD convention), each with a superscript count when more
|
|
60
|
+
// than one orbit occupies that letter — e.g. cubic perovskite (Pm-3m): `c b a`.
|
|
61
|
+
export function wyckoff_sequence(rows) {
|
|
62
|
+
const counts = new Map();
|
|
63
|
+
for (const row of rows) {
|
|
64
|
+
const letter = wyckoff_letter(row.wyckoff);
|
|
65
|
+
if (letter)
|
|
66
|
+
counts.set(letter, (counts.get(letter) ?? 0) + 1);
|
|
67
|
+
}
|
|
68
|
+
return [...counts.entries()]
|
|
69
|
+
.sort(([letter_1], [letter_2]) => letter_rank(letter_2) - letter_rank(letter_1))
|
|
70
|
+
.map(([letter, count]) => count > 1 ? `${letter}${superscript_digits(String(count))}` : letter)
|
|
71
|
+
.join(` `);
|
|
72
|
+
}
|
|
73
|
+
// Internal degrees of freedom of the structure: free fractional coordinates summed
|
|
74
|
+
// over occupied Wyckoff orbits. Requires every row to carry ITA coordinates (see
|
|
75
|
+
// enrich_wyckoff_rows); returns null for empty rows or when any row lacks coordinates
|
|
76
|
+
// so callers can hide the stat instead of showing a wrong number.
|
|
77
|
+
export function count_structure_free_params(rows) {
|
|
78
|
+
if (rows.length === 0)
|
|
79
|
+
return null;
|
|
80
|
+
let total = 0;
|
|
81
|
+
for (const row of rows) {
|
|
82
|
+
if (row.coordinates === undefined)
|
|
83
|
+
return null;
|
|
84
|
+
total += count_free_params(row.coordinates);
|
|
85
|
+
}
|
|
86
|
+
return total;
|
|
87
|
+
}
|