matterviz 0.1.12 → 0.1.13
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/ContextMenu.svelte +1 -1
- package/dist/ContextMenu.svelte.d.ts +3 -3
- package/dist/DraggablePane.svelte +10 -5
- package/dist/DraggablePane.svelte.d.ts +3 -3
- package/dist/FilePicker.svelte.d.ts +3 -3
- package/dist/Icon.svelte.d.ts +3 -3
- package/dist/Nav.svelte +76 -31
- package/dist/SettingsSection.svelte.d.ts +3 -3
- package/dist/Spinner.svelte +18 -29
- package/dist/Spinner.svelte.d.ts +3 -3
- package/dist/app.css +4 -0
- package/dist/bands/Bands.svelte +216 -0
- package/dist/bands/Bands.svelte.d.ts +16 -0
- package/dist/bands/BandsAndDos.svelte +26 -0
- package/dist/bands/BandsAndDos.svelte.d.ts +16 -0
- package/dist/bands/Dos.svelte +124 -0
- package/dist/bands/Dos.svelte.d.ts +18 -0
- package/dist/bands/helpers.d.ts +11 -0
- package/dist/bands/helpers.js +195 -0
- package/dist/bands/index.d.ts +5 -0
- package/dist/bands/index.js +6 -0
- package/dist/bands/types.d.ts +54 -0
- package/dist/bands/types.js +2 -0
- package/dist/brillouin/BrillouinZone.svelte +373 -0
- package/dist/brillouin/BrillouinZone.svelte.d.ts +57 -0
- package/dist/brillouin/BrillouinZoneControls.svelte +88 -0
- package/dist/brillouin/BrillouinZoneControls.svelte.d.ts +14 -0
- package/dist/brillouin/BrillouinZoneExportPane.svelte +129 -0
- package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +15 -0
- package/dist/brillouin/BrillouinZoneInfoPane.svelte +115 -0
- package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +13 -0
- package/dist/brillouin/BrillouinZoneScene.svelte +180 -0
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +34 -0
- package/dist/brillouin/compute.d.ts +7 -0
- package/dist/brillouin/compute.js +215 -0
- package/dist/brillouin/index.d.ts +7 -0
- package/dist/brillouin/index.js +7 -0
- package/dist/brillouin/types.d.ts +23 -0
- package/dist/brillouin/types.js +1 -0
- package/dist/composition/BarChart.svelte.d.ts +3 -3
- package/dist/composition/BubbleChart.svelte +7 -6
- package/dist/composition/BubbleChart.svelte.d.ts +3 -3
- package/dist/composition/Composition.svelte.d.ts +3 -3
- package/dist/composition/PieChart.svelte +1 -1
- package/dist/composition/PieChart.svelte.d.ts +3 -3
- package/dist/composition/parse.d.ts +3 -3
- package/dist/coordination/CoordinationBarPlot.svelte +241 -0
- package/dist/coordination/CoordinationBarPlot.svelte.d.ts +29 -0
- package/dist/coordination/calc-coordination.d.ts +15 -0
- package/dist/coordination/calc-coordination.js +66 -0
- package/dist/coordination/index.d.ts +8 -0
- package/dist/coordination/index.js +7 -0
- package/dist/element/BohrAtom.svelte.d.ts +3 -3
- package/dist/element/ElementHeading.svelte.d.ts +3 -3
- package/dist/element/ElementPhoto.svelte.d.ts +3 -3
- package/dist/element/ElementStats.svelte.d.ts +3 -3
- package/dist/element/ElementTile.svelte +1 -1
- package/dist/element/ElementTile.svelte.d.ts +4 -4
- package/dist/element/Nucleus.svelte.d.ts +3 -3
- package/dist/icons.d.ts +4 -0
- package/dist/icons.js +4 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.js +5 -1
- package/dist/io/export.d.ts +1 -6
- package/dist/io/export.js +12 -12
- package/dist/labels.d.ts +19 -0
- package/dist/labels.js +59 -0
- package/dist/math.d.ts +7 -2
- package/dist/math.js +24 -12
- package/dist/periodic-table/PeriodicTable.svelte.d.ts +3 -3
- package/dist/periodic-table/PeriodicTableControls.svelte.d.ts +3 -3
- package/dist/periodic-table/PropertySelect.svelte +1 -1
- package/dist/periodic-table/PropertySelect.svelte.d.ts +5 -4
- package/dist/periodic-table/TableInset.svelte.d.ts +3 -3
- package/dist/phase-diagram/PhaseDiagram2D.svelte +44 -107
- package/dist/phase-diagram/PhaseDiagram2D.svelte.d.ts +7 -27
- package/dist/phase-diagram/PhaseDiagram3D.svelte +67 -170
- package/dist/phase-diagram/PhaseDiagram3D.svelte.d.ts +7 -31
- package/dist/phase-diagram/PhaseDiagram4D.svelte +87 -145
- package/dist/phase-diagram/PhaseDiagram4D.svelte.d.ts +5 -28
- package/dist/phase-diagram/PhaseDiagramControls.svelte +9 -9
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +6 -6
- package/dist/phase-diagram/PhaseDiagramInfoPane.svelte +4 -4
- package/dist/phase-diagram/PhaseDiagramInfoPane.svelte.d.ts +5 -5
- package/dist/phase-diagram/PhaseDiagramStats.svelte +9 -16
- package/dist/phase-diagram/PhaseDiagramStats.svelte.d.ts +3 -3
- package/dist/phase-diagram/StructurePopup.svelte.d.ts +3 -3
- package/dist/phase-diagram/barycentric-coords.js +13 -24
- package/dist/phase-diagram/helpers.d.ts +12 -14
- package/dist/phase-diagram/helpers.js +70 -23
- package/dist/phase-diagram/index.d.ts +58 -0
- package/dist/phase-diagram/index.js +44 -0
- package/dist/phase-diagram/thermodynamics.js +2 -3
- package/dist/phase-diagram/types.d.ts +3 -8
- package/dist/plot/BarPlot.svelte +474 -240
- package/dist/plot/BarPlot.svelte.d.ts +16 -37
- package/dist/plot/BarPlotControls.svelte +33 -201
- package/dist/plot/BarPlotControls.svelte.d.ts +11 -22
- package/dist/plot/ColorBar.svelte.d.ts +3 -3
- package/dist/plot/ColorScaleSelect.svelte +1 -1
- package/dist/plot/ColorScaleSelect.svelte.d.ts +3 -3
- package/dist/plot/ElementScatter.svelte +5 -5
- package/dist/plot/ElementScatter.svelte.d.ts +8 -8
- package/dist/plot/Histogram.svelte +318 -170
- package/dist/plot/Histogram.svelte.d.ts +21 -41
- package/dist/plot/HistogramControls.svelte +115 -347
- package/dist/plot/HistogramControls.svelte.d.ts +13 -28
- package/dist/plot/Line.svelte +1 -1
- package/dist/plot/Line.svelte.d.ts +4 -4
- package/dist/plot/PlotControls.svelte +280 -0
- package/dist/plot/PlotControls.svelte.d.ts +4 -0
- package/dist/plot/PlotLegend.svelte +9 -24
- package/dist/plot/PlotLegend.svelte.d.ts +3 -3
- package/dist/plot/ScatterPlot.svelte +536 -571
- package/dist/plot/ScatterPlot.svelte.d.ts +18 -90
- package/dist/plot/ScatterPlotControls.svelte +108 -316
- package/dist/plot/ScatterPlotControls.svelte.d.ts +11 -38
- package/dist/plot/ScatterPoint.svelte +1 -1
- package/dist/plot/ScatterPoint.svelte.d.ts +5 -5
- package/dist/plot/SpacegroupBarPlot.svelte +235 -0
- package/dist/plot/SpacegroupBarPlot.svelte.d.ts +9 -0
- package/dist/plot/data-transform.d.ts +2 -2
- package/dist/plot/data-transform.js +1 -5
- package/dist/plot/index.d.ts +12 -200
- package/dist/plot/index.js +14 -6
- package/dist/plot/layout.d.ts +10 -16
- package/dist/plot/layout.js +40 -25
- package/dist/plot/scales.d.ts +7 -8
- package/dist/plot/scales.js +22 -7
- package/dist/plot/types.d.ts +303 -0
- package/dist/plot/types.js +1 -0
- package/dist/rdf/RdfPlot.svelte +156 -0
- package/dist/rdf/RdfPlot.svelte.d.ts +20 -0
- package/dist/rdf/calc-rdf.d.ts +4 -0
- package/dist/rdf/calc-rdf.js +107 -0
- package/dist/rdf/index.d.ts +22 -0
- package/dist/rdf/index.js +2 -0
- package/dist/settings.d.ts +86 -75
- package/dist/settings.js +257 -155
- package/dist/structure/Bond.svelte +126 -110
- package/dist/structure/Bond.svelte.d.ts +7 -20
- package/dist/structure/CanvasTooltip.svelte.d.ts +4 -4
- package/dist/structure/Cylinder.svelte +29 -0
- package/dist/structure/Cylinder.svelte.d.ts +10 -0
- package/dist/structure/Lattice.svelte +1 -2
- package/dist/structure/Lattice.svelte.d.ts +3 -3
- package/dist/structure/Structure.svelte +23 -8
- package/dist/structure/Structure.svelte.d.ts +10 -7
- package/dist/structure/StructureControls.svelte +25 -134
- package/dist/structure/StructureControls.svelte.d.ts +4 -9
- package/dist/structure/StructureExportPane.svelte +188 -0
- package/dist/structure/StructureExportPane.svelte.d.ts +17 -0
- package/dist/structure/StructureInfoPane.svelte.d.ts +3 -3
- package/dist/structure/StructureLegend.svelte +91 -27
- package/dist/structure/StructureLegend.svelte.d.ts +5 -4
- package/dist/structure/StructureScene.svelte +93 -100
- package/dist/structure/StructureScene.svelte.d.ts +15 -12
- package/dist/structure/Vector.svelte +19 -25
- package/dist/structure/Vector.svelte.d.ts +3 -3
- package/dist/structure/bonding.d.ts +16 -14
- package/dist/structure/bonding.js +207 -216
- package/dist/structure/export.d.ts +3 -0
- package/dist/structure/export.js +120 -0
- package/dist/structure/index.d.ts +15 -1
- package/dist/structure/index.js +2 -0
- package/dist/symmetry/WyckoffTable.svelte.d.ts +3 -3
- package/dist/symmetry/index.d.ts +1 -0
- package/dist/symmetry/index.js +1 -0
- package/dist/symmetry/spacegroups.d.ts +9 -0
- package/dist/symmetry/spacegroups.js +397 -0
- package/dist/theme/ThemeControl.svelte.d.ts +3 -3
- package/dist/theme/themes.js +2 -16
- package/dist/trajectory/Trajectory.svelte +52 -78
- package/dist/trajectory/Trajectory.svelte.d.ts +5 -5
- package/dist/trajectory/TrajectoryError.svelte.d.ts +3 -3
- package/dist/trajectory/TrajectoryExportPane.svelte +1 -1
- package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +5 -5
- package/dist/trajectory/TrajectoryInfoPane.svelte +1 -1
- package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +3 -3
- package/dist/trajectory/extract.js +2 -1
- package/dist/trajectory/index.d.ts +1 -1
- package/dist/trajectory/index.js +1 -1
- package/dist/trajectory/parse.js +21 -14
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +17 -0
- package/dist/xrd/XrdPlot.svelte +14 -11
- package/dist/xrd/XrdPlot.svelte.d.ts +6 -5
- package/package.json +20 -12
- package/readme.md +1 -1
- package/dist/material/MaterialCard.svelte +0 -123
- package/dist/material/MaterialCard.svelte.d.ts +0 -9
- package/dist/material/index.d.ts +0 -1
- package/dist/material/index.js +0 -1
- package/dist/plot/formatting.d.ts +0 -7
- package/dist/plot/formatting.js +0 -53
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
<script lang="ts">import { plot_colors } from '../colors';
|
|
2
|
+
import ScatterPlot from '../plot/ScatterPlot.svelte';
|
|
3
|
+
import { apply_gaussian_smearing, convert_frequencies, normalize_densities, normalize_dos, } from './helpers';
|
|
4
|
+
let { doses, stack = false, sigma = 0, units = `THz`, normalize = null, orientation = `vertical`, show_legend = true, x_axis = {}, y_axis = {}, ...rest } = $props();
|
|
5
|
+
// Normalize input to dict format
|
|
6
|
+
let doses_dict = $derived.by(() => {
|
|
7
|
+
if (!doses)
|
|
8
|
+
return {};
|
|
9
|
+
if (`densities` in doses && (`frequencies` in doses || `energies` in doses)) {
|
|
10
|
+
// Single DOS
|
|
11
|
+
const normalized = normalize_dos(doses);
|
|
12
|
+
return normalized ? { '': normalized } : {};
|
|
13
|
+
}
|
|
14
|
+
// Already a dict - normalize each DOS
|
|
15
|
+
const result = {};
|
|
16
|
+
for (const [key, dos] of Object.entries(doses)) {
|
|
17
|
+
const normalized = normalize_dos(dos);
|
|
18
|
+
if (normalized)
|
|
19
|
+
result[key] = normalized;
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
});
|
|
23
|
+
// Determine if this is phonon or electronic DOS using discriminated union
|
|
24
|
+
let is_phonon = $derived.by(() => {
|
|
25
|
+
const first_dos = Object.values(doses_dict)[0];
|
|
26
|
+
return first_dos?.type === `phonon`;
|
|
27
|
+
});
|
|
28
|
+
// Convert DOS data to scatter plot series
|
|
29
|
+
// Performance: Only recalculates when doses_dict, units, sigma, or normalize changes
|
|
30
|
+
let series_data = $derived.by(() => {
|
|
31
|
+
if (Object.keys(doses_dict).length === 0)
|
|
32
|
+
return []; // Early return for empty data
|
|
33
|
+
const all_series = [];
|
|
34
|
+
const dos_entries = Object.entries(doses_dict);
|
|
35
|
+
let cumulative_densities = null;
|
|
36
|
+
for (let dos_idx = 0; dos_idx < dos_entries.length; dos_idx++) {
|
|
37
|
+
const [label, dos] = dos_entries[dos_idx];
|
|
38
|
+
const color = plot_colors[dos_idx % plot_colors.length];
|
|
39
|
+
// Get frequencies or energies using discriminated union type narrowing
|
|
40
|
+
let x_values = dos.type === `phonon` ? dos.frequencies : dos.energies;
|
|
41
|
+
// Convert units if needed
|
|
42
|
+
if (dos.type === `phonon` && units !== `THz`) {
|
|
43
|
+
x_values = convert_frequencies(x_values, units);
|
|
44
|
+
}
|
|
45
|
+
// Apply Gaussian smearing if requested (expensive for large datasets)
|
|
46
|
+
let densities = sigma > 0
|
|
47
|
+
? apply_gaussian_smearing(x_values, dos.densities, sigma)
|
|
48
|
+
: [...dos.densities];
|
|
49
|
+
// Normalize densities
|
|
50
|
+
densities = normalize_densities(densities, x_values, normalize);
|
|
51
|
+
// For stacked plots, accumulate densities
|
|
52
|
+
if (stack && cumulative_densities) {
|
|
53
|
+
if (cumulative_densities.length !== densities.length) {
|
|
54
|
+
console.warn(`DOS stacking: length mismatch (cumulative=${cumulative_densities.length}, current=${densities.length})`);
|
|
55
|
+
}
|
|
56
|
+
densities = densities.map((d, idx) => d + (cumulative_densities?.[idx] ?? 0));
|
|
57
|
+
}
|
|
58
|
+
// Store cumulative for next iteration if stacking
|
|
59
|
+
if (stack)
|
|
60
|
+
cumulative_densities = densities;
|
|
61
|
+
// Determine x and y based on orientation
|
|
62
|
+
const series = orientation === `horizontal`
|
|
63
|
+
? {
|
|
64
|
+
x: densities,
|
|
65
|
+
y: x_values,
|
|
66
|
+
markers: `line`,
|
|
67
|
+
label: label || `DOS ${dos_idx + 1}`,
|
|
68
|
+
line_style: {
|
|
69
|
+
stroke: color,
|
|
70
|
+
stroke_width: 1.5,
|
|
71
|
+
},
|
|
72
|
+
point_style: {
|
|
73
|
+
fill: stack ? color : undefined,
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
: {
|
|
77
|
+
x: x_values,
|
|
78
|
+
y: densities,
|
|
79
|
+
markers: `line`,
|
|
80
|
+
label: label || `DOS ${dos_idx + 1}`,
|
|
81
|
+
line_style: {
|
|
82
|
+
stroke: color,
|
|
83
|
+
stroke_width: 1.5,
|
|
84
|
+
},
|
|
85
|
+
point_style: {
|
|
86
|
+
fill: stack ? color : undefined,
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
all_series.push(series);
|
|
90
|
+
}
|
|
91
|
+
return all_series;
|
|
92
|
+
});
|
|
93
|
+
// Calculate axis ranges
|
|
94
|
+
let x_range = $derived.by(() => {
|
|
95
|
+
if (!series_data.length)
|
|
96
|
+
return undefined;
|
|
97
|
+
const all_x = series_data.flatMap((s) => s.x);
|
|
98
|
+
return [Math.min(...all_x), Math.max(...all_x)];
|
|
99
|
+
});
|
|
100
|
+
let y_range = $derived.by(() => {
|
|
101
|
+
if (!series_data.length)
|
|
102
|
+
return undefined;
|
|
103
|
+
const all_y = series_data.flatMap((s) => s.y);
|
|
104
|
+
return [Math.min(...all_y), Math.max(...all_y)];
|
|
105
|
+
});
|
|
106
|
+
// Get axis labels based on orientation
|
|
107
|
+
let x_label = $derived(orientation === `horizontal`
|
|
108
|
+
? `Density of States`
|
|
109
|
+
: is_phonon
|
|
110
|
+
? `Frequency (${units})`
|
|
111
|
+
: `Energy (eV)`);
|
|
112
|
+
let y_label = $derived(orientation === `horizontal`
|
|
113
|
+
? is_phonon ? `Frequency (${units})` : `Energy (eV)`
|
|
114
|
+
: `Density of States`);
|
|
115
|
+
</script>
|
|
116
|
+
|
|
117
|
+
<ScatterPlot
|
|
118
|
+
series={series_data}
|
|
119
|
+
x_axis={{ label: x_label, format: `.2f`, range: x_range, ...x_axis }}
|
|
120
|
+
y_axis={{ label: y_label, format: `.2f`, range: y_range, ...y_axis }}
|
|
121
|
+
display={{ x_grid: true, y_grid: true, x_zero_line: true, y_zero_line: true }}
|
|
122
|
+
legend={show_legend ? {} : null}
|
|
123
|
+
{...rest}
|
|
124
|
+
/>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import ScatterPlot from '../plot/ScatterPlot.svelte';
|
|
2
|
+
import type { AxisConfig } from '../plot/types';
|
|
3
|
+
import type { ComponentProps } from 'svelte';
|
|
4
|
+
import type { Dos, FrequencyUnit, NormalizationMode } from './types';
|
|
5
|
+
type $$ComponentProps = ComponentProps<typeof ScatterPlot> & {
|
|
6
|
+
doses: Dos | Record<string, Dos>;
|
|
7
|
+
x_axis?: AxisConfig;
|
|
8
|
+
y_axis?: AxisConfig;
|
|
9
|
+
stack?: boolean;
|
|
10
|
+
sigma?: number;
|
|
11
|
+
units?: FrequencyUnit;
|
|
12
|
+
normalize?: NormalizationMode;
|
|
13
|
+
orientation?: `vertical` | `horizontal`;
|
|
14
|
+
show_legend?: boolean;
|
|
15
|
+
};
|
|
16
|
+
declare const Dos: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
17
|
+
type Dos = ReturnType<typeof Dos>;
|
|
18
|
+
export default Dos;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { BaseBandStructure, Dos, FrequencyUnit, NormalizationMode } from './types';
|
|
2
|
+
export declare const N_ACOUSTIC_MODES = 3;
|
|
3
|
+
export declare function pretty_sym_point(symbol: string): string;
|
|
4
|
+
export declare const get_segment_key: (start_label?: string, end_label?: string) => string;
|
|
5
|
+
export declare const get_ordered_segments: (band_struct: BaseBandStructure | null, segments: Set<string>) => string[];
|
|
6
|
+
export declare function get_band_xaxis_ticks(band_struct: BaseBandStructure, branches?: string[] | Set<string>): [number[], string[]];
|
|
7
|
+
export declare function convert_frequencies(frequencies: number[], unit?: FrequencyUnit): number[];
|
|
8
|
+
export declare function normalize_densities(densities: number[], freqs_or_energies: number[], mode: NormalizationMode): number[];
|
|
9
|
+
export declare function apply_gaussian_smearing(freqs_or_energies: number[], densities: number[], sigma: number): number[];
|
|
10
|
+
export declare function normalize_band_structure(bs: unknown): BaseBandStructure | null;
|
|
11
|
+
export declare function normalize_dos(dos: unknown): Dos | null;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
// Helper utilities for band structure and DOS data processing
|
|
2
|
+
import { subscript_map } from '../labels';
|
|
3
|
+
// Physical constants for unit conversions (SI units)
|
|
4
|
+
const PLANCK = 6.62607015e-34; // J⋅s
|
|
5
|
+
const EV_TO_J = 1.602176634e-19; // J
|
|
6
|
+
const C_LIGHT = 299792458; // m/s
|
|
7
|
+
const THz_TO_HZ = 1e12;
|
|
8
|
+
const THz_TO_EV = (PLANCK * THz_TO_HZ) / EV_TO_J;
|
|
9
|
+
const THz_TO_MEV = THz_TO_EV * 1000;
|
|
10
|
+
const THz_TO_HA = THz_TO_EV / 27.211386245988; // Hartree
|
|
11
|
+
const THz_TO_CM = (THz_TO_HZ / C_LIGHT) * 100; // cm^-1
|
|
12
|
+
// Band structure constants
|
|
13
|
+
export const N_ACOUSTIC_MODES = 3; // Number of acoustic modes in typical 3D crystals
|
|
14
|
+
// Convert symmetry point symbols to pretty-printed versions.
|
|
15
|
+
// Handles Greek letters and subscripts.
|
|
16
|
+
export function pretty_sym_point(symbol) {
|
|
17
|
+
if (!symbol)
|
|
18
|
+
return ``;
|
|
19
|
+
// Remove underscores (htmlify maps S0 → S<sub>0</sub> but leaves S_0 as is)
|
|
20
|
+
// Replace common symmetry point names with Greek letters
|
|
21
|
+
// Handle subscripts: convert S0 to S₀, K1 to K₁, Γ1 to Γ₁, etc.
|
|
22
|
+
// Use \p{L} to match any Unicode letter (not just ASCII A-Z)
|
|
23
|
+
return symbol
|
|
24
|
+
.replace(/_/g, ``)
|
|
25
|
+
.replace(/GAMMA/gi, `Γ`)
|
|
26
|
+
.replace(/DELTA/gi, `Δ`)
|
|
27
|
+
.replace(/SIGMA/gi, `Σ`)
|
|
28
|
+
.replace(/LAMBDA/gi, `Λ`)
|
|
29
|
+
.replace(/(\p{L})(\d+)/gu, (_, letter, num) => letter +
|
|
30
|
+
num.split(``).map((digit) => subscript_map[digit] ?? digit).join(``));
|
|
31
|
+
}
|
|
32
|
+
// Create segment key from start and end labels
|
|
33
|
+
export const get_segment_key = (start_label, end_label) => `${start_label ?? `null`}_${end_label ?? `null`}`;
|
|
34
|
+
// Get ordered segment keys from a band structure, preserving physical path order.
|
|
35
|
+
export const get_ordered_segments = (band_struct, segments) => {
|
|
36
|
+
if (!band_struct)
|
|
37
|
+
return Array.from(segments);
|
|
38
|
+
const ordered = band_struct.branches.map((br) => get_segment_key(band_struct.qpoints[br.start_index]?.label ?? undefined, band_struct.qpoints[br.end_index]?.label ?? undefined));
|
|
39
|
+
const remaining = Array.from(segments).filter((seg) => !ordered.includes(seg));
|
|
40
|
+
return [...ordered, ...remaining];
|
|
41
|
+
};
|
|
42
|
+
// Extract tick positions and labels for a band structure plot.
|
|
43
|
+
export function get_band_xaxis_ticks(band_struct, branches = []) {
|
|
44
|
+
const ticks_x_pos = [];
|
|
45
|
+
const tick_labels = [];
|
|
46
|
+
let prev_label = band_struct.qpoints[0]?.label || null;
|
|
47
|
+
let prev_branch = band_struct.branches[0]?.name || null;
|
|
48
|
+
// Convert branches to Set for consistent handling
|
|
49
|
+
const branches_set = Array.isArray(branches) ? new Set(branches) : branches;
|
|
50
|
+
for (let idx = 0; idx < band_struct.qpoints.length; idx++) {
|
|
51
|
+
const point = band_struct.qpoints[idx];
|
|
52
|
+
if (point.label === null)
|
|
53
|
+
continue;
|
|
54
|
+
// Find which branch this point belongs to
|
|
55
|
+
const branch_names = band_struct.branches
|
|
56
|
+
.filter((branch) => branch.start_index <= idx && idx <= branch.end_index)
|
|
57
|
+
.map((b) => b.name);
|
|
58
|
+
const this_branch = branch_names[0] || null;
|
|
59
|
+
if (point.label !== prev_label && prev_branch !== this_branch) {
|
|
60
|
+
// Branch transition - combine labels
|
|
61
|
+
tick_labels[tick_labels.length - 1] = `${prev_label || ``}|${point.label}`;
|
|
62
|
+
ticks_x_pos[ticks_x_pos.length - 1] = band_struct.distance[idx];
|
|
63
|
+
}
|
|
64
|
+
else if (branches_set.size === 0 || (this_branch && branches_set.has(this_branch))) {
|
|
65
|
+
tick_labels.push(point.label);
|
|
66
|
+
ticks_x_pos.push(band_struct.distance[idx]);
|
|
67
|
+
}
|
|
68
|
+
prev_label = point.label;
|
|
69
|
+
prev_branch = this_branch;
|
|
70
|
+
}
|
|
71
|
+
return [ticks_x_pos, tick_labels.map(pretty_sym_point)];
|
|
72
|
+
}
|
|
73
|
+
// Convert frequencies from THz to specified units.
|
|
74
|
+
export function convert_frequencies(frequencies, unit = `THz`) {
|
|
75
|
+
const conversion_factors = {
|
|
76
|
+
'THz': 1,
|
|
77
|
+
'eV': THz_TO_EV,
|
|
78
|
+
'meV': THz_TO_MEV,
|
|
79
|
+
'Ha': THz_TO_HA,
|
|
80
|
+
'cm-1': THz_TO_CM,
|
|
81
|
+
};
|
|
82
|
+
const factor = conversion_factors[unit];
|
|
83
|
+
if (!factor) {
|
|
84
|
+
const valid_units = Object.keys(conversion_factors).join(`, `);
|
|
85
|
+
throw new Error(`Invalid unit: ${unit}. Must be one of ${valid_units}`);
|
|
86
|
+
}
|
|
87
|
+
return frequencies.map((f) => f * factor);
|
|
88
|
+
}
|
|
89
|
+
// Normalize DOS densities according to specified mode.
|
|
90
|
+
export function normalize_densities(densities, freqs_or_energies, mode) {
|
|
91
|
+
if (!mode)
|
|
92
|
+
return densities;
|
|
93
|
+
const normalized = [...densities];
|
|
94
|
+
if (mode === `max`) {
|
|
95
|
+
const max_val = Math.max(...normalized);
|
|
96
|
+
if (max_val === 0)
|
|
97
|
+
return normalized;
|
|
98
|
+
return normalized.map((d) => d / max_val);
|
|
99
|
+
}
|
|
100
|
+
else if (mode === `sum`) {
|
|
101
|
+
const sum = normalized.reduce((acc, d) => acc + d, 0);
|
|
102
|
+
if (sum === 0)
|
|
103
|
+
return normalized;
|
|
104
|
+
return normalized.map((d) => d / sum);
|
|
105
|
+
}
|
|
106
|
+
else if (mode === `integral`) {
|
|
107
|
+
if (freqs_or_energies.length < 2)
|
|
108
|
+
return normalized;
|
|
109
|
+
const bin_width = freqs_or_energies[1] - freqs_or_energies[0];
|
|
110
|
+
if (bin_width === 0)
|
|
111
|
+
return normalized;
|
|
112
|
+
const sum = normalized.reduce((acc, d) => acc + d, 0);
|
|
113
|
+
if (sum === 0)
|
|
114
|
+
return normalized;
|
|
115
|
+
return normalized.map((d) => d / (sum * bin_width));
|
|
116
|
+
}
|
|
117
|
+
return normalized;
|
|
118
|
+
}
|
|
119
|
+
// Apply Gaussian smearing to DOS densities.
|
|
120
|
+
// Uses truncated Gaussian (±4σ) for O(n·w) complexity instead of O(n²).
|
|
121
|
+
export function apply_gaussian_smearing(freqs_or_energies, densities, sigma) {
|
|
122
|
+
const original_sum = densities.reduce((acc, d) => acc + d, 0);
|
|
123
|
+
if (sigma <= 0 || original_sum === 0)
|
|
124
|
+
return densities;
|
|
125
|
+
const smeared = new Array(densities.length).fill(0);
|
|
126
|
+
const truncation_width = 4; // Truncate Gaussian at ±4σ (contribution < 0.01%)
|
|
127
|
+
for (let idx = 0; idx < freqs_or_energies.length; idx++) {
|
|
128
|
+
const energy = freqs_or_energies[idx];
|
|
129
|
+
const cutoff = truncation_width * sigma;
|
|
130
|
+
for (let jdx = 0; jdx < freqs_or_energies.length; jdx++) {
|
|
131
|
+
const e_j = freqs_or_energies[jdx];
|
|
132
|
+
const delta = Math.abs(energy - e_j);
|
|
133
|
+
// Skip points beyond truncation width
|
|
134
|
+
if (delta > cutoff)
|
|
135
|
+
continue;
|
|
136
|
+
const gaussian = Math.exp(-((energy - e_j) ** 2) / (2 * sigma ** 2));
|
|
137
|
+
smeared[idx] += densities[jdx] * gaussian;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Normalize to preserve integral
|
|
141
|
+
const smeared_sum = smeared.reduce((acc, d) => acc + d, 0);
|
|
142
|
+
if (smeared_sum === 0)
|
|
143
|
+
return densities;
|
|
144
|
+
const normalization = original_sum / smeared_sum;
|
|
145
|
+
return smeared.map((d) => d * normalization);
|
|
146
|
+
}
|
|
147
|
+
export function normalize_band_structure(bs) {
|
|
148
|
+
if (!bs || typeof bs !== `object`)
|
|
149
|
+
return null;
|
|
150
|
+
const band_struct = bs;
|
|
151
|
+
// Check required fields exist and are arrays
|
|
152
|
+
const { qpoints, branches, bands, distance } = band_struct;
|
|
153
|
+
if (!Array.isArray(qpoints) ||
|
|
154
|
+
!Array.isArray(branches) ||
|
|
155
|
+
!Array.isArray(bands) ||
|
|
156
|
+
!Array.isArray(distance))
|
|
157
|
+
return null;
|
|
158
|
+
// Validate array lengths and branch indices
|
|
159
|
+
const n_qpts = qpoints.length;
|
|
160
|
+
if (distance.length !== n_qpts ||
|
|
161
|
+
bands.some((band) => !Array.isArray(band) || band.length !== n_qpts) ||
|
|
162
|
+
branches.some((br) => typeof br.start_index !== `number` ||
|
|
163
|
+
typeof br.end_index !== `number` ||
|
|
164
|
+
br.start_index < 0 ||
|
|
165
|
+
br.end_index >= n_qpts ||
|
|
166
|
+
br.start_index > br.end_index))
|
|
167
|
+
return null;
|
|
168
|
+
return band_struct;
|
|
169
|
+
}
|
|
170
|
+
// Validate and normalize a DOS object.
|
|
171
|
+
export function normalize_dos(dos) {
|
|
172
|
+
if (!dos || typeof dos !== `object`)
|
|
173
|
+
return null;
|
|
174
|
+
const { densities, frequencies, energies, spin_polarized } = dos;
|
|
175
|
+
if (!Array.isArray(densities))
|
|
176
|
+
return null;
|
|
177
|
+
// Phonon DOS: has frequencies
|
|
178
|
+
if (Array.isArray(frequencies)) {
|
|
179
|
+
if (frequencies.length !== densities.length)
|
|
180
|
+
return null;
|
|
181
|
+
return { type: `phonon`, frequencies, densities };
|
|
182
|
+
}
|
|
183
|
+
// Electronic DOS: has energies
|
|
184
|
+
if (Array.isArray(energies)) {
|
|
185
|
+
if (energies.length !== densities.length)
|
|
186
|
+
return null;
|
|
187
|
+
return {
|
|
188
|
+
type: `electronic`,
|
|
189
|
+
energies,
|
|
190
|
+
densities,
|
|
191
|
+
spin_polarized: spin_polarized,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Band structure and density of states visualization components
|
|
2
|
+
export { default as Bands } from './Bands.svelte';
|
|
3
|
+
export { default as Dos } from './Dos.svelte';
|
|
4
|
+
export { default as BandsAndDos } from './BandsAndDos.svelte';
|
|
5
|
+
export * from './types';
|
|
6
|
+
export * from './helpers';
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export type BandStructureType = `phonon` | `electronic`;
|
|
2
|
+
export type PathMode = `union` | `intersection` | `strict`;
|
|
3
|
+
export type FrequencyUnit = `THz` | `eV` | `meV` | `Ha` | `cm-1`;
|
|
4
|
+
export type NormalizationMode = `max` | `sum` | `integral` | null;
|
|
5
|
+
export interface QPoint {
|
|
6
|
+
label: string | null;
|
|
7
|
+
frac_coords: [number, number, number];
|
|
8
|
+
distance?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface Branch {
|
|
11
|
+
start_index: number;
|
|
12
|
+
end_index: number;
|
|
13
|
+
name: string;
|
|
14
|
+
}
|
|
15
|
+
export interface BaseBandStructure {
|
|
16
|
+
lattice_rec: {
|
|
17
|
+
matrix: number[][];
|
|
18
|
+
};
|
|
19
|
+
qpoints: QPoint[];
|
|
20
|
+
branches: Branch[];
|
|
21
|
+
labels_dict: Record<string, [number, number, number]>;
|
|
22
|
+
distance: number[];
|
|
23
|
+
nb_bands: number;
|
|
24
|
+
bands: number[][];
|
|
25
|
+
}
|
|
26
|
+
export interface PhononBandStructure extends BaseBandStructure {
|
|
27
|
+
has_imaginary_modes?: boolean;
|
|
28
|
+
has_nac?: boolean;
|
|
29
|
+
}
|
|
30
|
+
export interface ElectronicBandStructure extends BaseBandStructure {
|
|
31
|
+
is_spin_polarized: boolean;
|
|
32
|
+
efermi?: number;
|
|
33
|
+
is_metal?: boolean;
|
|
34
|
+
band_gap?: {
|
|
35
|
+
energy: number;
|
|
36
|
+
direct: boolean;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export interface PhononDos {
|
|
40
|
+
type: `phonon`;
|
|
41
|
+
frequencies: number[];
|
|
42
|
+
densities: number[];
|
|
43
|
+
}
|
|
44
|
+
export interface ElectronicDos {
|
|
45
|
+
type: `electronic`;
|
|
46
|
+
energies: number[];
|
|
47
|
+
densities: number[];
|
|
48
|
+
spin_polarized?: boolean;
|
|
49
|
+
}
|
|
50
|
+
export type Dos = PhononDos | ElectronicDos;
|
|
51
|
+
export type LineKwargs = Record<string, unknown> | {
|
|
52
|
+
acoustic?: Record<string, unknown>;
|
|
53
|
+
optical?: Record<string, unknown>;
|
|
54
|
+
} | ((frequencies: number[], band_idx: number) => Record<string, unknown>);
|