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

Lazy loading refactoring #105

Merged
merged 27 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
8d171b0
setting lazy loading
AndresOrtegaGuerrero Nov 28, 2024
6ec5f94
control of supercell with pbc
AndresOrtegaGuerrero Nov 29, 2024
1ea22a0
setting logic for size and resent hint buttons
AndresOrtegaGuerrero Nov 29, 2024
16b999d
adding logic for reset symprec
AndresOrtegaGuerrero Nov 29, 2024
b18fe6d
logic to estimate supercell button
AndresOrtegaGuerrero Nov 29, 2024
9524fbc
logic for the codes
AndresOrtegaGuerrero Nov 29, 2024
54035b7
cleaning settings - using disable_print decorator
AndresOrtegaGuerrero Nov 29, 2024
5917326
adapting workchain to names from model
AndresOrtegaGuerrero Nov 29, 2024
7486b06
organizing a result folder
AndresOrtegaGuerrero Nov 29, 2024
8ea879c
template of result tabs
AndresOrtegaGuerrero Nov 30, 2024
04d5d17
dielectric results model and widget
AndresOrtegaGuerrero Nov 30, 2024
3321f58
move the fetch data to dielectric model
AndresOrtegaGuerrero Nov 30, 2024
eaa337c
adding a logic for raman spectrum plot in model and widget
AndresOrtegaGuerrero Dec 1, 2024
194c3b3
setting IR/Raman Results tab
AndresOrtegaGuerrero Dec 2, 2024
a2b8d08
phonon tab results
AndresOrtegaGuerrero Dec 2, 2024
aa70434
phonon tab results
AndresOrtegaGuerrero Dec 2, 2024
4a7a378
Lazy loading euphonic (#106)
mikibonacci Dec 4, 2024
a78c55b
Fixing rendered=True in euphonic widgets.
mikibonacci Dec 4, 2024
5a0982f
new_widgets_modelf for euphonic tab
AndresOrtegaGuerrero Dec 5, 2024
91b4fd4
comment temp update
AndresOrtegaGuerrero Dec 5, 2024
b5f7d5c
setting the original Euphonic Widgets
AndresOrtegaGuerrero Dec 6, 2024
baa9d5a
Providing explicit phonopy version.
mikibonacci Dec 6, 2024
e454b16
Disabling the euphonic part
mikibonacci Dec 6, 2024
5fc101f
do a reset if the structure is none
AndresOrtegaGuerrero Dec 6, 2024
ea4f2eb
Merge branch 'lazy_loading_compatible' of https://github.com/mikibona…
AndresOrtegaGuerrero Dec 6, 2024
f901d8d
fix update input_structure settings
AndresOrtegaGuerrero Dec 6, 2024
3c80929
fix pre-comit
AndresOrtegaGuerrero Dec 6, 2024
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
5 changes: 2 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,11 @@ requires-python = ">=3.8"
dependencies = [
"aiida-vibroscopy>=1.0.2",
"aiida-phonopy>=1.1.3",
"phonopy",
#"euphonic==1.1.0",
"phonopy=2.25.0",
"pre-commit",
"euphonic",
"kaleido",
"weas-widget==0.1.15",
"weas-widget==0.1.19",
]

[tool.ruff.lint]
Expand Down
53 changes: 22 additions & 31 deletions src/aiidalab_qe_vibroscopy/app/__init__.py
Original file line number Diff line number Diff line change
@@ -1,43 +1,34 @@
from aiidalab_qe_vibroscopy.app.settings import Setting
from aiidalab_qe_vibroscopy.app.workchain import workchain_and_builder
from aiidalab_qe_vibroscopy.app.result import Result
from aiidalab_qe.common.panel import OutlinePanel
from aiidalab_qe.common.panel import PluginOutline

from aiidalab_qe.common.widgets import (
QEAppComputationalResourcesWidget,
PwCodeResourceSetupWidget,
from aiidalab_qe_vibroscopy.app.model import VibroConfigurationSettingsModel
from aiidalab_qe_vibroscopy.app.settings import VibroConfigurationSettingPanel
from aiidalab_qe_vibroscopy.app.code import (
VibroResourceSettingsModel,
VibroResourcesSettingsPanel,
)
from aiidalab_qe_vibroscopy.app.result.result import VibroResultsPanel
from aiidalab_qe_vibroscopy.app.result.model import VibroResultsModel

from aiidalab_qe_vibroscopy.app.workchain import workchain_and_builder

class Outline(OutlinePanel):
title = "Vibrational properties"
# description = "IR and Raman spectra; you may also select phononic and dielectric properties"

class VibroPluginOutline(PluginOutline):
title = "Vibrational Spectroscopy (VIBRO)"

PhononWorkChainPwCode = PwCodeResourceSetupWidget(
description="pw.x for phonons", # code for the PhononWorkChain workflow",
default_calc_job_plugin="quantumespresso.pw",
)

# The finite electric field does not support npools (does not work with npools>1), so we just set it as QEAppComputationalResourcesWidget
DielectricWorkChainPwCode = QEAppComputationalResourcesWidget(
description="pw.x for dielectric", # code for the DielectricWorChain workflow",
default_calc_job_plugin="quantumespresso.pw",
)

PhonopyCalculationCode = QEAppComputationalResourcesWidget(
description="phonopy", # code for the PhonopyCalculation calcjob",
default_calc_job_plugin="phonopy.phonopy",
)

property = {
"outline": Outline,
"outline": VibroPluginOutline,
"configuration": {
"panel": VibroConfigurationSettingPanel,
"model": VibroConfigurationSettingsModel,
},
"code": {
"phonon": PhononWorkChainPwCode,
"dielectric": DielectricWorkChainPwCode,
"phonopy": PhonopyCalculationCode,
"panel": VibroResourcesSettingsPanel,
"model": VibroResourceSettingsModel,
},
"result": {
"panel": VibroResultsPanel,
"model": VibroResultsModel,
},
"setting": Setting,
"workchain": workchain_and_builder,
"result": Result,
}
29 changes: 29 additions & 0 deletions src/aiidalab_qe_vibroscopy/app/code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from aiidalab_qe.common.code.model import CodeModel, PwCodeModel
from aiidalab_qe.common.panel import ResourceSettingsModel, ResourceSettingsPanel


class VibroResourceSettingsModel(ResourceSettingsModel):
"""Resource settings for the vibroscopy calculations."""

codes = {
"phonon": PwCodeModel(
description="pw.x for phonons",
default_calc_job_plugin="quantumespresso.pw",
),
"dielectric": PwCodeModel(
description="pw.x for dielectric",
default_calc_job_plugin="quantumespresso.pw",
),
"phonopy": CodeModel(
name="phonopy",
description="phonopy",
default_calc_job_plugin="phonopy.phonopy",
),
}


class VibroResourcesSettingsPanel(ResourceSettingsPanel[VibroResourceSettingsModel]):
"""Panel for the resource settings for the vibroscopy calculations."""

title = "Vibronic"
identifier = identifier = "vibronic"
Comment on lines +25 to +29
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess here in the future (near future) we can add the logic to display only subset of the defined codes, so if no dielectric is needed we don't show the pw dielectric and so on

221 changes: 221 additions & 0 deletions src/aiidalab_qe_vibroscopy/app/model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
import traitlets as tl

import numpy as np
from aiidalab_qe.common.mixins import HasInputStructure
from aiidalab_qe.common.panel import ConfigurationSettingsModel

from aiida_phonopy.data.preprocess import PreProcessData
from aiida.plugins import DataFactory
import sys
import os

HubbardStructureData = DataFactory("quantumespresso.hubbard_structure")
from aiida_vibroscopy.calculations.spectra_utils import get_supercells_for_hubbard
from aiida_vibroscopy.workflows.phonons.base import get_supercell_hubbard_structure

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


def disable_print(func):
def wrapper(*args, **kwargs):
# Save the current standard output
original_stdout = sys.stdout
# Redirect standard output to os.devnull
sys.stdout = open(os.devnull, "w")
try:
# Call the function
result = func(*args, **kwargs)
finally:
# Restore the original standard output
sys.stdout.close()
sys.stdout = original_stdout
return result

return wrapper


class VibroConfigurationSettingsModel(ConfigurationSettingsModel, HasInputStructure):
dependencies = [
"input_structure",
]

simulation_type_options = tl.List(
trait=tl.List(tl.Union([tl.Unicode(), tl.Int()])),
default_value=[
("IR/Raman, Phonon, Dielectric, INS properties", 1),
("IR/Raman and Dielectric in Primitive Cell Approach", 2),
("Phonons for non-polar materials and INS", 3),
("Dielectric properties", 4),
],
)
simulation_type = tl.Int(1)

symmetry_symprec = tl.Float(1e-5)
supercell_x = tl.Int(2)
supercell_y = tl.Int(2)
supercell_z = tl.Int(2)

# Control for disable the supercell widget

disable_x = tl.Bool(False)
disable_y = tl.Bool(False)
disable_z = tl.Bool(False)

supercell = tl.List(
trait=tl.Int(),
default_value=[2, 2, 2],
)
supercell_number_estimator = tl.Unicode(
"Click the button to estimate the supercell size."
)

def get_model_state(self):
return {
"simulation_type": self.simulation_type,
"symmetry_symprec": self.symmetry_symprec,
"supercell": self.supercell,
}

def set_model_state(self, parameters: dict):
self.simulation_type = parameters.get("simulation_type", 1)
self.symmetry_symprec = parameters.get("symmetry_symprec", 1e-5)
self.supercell = parameters.get("supercell", [2, 2, 2])
self.supercell_x, self.supercell_y, self.supercell_z = self.supercell

def reset(self):
with self.hold_trait_notifications():
self.simulation_type = 1
self.symmetry_symprec = 1e-5
self.supercell = [2, 2, 2]
self.supercell_x, self.supercell_y, self.supercell_z = self.supercell
self.supercell_number_estimator = self._get_default(
"supercell_number_estimator"
)

def _get_default(self, trait):
return self._defaults.get(trait, self.traits()[trait].default_value)

def on_input_structure_change(self, _=None):
if not self.input_structure:
self._get_default()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be self.reset() ? because otherwise we need to loop on all the traits, just calling the _get_default() will excepts.

A strange issue is that I just changed the dimensionality of the structure to 0D and confirmed, and somehow hitting this block (so it is like the self.input_structure is indeed none, but should not). I think however it is a qe app issue, and only happens for 0D (not 2D, 1D)


else:
self.disable_x, self.disable_y, self.disable_z = True, True, True
pbc = self.input_structure.pbc

if pbc == (False, False, False):
# No periodicity; fully disable and reset supercell
self.supercell_x = self.supercell_y = self.supercell_z = 1
elif pbc == (True, False, False):
self.supercell_y = self.supercell_z = 1
self.disable_x = False
self.symmetry_symprec = 1e-3
elif pbc == (True, True, False):
self.supercell_z = 1
self.disable_x = self.disable_y = False
elif pbc == (True, True, True):
self.disable_x = self.disable_y = self.disable_z = False

self.supercell = [self.supercell_x, self.supercell_y, self.supercell_z]

def suggest_supercell(self, _=None):
"""
minimal supercell size for phonons, imposing a minimum lattice parameter of 15 A.
"""
if self.input_structure and self.input_structure.pbc != (False, False, False):
ase_structure = self.input_structure.get_ase()
suggested_3D = 15 // np.array(ase_structure.cell.cellpar()[:3]) + 1

# Update only dimensions that are not disabled
if not self.disable_x:
self.supercell_x = int(suggested_3D[0])
if not self.disable_y:
self.supercell_y = int(suggested_3D[1])
if not self.disable_z:
self.supercell_z = int(suggested_3D[2])

# Sync the updated values to the supercell list
self.supercell = [self.supercell_x, self.supercell_y, self.supercell_z]

else:
return

def supercell_reset(self, _=None):
if not self.disable_x:
self.supercell_x = self._get_default("supercell_x")
if not self.disable_y:
self.supercell_y = self._get_default("supercell_x")
if not self.disable_z:
self.supercell_z = self._get_default("supercell_x")
self.supercell = [self.supercell_x, self.supercell_y, self.supercell_z]

def reset_symprec(self, _=None):
self.symmetry_symprec = (
self._get_default("symmetry_symprec")
if self.input_structure.pbc != (True, False, False)
else 1e-3
)
self.supercell_number_estimator = self._get_default(
"supercell_number_estimator"
)

@disable_print
def _estimate_supercells(self, _=None):
if self.input_structure:
self.supercell_number_estimator = spinner_html

preprocess_data = PreProcessData(
structure=self.input_structure,
supercell_matrix=[
[self.supercell_x, 0, 0],
[0, self.supercell_y, 0],
[0, 0, self.supercell_z],
],
symprec=self.symmetry_symprec,
distinguish_kinds=False,
is_symmetry=True,
)

if isinstance(self.input_structure, HubbardStructureData):
supercell = get_supercell_hubbard_structure(
self.input_structure,
self.input_structure,
metadata={"store_provenance": False},
)
supercells = get_supercells_for_hubbard(
preprocess_data=preprocess_data,
ref_structure=supercell,
metadata={"store_provenance": False},
)
else:
supercells = preprocess_data.get_supercells_with_displacements()

self.supercell_number_estimator = f"{len(supercells)}"

return
Loading
Loading