Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 6 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/aiidalab_qe_vibroscopy/app/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ def _update_view(self):
_bands_plot_view_class.update_layout(
yaxis=dict(autorange=True), # Automatically scale the y-axis
)


# the data (bands and pdos) are the first element of the lists phonon_data["bands"] and phonon_data["pdos"]!
downloadBandsPdos_widget = DownloadBandsPdosWidget(
Expand Down Expand Up @@ -209,14 +208,15 @@ def _update_view(self):
dielectric_results = DielectricResults(dielectric_data)
children_result_widget += (dielectric_results,)
tab_titles.append("Dielectric properties")

# 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")


self.result_tabs = ipw.Tab(children=children_result_widget)

for title_index in range(len(tab_titles)):
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
Loading