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.
Files changed (195) hide show
  1. package/dist/ContextMenu.svelte +1 -1
  2. package/dist/ContextMenu.svelte.d.ts +3 -3
  3. package/dist/DraggablePane.svelte +10 -5
  4. package/dist/DraggablePane.svelte.d.ts +3 -3
  5. package/dist/FilePicker.svelte.d.ts +3 -3
  6. package/dist/Icon.svelte.d.ts +3 -3
  7. package/dist/Nav.svelte +76 -31
  8. package/dist/SettingsSection.svelte.d.ts +3 -3
  9. package/dist/Spinner.svelte +18 -29
  10. package/dist/Spinner.svelte.d.ts +3 -3
  11. package/dist/app.css +4 -0
  12. package/dist/bands/Bands.svelte +216 -0
  13. package/dist/bands/Bands.svelte.d.ts +16 -0
  14. package/dist/bands/BandsAndDos.svelte +26 -0
  15. package/dist/bands/BandsAndDos.svelte.d.ts +16 -0
  16. package/dist/bands/Dos.svelte +124 -0
  17. package/dist/bands/Dos.svelte.d.ts +18 -0
  18. package/dist/bands/helpers.d.ts +11 -0
  19. package/dist/bands/helpers.js +195 -0
  20. package/dist/bands/index.d.ts +5 -0
  21. package/dist/bands/index.js +6 -0
  22. package/dist/bands/types.d.ts +54 -0
  23. package/dist/bands/types.js +2 -0
  24. package/dist/brillouin/BrillouinZone.svelte +373 -0
  25. package/dist/brillouin/BrillouinZone.svelte.d.ts +57 -0
  26. package/dist/brillouin/BrillouinZoneControls.svelte +88 -0
  27. package/dist/brillouin/BrillouinZoneControls.svelte.d.ts +14 -0
  28. package/dist/brillouin/BrillouinZoneExportPane.svelte +129 -0
  29. package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +15 -0
  30. package/dist/brillouin/BrillouinZoneInfoPane.svelte +115 -0
  31. package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +13 -0
  32. package/dist/brillouin/BrillouinZoneScene.svelte +180 -0
  33. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +34 -0
  34. package/dist/brillouin/compute.d.ts +7 -0
  35. package/dist/brillouin/compute.js +215 -0
  36. package/dist/brillouin/index.d.ts +7 -0
  37. package/dist/brillouin/index.js +7 -0
  38. package/dist/brillouin/types.d.ts +23 -0
  39. package/dist/brillouin/types.js +1 -0
  40. package/dist/composition/BarChart.svelte.d.ts +3 -3
  41. package/dist/composition/BubbleChart.svelte +7 -6
  42. package/dist/composition/BubbleChart.svelte.d.ts +3 -3
  43. package/dist/composition/Composition.svelte.d.ts +3 -3
  44. package/dist/composition/PieChart.svelte +1 -1
  45. package/dist/composition/PieChart.svelte.d.ts +3 -3
  46. package/dist/composition/parse.d.ts +3 -3
  47. package/dist/coordination/CoordinationBarPlot.svelte +241 -0
  48. package/dist/coordination/CoordinationBarPlot.svelte.d.ts +29 -0
  49. package/dist/coordination/calc-coordination.d.ts +15 -0
  50. package/dist/coordination/calc-coordination.js +66 -0
  51. package/dist/coordination/index.d.ts +8 -0
  52. package/dist/coordination/index.js +7 -0
  53. package/dist/element/BohrAtom.svelte.d.ts +3 -3
  54. package/dist/element/ElementHeading.svelte.d.ts +3 -3
  55. package/dist/element/ElementPhoto.svelte.d.ts +3 -3
  56. package/dist/element/ElementStats.svelte.d.ts +3 -3
  57. package/dist/element/ElementTile.svelte +1 -1
  58. package/dist/element/ElementTile.svelte.d.ts +4 -4
  59. package/dist/element/Nucleus.svelte.d.ts +3 -3
  60. package/dist/icons.d.ts +4 -0
  61. package/dist/icons.js +4 -0
  62. package/dist/index.d.ts +5 -1
  63. package/dist/index.js +5 -1
  64. package/dist/io/export.d.ts +1 -6
  65. package/dist/io/export.js +12 -12
  66. package/dist/labels.d.ts +19 -0
  67. package/dist/labels.js +59 -0
  68. package/dist/math.d.ts +7 -2
  69. package/dist/math.js +24 -12
  70. package/dist/periodic-table/PeriodicTable.svelte.d.ts +3 -3
  71. package/dist/periodic-table/PeriodicTableControls.svelte.d.ts +3 -3
  72. package/dist/periodic-table/PropertySelect.svelte +1 -1
  73. package/dist/periodic-table/PropertySelect.svelte.d.ts +5 -4
  74. package/dist/periodic-table/TableInset.svelte.d.ts +3 -3
  75. package/dist/phase-diagram/PhaseDiagram2D.svelte +44 -107
  76. package/dist/phase-diagram/PhaseDiagram2D.svelte.d.ts +7 -27
  77. package/dist/phase-diagram/PhaseDiagram3D.svelte +67 -170
  78. package/dist/phase-diagram/PhaseDiagram3D.svelte.d.ts +7 -31
  79. package/dist/phase-diagram/PhaseDiagram4D.svelte +87 -145
  80. package/dist/phase-diagram/PhaseDiagram4D.svelte.d.ts +5 -28
  81. package/dist/phase-diagram/PhaseDiagramControls.svelte +9 -9
  82. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +6 -6
  83. package/dist/phase-diagram/PhaseDiagramInfoPane.svelte +4 -4
  84. package/dist/phase-diagram/PhaseDiagramInfoPane.svelte.d.ts +5 -5
  85. package/dist/phase-diagram/PhaseDiagramStats.svelte +9 -16
  86. package/dist/phase-diagram/PhaseDiagramStats.svelte.d.ts +3 -3
  87. package/dist/phase-diagram/StructurePopup.svelte.d.ts +3 -3
  88. package/dist/phase-diagram/barycentric-coords.js +13 -24
  89. package/dist/phase-diagram/helpers.d.ts +12 -14
  90. package/dist/phase-diagram/helpers.js +70 -23
  91. package/dist/phase-diagram/index.d.ts +58 -0
  92. package/dist/phase-diagram/index.js +44 -0
  93. package/dist/phase-diagram/thermodynamics.js +2 -3
  94. package/dist/phase-diagram/types.d.ts +3 -8
  95. package/dist/plot/BarPlot.svelte +474 -240
  96. package/dist/plot/BarPlot.svelte.d.ts +16 -37
  97. package/dist/plot/BarPlotControls.svelte +33 -201
  98. package/dist/plot/BarPlotControls.svelte.d.ts +11 -22
  99. package/dist/plot/ColorBar.svelte.d.ts +3 -3
  100. package/dist/plot/ColorScaleSelect.svelte +1 -1
  101. package/dist/plot/ColorScaleSelect.svelte.d.ts +3 -3
  102. package/dist/plot/ElementScatter.svelte +5 -5
  103. package/dist/plot/ElementScatter.svelte.d.ts +8 -8
  104. package/dist/plot/Histogram.svelte +318 -170
  105. package/dist/plot/Histogram.svelte.d.ts +21 -41
  106. package/dist/plot/HistogramControls.svelte +115 -347
  107. package/dist/plot/HistogramControls.svelte.d.ts +13 -28
  108. package/dist/plot/Line.svelte +1 -1
  109. package/dist/plot/Line.svelte.d.ts +4 -4
  110. package/dist/plot/PlotControls.svelte +280 -0
  111. package/dist/plot/PlotControls.svelte.d.ts +4 -0
  112. package/dist/plot/PlotLegend.svelte +9 -24
  113. package/dist/plot/PlotLegend.svelte.d.ts +3 -3
  114. package/dist/plot/ScatterPlot.svelte +536 -571
  115. package/dist/plot/ScatterPlot.svelte.d.ts +18 -90
  116. package/dist/plot/ScatterPlotControls.svelte +108 -316
  117. package/dist/plot/ScatterPlotControls.svelte.d.ts +11 -38
  118. package/dist/plot/ScatterPoint.svelte +1 -1
  119. package/dist/plot/ScatterPoint.svelte.d.ts +5 -5
  120. package/dist/plot/SpacegroupBarPlot.svelte +235 -0
  121. package/dist/plot/SpacegroupBarPlot.svelte.d.ts +9 -0
  122. package/dist/plot/data-transform.d.ts +2 -2
  123. package/dist/plot/data-transform.js +1 -5
  124. package/dist/plot/index.d.ts +12 -200
  125. package/dist/plot/index.js +14 -6
  126. package/dist/plot/layout.d.ts +10 -16
  127. package/dist/plot/layout.js +40 -25
  128. package/dist/plot/scales.d.ts +7 -8
  129. package/dist/plot/scales.js +22 -7
  130. package/dist/plot/types.d.ts +303 -0
  131. package/dist/plot/types.js +1 -0
  132. package/dist/rdf/RdfPlot.svelte +156 -0
  133. package/dist/rdf/RdfPlot.svelte.d.ts +20 -0
  134. package/dist/rdf/calc-rdf.d.ts +4 -0
  135. package/dist/rdf/calc-rdf.js +107 -0
  136. package/dist/rdf/index.d.ts +22 -0
  137. package/dist/rdf/index.js +2 -0
  138. package/dist/settings.d.ts +86 -75
  139. package/dist/settings.js +257 -155
  140. package/dist/structure/Bond.svelte +126 -110
  141. package/dist/structure/Bond.svelte.d.ts +7 -20
  142. package/dist/structure/CanvasTooltip.svelte.d.ts +4 -4
  143. package/dist/structure/Cylinder.svelte +29 -0
  144. package/dist/structure/Cylinder.svelte.d.ts +10 -0
  145. package/dist/structure/Lattice.svelte +1 -2
  146. package/dist/structure/Lattice.svelte.d.ts +3 -3
  147. package/dist/structure/Structure.svelte +23 -8
  148. package/dist/structure/Structure.svelte.d.ts +10 -7
  149. package/dist/structure/StructureControls.svelte +25 -134
  150. package/dist/structure/StructureControls.svelte.d.ts +4 -9
  151. package/dist/structure/StructureExportPane.svelte +188 -0
  152. package/dist/structure/StructureExportPane.svelte.d.ts +17 -0
  153. package/dist/structure/StructureInfoPane.svelte.d.ts +3 -3
  154. package/dist/structure/StructureLegend.svelte +91 -27
  155. package/dist/structure/StructureLegend.svelte.d.ts +5 -4
  156. package/dist/structure/StructureScene.svelte +93 -100
  157. package/dist/structure/StructureScene.svelte.d.ts +15 -12
  158. package/dist/structure/Vector.svelte +19 -25
  159. package/dist/structure/Vector.svelte.d.ts +3 -3
  160. package/dist/structure/bonding.d.ts +16 -14
  161. package/dist/structure/bonding.js +207 -216
  162. package/dist/structure/export.d.ts +3 -0
  163. package/dist/structure/export.js +120 -0
  164. package/dist/structure/index.d.ts +15 -1
  165. package/dist/structure/index.js +2 -0
  166. package/dist/symmetry/WyckoffTable.svelte.d.ts +3 -3
  167. package/dist/symmetry/index.d.ts +1 -0
  168. package/dist/symmetry/index.js +1 -0
  169. package/dist/symmetry/spacegroups.d.ts +9 -0
  170. package/dist/symmetry/spacegroups.js +397 -0
  171. package/dist/theme/ThemeControl.svelte.d.ts +3 -3
  172. package/dist/theme/themes.js +2 -16
  173. package/dist/trajectory/Trajectory.svelte +52 -78
  174. package/dist/trajectory/Trajectory.svelte.d.ts +5 -5
  175. package/dist/trajectory/TrajectoryError.svelte.d.ts +3 -3
  176. package/dist/trajectory/TrajectoryExportPane.svelte +1 -1
  177. package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +5 -5
  178. package/dist/trajectory/TrajectoryInfoPane.svelte +1 -1
  179. package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +3 -3
  180. package/dist/trajectory/extract.js +2 -1
  181. package/dist/trajectory/index.d.ts +1 -1
  182. package/dist/trajectory/index.js +1 -1
  183. package/dist/trajectory/parse.js +21 -14
  184. package/dist/utils.d.ts +1 -0
  185. package/dist/utils.js +17 -0
  186. package/dist/xrd/XrdPlot.svelte +14 -11
  187. package/dist/xrd/XrdPlot.svelte.d.ts +6 -5
  188. package/package.json +20 -12
  189. package/readme.md +1 -1
  190. package/dist/material/MaterialCard.svelte +0 -123
  191. package/dist/material/MaterialCard.svelte.d.ts +0 -9
  192. package/dist/material/index.d.ts +0 -1
  193. package/dist/material/index.js +0 -1
  194. package/dist/plot/formatting.d.ts +0 -7
  195. 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,5 @@
1
+ export { default as Bands } from './Bands.svelte';
2
+ export { default as Dos } from './Dos.svelte';
3
+ export { default as BandsAndDos } from './BandsAndDos.svelte';
4
+ export * from './types';
5
+ export * from './helpers';
@@ -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>);
@@ -0,0 +1,2 @@
1
+ // TypeScript type definitions for band structures and density of states
2
+ export {};