Skip to content

Commit

Permalink
For INS in low dimensional systems, parsing the band path from the Wo…
Browse files Browse the repository at this point in the history
…rkChain inputs (#93)

* For INS in low dimensional systems, parsing the band path from the WorkChain inputs

This fix #69

* Bug fixing the q_path in Result panel.

* Pre-commit fixings

* Adding a check for emin and emax

and a loading spinner for INS data initialization.

* Adding an on-the-fly test for emin, emax.
  • Loading branch information
mikibonacci authored Oct 3, 2024
1 parent 89c70a2 commit 634dc6e
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 5 deletions.
4 changes: 3 additions & 1 deletion src/aiidalab_qe_vibroscopy/app/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down
72 changes: 70 additions & 2 deletions src/aiidalab_qe_vibroscopy/utils/euphonic/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,34 @@

###### START for detached app:

# spinner for waiting time (supercell estimations)
spinner_html = """
<style>
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.spinner {
display: inline-block;
width: 15px;
height: 15px;
}
.spinner div {
width: 100%;
height: 100%;
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
}
</style>
<div class="spinner">
<div></div>
</div>
"""


# Upload buttons
class UploadPhonopyYamlWidget(ipw.FileUpload):
Expand Down Expand Up @@ -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()
Expand All @@ -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",
Expand All @@ -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
Expand All @@ -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,
],
)
Expand Down Expand Up @@ -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,
Expand All @@ -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"


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
)

Expand Down Expand Up @@ -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_,
Expand Down
39 changes: 39 additions & 0 deletions src/aiidalab_qe_vibroscopy/utils/euphonic/intensity_maps.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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}


Expand Down

0 comments on commit 634dc6e

Please sign in to comment.