matterviz 0.4.0 → 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/brillouin/BrillouinZone.svelte +68 -145
- package/dist/brillouin/BrillouinZone.svelte.d.ts +5 -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 +49 -203
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +3 -23
- 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 +80 -77
- 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.d.ts +1 -1
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +100 -191
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +4 -1
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +176 -464
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +7 -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 +3 -3
- package/dist/chempot-diagram/compute.js +3 -1
- 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 +2 -2
- package/dist/composition/FormulaFilter.svelte +6 -5
- package/dist/composition/PieChart.svelte +5 -5
- package/dist/composition/chem-sys.js +3 -2
- package/dist/composition/format.js +3 -2
- package/dist/composition/parse.d.ts +0 -1
- package/dist/composition/parse.js +17 -19
- 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 +94 -175
- package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull3D.svelte +176 -680
- package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull4D.svelte +180 -680
- 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 +29 -168
- 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/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/helpers.d.ts +39 -7
- package/dist/convex-hull/helpers.js +154 -69
- 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 +9 -7
- package/dist/convex-hull/index.js +7 -2
- package/dist/convex-hull/thermodynamics.js +91 -920
- package/dist/convex-hull/types.d.ts +12 -4
- package/dist/convex-hull/types.js +12 -0
- package/dist/coordination/CoordinationBarPlot.svelte +4 -11
- package/dist/element/BohrAtom.svelte +2 -1
- package/dist/element/ElementTile.svelte.d.ts +1 -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/FermiSurface.svelte +67 -146
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +5 -14
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte +72 -224
- package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +3 -23
- package/dist/fermi-surface/compute.js +11 -10
- package/dist/fermi-surface/export.js +4 -15
- 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 +64 -75
- package/dist/fermi-surface/types.d.ts +2 -2
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +55 -40
- 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/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 +1 -2
- package/dist/io/export.d.ts +5 -1
- package/dist/io/export.js +32 -28
- package/dist/io/fetch.d.ts +2 -1
- package/dist/io/file-drop.d.ts +7 -0
- package/dist/io/file-drop.js +13 -0
- 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/isosurface/parse.js +46 -44
- package/dist/labels.js +1 -1
- 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/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/math.d.ts +7 -3
- package/dist/math.js +18 -21
- package/dist/overlays/index.d.ts +4 -0
- package/dist/periodic-table/PeriodicTable.svelte +9 -8
- 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 +2 -1
- 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/colors.js +1 -1
- package/dist/phase-diagram/parse.d.ts +2 -1
- package/dist/plot/bar/BarPlot.svelte +79 -316
- package/dist/plot/bar/BarPlot.svelte.d.ts +7 -15
- package/dist/plot/bar/BarPlotControls.svelte.d.ts +1 -1
- package/dist/plot/bar/SpacegroupBarPlot.svelte +2 -1
- package/dist/plot/box/BoxPlot.svelte +76 -246
- package/dist/plot/box/BoxPlot.svelte.d.ts +4 -3
- package/dist/plot/box/BoxPlotControls.svelte.d.ts +1 -1
- package/dist/plot/box/Violin.svelte.d.ts +1 -1
- package/dist/plot/box/box-plot.d.ts +3 -2
- package/dist/plot/box/box-plot.js +5 -2
- package/dist/plot/box/kde.d.ts +2 -1
- package/dist/plot/box/kde.js +4 -4
- package/dist/plot/core/auto-place.d.ts +1 -1
- package/dist/plot/core/auto-place.js +4 -1
- package/dist/plot/core/components/ColorBar.svelte +5 -5
- package/dist/plot/core/components/ColorBar.svelte.d.ts +5 -4
- package/dist/plot/core/components/Line.svelte +3 -2
- package/dist/plot/core/components/Line.svelte.d.ts +3 -2
- package/dist/plot/core/components/PlotAxis.svelte +2 -1
- package/dist/plot/core/components/PlotAxis.svelte.d.ts +2 -1
- package/dist/plot/core/components/PlotControls.svelte.d.ts +1 -1
- package/dist/plot/core/components/ReferenceLine3D.svelte +2 -2
- package/dist/plot/core/components/ReferenceLine3D.svelte.d.ts +4 -4
- package/dist/plot/core/components/ReferencePlane.svelte +2 -2
- package/dist/plot/core/components/ReferencePlane.svelte.d.ts +4 -4
- package/dist/plot/core/data-cleaning.js +18 -18
- package/dist/plot/core/fill-utils.d.ts +4 -3
- package/dist/plot/core/fill-utils.js +6 -3
- package/dist/plot/core/interactions.d.ts +5 -1
- package/dist/plot/core/interactions.js +14 -0
- 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/core/reference-line.d.ts +10 -10
- package/dist/plot/core/reference-line.js +6 -6
- package/dist/plot/core/scales.d.ts +17 -25
- package/dist/plot/core/scales.js +10 -8
- package/dist/plot/core/svg.d.ts +2 -1
- package/dist/plot/core/types.d.ts +18 -7
- package/dist/plot/core/utils/label-placement.d.ts +1 -1
- package/dist/plot/core/utils/label-placement.js +3 -3
- package/dist/plot/core/utils.d.ts +2 -1
- package/dist/plot/histogram/Histogram.svelte +77 -314
- package/dist/plot/histogram/HistogramControls.svelte.d.ts +1 -1
- package/dist/plot/sankey/Sankey.svelte +2 -5
- package/dist/plot/sankey/Sankey.svelte.d.ts +1 -1
- package/dist/plot/sankey/sankey.js +3 -1
- package/dist/plot/scatter/BinnedScatterPlot.svelte +3 -5
- package/dist/plot/scatter/BinnedScatterPlot.svelte.d.ts +4 -4
- package/dist/plot/scatter/ScatterPlot.svelte +160 -450
- package/dist/plot/scatter/ScatterPlot.svelte.d.ts +7 -15
- package/dist/plot/scatter/ScatterPlotControls.svelte.d.ts +1 -1
- package/dist/plot/scatter/binned-scatter-types.d.ts +4 -11
- package/dist/plot/scatter/index.d.ts +1 -1
- package/dist/plot/scatter-3d/ScatterPlot3D.svelte +15 -26
- package/dist/plot/scatter-3d/ScatterPlot3D.svelte.d.ts +6 -14
- package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte +9 -10
- package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte.d.ts +5 -5
- package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte +122 -121
- package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte.d.ts +5 -14
- package/dist/plot/scatter-3d/Surface3D.svelte +6 -5
- package/dist/plot/scatter-3d/Surface3D.svelte.d.ts +4 -3
- package/dist/plot/sunburst/Sunburst.svelte +16 -20
- package/dist/plot/sunburst/Sunburst.svelte.d.ts +4 -3
- package/dist/plot/sunburst/SunburstControls.svelte.d.ts +1 -1
- package/dist/plot/sunburst/sunburst.js +4 -1
- package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
- package/dist/sanitize.js +13 -2
- 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 +14 -2
- package/dist/settings.js +59 -1
- package/dist/spectral/Bands.svelte +8 -7
- package/dist/spectral/Bands.svelte.d.ts +3 -2
- package/dist/spectral/BandsAndDos.svelte +22 -24
- package/dist/spectral/BrillouinBandsDos.svelte +3 -3
- package/dist/spectral/Dos.svelte +5 -4
- package/dist/spectral/Dos.svelte.d.ts +2 -1
- package/dist/spectral/helpers.d.ts +6 -6
- package/dist/spectral/helpers.js +43 -37
- 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.d.ts +1 -1
- package/dist/structure/CanvasTooltip.svelte +1 -0
- package/dist/structure/CellSelect.svelte +11 -3
- package/dist/structure/CellSelect.svelte.d.ts +2 -1
- package/dist/structure/Lattice.svelte +2 -2
- package/dist/structure/Structure.svelte +291 -355
- 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 +5 -3
- package/dist/structure/StructureInfoPane.svelte.d.ts +5 -5
- package/dist/structure/StructureScene.svelte +365 -198
- 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} +12 -2
- package/dist/structure/atom-properties.d.ts +1 -1
- package/dist/structure/atom-properties.js +11 -16
- package/dist/structure/bond-order-perception.js +2 -4
- package/dist/structure/bonding.d.ts +3 -0
- package/dist/structure/bonding.js +91 -48
- package/dist/structure/export.d.ts +24 -4
- package/dist/structure/export.js +64 -122
- package/dist/structure/index.d.ts +2 -0
- package/dist/structure/index.js +2 -0
- package/dist/structure/parse.d.ts +3 -2
- package/dist/structure/parse.js +333 -370
- 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 +186 -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 +111 -6
- 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 +301 -80
- package/dist/symmetry/spacegroups.d.ts +5 -1
- package/dist/symmetry/spacegroups.js +15 -1
- 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 +4 -15
- package/dist/table/HeatmapTable.svelte.d.ts +1 -1
- package/dist/trajectory/Trajectory.svelte +58 -61
- package/dist/trajectory/Trajectory.svelte.d.ts +10 -22
- package/dist/trajectory/TrajectoryExportPane.svelte +15 -24
- package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +4 -5
- package/dist/trajectory/TrajectoryInfoPane.svelte +3 -2
- 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 +0 -1
- package/dist/trajectory/format-detect.js +3 -9
- package/dist/trajectory/frame-reader.d.ts +0 -1
- package/dist/trajectory/frame-reader.js +62 -128
- package/dist/trajectory/helpers.d.ts +10 -2
- package/dist/trajectory/helpers.js +56 -36
- 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/index.d.ts +1 -1
- package/dist/trajectory/parse/index.js +54 -102
- 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 +4 -3
- package/dist/trajectory/parse/xyz.d.ts +9 -21
- package/dist/trajectory/parse/xyz.js +28 -33
- package/dist/trajectory/plotting.d.ts +0 -1
- package/dist/trajectory/plotting.js +3 -100
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +1 -1
- package/dist/xrd/XrdPlot.svelte +14 -29
- package/dist/xrd/broadening.d.ts +2 -1
- package/dist/xrd/calc-xrd.js +6 -11
- package/dist/xrd/index.d.ts +2 -2
- package/package.json +29 -16
- 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/core/hover-lock.svelte.d.ts +0 -14
- package/dist/plot/core/hover-lock.svelte.js +0 -45
package/dist/symmetry/index.js
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { ATOMIC_NUMBER_TO_SYMBOL, SYMBOL_TO_ATOMIC_NUMBER } from '../composition/parse';
|
|
2
|
+
import * as math from '../math';
|
|
2
3
|
import { DEFAULTS } from '../settings';
|
|
3
4
|
import { merge_split_partial_sites } from '../structure/partial-occupancy';
|
|
4
5
|
import init, { analyze_cell } from '@spglib/moyo-wasm';
|
|
5
6
|
import moyo_wasm_url from '@spglib/moyo-wasm/moyo_wasm_bg.wasm?url';
|
|
7
|
+
import { mat3_from_flat_col_major } from './symmetry-elements';
|
|
8
|
+
import { wyckoff_letter } from './wyckoff-db';
|
|
6
9
|
export * from './cell-transform';
|
|
7
10
|
export * from './spacegroups';
|
|
11
|
+
export * from './symmetry-elements';
|
|
12
|
+
export * from './wyckoff-db';
|
|
13
|
+
export { default as SymmetryElementControls } from './SymmetryElementControls.svelte';
|
|
14
|
+
export { default as SymmetryElements } from './SymmetryElements.svelte';
|
|
8
15
|
export { default as SymmetryStats } from './SymmetryStats.svelte';
|
|
9
16
|
export { default as WyckoffTable } from './WyckoffTable.svelte';
|
|
10
17
|
// Keys are standard crystallographic symbols (P, I, F, A, B, C, R)
|
|
@@ -27,13 +34,37 @@ const to_unit = (value) => value - Math.floor(value);
|
|
|
27
34
|
const near_zero = (value) => Math.min(value, 1 - value);
|
|
28
35
|
const near_half = (value) => Math.abs(value - 0.5);
|
|
29
36
|
const symmetry_position_key = (pos) => pos.map((coord) => to_unit(coord).toFixed(8)).join(`,`);
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
const is_near_integer_vec = (vec, tol) => vec.every((coord) => Math.abs(coord - Math.round(coord)) < tol);
|
|
38
|
+
// Wrap fractional coordinates into [0, 1), snapping values within 1e-9 of 1 back to 0.
|
|
39
|
+
// NOTE on epsilon: 1e-9 is deliberately looser than wrap_frac_coord @1e-10
|
|
40
|
+
// [[src/lib/structure/pbc.ts:26]] because inputs here passed through moyo
|
|
41
|
+
// standardization plus a P⁻¹(x − p) matrix transform (make_frac_coord_mapper),
|
|
42
|
+
// accumulating more float error than freshly parsed coords. It is tighter than
|
|
43
|
+
// wrap_point @1e-8 [[src/lib/symmetry/symmetry-elements.ts:214]], which must
|
|
44
|
+
// keep dedup keys stable for fixed points solved from linear systems. Do not
|
|
45
|
+
// unify: each epsilon matches the noise level of its inputs.
|
|
46
|
+
const wrap_frac = (pos) => pos.map((coord) => {
|
|
47
|
+
const wrapped = coord - Math.floor(coord);
|
|
48
|
+
return wrapped > 1 - 1e-9 ? 0 : wrapped;
|
|
49
|
+
});
|
|
50
|
+
// Build a mapper from input-cell to standardized-cell fractional coordinates.
|
|
51
|
+
// moyo's (std_linear P, std_origin_shift p) follow the ITA convention for the
|
|
52
|
+
// transformation from the input cell to the standardized cell: x_std = P⁻¹ (x_input − p).
|
|
53
|
+
// Returns null if std_linear is absent or singular.
|
|
54
|
+
function make_frac_coord_mapper(linear_flat, origin_shift) {
|
|
55
|
+
if (linear_flat?.length !== 9)
|
|
56
|
+
return null;
|
|
57
|
+
try {
|
|
58
|
+
const linear = mat3_from_flat_col_major(linear_flat);
|
|
59
|
+
const linear_inv = math.matrix_inverse_3x3(linear);
|
|
60
|
+
const shift = (origin_shift ?? [0, 0, 0]);
|
|
61
|
+
const to_std = (pos) => math.mat3x3_vec3_multiply(linear_inv, math.subtract(pos, shift));
|
|
62
|
+
return { to_std, linear, linear_inv, shift };
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
37
68
|
export async function ensure_moyo_wasm_ready(wasm_url) {
|
|
38
69
|
if (initialized)
|
|
39
70
|
return;
|
|
@@ -93,23 +124,42 @@ export function to_cell_json(structure) {
|
|
|
93
124
|
const fractional_sq_dist = (pos_1, pos_2) => (pos_1[0] - pos_2[0] - Math.round(pos_1[0] - pos_2[0])) ** 2 +
|
|
94
125
|
(pos_1[1] - pos_2[1] - Math.round(pos_1[1] - pos_2[1])) ** 2 +
|
|
95
126
|
(pos_1[2] - pos_2[2] - Math.round(pos_1[2] - pos_2[2])) ** 2;
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
127
|
+
// Map each standardized-cell site to the input-cell site it descends from, then to
|
|
128
|
+
// original structure indices. When moyo's (std_linear, std_origin_shift) transform is
|
|
129
|
+
// provided, std positions are first mapped into the input frame via x_in = P·x_std + p
|
|
130
|
+
// (the std and input cells use DIFFERENT bases in general, so comparing raw fractional
|
|
131
|
+
// coordinates across them is meaningless). Matches account for crystal translations of
|
|
132
|
+
// both lattices: a difference d is a translation if d ∈ ℤ³ (input lattice) or P⁻¹d ∈ ℤ³
|
|
133
|
+
// (standardized lattice expressed in the input frame).
|
|
134
|
+
export const map_std_to_orig_site_indices = (std_positions, std_numbers, input_positions, input_numbers, orig_site_indices_by_input_idx, transform, tol = 1e-4) => {
|
|
135
|
+
const mapper = make_frac_coord_mapper(transform?.std_linear, transform?.std_origin_shift);
|
|
136
|
+
return std_positions.map((std_pos, std_idx) => {
|
|
137
|
+
// Predicted input-frame position of this std site: x_in = P·x_std + p
|
|
138
|
+
const pred = mapper
|
|
139
|
+
? math.add(math.mat3x3_vec3_multiply(mapper.linear, std_pos), mapper.shift)
|
|
140
|
+
: std_pos;
|
|
141
|
+
const std_number = std_numbers[std_idx];
|
|
142
|
+
let nearest_input_idx = -1;
|
|
143
|
+
let nearest_sq_dist = Infinity;
|
|
144
|
+
for (let input_idx = 0; input_idx < input_positions.length; input_idx += 1) {
|
|
145
|
+
if (input_numbers[input_idx] !== std_number)
|
|
146
|
+
continue;
|
|
147
|
+
const delta = math.subtract(pred, input_positions[input_idx]);
|
|
148
|
+
// Exact match modulo a translation of the standardized lattice
|
|
149
|
+
const is_std_translation = mapper && is_near_integer_vec(math.mat3x3_vec3_multiply(mapper.linear_inv, delta), tol);
|
|
150
|
+
const sq_dist = is_std_translation
|
|
151
|
+
? 0
|
|
152
|
+
: fractional_sq_dist(pred, input_positions[input_idx]);
|
|
153
|
+
if (sq_dist < nearest_sq_dist) {
|
|
154
|
+
nearest_sq_dist = sq_dist;
|
|
155
|
+
nearest_input_idx = input_idx;
|
|
156
|
+
}
|
|
107
157
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return [];
|
|
111
|
-
|
|
112
|
-
}
|
|
158
|
+
if (nearest_input_idx === -1)
|
|
159
|
+
return [];
|
|
160
|
+
return orig_site_indices_by_input_idx[nearest_input_idx] ?? [];
|
|
161
|
+
});
|
|
162
|
+
};
|
|
113
163
|
export async function analyze_structure_symmetry(struct_or_mol, settings) {
|
|
114
164
|
await ensure_moyo_wasm_ready();
|
|
115
165
|
if (!(`lattice` in struct_or_mol)) {
|
|
@@ -121,8 +171,16 @@ export async function analyze_structure_symmetry(struct_or_mol, settings) {
|
|
|
121
171
|
// Map "Moyo" to "Standard" for moyo-wasm
|
|
122
172
|
const moyo_algo = algo === `Moyo` ? `Standard` : algo;
|
|
123
173
|
const sym_data = analyze_cell(cell_json, symprec, moyo_algo);
|
|
124
|
-
const orig_site_indices_by_std_idx = map_std_to_orig_site_indices(sym_data.std_cell.positions, sym_data.std_cell.numbers, moyo_input_cell.positions, moyo_input_cell.numbers, moyo_input_cell.orig_site_indices_by_input_idx);
|
|
125
|
-
return {
|
|
174
|
+
const orig_site_indices_by_std_idx = map_std_to_orig_site_indices(sym_data.std_cell.positions, sym_data.std_cell.numbers, moyo_input_cell.positions, moyo_input_cell.numbers, moyo_input_cell.orig_site_indices_by_input_idx, { std_linear: sym_data.std_linear, std_origin_shift: sym_data.std_origin_shift }, Math.max(1e-5, symprec * 10));
|
|
175
|
+
return {
|
|
176
|
+
...sym_data,
|
|
177
|
+
orig_site_indices_by_std_idx,
|
|
178
|
+
input_cell: {
|
|
179
|
+
positions: moyo_input_cell.positions,
|
|
180
|
+
numbers: moyo_input_cell.numbers,
|
|
181
|
+
},
|
|
182
|
+
orig_site_indices_by_input_idx: moyo_input_cell.orig_site_indices_by_input_idx,
|
|
183
|
+
};
|
|
126
184
|
}
|
|
127
185
|
// Helper function to score coordinate simplicity for Wyckoff table
|
|
128
186
|
export function simplicity_score(vec) {
|
|
@@ -132,59 +190,67 @@ export function simplicity_score(vec) {
|
|
|
132
190
|
near_zero(az) +
|
|
133
191
|
0.5 * (near_half(ax) + near_half(ay) + near_half(az)));
|
|
134
192
|
}
|
|
135
|
-
//
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
: indices;
|
|
170
|
-
const wyckoff = letter ? `${indices.length}${letter}` : `1`;
|
|
193
|
+
// Pick the representative coordinate with the lowest simplicity score (ties keep first)
|
|
194
|
+
const simplest_position = (positions) => positions.reduce((best, pos) => simplicity_score(pos) < simplicity_score(best) ? pos : best);
|
|
195
|
+
// Build Wyckoff rows from moyo's input-cell orbits. moyo's per-site arrays (wyckoffs,
|
|
196
|
+
// orbits, site_symmetry_symbols) are indexed by INPUT cell sites — NOT std_cell sites —
|
|
197
|
+
// so rows must be derived by grouping input sites into crystallographic orbits.
|
|
198
|
+
// Multiplicity in the conventional cell is the orbit size scaled by the std/input cell
|
|
199
|
+
// size ratio (e.g. a 1-atom primitive FCC input has orbit size 1 but multiplicity 4).
|
|
200
|
+
function wyckoff_rows_from_input_orbits(sym_data) {
|
|
201
|
+
const { input_cell, orbits, wyckoffs, site_symmetry_symbols, std_cell, orig_site_indices_by_input_idx, } = sym_data;
|
|
202
|
+
const n_input = input_cell?.positions.length ?? 0;
|
|
203
|
+
if (!input_cell || n_input === 0)
|
|
204
|
+
return null;
|
|
205
|
+
if (orbits?.length !== n_input || wyckoffs?.length !== n_input)
|
|
206
|
+
return null;
|
|
207
|
+
const mapper = make_frac_coord_mapper(sym_data.std_linear, sym_data.std_origin_shift);
|
|
208
|
+
if (!mapper)
|
|
209
|
+
return null;
|
|
210
|
+
// Group input-cell sites by crystallographic orbit (keyed by orbit representative).
|
|
211
|
+
// Distinct orbits sharing the same Wyckoff letter and element stay separate rows.
|
|
212
|
+
const orbit_members = new Map();
|
|
213
|
+
orbits.forEach((rep, idx) => {
|
|
214
|
+
const members = orbit_members.get(rep) ?? [];
|
|
215
|
+
members.push(idx);
|
|
216
|
+
orbit_members.set(rep, members);
|
|
217
|
+
});
|
|
218
|
+
const n_std = std_cell?.positions.length ?? n_input;
|
|
219
|
+
return [...orbit_members.entries()].map(([rep, members]) => {
|
|
220
|
+
const letter = wyckoff_letter(wyckoffs[rep] ?? ``);
|
|
221
|
+
const elem = ATOMIC_NUMBER_TO_SYMBOL[input_cell.numbers[rep]] ?? `?`;
|
|
222
|
+
const multiplicity = Math.round((members.length * n_std) / n_input);
|
|
223
|
+
// Representative coordinate in the standardized frame, simplest first
|
|
224
|
+
const best_pos = simplest_position(members.map((idx) => wrap_frac(mapper.to_std(input_cell.positions[idx]))));
|
|
225
|
+
const orig_site_indices = members.flatMap((idx) => orig_site_indices_by_input_idx?.[idx] ?? [idx]);
|
|
226
|
+
const site_symmetry = site_symmetry_symbols?.[rep];
|
|
171
227
|
return {
|
|
172
|
-
wyckoff
|
|
228
|
+
wyckoff: letter ? `${multiplicity}${letter}` : `${multiplicity}`,
|
|
173
229
|
elem,
|
|
174
230
|
abc: best_pos,
|
|
175
231
|
site_indices: [...new Set(orig_site_indices)].sort((idx_a, idx_b) => idx_a - idx_b),
|
|
232
|
+
...(site_symmetry ? { site_symmetry } : {}),
|
|
176
233
|
};
|
|
177
234
|
});
|
|
178
|
-
|
|
235
|
+
}
|
|
236
|
+
// Generate Wyckoff table rows from symmetry data by grouping moyo's input-cell sites into
|
|
237
|
+
// crystallographic orbits. moyo's per-site arrays (wyckoffs, orbits, site_symmetry_symbols)
|
|
238
|
+
// always index the input cell and analyze_structure_symmetry always attaches input_cell, so
|
|
239
|
+
// the orbit grouping is the single source of truth for any input cell setting.
|
|
240
|
+
// Rows sort by ascending multiplicity, then Wyckoff label.
|
|
241
|
+
export function wyckoff_positions_from_moyo(sym_data) {
|
|
242
|
+
if (!sym_data)
|
|
243
|
+
return [];
|
|
244
|
+
const orbit_rows = wyckoff_rows_from_input_orbits(sym_data);
|
|
245
|
+
return (orbit_rows ?? []).sort((w1, w2) => {
|
|
179
246
|
const [w1_mult, w2_mult] = [parseInt(w1.wyckoff, 10), parseInt(w2.wyckoff, 10)];
|
|
180
247
|
if (w1_mult !== w2_mult)
|
|
181
248
|
return w1_mult - w2_mult;
|
|
182
249
|
return w1.wyckoff.localeCompare(w2.wyckoff);
|
|
183
250
|
});
|
|
184
|
-
return rows;
|
|
185
251
|
}
|
|
186
252
|
// Apply symmetry operations to find all equivalent positions for a given fractional coordinate
|
|
187
|
-
export function apply_symmetry_operations(position, operations
|
|
253
|
+
export function apply_symmetry_operations(position, operations) {
|
|
188
254
|
const seen = new Set();
|
|
189
255
|
return operations
|
|
190
256
|
.map(({ rotation, translation }) => {
|
|
@@ -203,24 +269,179 @@ export function apply_symmetry_operations(position, operations, _tolerance = 1e-
|
|
|
203
269
|
return true;
|
|
204
270
|
});
|
|
205
271
|
}
|
|
206
|
-
//
|
|
272
|
+
// Build candidate frames for the displayed structure: original, conventional (moyo
|
|
273
|
+
// std_cell), and primitive (moyo prim_std_cell). The displayed structure's fractional
|
|
274
|
+
// coordinates only match symmetry-equivalent positions when expressed in the same frame.
|
|
275
|
+
function candidate_display_frames(orig_structure, sym_data) {
|
|
276
|
+
const frames = [
|
|
277
|
+
{
|
|
278
|
+
lattice: orig_structure.lattice.matrix,
|
|
279
|
+
map_equiv: (pos) => pos,
|
|
280
|
+
input_translation_check: null,
|
|
281
|
+
},
|
|
282
|
+
];
|
|
283
|
+
const cells = [
|
|
284
|
+
{ cell: sym_data.std_cell, linear: sym_data.std_linear, shift: sym_data.std_origin_shift },
|
|
285
|
+
{
|
|
286
|
+
cell: sym_data.prim_std_cell,
|
|
287
|
+
linear: sym_data.prim_std_linear,
|
|
288
|
+
shift: sym_data.prim_std_origin_shift,
|
|
289
|
+
},
|
|
290
|
+
];
|
|
291
|
+
for (const { cell, linear, shift } of cells) {
|
|
292
|
+
const basis = cell?.lattice?.basis;
|
|
293
|
+
const mapper = make_frac_coord_mapper(linear, shift);
|
|
294
|
+
if (basis?.length !== 9 || !mapper)
|
|
295
|
+
continue;
|
|
296
|
+
// basis is row-major (each row a lattice vector); same reshape as moyo_cell_to_structure
|
|
297
|
+
frames.push({
|
|
298
|
+
lattice: math.vec9_to_mat3x3([...basis]),
|
|
299
|
+
map_equiv: mapper.to_std,
|
|
300
|
+
input_translation_check: mapper.linear,
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
return frames;
|
|
304
|
+
}
|
|
305
|
+
// Spatial hash over wrapped fractional coordinates for tolerance-based, mod-1 position
|
|
306
|
+
// lookups. Cell size is chosen ≥ tolerance so probing the ±1 neighbor cells (with
|
|
307
|
+
// wraparound) covers every point within tolerance of the query.
|
|
308
|
+
class WrappedPositionIndex {
|
|
309
|
+
tolerance;
|
|
310
|
+
buckets = new Map();
|
|
311
|
+
coords;
|
|
312
|
+
n_cells;
|
|
313
|
+
constructor(positions, tolerance) {
|
|
314
|
+
this.tolerance = tolerance;
|
|
315
|
+
this.n_cells = Math.min(64, Math.max(1, Math.floor(1 / Math.max(tolerance, 1e-9))));
|
|
316
|
+
this.coords = positions;
|
|
317
|
+
positions.forEach((pos, idx) => {
|
|
318
|
+
const key = this.cell_key(pos, 0, 0, 0);
|
|
319
|
+
const bucket = this.buckets.get(key);
|
|
320
|
+
if (bucket)
|
|
321
|
+
bucket.push(idx);
|
|
322
|
+
else
|
|
323
|
+
this.buckets.set(key, [idx]);
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
cell_key(pos, dx, dy, dz) {
|
|
327
|
+
const n_cells = this.n_cells;
|
|
328
|
+
const cell = (coord, offset) => {
|
|
329
|
+
const wrapped = coord - Math.floor(coord);
|
|
330
|
+
return (((Math.floor(wrapped * n_cells) + offset) % n_cells) + n_cells) % n_cells;
|
|
331
|
+
};
|
|
332
|
+
return `${cell(pos[0], dx)},${cell(pos[1], dy)},${cell(pos[2], dz)}`;
|
|
333
|
+
}
|
|
334
|
+
// Indices of stored positions within `tolerance` of `query` modulo ℤ³
|
|
335
|
+
query(query, out) {
|
|
336
|
+
const tol = this.tolerance;
|
|
337
|
+
for (let dx = -1; dx <= 1; dx++) {
|
|
338
|
+
for (let dy = -1; dy <= 1; dy++) {
|
|
339
|
+
for (let dz = -1; dz <= 1; dz++) {
|
|
340
|
+
const bucket = this.buckets.get(this.cell_key(query, dx, dy, dz));
|
|
341
|
+
if (!bucket)
|
|
342
|
+
continue;
|
|
343
|
+
for (const idx of bucket) {
|
|
344
|
+
const pos = this.coords[idx];
|
|
345
|
+
const d0 = pos[0] - query[0];
|
|
346
|
+
const d1 = pos[1] - query[1];
|
|
347
|
+
const d2 = pos[2] - query[2];
|
|
348
|
+
if (Math.abs(d0 - Math.round(d0)) < tol &&
|
|
349
|
+
Math.abs(d1 - Math.round(d1)) < tol &&
|
|
350
|
+
Math.abs(d2 - Math.round(d2)) < tol)
|
|
351
|
+
out.add(idx);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
// Map Wyckoff positions to all equivalent atoms in the displayed structure (including
|
|
359
|
+
// image atoms). Handles displayed structures in the original frame as well as
|
|
360
|
+
// conventional/primitive cell transforms and integer supercells of any of those: the
|
|
361
|
+
// displayed lattice L_disp is matched against each candidate frame's lattice L_F via
|
|
362
|
+
// S = L_disp·L_F⁻¹ (S must be near-integer), displayed coords are converted into the
|
|
363
|
+
// frame via x_F = x_disp·S, and matches allow crystal translations of both the frame
|
|
364
|
+
// lattice (d ∈ ℤ³) and the input lattice (P·d ∈ ℤ³). Matching uses spatial hashing:
|
|
365
|
+
// O(N_disp + N_orig·N_ops) instead of O(N_orig·N_disp·N_ops).
|
|
207
366
|
export function map_wyckoff_to_all_atoms(wyckoff_positions, displayed_structure, orig_structure, sym_data, tolerance = 1e-5) {
|
|
208
367
|
if (!sym_data?.operations || !displayed_structure.sites || !orig_structure.sites) {
|
|
209
368
|
return wyckoff_positions;
|
|
210
369
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
return
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
370
|
+
const map_in_frame = (frame) => {
|
|
371
|
+
// Supercell factor S = L_disp·L_F⁻¹ must be a near-integer matrix with |det| ≥ 1
|
|
372
|
+
let scaling;
|
|
373
|
+
try {
|
|
374
|
+
scaling = math.dot(displayed_structure.lattice.matrix, math.matrix_inverse_3x3(frame.lattice));
|
|
375
|
+
}
|
|
376
|
+
catch {
|
|
377
|
+
return null;
|
|
378
|
+
}
|
|
379
|
+
const is_integer_scaling = scaling.every((row) => row.every((val) => Math.abs(val - Math.round(val)) < tolerance));
|
|
380
|
+
if (!is_integer_scaling || Math.abs(math.det_3x3(scaling)) < 0.99)
|
|
381
|
+
return null;
|
|
382
|
+
// Displayed site coords expressed in frame-F fractional coordinates: x_F = x_disp·S
|
|
383
|
+
const scaling_transpose = math.transpose_3x3_matrix(scaling);
|
|
384
|
+
const displayed_frame_coords = displayed_structure.sites.map((site) => math.mat3x3_vec3_multiply(scaling_transpose, site.abc));
|
|
385
|
+
const displayed_elements = displayed_structure.sites.map((site) => site.species[0]?.element);
|
|
386
|
+
// Spatial hashes: one over the frame coords directly (matches d ∈ ℤ³), and one over
|
|
387
|
+
// P·x_F (matches input-lattice translations: d ∈ P⁻¹ℤ³ ⟺ P·d ∈ ℤ³)
|
|
388
|
+
const direct_index = new WrappedPositionIndex(displayed_frame_coords, tolerance);
|
|
389
|
+
const check = frame.input_translation_check;
|
|
390
|
+
const check_index = check
|
|
391
|
+
? new WrappedPositionIndex(displayed_frame_coords.map((pos) => math.mat3x3_vec3_multiply(check, pos)), tolerance)
|
|
392
|
+
: null;
|
|
393
|
+
let any_matched = false;
|
|
394
|
+
const rows = wyckoff_positions.map((wyckoff_pos) => {
|
|
395
|
+
// Union the symmetry orbits of all original sites in this row, grouped by element.
|
|
396
|
+
// Sites whose (wrapped) position already appears in the accumulated orbit are
|
|
397
|
+
// skipped — orbit members generate identical orbits, so rows with many sites of
|
|
398
|
+
// one orbit (e.g. supercells) only pay for one full operation sweep
|
|
399
|
+
const equiv_by_element = new Map();
|
|
400
|
+
for (const orig_idx of wyckoff_pos.site_indices ?? []) {
|
|
401
|
+
if (orig_idx >= orig_structure.sites.length)
|
|
402
|
+
continue;
|
|
403
|
+
const { abc: orig_abc, species } = orig_structure.sites[orig_idx];
|
|
404
|
+
const element = species[0]?.element;
|
|
405
|
+
const equivalents = equiv_by_element.get(element) ?? new Map();
|
|
406
|
+
equiv_by_element.set(element, equivalents);
|
|
407
|
+
const member_key = symmetry_position_key(frame.map_equiv(orig_abc.map(to_unit)));
|
|
408
|
+
if (equivalents.has(member_key))
|
|
409
|
+
continue;
|
|
410
|
+
for (const equiv_pos of apply_symmetry_operations(orig_abc, sym_data.operations)) {
|
|
411
|
+
const frame_pos = frame.map_equiv(equiv_pos);
|
|
412
|
+
const key = symmetry_position_key(frame_pos);
|
|
413
|
+
if (!equivalents.has(key))
|
|
414
|
+
equivalents.set(key, frame_pos);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
const matched = new Set();
|
|
418
|
+
for (const [element, equivalents] of equiv_by_element) {
|
|
419
|
+
const candidates = new Set();
|
|
420
|
+
for (const equiv_pos of equivalents.values()) {
|
|
421
|
+
direct_index.query(equiv_pos, candidates);
|
|
422
|
+
if (check && check_index) {
|
|
423
|
+
check_index.query(math.mat3x3_vec3_multiply(check, equiv_pos), candidates);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
for (const display_idx of candidates) {
|
|
427
|
+
if (displayed_elements[display_idx] === element)
|
|
428
|
+
matched.add(display_idx);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
if (matched.size > 0)
|
|
432
|
+
any_matched = true;
|
|
433
|
+
return { ...wyckoff_pos, site_indices: [...matched].sort((a, b) => a - b) };
|
|
223
434
|
});
|
|
224
|
-
return
|
|
225
|
-
}
|
|
435
|
+
return any_matched || displayed_structure.sites.length === 0 ? rows : null;
|
|
436
|
+
};
|
|
437
|
+
// Try frames in order; accept the first whose lattice fits AND that matches any site
|
|
438
|
+
// (lattices can coincide across frames while origins differ, so a lattice match alone
|
|
439
|
+
// is not conclusive)
|
|
440
|
+
for (const frame of candidate_display_frames(orig_structure, sym_data)) {
|
|
441
|
+
const rows = map_in_frame(frame);
|
|
442
|
+
if (rows)
|
|
443
|
+
return rows;
|
|
444
|
+
}
|
|
445
|
+
// No frame fits — site indices into the displayed structure cannot be determined
|
|
446
|
+
return wyckoff_positions.map((pos) => ({ ...pos, site_indices: [] }));
|
|
226
447
|
}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
import type { Vec2 } from '../math';
|
|
1
2
|
import type { SunburstNode } from '../plot/core/types';
|
|
2
|
-
export declare const CRYSTAL_SYSTEM_RANGES: Record<CrystalSystem,
|
|
3
|
+
export declare const CRYSTAL_SYSTEM_RANGES: Record<CrystalSystem, Vec2>;
|
|
3
4
|
export declare const CRYSTAL_SYSTEM_COLORS: Record<CrystalSystem, string>;
|
|
4
5
|
export declare const CRYSTAL_SYSTEMS: readonly ["triclinic", "monoclinic", "orthorhombic", "tetragonal", "trigonal", "hexagonal", "cubic"];
|
|
5
6
|
export type CrystalSystem = (typeof CRYSTAL_SYSTEMS)[number];
|
|
6
7
|
export declare function spacegroup_num_to_crystal_sys(spacegroup: number): CrystalSystem | null;
|
|
7
8
|
export declare function spacegroup_to_crystal_sys(spacegroup: number | string): CrystalSystem | null;
|
|
9
|
+
export declare const RHOMBOHEDRAL_SPACEGROUPS: readonly number[];
|
|
10
|
+
export type LatticeSystem = Exclude<CrystalSystem, `trigonal`> | `rhombohedral`;
|
|
11
|
+
export declare function spacegroup_num_to_lattice_system(spacegroup: number): LatticeSystem | null;
|
|
8
12
|
export declare function normalize_spacegroup(spacegroup: number | string): number | null;
|
|
9
13
|
export declare const SPACEGROUP_SYMBOL_TO_NUM: Record<string, number>;
|
|
10
14
|
export declare const SPACEGROUP_NUM_TO_SYMBOL: Record<number, string>;
|
|
@@ -43,6 +43,20 @@ export function spacegroup_to_crystal_sys(spacegroup) {
|
|
|
43
43
|
const num = normalize_spacegroup(spacegroup);
|
|
44
44
|
return num == null ? null : spacegroup_num_to_crystal_sys(num);
|
|
45
45
|
}
|
|
46
|
+
// Trigonal space groups with rhombohedral (R-centered) Bravais lattices. All other
|
|
47
|
+
// trigonal groups have primitive hexagonal lattices.
|
|
48
|
+
export const RHOMBOHEDRAL_SPACEGROUPS = [146, 148, 155, 160, 161, 166, 167];
|
|
49
|
+
// Convert space group number to lattice system (classification of the Bravais lattice).
|
|
50
|
+
// Differs from the crystal system only for trigonal groups: R-centered ones (R3, R-3m, …)
|
|
51
|
+
// have rhombohedral lattices while P-trigonal ones (P3, P-3m1, …) have hexagonal lattices.
|
|
52
|
+
export function spacegroup_num_to_lattice_system(spacegroup) {
|
|
53
|
+
const crystal_sys = spacegroup_num_to_crystal_sys(spacegroup);
|
|
54
|
+
if (crystal_sys === null)
|
|
55
|
+
return null;
|
|
56
|
+
if (crystal_sys !== `trigonal`)
|
|
57
|
+
return crystal_sys;
|
|
58
|
+
return RHOMBOHEDRAL_SPACEGROUPS.includes(spacegroup) ? `rhombohedral` : `hexagonal`;
|
|
59
|
+
}
|
|
46
60
|
// Normalize space group input (number, Hermann-Mauguin symbol, or numeric string
|
|
47
61
|
// like "225") to a space group number in [1, 230], or null if invalid
|
|
48
62
|
export function normalize_spacegroup(spacegroup) {
|
|
@@ -202,13 +216,13 @@ export const SPACEGROUP_SYMBOL_TO_NUM = {
|
|
|
202
216
|
'I4/mcm': 140,
|
|
203
217
|
'I4_1/amd': 141,
|
|
204
218
|
'I4_1/acd': 142,
|
|
219
|
+
// Trigonal
|
|
205
220
|
P3: 143,
|
|
206
221
|
P3_1: 144,
|
|
207
222
|
P3_2: 145,
|
|
208
223
|
R3: 146,
|
|
209
224
|
'P-3': 147,
|
|
210
225
|
'R-3': 148,
|
|
211
|
-
// Trigonal
|
|
212
226
|
P312: 149,
|
|
213
227
|
P321: 150,
|
|
214
228
|
P3_112: 151,
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Matrix3x3, Vec3 } from '../math';
|
|
2
|
+
import type { MoyoDataset } from '@spglib/moyo-wasm';
|
|
3
|
+
export type SymmetryElementKind = `rotation` | `screw` | `mirror` | `glide` | `inversion` | `rotoinversion`;
|
|
4
|
+
export type SymmetryElement = {
|
|
5
|
+
kind: SymmetryElementKind;
|
|
6
|
+
order: number;
|
|
7
|
+
label: string;
|
|
8
|
+
axis: Vec3 | null;
|
|
9
|
+
point: Vec3;
|
|
10
|
+
translation: Vec3 | null;
|
|
11
|
+
};
|
|
12
|
+
export declare const SYM_ELEM_KINDS: readonly ["rotation", "screw", "rotoinversion", "mirror", "glide", "inversion"];
|
|
13
|
+
export type ShowSymmetryKinds = Partial<Record<SymmetryElementKind, boolean>>;
|
|
14
|
+
export declare const DEFAULT_SHOW_SYM_KINDS: ShowSymmetryKinds;
|
|
15
|
+
export declare const SYM_ELEM_KIND_INFO: Record<SymmetryElementKind, {
|
|
16
|
+
label: string;
|
|
17
|
+
color: string;
|
|
18
|
+
}>;
|
|
19
|
+
export declare function count_symmetry_elements(elements: readonly SymmetryElement[]): Partial<Record<SymmetryElementKind, number>>;
|
|
20
|
+
export declare const has_visible_symmetry_overlay: (elements: readonly SymmetryElement[], show_kinds?: ShowSymmetryKinds) => boolean;
|
|
21
|
+
export declare const mat3_from_flat_col_major: (flat: readonly number[]) => Matrix3x3;
|
|
22
|
+
export type ClassifiedOperation = Omit<SymmetryElement, `point`> & {
|
|
23
|
+
point: Vec3;
|
|
24
|
+
};
|
|
25
|
+
export declare function classify_symmetry_op(rotation: readonly number[], translation: readonly number[], centerings?: readonly Vec3[]): ClassifiedOperation | null;
|
|
26
|
+
export declare function symmetry_elements_from_ops(operations: MoyoDataset[`operations`]): SymmetryElement[];
|
|
27
|
+
export declare function dash_segments(length: number, dash: number, gap: number): {
|
|
28
|
+
center: number;
|
|
29
|
+
length: number;
|
|
30
|
+
}[];
|
|
31
|
+
export declare const frac_to_cart_direction: (frac: Vec3, lattice: Matrix3x3) => Vec3;
|
|
32
|
+
export declare function clip_line_to_cell(point: Vec3, direction: Vec3, lattice: Matrix3x3, eps?: number): [Vec3, Vec3] | null;
|
|
33
|
+
export declare function clip_plane_to_cell(point: Vec3, normal_frac: Vec3, lattice: Matrix3x3): Vec3[];
|