-
Notifications
You must be signed in to change notification settings - Fork 1
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
Changes from 22 commits
8d171b0
6ec5f94
1ea22a0
16b999d
b18fe6d
9524fbc
54035b7
5917326
7486b06
8ea879c
04d5d17
3321f58
eaa337c
194c3b3
a2b8d08
aa70434
4a7a378
a78c55b
5a0982f
91b4fd4
b5f7d5c
baa9d5a
e454b16
5fc101f
ea4f2eb
f901d8d
3c80929
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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, | ||
} |
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" | ||
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() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
There was a problem hiding this comment.
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