matterviz 0.3.5 → 0.3.7
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/MillerIndexInput.svelte +5 -5
- package/dist/api/optimade.js +3 -3
- package/dist/brillouin/BrillouinZone.svelte +5 -2
- package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
- package/dist/brillouin/BrillouinZoneExportPane.svelte +1 -3
- package/dist/brillouin/BrillouinZoneInfoPane.svelte +1 -1
- package/dist/brillouin/BrillouinZoneScene.svelte +5 -5
- package/dist/brillouin/compute.js +21 -21
- package/dist/brillouin/index.d.ts +1 -1
- package/dist/brillouin/index.js +0 -1
- package/dist/brillouin/types.d.ts +8 -13
- package/dist/chempot-diagram/ChemPotDiagram.svelte +3 -3
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +3 -4
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +33 -34
- package/dist/chempot-diagram/compute.js +1 -7
- package/dist/chempot-diagram/temperature.d.ts +1 -1
- package/dist/chempot-diagram/temperature.js +1 -3
- package/dist/chempot-diagram/types.d.ts +4 -9
- package/dist/colors/index.js +5 -5
- package/dist/composition/Composition.svelte +2 -1
- package/dist/composition/Formula.svelte +7 -4
- package/dist/composition/FormulaFilter.svelte +1 -3
- package/dist/composition/format.js +4 -4
- package/dist/composition/parse.d.ts +2 -1
- package/dist/composition/parse.js +61 -46
- package/dist/convex-hull/ConvexHull2D.svelte +62 -51
- package/dist/convex-hull/ConvexHull3D.svelte +101 -90
- package/dist/convex-hull/ConvexHull4D.svelte +70 -58
- package/dist/convex-hull/ConvexHullControls.svelte +24 -35
- package/dist/convex-hull/ConvexHullInfoPane.svelte +8 -5
- package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +2 -0
- package/dist/convex-hull/ConvexHullStats.svelte +9 -2
- package/dist/convex-hull/ConvexHullStats.svelte.d.ts +2 -0
- package/dist/convex-hull/GasPressureControls.svelte +7 -7
- package/dist/convex-hull/StructurePopup.svelte +65 -30
- package/dist/convex-hull/StructurePopup.svelte.d.ts +6 -6
- package/dist/convex-hull/TemperatureSlider.svelte +8 -5
- package/dist/convex-hull/barycentric-coords.d.ts +2 -2
- package/dist/convex-hull/barycentric-coords.js +2 -2
- package/dist/convex-hull/gas-thermodynamics.js +2 -4
- package/dist/convex-hull/helpers.d.ts +13 -2
- package/dist/convex-hull/helpers.js +37 -16
- package/dist/convex-hull/index.d.ts +1 -0
- package/dist/convex-hull/index.js +1 -0
- package/dist/convex-hull/thermodynamics.d.ts +2 -1
- package/dist/convex-hull/thermodynamics.js +7 -7
- package/dist/convex-hull/types.d.ts +15 -15
- package/dist/effects.svelte.d.ts +12 -0
- package/dist/effects.svelte.js +37 -0
- package/dist/element/BohrAtom.svelte +4 -4
- package/dist/element/data.json.gz.d.ts +3 -1
- package/dist/element/index.d.ts +1 -1
- package/dist/element/index.js +0 -1
- package/dist/fermi-surface/FermiSurface.svelte +4 -4
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceControls.svelte +15 -19
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte +8 -6
- package/dist/fermi-surface/compute.js +2 -2
- package/dist/fermi-surface/export.js +13 -26
- package/dist/fermi-surface/parse.js +8 -12
- package/dist/fermi-surface/types.d.ts +2 -5
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +21 -3
- package/dist/heatmap-matrix/index.js +6 -6
- package/dist/io/decompress.d.ts +2 -1
- package/dist/io/decompress.js +1 -1
- package/dist/io/export.js +1 -1
- package/dist/io/index.d.ts +1 -1
- package/dist/io/index.js +0 -1
- package/dist/io/url-drop.js +7 -1
- package/dist/isosurface/IsosurfaceControls.svelte +11 -25
- package/dist/isosurface/slice.js +1 -1
- package/dist/isosurface/types.js +12 -12
- package/dist/labels.d.ts +1 -1
- package/dist/labels.js +14 -11
- package/dist/layout/InfoTag.svelte +6 -4
- package/dist/layout/PropertyFilter.svelte +4 -2
- package/dist/layout/json-tree/JsonTree.svelte +22 -14
- package/dist/layout/json-tree/JsonValue.svelte +2 -2
- package/dist/layout/json-tree/types.d.ts +3 -2
- package/dist/layout/json-tree/types.js +0 -1
- package/dist/layout/json-tree/utils.d.ts +4 -4
- package/dist/layout/json-tree/utils.js +12 -20
- package/dist/marching-cubes.js +13 -15
- package/dist/math.d.ts +11 -1
- package/dist/math.js +15 -6
- package/dist/overlays/DragControlTab.svelte +98 -0
- package/dist/overlays/DragControlTab.svelte.d.ts +8 -0
- package/dist/overlays/DraggablePane.svelte +7 -84
- package/dist/overlays/index.d.ts +1 -0
- package/dist/overlays/index.js +1 -0
- package/dist/periodic-table/PeriodicTable.svelte +11 -11
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +4 -2
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramControls.svelte +4 -9
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +2 -10
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte +2 -3
- package/dist/phase-diagram/TdbInfoPanel.svelte +3 -3
- package/dist/phase-diagram/build-diagram.js +11 -18
- package/dist/phase-diagram/diagram-input.d.ts +5 -9
- package/dist/phase-diagram/index.d.ts +2 -2
- package/dist/phase-diagram/index.js +0 -2
- package/dist/phase-diagram/parse.d.ts +2 -2
- package/dist/phase-diagram/parse.js +6 -10
- package/dist/phase-diagram/svg-to-diagram.js +15 -15
- package/dist/phase-diagram/types.d.ts +5 -11
- package/dist/phase-diagram/utils.d.ts +2 -2
- package/dist/phase-diagram/utils.js +9 -11
- package/dist/plot/BarPlot.svelte +162 -314
- package/dist/plot/BarPlot.svelte.d.ts +5 -4
- package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
- package/dist/plot/BinnedScatterPlot.svelte +1114 -0
- package/dist/plot/BinnedScatterPlot.svelte.d.ts +66 -0
- package/dist/plot/ColorBar.svelte +19 -17
- package/dist/plot/ColorBar.svelte.d.ts +1 -1
- package/dist/plot/FillArea.svelte +2 -4
- package/dist/plot/FillArea.svelte.d.ts +1 -1
- package/dist/plot/Histogram.svelte +167 -281
- package/dist/plot/Histogram.svelte.d.ts +1 -1
- package/dist/plot/HistogramControls.svelte.d.ts +1 -1
- package/dist/plot/InteractiveAxisLabel.svelte +5 -3
- package/dist/plot/InteractiveAxisLabel.svelte.d.ts +1 -1
- package/dist/plot/PlotAxis.svelte +169 -0
- package/dist/plot/PlotAxis.svelte.d.ts +24 -0
- package/dist/plot/PlotControls.svelte.d.ts +1 -1
- package/dist/plot/ReferenceLine3D.svelte +53 -51
- package/dist/plot/ReferencePlane.svelte +39 -42
- package/dist/plot/ScatterPlot.svelte +300 -367
- package/dist/plot/ScatterPlot.svelte.d.ts +8 -5
- package/dist/plot/ScatterPlot3D.svelte +33 -6
- package/dist/plot/ScatterPlot3D.svelte.d.ts +3 -2
- package/dist/plot/ScatterPlot3DControls.svelte +9 -9
- package/dist/plot/ScatterPlotControls.svelte +3 -4
- package/dist/plot/ScatterPoint.svelte +18 -27
- package/dist/plot/ScatterPoint.svelte.d.ts +4 -3
- package/dist/plot/Surface3D.svelte +4 -7
- package/dist/plot/ZeroLines.svelte +2 -1
- package/dist/plot/ZeroLines.svelte.d.ts +2 -1
- package/dist/plot/ZoomRect.svelte +2 -2
- package/dist/plot/ZoomRect.svelte.d.ts +3 -3
- package/dist/plot/adaptive-density.d.ts +69 -0
- package/dist/plot/adaptive-density.js +191 -0
- package/dist/plot/auto-place.d.ts +43 -0
- package/dist/plot/auto-place.js +122 -0
- package/dist/plot/axis-utils.js +3 -5
- package/dist/plot/binned-scatter-types.d.ts +59 -0
- package/dist/plot/binned-scatter-types.js +1 -0
- package/dist/plot/data-cleaning.js +1 -1
- package/dist/plot/data-transform.js +1 -1
- package/dist/plot/fill-utils.d.ts +4 -9
- package/dist/plot/fill-utils.js +29 -44
- package/dist/plot/index.d.ts +4 -0
- package/dist/plot/index.js +2 -0
- package/dist/plot/interactions.d.ts +4 -4
- package/dist/plot/interactions.js +4 -3
- package/dist/plot/layout.d.ts +20 -2
- package/dist/plot/layout.js +59 -16
- package/dist/plot/reference-line.d.ts +1 -1
- package/dist/plot/reference-line.js +9 -11
- package/dist/plot/scales.d.ts +1 -1
- package/dist/plot/scales.js +20 -23
- package/dist/plot/types.d.ts +30 -58
- package/dist/plot/types.js +2 -6
- package/dist/plot/utils/label-placement.d.ts +24 -3
- package/dist/plot/utils/label-placement.js +82 -12
- package/dist/plot/utils/series-visibility.d.ts +8 -2
- package/dist/plot/utils/series-visibility.js +23 -5
- package/dist/rdf/RdfPlot.svelte +5 -5
- package/dist/rdf/calc-rdf.js +3 -3
- package/dist/sanitize.d.ts +2 -0
- package/dist/sanitize.js +2 -0
- package/dist/spectral/Bands.svelte +1 -1
- package/dist/spectral/BandsAndDos.svelte +22 -16
- package/dist/spectral/BrillouinBandsDos.svelte +20 -16
- package/dist/spectral/Dos.svelte +1 -1
- package/dist/spectral/helpers.d.ts +4 -2
- package/dist/spectral/helpers.js +44 -35
- package/dist/spectral/index.d.ts +1 -1
- package/dist/spectral/index.js +0 -1
- package/dist/structure/AtomLegend.svelte +23 -6
- package/dist/structure/AtomLegend.svelte.d.ts +1 -0
- package/dist/structure/CanvasTooltip.svelte +9 -9
- package/dist/structure/CanvasTooltip.svelte.d.ts +1 -1
- package/dist/structure/CellSelect.svelte +14 -16
- package/dist/structure/Structure.svelte +317 -68
- package/dist/structure/Structure.svelte.d.ts +4 -2
- package/dist/structure/StructureControls.svelte +20 -45
- package/dist/structure/StructureExportPane.svelte +2 -1
- package/dist/structure/StructureInfoPane.svelte +10 -8
- package/dist/structure/StructureScene.svelte +527 -177
- package/dist/structure/StructureScene.svelte.d.ts +5 -2
- package/dist/structure/atom-properties.js +4 -4
- package/dist/structure/bond-order-perception.js +115 -98
- package/dist/structure/bonding.d.ts +27 -1
- package/dist/structure/bonding.js +187 -16
- package/dist/structure/export.js +1 -1
- package/dist/structure/index.d.ts +3 -2
- package/dist/structure/index.js +0 -2
- package/dist/structure/parse.js +88 -59
- package/dist/symmetry/WyckoffTable.svelte +7 -0
- package/dist/symmetry/index.js +13 -14
- package/dist/table/HeatmapTable.svelte +45 -66
- package/dist/table/HeatmapTable.svelte.d.ts +1 -1
- package/dist/table/ToggleMenu.svelte +19 -10
- package/dist/theme/themes.mjs +12 -0
- package/dist/tooltip/index.d.ts +1 -1
- package/dist/tooltip/index.js +0 -1
- package/dist/trajectory/Trajectory.svelte +43 -15
- package/dist/trajectory/TrajectoryInfoPane.svelte +2 -2
- package/dist/trajectory/extract.js +1 -1
- package/dist/trajectory/frame-reader.js +4 -4
- package/dist/trajectory/helpers.d.ts +5 -4
- package/dist/trajectory/helpers.js +9 -17
- package/dist/trajectory/index.d.ts +2 -2
- package/dist/trajectory/index.js +2 -2
- package/dist/trajectory/parse/ase.js +4 -4
- package/dist/trajectory/parse/hdf5.js +1 -1
- package/dist/trajectory/parse/index.js +2 -3
- package/dist/trajectory/parse/lammps.js +1 -1
- package/dist/trajectory/parse/vasp.js +1 -1
- package/dist/trajectory/plotting.d.ts +1 -1
- package/dist/trajectory/plotting.js +38 -38
- package/dist/trajectory/types.d.ts +1 -1
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +9 -0
- package/dist/xrd/calc-xrd.js +3 -4
- package/dist/xrd/parse.js +1 -1
- package/package.json +42 -22
|
@@ -3,7 +3,7 @@ import type { ElementSymbol } from '../element';
|
|
|
3
3
|
import type { IsosurfaceSettings, VolumetricData } from '../isosurface/types';
|
|
4
4
|
import type { Vec3 } from '../math';
|
|
5
5
|
import type { CameraProjection, ShowBonds, VectorColorMode, VectorLayerConfig } from '../settings';
|
|
6
|
-
import type { AnyStructure, MeasureMode, Site, StructureBond } from './';
|
|
6
|
+
import type { AnyStructure, BondEditMode, BondOrder, MeasureMode, Site, StructureBond } from './';
|
|
7
7
|
import { Lattice } from './';
|
|
8
8
|
import type { AtomColorConfig } from './atom-properties';
|
|
9
9
|
import type { MoyoDataset } from '@spglib/moyo-wasm';
|
|
@@ -78,6 +78,8 @@ type $$ComponentProps = {
|
|
|
78
78
|
removed_bonds?: StructureBond[];
|
|
79
79
|
bond_order_overrides?: StructureBond[];
|
|
80
80
|
bond_edits_enabled?: boolean;
|
|
81
|
+
bond_edit_mode?: BondEditMode;
|
|
82
|
+
bond_edit_order?: BondOrder;
|
|
81
83
|
selection_highlight_color?: string;
|
|
82
84
|
active_sites?: number[];
|
|
83
85
|
active_highlight_color?: string;
|
|
@@ -95,6 +97,7 @@ type $$ComponentProps = {
|
|
|
95
97
|
sym_data?: MoyoDataset | null;
|
|
96
98
|
on_sites_moved?: (scene_indices: number[], delta: Vec3) => void;
|
|
97
99
|
on_operation_start?: () => void;
|
|
100
|
+
on_bond_edit_start?: () => void;
|
|
98
101
|
on_add_atom?: (xyz: Vec3, element: ElementSymbol) => void;
|
|
99
102
|
add_atom_mode?: boolean;
|
|
100
103
|
add_element?: ElementSymbol;
|
|
@@ -103,6 +106,6 @@ type $$ComponentProps = {
|
|
|
103
106
|
volumetric_data?: VolumetricData;
|
|
104
107
|
isosurface_settings?: IsosurfaceSettings;
|
|
105
108
|
};
|
|
106
|
-
declare const StructureScene: import("svelte").Component<$$ComponentProps, {}, "cursor" | "site_label_offset" | "vector_configs" | "camera" | "scene" | "orbit_controls" | "site_radius_overrides" | "hovered_idx" | "hovered_site" | "camera_is_moving" | "selected_sites" | "measured_sites" | "added_bonds" | "removed_bonds" | "bond_order_overrides" | "active_sites" | "rotation_target_ref" | "initial_computed_zoom" | "hidden_elements" | "hidden_prop_vals" | "element_radius_overrides" | "add_atom_mode" | "add_element" | "dragging_atoms">;
|
|
109
|
+
declare const StructureScene: import("svelte").Component<$$ComponentProps, {}, "cursor" | "site_label_offset" | "vector_configs" | "camera" | "scene" | "orbit_controls" | "site_radius_overrides" | "hovered_idx" | "hovered_site" | "camera_is_moving" | "selected_sites" | "measured_sites" | "added_bonds" | "removed_bonds" | "bond_order_overrides" | "bond_edit_mode" | "active_sites" | "rotation_target_ref" | "initial_computed_zoom" | "hidden_elements" | "hidden_prop_vals" | "element_radius_overrides" | "add_atom_mode" | "add_element" | "dragging_atoms">;
|
|
107
110
|
type StructureScene = ReturnType<typeof StructureScene>;
|
|
108
111
|
export default StructureScene;
|
|
@@ -126,11 +126,11 @@ export function get_coordination_colors(structure, strategy = `electroneg_ratio`
|
|
|
126
126
|
return build_prop_colors(coord_nums, colors, unique_values);
|
|
127
127
|
}
|
|
128
128
|
export function get_wyckoff_colors(structure, sym_data, scale = DEFAULT_COLOR_SCALE) {
|
|
129
|
-
const
|
|
129
|
+
const n_sites = structure.sites.length;
|
|
130
130
|
if (!sym_data?.wyckoffs || sym_data.wyckoffs.length === 0) {
|
|
131
131
|
return {
|
|
132
|
-
colors: Array(
|
|
133
|
-
values: Array(
|
|
132
|
+
colors: Array(n_sites).fill(GRAY),
|
|
133
|
+
values: Array(n_sites).fill(`unknown`),
|
|
134
134
|
unique_values: [`unknown`],
|
|
135
135
|
};
|
|
136
136
|
}
|
|
@@ -155,7 +155,7 @@ export function get_wyckoff_colors(structure, sym_data, scale = DEFAULT_COLOR_SC
|
|
|
155
155
|
}
|
|
156
156
|
if (sym_idx >= sym_data.wyckoffs.length) {
|
|
157
157
|
console.error(`[get_wyckoff_colors] Site ${idx} (maps to ${sym_idx}) has no Wyckoff data. ` +
|
|
158
|
-
`Structure has ${
|
|
158
|
+
`Structure has ${n_sites} sites but symmetry data only has ${sym_data.wyckoffs.length}.`);
|
|
159
159
|
return `unknown`;
|
|
160
160
|
}
|
|
161
161
|
const wyckoff = sym_data.wyckoffs[sym_idx];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { get_bond_key } from './bonding';
|
|
2
2
|
const primary_element = (site) => {
|
|
3
|
-
return (site.species?.reduce((
|
|
3
|
+
return (site.species?.reduce((best_species, species) => (species.occu > best_species.occu ? species : best_species), site.species[0])?.element ?? ``);
|
|
4
4
|
};
|
|
5
5
|
// xyz2mol atomic_valence. Valence combinations are re-sorted by total
|
|
6
6
|
// valence sum so the least-saturated solution is tried first.
|
|
@@ -51,19 +51,17 @@ function formal_charge(symbol, bond_valence) {
|
|
|
51
51
|
return 0;
|
|
52
52
|
return VALENCE_ELECTRONS[symbol] - 8 + bond_valence;
|
|
53
53
|
}
|
|
54
|
-
|
|
55
|
-
return symbol in ATOMIC_VALENCE;
|
|
56
|
-
}
|
|
54
|
+
const is_main_group = (symbol) => symbol in ATOMIC_VALENCE;
|
|
57
55
|
// Cap per-fragment valence enumeration (3^k for catenated S/Se/Te/P chains).
|
|
58
56
|
const MAX_VALENCE_COMBOS = 4096;
|
|
59
57
|
function split_fragments(n_atoms, edges) {
|
|
60
58
|
const adjacency = Array.from({ length: n_atoms }, () => []);
|
|
61
|
-
for (const [
|
|
62
|
-
if (adjacency[
|
|
63
|
-
throw new Error(`Invalid edge ${
|
|
59
|
+
for (const [atom_idx_1, atom_idx_2] of edges) {
|
|
60
|
+
if (adjacency[atom_idx_1] === undefined || adjacency[atom_idx_2] === undefined) {
|
|
61
|
+
throw new Error(`Invalid edge ${atom_idx_1}-${atom_idx_2} for ${n_atoms} atoms`);
|
|
64
62
|
}
|
|
65
|
-
adjacency[
|
|
66
|
-
adjacency[
|
|
63
|
+
adjacency[atom_idx_1].push(atom_idx_2);
|
|
64
|
+
adjacency[atom_idx_2].push(atom_idx_1);
|
|
67
65
|
}
|
|
68
66
|
const seen = new Set();
|
|
69
67
|
const fragments = [];
|
|
@@ -95,18 +93,21 @@ function* valence_combinations(valence_lists) {
|
|
|
95
93
|
const combos = [];
|
|
96
94
|
const rec = (pos, acc) => {
|
|
97
95
|
if (pos === valence_lists.length) {
|
|
98
|
-
combos.push({
|
|
96
|
+
combos.push({
|
|
97
|
+
sum: acc.reduce((sum, valence) => sum + valence, 0),
|
|
98
|
+
pick: [...acc],
|
|
99
|
+
});
|
|
99
100
|
return;
|
|
100
101
|
}
|
|
101
|
-
for (const
|
|
102
|
-
rec(pos + 1, [...acc,
|
|
102
|
+
for (const valence of valence_lists[pos])
|
|
103
|
+
rec(pos + 1, [...acc, valence]);
|
|
103
104
|
};
|
|
104
105
|
rec(0, []);
|
|
105
|
-
combos.sort((
|
|
106
|
-
for (const
|
|
107
|
-
yield
|
|
106
|
+
combos.sort((left_combo, right_combo) => left_combo.sum - right_combo.sum);
|
|
107
|
+
for (const combo of combos)
|
|
108
|
+
yield combo.pick;
|
|
108
109
|
}
|
|
109
|
-
const atom_valence = (atom, edges, orders) => edges.reduce((sum, edge, edge_idx) => sum + (edge.
|
|
110
|
+
const atom_valence = (atom, edges, orders) => edges.reduce((sum, edge, edge_idx) => sum + (edge.from === atom || edge.to === atom ? orders[edge_idx] : 0), 0);
|
|
110
111
|
// Greedily raise bond orders toward each atom's target valence; succeeds
|
|
111
112
|
// only if every atom's used valence ends exactly at its target.
|
|
112
113
|
function assign_bond_orders(edges, target_valence) {
|
|
@@ -117,13 +118,13 @@ function assign_bond_orders(edges, target_valence) {
|
|
|
117
118
|
progressed = false;
|
|
118
119
|
let best = -1;
|
|
119
120
|
let best_deficit = 0;
|
|
120
|
-
edges.forEach((
|
|
121
|
-
const
|
|
122
|
-
const
|
|
123
|
-
const
|
|
124
|
-
if (
|
|
125
|
-
best_deficit =
|
|
126
|
-
best =
|
|
121
|
+
edges.forEach((edge, edge_idx) => {
|
|
122
|
+
const deficit_1 = target_valence[edge.from] - used(edge.from);
|
|
123
|
+
const deficit_2 = target_valence[edge.to] - used(edge.to);
|
|
124
|
+
const shared_deficit = Math.min(deficit_1, deficit_2);
|
|
125
|
+
if (shared_deficit > best_deficit && orders[edge_idx] < 3) {
|
|
126
|
+
best_deficit = shared_deficit;
|
|
127
|
+
best = edge_idx;
|
|
127
128
|
}
|
|
128
129
|
});
|
|
129
130
|
if (best >= 0) {
|
|
@@ -138,46 +139,52 @@ function assign_bond_orders(edges, target_valence) {
|
|
|
138
139
|
return orders;
|
|
139
140
|
}
|
|
140
141
|
// Spanning-tree cycle basis, deduplicated by sorted vertex set.
|
|
141
|
-
function find_rings(
|
|
142
|
-
const adjacency = Array.from({ length:
|
|
143
|
-
for (const [
|
|
144
|
-
if (adjacency[
|
|
145
|
-
throw new Error(`Invalid edge ${
|
|
142
|
+
function find_rings(n_atoms, edges) {
|
|
143
|
+
const adjacency = Array.from({ length: n_atoms }, () => new Set());
|
|
144
|
+
for (const [atom_idx_1, atom_idx_2] of edges) {
|
|
145
|
+
if (adjacency[atom_idx_1] === undefined || adjacency[atom_idx_2] === undefined) {
|
|
146
|
+
throw new Error(`Invalid edge ${atom_idx_1}-${atom_idx_2} for ${n_atoms} atoms`);
|
|
146
147
|
}
|
|
147
|
-
adjacency[
|
|
148
|
-
adjacency[
|
|
148
|
+
adjacency[atom_idx_1].add(atom_idx_2);
|
|
149
|
+
adjacency[atom_idx_2].add(atom_idx_1);
|
|
149
150
|
}
|
|
150
|
-
const parent = Array.from({ length:
|
|
151
|
+
const parent = Array.from({ length: n_atoms }, () => -1);
|
|
151
152
|
const seen = new Set();
|
|
152
153
|
const rings = [];
|
|
153
|
-
|
|
154
|
-
|
|
154
|
+
const path_to_ancestor = (start_idx, ancestor_idx) => {
|
|
155
|
+
const path = [];
|
|
156
|
+
for (let path_atom_idx = start_idx; path_atom_idx !== ancestor_idx; path_atom_idx = parent[path_atom_idx]) {
|
|
157
|
+
path.push(path_atom_idx);
|
|
158
|
+
}
|
|
159
|
+
return path;
|
|
160
|
+
};
|
|
161
|
+
for (let start_idx = 0; start_idx < n_atoms; start_idx++) {
|
|
162
|
+
if (seen.has(start_idx))
|
|
155
163
|
continue;
|
|
156
|
-
const queue = [
|
|
164
|
+
const queue = [start_idx];
|
|
157
165
|
let queue_idx = 0;
|
|
158
|
-
seen.add(
|
|
159
|
-
parent[
|
|
166
|
+
seen.add(start_idx);
|
|
167
|
+
parent[start_idx] = -1;
|
|
160
168
|
while (queue_idx < queue.length) {
|
|
161
|
-
const
|
|
162
|
-
for (const
|
|
163
|
-
if (!seen.has(
|
|
164
|
-
seen.add(
|
|
165
|
-
parent[
|
|
166
|
-
queue.push(
|
|
169
|
+
const current_atom_idx = queue[queue_idx++];
|
|
170
|
+
for (const neighbor_idx of adjacency[current_atom_idx]) {
|
|
171
|
+
if (!seen.has(neighbor_idx)) {
|
|
172
|
+
seen.add(neighbor_idx);
|
|
173
|
+
parent[neighbor_idx] = current_atom_idx;
|
|
174
|
+
queue.push(neighbor_idx);
|
|
167
175
|
}
|
|
168
|
-
else if (parent[
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const ring = [x, ...path_u, ...path_v.toReversed()];
|
|
176
|
+
else if (parent[current_atom_idx] !== neighbor_idx) {
|
|
177
|
+
const current_ancestors = new Set();
|
|
178
|
+
for (let ancestor_idx = current_atom_idx; ancestor_idx !== -1; ancestor_idx = parent[ancestor_idx]) {
|
|
179
|
+
current_ancestors.add(ancestor_idx);
|
|
180
|
+
}
|
|
181
|
+
for (let ancestor_idx = neighbor_idx; ancestor_idx !== -1; ancestor_idx = parent[ancestor_idx]) {
|
|
182
|
+
if (current_ancestors.has(ancestor_idx)) {
|
|
183
|
+
const ring = [
|
|
184
|
+
ancestor_idx,
|
|
185
|
+
...path_to_ancestor(current_atom_idx, ancestor_idx),
|
|
186
|
+
...path_to_ancestor(neighbor_idx, ancestor_idx).toReversed(),
|
|
187
|
+
];
|
|
181
188
|
if (ring.length >= 3)
|
|
182
189
|
rings.push(ring);
|
|
183
190
|
break;
|
|
@@ -188,31 +195,39 @@ function find_rings(n, edges) {
|
|
|
188
195
|
}
|
|
189
196
|
}
|
|
190
197
|
const uniq = new Map();
|
|
191
|
-
for (const
|
|
192
|
-
const key = [...
|
|
198
|
+
for (const ring of rings) {
|
|
199
|
+
const key = [...ring].sort((left_idx, right_idx) => left_idx - right_idx).join(`,`);
|
|
193
200
|
if (!uniq.has(key))
|
|
194
|
-
uniq.set(key,
|
|
201
|
+
uniq.set(key, ring);
|
|
195
202
|
}
|
|
196
203
|
return [...uniq.values()];
|
|
197
204
|
}
|
|
198
|
-
|
|
199
|
-
return o >= 3 ? 3 : o === 2 ? 2 : 1;
|
|
200
|
-
}
|
|
205
|
+
const order_to_bond_order = (order) => order >= 3 ? 3 : order === 2 ? 2 : 1;
|
|
201
206
|
// Conservative planarity check: degenerate first-3-atom planes are non-planar.
|
|
202
207
|
function ring_is_planar(ring, sites) {
|
|
203
208
|
if (ring.length < 3)
|
|
204
209
|
return false;
|
|
205
|
-
const
|
|
206
|
-
const v1 = [
|
|
207
|
-
|
|
210
|
+
const points = ring.map((atom_idx) => sites[atom_idx].xyz);
|
|
211
|
+
const v1 = [
|
|
212
|
+
points[1][0] - points[0][0],
|
|
213
|
+
points[1][1] - points[0][1],
|
|
214
|
+
points[1][2] - points[0][2],
|
|
215
|
+
];
|
|
216
|
+
const v2 = [
|
|
217
|
+
points[2][0] - points[0][0],
|
|
218
|
+
points[2][1] - points[0][1],
|
|
219
|
+
points[2][2] - points[0][2],
|
|
220
|
+
];
|
|
208
221
|
const nx = v1[1] * v2[2] - v1[2] * v2[1];
|
|
209
222
|
const ny = v1[2] * v2[0] - v1[0] * v2[2];
|
|
210
223
|
const nz = v1[0] * v2[1] - v1[1] * v2[0];
|
|
211
224
|
const len = Math.hypot(nx, ny, nz);
|
|
212
225
|
if (len < 1e-6)
|
|
213
226
|
return false;
|
|
214
|
-
return
|
|
215
|
-
const dev = Math.abs((
|
|
227
|
+
return points.every((point) => {
|
|
228
|
+
const dev = Math.abs((point[0] - points[0][0]) * nx +
|
|
229
|
+
(point[1] - points[0][1]) * ny +
|
|
230
|
+
(point[2] - points[0][2]) * nz) / len;
|
|
216
231
|
return dev < 0.3;
|
|
217
232
|
});
|
|
218
233
|
}
|
|
@@ -225,7 +240,7 @@ const SP2_OK = new Set([`C`, `N`, `O`, `S`]);
|
|
|
225
240
|
export function perceive_bond_orders(sites, bonds, opts = {}) {
|
|
226
241
|
const max_atoms = opts.max_atoms ?? 5000;
|
|
227
242
|
if (sites.length > max_atoms) {
|
|
228
|
-
return bonds.map((
|
|
243
|
+
return bonds.map((bond) => ({ ...bond, bond_order: 1, perceived: false }));
|
|
229
244
|
}
|
|
230
245
|
const edges = [];
|
|
231
246
|
const result = new Map();
|
|
@@ -237,30 +252,30 @@ export function perceive_bond_orders(sites, bonds, opts = {}) {
|
|
|
237
252
|
bond.site_idx_2 >= sites.length)
|
|
238
253
|
continue;
|
|
239
254
|
edges.push({
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
255
|
+
from: bond.site_idx_1,
|
|
256
|
+
to: bond.site_idx_2,
|
|
257
|
+
bond,
|
|
243
258
|
});
|
|
244
259
|
}
|
|
245
|
-
const frags = split_fragments(sites.length, edges.map((
|
|
260
|
+
const frags = split_fragments(sites.length, edges.map((edge) => [edge.from, edge.to]));
|
|
246
261
|
let ring_id = 0;
|
|
247
262
|
for (const frag of frags) {
|
|
248
263
|
const atom_set = new Set(frag);
|
|
249
|
-
const frag_edges = edges.filter((
|
|
250
|
-
const symbols = frag.map((
|
|
264
|
+
const frag_edges = edges.filter((edge) => atom_set.has(edge.from));
|
|
265
|
+
const symbols = frag.map((atom_idx) => primary_element(sites[atom_idx]));
|
|
251
266
|
if (!symbols.every(is_main_group))
|
|
252
267
|
continue;
|
|
253
268
|
const idx_of = Array.from({ length: sites.length }, () => -1);
|
|
254
269
|
frag.forEach((site_idx, local_idx) => {
|
|
255
270
|
idx_of[site_idx] = local_idx;
|
|
256
271
|
});
|
|
257
|
-
const local_edges = frag_edges.map((
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
272
|
+
const local_edges = frag_edges.map((edge) => ({
|
|
273
|
+
from: idx_of[edge.from],
|
|
274
|
+
to: idx_of[edge.to],
|
|
275
|
+
bond: edge.bond,
|
|
261
276
|
}));
|
|
262
|
-
const valence_lists = symbols.map((
|
|
263
|
-
const combo_count = valence_lists.reduce((
|
|
277
|
+
const valence_lists = symbols.map((symbol) => ATOMIC_VALENCE[symbol]);
|
|
278
|
+
const combo_count = valence_lists.reduce((product, valence_list) => product * valence_list.length, 1);
|
|
264
279
|
if (combo_count > MAX_VALENCE_COMBOS)
|
|
265
280
|
continue;
|
|
266
281
|
let solved = null;
|
|
@@ -270,8 +285,8 @@ export function perceive_bond_orders(sites, bonds, opts = {}) {
|
|
|
270
285
|
if (!candidate)
|
|
271
286
|
continue;
|
|
272
287
|
let sum_fc = 0;
|
|
273
|
-
for (let
|
|
274
|
-
sum_fc += formal_charge(symbols[
|
|
288
|
+
for (let local_atom_idx = 0; local_atom_idx < frag.length; local_atom_idx++) {
|
|
289
|
+
sum_fc += formal_charge(symbols[local_atom_idx], atom_valence(local_atom_idx, local_edges, candidate));
|
|
275
290
|
}
|
|
276
291
|
if (sum_fc === want_charge) {
|
|
277
292
|
solved = candidate;
|
|
@@ -280,35 +295,37 @@ export function perceive_bond_orders(sites, bonds, opts = {}) {
|
|
|
280
295
|
}
|
|
281
296
|
if (!solved)
|
|
282
297
|
continue;
|
|
283
|
-
local_edges.forEach((
|
|
284
|
-
const
|
|
285
|
-
result.set(
|
|
298
|
+
local_edges.forEach((edge, edge_idx) => {
|
|
299
|
+
const order = order_to_bond_order(solved[edge_idx]);
|
|
300
|
+
result.set(edge.bond, { ...edge.bond, bond_order: order, perceived: true });
|
|
286
301
|
});
|
|
287
302
|
// Hückel aromatic post-pass, retaining Kekulé orders for display toggles.
|
|
288
|
-
const rings = find_rings(frag.length, local_edges.map((
|
|
303
|
+
const rings = find_rings(frag.length, local_edges.map((edge) => [edge.from, edge.to]));
|
|
289
304
|
for (const ring of rings) {
|
|
290
|
-
const global_ring = ring.map((
|
|
291
|
-
|
|
305
|
+
const global_ring = ring.map((local_atom_idx) => frag[local_atom_idx]);
|
|
306
|
+
const has_only_sp2_ring_atoms = global_ring.every((global_atom_idx) => SP2_OK.has(primary_element(sites[global_atom_idx])));
|
|
307
|
+
if (!has_only_sp2_ring_atoms)
|
|
292
308
|
continue;
|
|
293
309
|
if (!ring_is_planar(global_ring, sites))
|
|
294
310
|
continue;
|
|
295
311
|
const ring_set = new Set(ring);
|
|
312
|
+
const edge_is_in_ring = (edge) => ring_set.has(edge.from) && ring_set.has(edge.to);
|
|
296
313
|
const has_ring_multiple = new Set();
|
|
297
|
-
local_edges.forEach((
|
|
298
|
-
if (
|
|
299
|
-
has_ring_multiple.add(
|
|
300
|
-
has_ring_multiple.add(
|
|
314
|
+
local_edges.forEach((edge, edge_idx) => {
|
|
315
|
+
if (edge_is_in_ring(edge) && solved[edge_idx] > 1) {
|
|
316
|
+
has_ring_multiple.add(edge.from);
|
|
317
|
+
has_ring_multiple.add(edge.to);
|
|
301
318
|
}
|
|
302
319
|
});
|
|
303
320
|
const has_any_multiple_bond = (atom_idx) => local_edges.some((edge, edge_idx) => {
|
|
304
|
-
if (edge.
|
|
321
|
+
if (edge.from !== atom_idx && edge.to !== atom_idx)
|
|
305
322
|
return false;
|
|
306
323
|
return solved[edge_idx] > 1;
|
|
307
324
|
});
|
|
308
325
|
const has_non_ring_neighbor = (atom_idx) => local_edges.some((edge) => {
|
|
309
|
-
if (edge.
|
|
326
|
+
if (edge.from !== atom_idx && edge.to !== atom_idx)
|
|
310
327
|
return false;
|
|
311
|
-
const neighbor_idx = edge.
|
|
328
|
+
const neighbor_idx = edge.from === atom_idx ? edge.to : edge.from;
|
|
312
329
|
return !ring_set.has(neighbor_idx);
|
|
313
330
|
});
|
|
314
331
|
const pi_by_atom = ring.map((atom_idx) => {
|
|
@@ -324,12 +341,12 @@ export function perceive_bond_orders(sites, bonds, opts = {}) {
|
|
|
324
341
|
const pi = pi_by_atom.reduce((sum, val) => sum + val, 0);
|
|
325
342
|
if (pi_by_atom.every((val) => val > 0) && pi >= 2 && (pi - 2) % 4 === 0) {
|
|
326
343
|
const this_ring = ring_id++;
|
|
327
|
-
local_edges.forEach((
|
|
328
|
-
if (
|
|
329
|
-
const prev = result.get(
|
|
344
|
+
local_edges.forEach((edge) => {
|
|
345
|
+
if (edge_is_in_ring(edge)) {
|
|
346
|
+
const prev = result.get(edge.bond);
|
|
330
347
|
if (prev === undefined)
|
|
331
348
|
throw new Error(`Missing perceived bond`);
|
|
332
|
-
result.set(
|
|
349
|
+
result.set(edge.bond, {
|
|
333
350
|
...prev,
|
|
334
351
|
bond_order: `aromatic`,
|
|
335
352
|
aromatic_ring: this_ring,
|
|
@@ -1,7 +1,32 @@
|
|
|
1
1
|
import type { Vec3 } from '../math';
|
|
2
|
-
import type { AnyStructure, BondOrder, BondPair, StructureBond } from './';
|
|
2
|
+
import type { AnyStructure, BondOrder, BondPair, Site, StructureBond } from './';
|
|
3
3
|
export declare const normalize_structure_bond: (site_idx_1: number, site_idx_2: number, order: BondOrder, cell_shift?: Vec3) => StructureBond;
|
|
4
4
|
export declare const get_bond_key: (idx_1: number, idx_2: number, cell_shift?: Vec3) => string;
|
|
5
|
+
export type BondEditState = {
|
|
6
|
+
added_bonds: StructureBond[];
|
|
7
|
+
removed_bonds: StructureBond[];
|
|
8
|
+
bond_order_overrides: StructureBond[];
|
|
9
|
+
};
|
|
10
|
+
export type BondEditAction = `added` | `already-visible` | `deleted-added` | `deleted-calculated` | `not-visible` | `ordered-added` | `ordered-calculated` | `restored`;
|
|
11
|
+
export type BondEditResult = {
|
|
12
|
+
action: BondEditAction;
|
|
13
|
+
changed: boolean;
|
|
14
|
+
state: BondEditState;
|
|
15
|
+
};
|
|
16
|
+
export type BondKeyTarget = Pick<StructureBond, `site_idx_1` | `site_idx_2` | `cell_shift`>;
|
|
17
|
+
type BondOrderTarget = BondKeyTarget & {
|
|
18
|
+
bond_order?: BondOrder;
|
|
19
|
+
order?: BondOrder;
|
|
20
|
+
};
|
|
21
|
+
export declare const BOND_ORDER_OPTIONS: {
|
|
22
|
+
order: BondOrder;
|
|
23
|
+
label: string;
|
|
24
|
+
}[];
|
|
25
|
+
export declare const canonicalize_bond_target: (bond: BondKeyTarget, sites: Site[] | undefined) => BondKeyTarget;
|
|
26
|
+
export declare function has_visible_bond(edit_state: BondEditState, bond: BondKeyTarget, calculated_bonds: BondOrderTarget[]): boolean;
|
|
27
|
+
export declare function add_or_restore_bond(edit_state: BondEditState, bond: BondKeyTarget, calculated_bonds: BondOrderTarget[], order: BondOrder): BondEditResult;
|
|
28
|
+
export declare function delete_bond(edit_state: BondEditState, bond: BondKeyTarget, calculated_bonds: BondOrderTarget[]): BondEditResult;
|
|
29
|
+
export declare function set_bond_order(edit_state: BondEditState, bond: BondKeyTarget, calculated_bonds: BondOrderTarget[], order: BondOrder): BondEditResult;
|
|
5
30
|
export declare const merge_bond_edits: (base_bonds: StructureBond[], added: StructureBond[], removed: StructureBond[], overrides: StructureBond[]) => StructureBond[];
|
|
6
31
|
export declare function normalize_bond_order(order: unknown): BondOrder | null;
|
|
7
32
|
export declare function structure_bond_to_bond_pair(structure: AnyStructure, bond: StructureBond): BondPair;
|
|
@@ -40,3 +65,4 @@ export declare function solid_angle(structure: AnyStructure, { min_solid_angle,
|
|
|
40
65
|
min_bond_dist?: number | undefined;
|
|
41
66
|
strength_threshold?: number | undefined;
|
|
42
67
|
}): BondPair[];
|
|
68
|
+
export {};
|