diff --git a/src/aiidalab_qe_vibroscopy/app/result.py b/src/aiidalab_qe_vibroscopy/app/result.py
index 36cc7c8..30dae04 100644
--- a/src/aiidalab_qe_vibroscopy/app/result.py
+++ b/src/aiidalab_qe_vibroscopy/app/result.py
@@ -211,7 +211,9 @@ def _update_view(self):
# euphonic
if ins_data:
- intensity_maps = EuphonicSuperWidget(fc=ins_data["fc"])
+ intensity_maps = EuphonicSuperWidget(
+ fc=ins_data["fc"], q_path=ins_data["q_path"]
+ )
children_result_widget += (intensity_maps,)
tab_titles.append("Inelastic Neutrons")
diff --git a/src/aiidalab_qe_vibroscopy/utils/euphonic/__init__.py b/src/aiidalab_qe_vibroscopy/utils/euphonic/__init__.py
index d169a46..0d60410 100644
--- a/src/aiidalab_qe_vibroscopy/utils/euphonic/__init__.py
+++ b/src/aiidalab_qe_vibroscopy/utils/euphonic/__init__.py
@@ -18,6 +18,34 @@
###### START for detached app:
+# spinner for waiting time (supercell estimations)
+spinner_html = """
+
+
+"""
+
# Upload buttons
class UploadPhonopyYamlWidget(ipw.FileUpload):
@@ -111,7 +139,34 @@ class EuphonicSuperWidget(ipw.VBox):
In between, we trigger the initialization of plots via a button.
"""
- def __init__(self, mode="aiidalab-qe app plugin", fc=None):
+ def __init__(self, mode="aiidalab-qe app plugin", fc=None, q_path=None):
+ """
+ Initialize the Euphonic utility class.
+ Parameters:
+ -----------
+ mode : str, optional
+ The mode of operation, default is "aiidalab-qe app plugin".
+ fc : optional
+ Force constants, default is None.
+ q_path : optional
+ Q-path for phonon calculations, default is None. If Low-D system, this can be provided.
+ It is the same path obtained for the PhonopyCalculation of the phonopy_bands.
+ Attributes:
+ -----------
+ mode : str
+ The mode of operation.
+ upload_widget : UploadPhonopyWidget
+ Widget for uploading phonopy files.
+ fc_hdf5_content : None
+ Content of the force constants HDF5 file.
+ tab_widget : ipw.Tab
+ Tab widget for different views.
+ plot_button : ipw.Button
+ Button to initialize INS data.
+ fc : optional
+ Force constants if provided.
+ """
+
self.mode = mode
self.upload_widget = UploadPhonopyWidget()
@@ -128,6 +183,8 @@ def __init__(self, mode="aiidalab-qe app plugin", fc=None):
if fc:
self.fc = fc
+ self.q_path = q_path
+
self.plot_button = ipw.Button(
description="Initialise INS data",
icon="pencil",
@@ -137,6 +194,11 @@ def __init__(self, mode="aiidalab-qe app plugin", fc=None):
)
self.plot_button.on_click(self._on_first_plot_button_clicked)
+ self.loading_widget = ipw.HTML(
+ value=spinner_html,
+ )
+ self.loading_widget.layout.display = "none"
+
if self.mode == "aiidalab-qe app plugin":
self.upload_widget.layout.display = "none"
self.plot_button.disabled = False
@@ -148,6 +210,7 @@ def __init__(self, mode="aiidalab-qe app plugin", fc=None):
children=[
self.upload_widget,
self.plot_button,
+ self.loading_widget,
self.tab_widget,
],
)
@@ -203,10 +266,13 @@ def _generate_force_constants(
def _on_first_plot_button_clicked(self, change=None):
# It creates the widgets
self.plot_button.layout.display = "none"
+
+ self.loading_widget.layout.display = "block"
+
self.fc = self._generate_force_constants()
# I first initialise this widget, to then have the 0K ref for the other two.
- singlecrystalwidget = SingleCrystalFullWidget(self.fc)
+ singlecrystalwidget = SingleCrystalFullWidget(self.fc, self.q_path)
self.tab_widget.children = (
singlecrystalwidget,
@@ -218,6 +284,8 @@ def _on_first_plot_button_clicked(self, change=None):
),
)
+ self.loading_widget.layout.display = "none"
+
self.tab_widget.layout.display = "block"
diff --git a/src/aiidalab_qe_vibroscopy/utils/euphonic/euphonic_single_crystal_widgets.py b/src/aiidalab_qe_vibroscopy/utils/euphonic/euphonic_single_crystal_widgets.py
index 1437772..f03df86 100644
--- a/src/aiidalab_qe_vibroscopy/utils/euphonic/euphonic_single_crystal_widgets.py
+++ b/src/aiidalab_qe_vibroscopy/utils/euphonic/euphonic_single_crystal_widgets.py
@@ -2,6 +2,7 @@
from IPython.display import display
import numpy as np
+import copy
import ipywidgets as ipw
import plotly.graph_objects as go
import plotly.io as pio
@@ -196,11 +197,13 @@ class SingleCrystalFullWidget(ipw.VBox):
and are from Sears (1992) Neutron News 3(3) pp26--37.
"""
- def __init__(self, fc, **kwargs):
+ def __init__(self, fc, q_path, **kwargs):
self.fc = fc
+ self.q_path = q_path
self.spectra, self.parameters = produce_bands_weigthed_data(
fc=self.fc,
+ linear_path=self.q_path,
plot=False, # CHANGED
)
@@ -248,7 +251,9 @@ def _on_plot_button_clicked(self, change=None):
"delta_q": parameters_["q_spacing"],
}
else:
- linear_path = None
+ linear_path = copy.deepcopy(self.q_path)
+ if linear_path:
+ linear_path["delta_q"] = parameters_["q_spacing"]
self.spectra, self.parameters = produce_bands_weigthed_data(
params=parameters_,
diff --git a/src/aiidalab_qe_vibroscopy/utils/euphonic/intensity_maps.py b/src/aiidalab_qe_vibroscopy/utils/euphonic/intensity_maps.py
index 0bc1a0e..6a7490b 100644
--- a/src/aiidalab_qe_vibroscopy/utils/euphonic/intensity_maps.py
+++ b/src/aiidalab_qe_vibroscopy/utils/euphonic/intensity_maps.py
@@ -299,6 +299,21 @@ def produce_bands_weigthed_data(
x_tick_labels = get_qpoint_labels(
modes.qpts, cell=modes.crystal.to_spglib_cell()
)
+
+ # duplication from euphonic/cli/utils.py
+ if args.e_min is None:
+ # Subtract small amount from min frequency - otherwise due to unit
+ # conversions binning of this frequency can vary with different
+ # architectures/lib versions, making it difficult to test
+ emin_room = 1e-5 * ureg("meV").to(modes.frequencies.units).magnitude
+ args.e_min = min(np.min(modes.frequencies.magnitude - emin_room), 0.0)
+ if args.e_max is None:
+ args.e_max = np.max(modes.frequencies.magnitude) * 1.05
+ if args.e_min >= args.e_max:
+ raise ValueError(
+ f"Maximum energy ({args.e_max}) should be greater than minimum ({args.e_min}). "
+ )
+
modes.frequencies_unit = args.energy_unit
ebins = _get_energy_bins(modes, args.ebins + 1, emin=args.e_min, emax=args.e_max)
@@ -753,12 +768,36 @@ def export_euphonic_data(node, fermi_energy=None):
output_set = node.outputs.vibronic.phonon_bands
+ if any(not element for element in node.inputs.structure.pbc):
+ vibro_bands = node.inputs.vibronic.phonopy_bands_dict.get_dict()
+ # Group the band and band_labels
+ band = vibro_bands["band"]
+ band_labels = vibro_bands["band_labels"]
+
+ grouped_bands = [
+ item
+ for sublist in [band_labels[i : i + 2] for i in range(len(band_labels) - 1)]
+ for item in sublist
+ ]
+ grouped_q = [
+ [tuple(band[i : i + 3]), tuple(band[i + 3 : i + 6])]
+ for i in range(0, len(band) - 3, 3)
+ ]
+ q_path = {
+ "coordinates": grouped_q,
+ "labels": grouped_bands,
+ "delta_q": 0.01, # 1/A
+ }
+ else:
+ q_path = None
+
phonopy_calc = output_set.creator
fc = generate_force_constant_instance(phonopy_calc)
# bands = compute_bands(fc)
# pdos = compute_pdos(fc)
return {
"fc": fc,
+ "q_path": q_path,
} # "bands": bands, "pdos": pdos, "thermal": None}