From 9d952b9572d1b6754a91ac9b2598e2f82fa23aca Mon Sep 17 00:00:00 2001 From: superstar54 Date: Tue, 21 Nov 2023 14:26:15 +0000 Subject: [PATCH 01/21] add new ComputationalResourcesWidget with nodes and cpus --- src/aiidalab_qe/common/widgets.py | 139 +++++++++++++++++++++++++++++- 1 file changed, 138 insertions(+), 1 deletion(-) diff --git a/src/aiidalab_qe/common/widgets.py b/src/aiidalab_qe/common/widgets.py index 8360ce783..ef8c51b0b 100644 --- a/src/aiidalab_qe/common/widgets.py +++ b/src/aiidalab_qe/common/widgets.py @@ -17,7 +17,8 @@ import traitlets from aiida.orm import CalcJobNode from aiida.orm import Data as orm_Data -from aiida.orm import load_node +from aiida.orm import load_code, load_node +from aiidalab_widgets_base import ComputationalResourcesWidget as AiiDACodeWidget from aiidalab_widgets_base.utils import ( StatusHTML, list_to_string_range, @@ -617,3 +618,139 @@ def _select_periodicity(self, _=None): new_structure.set_pbc(periodicity_options[self.periodicity.value]) self.structure = None self.structure = deepcopy(new_structure) + + +class ComputationalResourcesWidget(AiiDACodeWidget): + nodes = traitlets.Int(default_value=1) + cpus = traitlets.Int(default_value=1) + + def __init__(self, max_num_nodes=1000, **kwargs): + """Widget for the selection of compute resources. + max_num_nodes: maximum number of nodes allowed. + """ + super().__init__(**kwargs) + + self.num_nodes = ipw.BoundedIntText( + value=1, step=1, min=1, max=max_num_nodes, description="Nodes", width="10%" + ) + self.num_cpus = ipw.BoundedIntText( + value=1, step=1, min=1, description="CPUs", width="10%" + ) + # add nodes and cpus into the children of the widget + self.children[0].children += ( + self.num_nodes, + self.num_cpus, + ) + + @traitlets.observe("value") + def _update_resources(self, change): + if change["new"] and ( + change["old"] is None + or load_code(change["new"]).computer.pk + != load_code(change["old"]).computer.pk + ): + self.set_resource_defaults(load_code(change["new"]).computer) + + def set_resource_defaults(self, computer=None): + import os + + if computer is None or computer.hostname == "localhost": + self.num_nodes.disabled = True + self.num_nodes.value = 1 + self.num_cpus.max = os.cpu_count() + self.num_cpus.value = 1 + self.num_cpus.description = "CPUs" + else: + default_mpiprocs = computer.get_default_mpiprocs_per_machine() + self.num_nodes.disabled = False + self.num_cpus.max = default_mpiprocs + self.num_cpus.value = default_mpiprocs + self.num_cpus.description = "CPUs" + + @property + def parameters(self): + return self.get_parameters() + + def get_parameters(self): + return { + "code": self.value, + "nodes": self.num_nodes.value, + "cpus": self.num_cpus.value, + } + + @parameters.setter + def set_parameters(self, parameters): + self.value = parameters["code"] + self.num_nodes.value = parameters["nodes"] + self.num_cpus.value = parameters["cpus"] + + +class ParallelizationSettings(ipw.VBox): + """Widget for setting the parallelization settings.""" + + prompt = ipw.HTML( + """
+

+ Specify the number of k-points pools for the pw.x calculations. +

""" + ) + + def __init__(self, **kwargs): + extra = { + "style": {"description_width": "150px"}, + "layout": {"min_width": "180px"}, + } + self.npool = ipw.BoundedIntText( + value=1, step=1, min=1, max=128, description="Number of k-pools", **extra + ) + super().__init__( + children=[ + ipw.HBox( + children=[self.prompt, self.npool], + layout=ipw.Layout(justify_content="space-between"), + ), + ] + ) + + def reset(self): + self.npool.value = 1 + + +class PWscfWidget(ComputationalResourcesWidget): + nodes = traitlets.Int(default_value=1) + + def __init__(self, **kwargs): + super().__init__(**kwargs) + # By definition, npool must be a divisor of the total number of k-points + # thus we can not set a default value here, or from the computer. + self.parallelization = ParallelizationSettings() + # add nodes and cpus into the children of the widget + self.children += (self.parallelization,) + + def get_parallelization(self): + parallelization = { + "npool": self.parallelization.npool.value, + } + return parallelization + + def set_parallelization(self, parallelization): + self.parallelization.npool.value = parallelization["npool"] + + @property + def parameters(self): + return self.get_parameters() + + def get_parameters(self): + return { + "code": self.value, + "nodes": self.num_nodes.value, + "cpus": self.num_cpus.value, + "parallelization": self.get_parallelization(), + } + + @parameters.setter + def set_parameters(self, parameters): + self.value = parameters["code"] + self.num_nodes.value = parameters["nodes"] + self.num_cpus.value = parameters["cpus"] + self.set_parallelization(parameters["parallelization"]) From b7d1752943f7e276f5b9bf4b3801a3a7370e1147 Mon Sep 17 00:00:00 2001 From: superstar54 Date: Tue, 21 Nov 2023 14:26:26 +0000 Subject: [PATCH 02/21] use new widget in submission --- src/aiidalab_qe/app/parameters/qeapp.yaml | 11 +- src/aiidalab_qe/app/submission/__init__.py | 114 ++++----------------- src/aiidalab_qe/app/submission/resource.py | 85 --------------- src/aiidalab_qe/plugins/bands/workchain.py | 19 +++- src/aiidalab_qe/plugins/pdos/__init__.py | 3 +- src/aiidalab_qe/plugins/pdos/workchain.py | 31 +++++- src/aiidalab_qe/workflows/__init__.py | 11 +- 7 files changed, 77 insertions(+), 197 deletions(-) diff --git a/src/aiidalab_qe/app/parameters/qeapp.yaml b/src/aiidalab_qe/app/parameters/qeapp.yaml index 613f25dc9..0ed1879ce 100644 --- a/src/aiidalab_qe/app/parameters/qeapp.yaml +++ b/src/aiidalab_qe/app/parameters/qeapp.yaml @@ -22,8 +22,11 @@ advanced: accuracy: efficiency tot_charge: 0 -## Codes +## Computational resources codes: - dos: dos-7.2@localhost - projwfc: projwfc-7.2@localhost - pw: pw-7.2@localhost + dos: + code: dos-7.2@localhost + projwfc: + code: projwfc-7.2@localhost + pw: + code: pw-7.2@localhost diff --git a/src/aiidalab_qe/app/submission/__init__.py b/src/aiidalab_qe/app/submission/__init__.py index 372df860b..5c3a04643 100644 --- a/src/aiidalab_qe/app/submission/__init__.py +++ b/src/aiidalab_qe/app/submission/__init__.py @@ -5,24 +5,21 @@ """ from __future__ import annotations -import os - import ipywidgets as ipw import traitlets as tl from aiida import orm from aiida.common import NotExistent from aiida.engine import ProcessBuilderNamespace, submit -from aiidalab_widgets_base import ComputationalResourcesWidget, WizardAppWidgetStep +from aiidalab_widgets_base import WizardAppWidgetStep from IPython.display import display from aiidalab_qe.app.parameters import DEFAULT_PARAMETERS from aiidalab_qe.app.utils import get_entry_items from aiidalab_qe.common.setup_codes import QESetupWidget from aiidalab_qe.common.setup_pseudos import PseudosInstallWidget +from aiidalab_qe.common.widgets import PWscfWidget from aiidalab_qe.workflows import QeAppWorkChain -from .resource import ParallelizationSettings, ResourceSelectionWidget - class SubmitQeAppWorkChainStep(ipw.VBox, WizardAppWidgetStep): """Step for submission of a bands workchain.""" @@ -61,17 +58,11 @@ def __init__(self, qe_auto_setup=True, **kwargs): self.message_area = ipw.Output() self._submission_blocker_messages = ipw.HTML() - self.pw_code = ComputationalResourcesWidget( + self.pw_code = PWscfWidget( description="pw.x:", default_calc_job_plugin="quantumespresso.pw" ) - self.resources_config = ResourceSelectionWidget() - self.parallelization = ParallelizationSettings() - - self.set_resource_defaults() - self.pw_code.observe(self._update_state, "value") - self.pw_code.observe(self._update_resources, "value") # add plugin's entry points self.codes = {"pw": self.pw_code} @@ -123,8 +114,6 @@ def __init__(self, qe_auto_setup=True, **kwargs): super().__init__( children=[ *self.code_children, - self.resources_config, - self.parallelization, self.message_area, self.sssp_installation_status, self.qe_setup_status, @@ -221,55 +210,6 @@ def _show_alert_message(self, message, alert_class="info"): ) ) - def _update_resources(self, change): - if change["new"] and ( - change["old"] is None - or orm.load_code(change["new"]).computer.pk - != orm.load_code(change["old"]).computer.pk - ): - self.set_resource_defaults(orm.load_code(change["new"]).computer) - - def get_resources(self): - resources = { - "num_machines": self.resources_config.num_nodes.value, - "num_mpiprocs_per_machine": self.resources_config.num_cpus.value, - "npools": self.parallelization.npools.value, - } - return resources - - def set_resources(self, resources): - self.resources_config.num_nodes.value = resources["num_machines"] - self.resources_config.num_cpus.value = resources["num_mpiprocs_per_machine"] - self.parallelization.npools.value = resources["npools"] - - def set_resource_defaults(self, computer=None): - if computer is None or computer.hostname == "localhost": - self.resources_config.num_nodes.disabled = True - self.resources_config.num_nodes.value = 1 - self.resources_config.num_cpus.max = os.cpu_count() - self.resources_config.num_cpus.value = 1 - self.resources_config.num_cpus.description = "CPUs" - self.parallelization.npools.value = 1 - else: - default_mpiprocs = computer.get_default_mpiprocs_per_machine() - self.resources_config.num_nodes.disabled = False - self.resources_config.num_cpus.max = default_mpiprocs - self.resources_config.num_cpus.value = default_mpiprocs - self.resources_config.num_cpus.description = "CPUs/node" - self.parallelization.npools.value = self._get_default_parallelization() - - self._check_resources() - - def _get_default_parallelization(self): - """A _very_ rudimentary approach for obtaining a minimal npools setting.""" - num_mpiprocs = ( - self.resources_config.num_nodes.value * self.resources_config.num_cpus.value - ) - - for i in range(1, num_mpiprocs + 1): - if num_mpiprocs % i == 0 and num_mpiprocs // i < self.MAX_MPI_PER_POOL: - return i - def _check_resources(self): """Check whether the currently selected resources will be sufficient and warn if not.""" if not self.pw_code.value: @@ -328,7 +268,7 @@ def get_selected_codes(self): return: A dict with the code names as keys and the code UUIDs as values. """ - codes = {key: code.value for key, code in self.codes.items()} + codes = {key: code.parameters for key, code in self.codes.items()} return codes def set_selected_codes(self, codes): @@ -344,7 +284,7 @@ def _get_code_uuid(code): with self.hold_trait_notifications(): for name, code in self.codes.items(): - code.value = _get_code_uuid(codes.get(name)) + code.value = _get_code_uuid(codes.get(name)["code"]) def update_codes_display(self): """Hide code if no related property is selected.""" @@ -400,53 +340,36 @@ def _create_builder(self) -> ProcessBuilderNamespace: from copy import deepcopy self.ui_parameters = deepcopy(self.input_parameters) - self.ui_parameters["resources"] = self.get_resources() # add codes and resource info into ui_parameters - self.ui_parameters.update(self.get_submission_parameters()) + submission_parameters = self.get_submission_parameters() + self.ui_parameters.update(submission_parameters) builder = QeAppWorkChain.get_builder_from_protocol( structure=self.input_structure, parameters=deepcopy(self.ui_parameters), ) - self._update_builder(builder, self.MAX_MPI_PER_POOL) + self._update_builder(builder, submission_parameters["codes"]) return builder - def _update_builder(self, buildy, max_mpi_per_pool): - resources = self.get_resources() - npools = resources.pop("npools", 1) - """Update the resources and parallelization of the ``QeAppWorkChain`` builder.""" - for k, v in buildy.items(): - if isinstance(v, (dict, ProcessBuilderNamespace)): - if k == "pw" and v["pseudos"]: - v["parallelization"] = orm.Dict(dict={"npool": npools}) - if k == "projwfc": - v["settings"] = orm.Dict(dict={"cmdline": ["-nk", str(npools)]}) - if k == "dos": - v["metadata"]["options"]["resources"] = { - "num_machines": 1, - "num_mpiprocs_per_machine": min( - max_mpi_per_pool, - resources["num_mpiprocs_per_machine"], - ), - } - # Continue to the next item to avoid overriding the resources in the - # recursive `update_builder` call. - continue - if k == "resources": - buildy["resources"] = resources - else: - self._update_builder(v, max_mpi_per_pool) + def _update_builder(self, builder, codes): + """Update the resources and parallelization of the ``relax`` builder.""" + # update resources + builder.relax.base.pw.metadata.options.resources = { + "num_machines": codes.get("pw")["nodes"], + "num_mpiprocs_per_machine": codes.get("pw")["cpus"], + } + builder.relax.base.pw.parallelization = orm.Dict( + dict=codes["pw"]["parallelization"] + ) def set_submission_parameters(self, parameters): - self.set_resources(parameters["resources"]) self.set_selected_codes(parameters["codes"]) def get_submission_parameters(self): """Get the parameters for the submission step.""" return { "codes": self.get_selected_codes(), - "resources": self.get_resources(), } def reset(self): @@ -455,4 +378,3 @@ def reset(self): self.process = None self.input_structure = None self.set_selected_codes(DEFAULT_PARAMETERS["codes"]) - self.set_resource_defaults() diff --git a/src/aiidalab_qe/app/submission/resource.py b/src/aiidalab_qe/app/submission/resource.py index 3d3e5fb9b..e69de29bb 100644 --- a/src/aiidalab_qe/app/submission/resource.py +++ b/src/aiidalab_qe/app/submission/resource.py @@ -1,85 +0,0 @@ -# -*- coding: utf-8 -*- -"""Widgets for the submission of bands work chains. - -Authors: AiiDAlab team -""" -import ipywidgets as ipw - - -class ResourceSelectionWidget(ipw.VBox): - """Widget for the selection of compute resources.""" - - title = ipw.HTML( - """
-

Resources

-
""" - ) - prompt = ipw.HTML( - """
-

- Specify the resources to use for the pw.x calculation. -

""" - ) - - def __init__(self, **kwargs): - extra = { - "style": {"description_width": "150px"}, - "layout": {"min_width": "180px"}, - } - self.num_nodes = ipw.BoundedIntText( - value=1, step=1, min=1, max=1000, description="Nodes", **extra - ) - self.num_cpus = ipw.BoundedIntText( - value=1, step=1, min=1, description="CPUs", **extra - ) - - super().__init__( - children=[ - self.title, - ipw.HBox( - children=[self.prompt, self.num_nodes, self.num_cpus], - layout=ipw.Layout(justify_content="space-between"), - ), - ] - ) - - def reset(self): - self.num_nodes.value = 1 - self.num_cpus.value = 1 - - -class ParallelizationSettings(ipw.VBox): - """Widget for setting the parallelization settings.""" - - title = ipw.HTML( - """
-

Parallelization

-
""" - ) - prompt = ipw.HTML( - """
-

- Specify the number of k-points pools for the calculations. -

""" - ) - - def __init__(self, **kwargs): - extra = { - "style": {"description_width": "150px"}, - "layout": {"min_width": "180px"}, - } - self.npools = ipw.BoundedIntText( - value=1, step=1, min=1, max=128, description="Number of k-pools", **extra - ) - super().__init__( - children=[ - self.title, - ipw.HBox( - children=[self.prompt, self.npools], - layout=ipw.Layout(justify_content="space-between"), - ), - ] - ) - - def reset(self): - self.npools.value = 1 diff --git a/src/aiidalab_qe/plugins/bands/workchain.py b/src/aiidalab_qe/plugins/bands/workchain.py index 4574032af..d8447c961 100644 --- a/src/aiidalab_qe/plugins/bands/workchain.py +++ b/src/aiidalab_qe/plugins/bands/workchain.py @@ -1,4 +1,5 @@ import numpy as np +from aiida import orm from aiida.plugins import DataFactory, WorkflowFactory from aiida_quantumespresso.common.types import ElectronicType, SpinType @@ -170,11 +171,24 @@ def generate_kpath_2d(structure, kpoints_distance, kpath_2d): return kpoints +def update_resources(builder, codes): + builder.scf.pw.metadata.options.resources = { + "num_machines": codes.get("pw")["nodes"], + "num_mpiprocs_per_machine": codes.get("pw")["cpus"], + } + builder.scf.pw.parallelization = orm.Dict(dict=codes["pw"]["parallelization"]) + builder.bands.pw.metadata.options.resources = { + "num_machines": codes.get("pw")["nodes"], + "num_mpiprocs_per_machine": codes.get("pw")["cpus"], + } + builder.bands.pw.parallelization = orm.Dict(dict=codes["pw"]["parallelization"]) + + def get_builder(codes, structure, parameters, **kwargs): """Get a builder for the PwBandsWorkChain.""" from copy import deepcopy - pw_code = codes.get("pw") + pw_code = codes.get("pw")["code"] protocol = parameters["workchain"]["protocol"] scf_overrides = deepcopy(parameters["advanced"]) bands_overrides = deepcopy(parameters["advanced"]) @@ -211,6 +225,9 @@ def get_builder(codes, structure, parameters, **kwargs): bands.pop("relax") bands.pop("structure", None) bands.pop("clean_workdir", None) + # update resources + update_resources(bands, codes) + return bands diff --git a/src/aiidalab_qe/plugins/pdos/__init__.py b/src/aiidalab_qe/plugins/pdos/__init__.py index e84e4f31f..c96191078 100644 --- a/src/aiidalab_qe/plugins/pdos/__init__.py +++ b/src/aiidalab_qe/plugins/pdos/__init__.py @@ -1,6 +1,5 @@ -from aiidalab_widgets_base import ComputationalResourcesWidget - from aiidalab_qe.common.panel import OutlinePanel +from aiidalab_qe.common.widgets import ComputationalResourcesWidget from .result import Result from .setting import Setting diff --git a/src/aiidalab_qe/plugins/pdos/workchain.py b/src/aiidalab_qe/plugins/pdos/workchain.py index bd9915f2e..b15469917 100644 --- a/src/aiidalab_qe/plugins/pdos/workchain.py +++ b/src/aiidalab_qe/plugins/pdos/workchain.py @@ -1,3 +1,4 @@ +from aiida import orm from aiida.plugins import WorkflowFactory from aiida_quantumespresso.common.types import ElectronicType, SpinType @@ -31,12 +32,33 @@ def check_codes(pw_code, dos_code, projwfc_code): ) +def update_resources(builder, codes): + builder.scf.pw.metadata.options.resources = { + "num_machines": codes.get("pw")["nodes"], + "num_mpiprocs_per_machine": codes.get("pw")["cpus"], + } + builder.scf.pw.parallelization = orm.Dict(dict=codes["pw"]["parallelization"]) + builder.nscf.pw.metadata.options.resources = { + "num_machines": codes.get("pw")["nodes"], + "num_mpiprocs_per_machine": codes.get("pw")["cpus"], + } + builder.nscf.pw.parallelization = orm.Dict(dict=codes["pw"]["parallelization"]) + builder.dos.metadata.options.resources = { + "num_machines": codes.get("dos")["nodes"], + "num_mpiprocs_per_machine": codes.get("dos")["cpus"], + } + builder.projwfc.metadata.options.resources = { + "num_machines": codes.get("projwfc")["nodes"], + "num_mpiprocs_per_machine": codes.get("projwfc")["cpus"], + } + + def get_builder(codes, structure, parameters, **kwargs): from copy import deepcopy - pw_code = codes.get("pw") - dos_code = codes.get("dos") - projwfc_code = codes.get("projwfc") + pw_code = codes.get("pw")["code"] + dos_code = codes.get("dos")["code"] + projwfc_code = codes.get("projwfc")["code"] check_codes(pw_code, dos_code, projwfc_code) protocol = parameters["workchain"]["protocol"] @@ -66,6 +88,9 @@ def get_builder(codes, structure, parameters, **kwargs): # pop the inputs that are exclueded from the expose_inputs pdos.pop("structure", None) pdos.pop("clean_workdir", None) + # update resources + update_resources(pdos, codes) + else: raise ValueError("The dos_code and projwfc_code are required.") return pdos diff --git a/src/aiidalab_qe/workflows/__init__.py b/src/aiidalab_qe/workflows/__init__.py index 75a74029b..8ce022cd1 100644 --- a/src/aiidalab_qe/workflows/__init__.py +++ b/src/aiidalab_qe/workflows/__init__.py @@ -111,11 +111,10 @@ def get_builder_from_protocol( parameters = parameters or {} properties = parameters["workchain"].pop("properties", []) codes = parameters.pop("codes", {}) - codes = { - key: orm.load_node(value) - for key, value in codes.items() - if value is not None - } + # load codes from uuid + for _, value in codes.items(): + if value["code"] is not None: + value["code"] = orm.load_node(value["code"]) # update pseudos for kind, uuid in parameters["advanced"]["pw"]["pseudos"].items(): parameters["advanced"]["pw"]["pseudos"][kind] = orm.load_node(uuid) @@ -127,7 +126,7 @@ def get_builder_from_protocol( relax_overrides = {"base": parameters["advanced"]} protocol = parameters["workchain"]["protocol"] relax_builder = PwRelaxWorkChain.get_builder_from_protocol( - code=codes.get("pw"), + code=codes.get("pw")["code"], structure=structure, protocol=protocol, relax_type=RelaxType(parameters["workchain"]["relax_type"]), From 85d888c9eed875b2121ed399994c6e6dac05e349 Mon Sep 17 00:00:00 2001 From: superstar54 Date: Tue, 21 Nov 2023 14:58:24 +0000 Subject: [PATCH 03/21] update test --- src/aiidalab_qe/app/submission/__init__.py | 16 ++++----- src/aiidalab_qe/common/widgets.py | 42 +++++++++++----------- tests/conftest.py | 4 +-- tests/test_app.py | 2 +- 4 files changed, 33 insertions(+), 31 deletions(-) diff --git a/src/aiidalab_qe/app/submission/__init__.py b/src/aiidalab_qe/app/submission/__init__.py index 5c3a04643..068212a23 100644 --- a/src/aiidalab_qe/app/submission/__init__.py +++ b/src/aiidalab_qe/app/submission/__init__.py @@ -77,8 +77,6 @@ def __init__(self, qe_auto_setup=True, **kwargs): self.codes[name] = code code.observe(self._update_state, "value") self.code_children.append(self.codes[name]) - # set default codes - self.set_selected_codes(DEFAULT_PARAMETERS["codes"]) # self.submit_button = ipw.Button( description="Submit", @@ -121,6 +119,8 @@ def __init__(self, qe_auto_setup=True, **kwargs): self.submit_button, ] ) + # set default codes + self.set_selected_codes(DEFAULT_PARAMETERS["codes"]) @tl.observe("internal_submission_blockers", "external_submission_blockers") def _observe_submission_blockers(self, _change): @@ -186,12 +186,10 @@ def _toggle_install_widgets(self, change): def _auto_select_code(self, change): if change["new"] and not change["old"]: - for name, code_widget in self.codes.items(): + for name, code in self.codes.items(): try: - code_widget.refresh() - code_widget.value = orm.load_code( - DEFAULT_PARAMETERS["codes"][name] - ).uuid + code.refresh() + code.value = orm.load_code(DEFAULT_PARAMETERS["codes"][name]).uuid except NotExistent: pass @@ -284,7 +282,9 @@ def _get_code_uuid(code): with self.hold_trait_notifications(): for name, code in self.codes.items(): - code.value = _get_code_uuid(codes.get(name)["code"]) + # get code uuid from code label in case of using DEFAULT_PARAMETERS + codes.get(name)["code"] = _get_code_uuid(codes.get(name)["code"]) + code.parameters = codes.get(name) def update_codes_display(self): """Hide code if no related property is selected.""" diff --git a/src/aiidalab_qe/common/widgets.py b/src/aiidalab_qe/common/widgets.py index ef8c51b0b..499451b4e 100644 --- a/src/aiidalab_qe/common/widgets.py +++ b/src/aiidalab_qe/common/widgets.py @@ -628,14 +628,13 @@ def __init__(self, max_num_nodes=1000, **kwargs): """Widget for the selection of compute resources. max_num_nodes: maximum number of nodes allowed. """ - super().__init__(**kwargs) - self.num_nodes = ipw.BoundedIntText( value=1, step=1, min=1, max=max_num_nodes, description="Nodes", width="10%" ) self.num_cpus = ipw.BoundedIntText( value=1, step=1, min=1, description="CPUs", width="10%" ) + super().__init__(**kwargs) # add nodes and cpus into the children of the widget self.children[0].children += ( self.num_nodes, @@ -672,6 +671,7 @@ def parameters(self): return self.get_parameters() def get_parameters(self): + """Return the parameters.""" return { "code": self.value, "nodes": self.num_nodes.value, @@ -679,10 +679,16 @@ def get_parameters(self): } @parameters.setter + def parameters(self, parameters): + self.set_parameters(parameters) + def set_parameters(self, parameters): + """Set the parameters.""" self.value = parameters["code"] - self.num_nodes.value = parameters["nodes"] - self.num_cpus.value = parameters["cpus"] + if "nodes" in parameters: + self.num_nodes.value = parameters["nodes"] + if "cpus" in parameters: + self.num_cpus.value = parameters["cpus"] class ParallelizationSettings(ipw.VBox): @@ -713,6 +719,7 @@ def __init__(self, **kwargs): ) def reset(self): + """Reset the parallelization settings.""" self.npool.value = 1 @@ -720,37 +727,32 @@ class PWscfWidget(ComputationalResourcesWidget): nodes = traitlets.Int(default_value=1) def __init__(self, **kwargs): - super().__init__(**kwargs) # By definition, npool must be a divisor of the total number of k-points # thus we can not set a default value here, or from the computer. self.parallelization = ParallelizationSettings() + super().__init__(**kwargs) # add nodes and cpus into the children of the widget self.children += (self.parallelization,) def get_parallelization(self): + """Return the parallelization settings.""" parallelization = { "npool": self.parallelization.npool.value, } return parallelization def set_parallelization(self, parallelization): + """Set the parallelization settings.""" self.parallelization.npool.value = parallelization["npool"] - @property - def parameters(self): - return self.get_parameters() - def get_parameters(self): - return { - "code": self.value, - "nodes": self.num_nodes.value, - "cpus": self.num_cpus.value, - "parallelization": self.get_parallelization(), - } + """Return the parameters.""" + parameters = super().get_parameters() + parameters.update({"parallelization": self.get_parallelization()}) + return parameters - @parameters.setter def set_parameters(self, parameters): - self.value = parameters["code"] - self.num_nodes.value = parameters["nodes"] - self.num_cpus.value = parameters["cpus"] - self.set_parallelization(parameters["parallelization"]) + """Set the parameters.""" + super().set_parameters(parameters) + if "parallelization" in parameters: + self.set_parallelization(parameters["parallelization"]) diff --git a/tests/conftest.py b/tests/conftest.py index d73f258fd..acb042a9b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -363,7 +363,7 @@ def _submit_app_generator( # submit_step = app.submit_step submit_step.input_structure = generate_structure_data() - submit_step.resources_config.num_cpus.value = 2 + submit_step.pw_code.num_cpus.value = 2 return app @@ -609,7 +609,7 @@ def _generate_qeapp_workchain( s2.confirm() # step 3 setup code and resources s3 = app.submit_step - s3.resources_config.num_cpus.value = 4 + s3.pw_code.num_cpus.value = 4 builder = s3._create_builder() inputs = builder._inputs() inputs["relax"]["base_final_scf"] = deepcopy(inputs["relax"]["base"]) diff --git a/tests/test_app.py b/tests/test_app.py index 65bfac6c2..c538a854a 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -39,7 +39,7 @@ def test_reload_and_reset(submit_app_generator, generate_qeapp_workchain): ) == 0 ) - assert app.submit_step.resources_config.num_cpus.value == 1 + assert app.submit_step.pw_code.num_cpus.value == 4 def test_select_new_structure(app_to_submit, generate_structure_data): From 4664bcfbbbd8129db6082c7b3b7137112856ba61 Mon Sep 17 00:00:00 2001 From: superstar54 Date: Tue, 21 Nov 2023 15:29:17 +0000 Subject: [PATCH 04/21] fix test for pdos --- src/aiidalab_qe/plugins/pdos/workchain.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/aiidalab_qe/plugins/pdos/workchain.py b/src/aiidalab_qe/plugins/pdos/workchain.py index b15469917..6d54d2959 100644 --- a/src/aiidalab_qe/plugins/pdos/workchain.py +++ b/src/aiidalab_qe/plugins/pdos/workchain.py @@ -51,6 +51,8 @@ def update_resources(builder, codes): "num_machines": codes.get("projwfc")["nodes"], "num_mpiprocs_per_machine": codes.get("projwfc")["cpus"], } + npool = codes["pw"]["parallelization"]["npool"] + builder.projwfc.settings = orm.Dict(dict={"cmdline": ["-nk", str(npool)]}) def get_builder(codes, structure, parameters, **kwargs): From 63a6a3583933eda5bb70081a72dbb7853258a851 Mon Sep 17 00:00:00 2001 From: superstar54 Date: Wed, 22 Nov 2023 13:15:47 +0000 Subject: [PATCH 05/21] fix code not exist when setting --- src/aiidalab_qe/app/submission/__init__.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/aiidalab_qe/app/submission/__init__.py b/src/aiidalab_qe/app/submission/__init__.py index 068212a23..dbc52a235 100644 --- a/src/aiidalab_qe/app/submission/__init__.py +++ b/src/aiidalab_qe/app/submission/__init__.py @@ -269,7 +269,7 @@ def get_selected_codes(self): codes = {key: code.parameters for key, code in self.codes.items()} return codes - def set_selected_codes(self, codes): + def set_selected_codes(self, code_data): """Set the inputs in the GUI based on a set of codes.""" # Codes @@ -283,8 +283,12 @@ def _get_code_uuid(code): with self.hold_trait_notifications(): for name, code in self.codes.items(): # get code uuid from code label in case of using DEFAULT_PARAMETERS - codes.get(name)["code"] = _get_code_uuid(codes.get(name)["code"]) - code.parameters = codes.get(name) + if name not in code_data: + continue + code_data.get(name)["code"] = _get_code_uuid( + code_data.get(name)["code"] + ) + code.parameters = code_data.get(name) def update_codes_display(self): """Hide code if no related property is selected.""" From 38f5db20ae916f7e6403379bb0620f6eaa9d0438 Mon Sep 17 00:00:00 2001 From: superstar54 Date: Wed, 22 Nov 2023 13:31:23 +0000 Subject: [PATCH 06/21] backward compatibility for v2023.11 --- src/aiidalab_qe/app/submission/__init__.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/aiidalab_qe/app/submission/__init__.py b/src/aiidalab_qe/app/submission/__init__.py index dbc52a235..9951ef23e 100644 --- a/src/aiidalab_qe/app/submission/__init__.py +++ b/src/aiidalab_qe/app/submission/__init__.py @@ -368,6 +368,19 @@ def _update_builder(self, builder, codes): ) def set_submission_parameters(self, parameters): + # backward compatibility for v2023.11 + # which have a separate "resources" section for pw code + if "resources" in parameters: + parameters["codes"] = { + key: {"code": value} for key, value in parameters["codes"].items() + } + parameters["codes"]["pw"]["nodes"] = parameters["resources"]["num_machines"] + parameters["codes"]["pw"]["cpus"] = parameters["resources"][ + "num_mpiprocs_per_machine" + ] + parameters["codes"]["pw"]["parallelization"] = { + "npool": parameters["resources"]["npools"] + } self.set_selected_codes(parameters["codes"]) def get_submission_parameters(self): From 4ec0817b9cd764da75425405a338eae3bebe9281 Mon Sep 17 00:00:00 2001 From: superstar54 Date: Wed, 22 Nov 2023 15:00:36 +0000 Subject: [PATCH 07/21] change name to QEAppComputationalResourcesWidget, and add blocker if wrong widget is used. --- src/aiidalab_qe/app/submission/__init__.py | 9 ++++++++- src/aiidalab_qe/common/widgets.py | 4 ++-- src/aiidalab_qe/plugins/pdos/__init__.py | 6 +++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/aiidalab_qe/app/submission/__init__.py b/src/aiidalab_qe/app/submission/__init__.py index 9951ef23e..7c8466cf5 100644 --- a/src/aiidalab_qe/app/submission/__init__.py +++ b/src/aiidalab_qe/app/submission/__init__.py @@ -17,7 +17,7 @@ from aiidalab_qe.app.utils import get_entry_items from aiidalab_qe.common.setup_codes import QESetupWidget from aiidalab_qe.common.setup_pseudos import PseudosInstallWidget -from aiidalab_qe.common.widgets import PWscfWidget +from aiidalab_qe.common.widgets import PWscfWidget, QEAppComputationalResourcesWidget from aiidalab_qe.workflows import QeAppWorkChain @@ -154,6 +154,13 @@ def _identify_submission_blockers(self): if not self.sssp_installation_status.installed: yield "The SSSP library is not installed." + # check if the QEAppComputationalResourcesWidget is used + for name, code in self.codes.items(): + if not isinstance(code, QEAppComputationalResourcesWidget): + yield ( + f"Error: hi, plugin developer, please use the QEAppComputationalResourcesWidget from aiidalab_qe.common.widgets for code {name}." + ) + def _update_state(self, _=None): # If the previous step has failed, this should fail as well. if self.previous_step_state is self.State.FAIL: diff --git a/src/aiidalab_qe/common/widgets.py b/src/aiidalab_qe/common/widgets.py index 499451b4e..1de61f800 100644 --- a/src/aiidalab_qe/common/widgets.py +++ b/src/aiidalab_qe/common/widgets.py @@ -620,7 +620,7 @@ def _select_periodicity(self, _=None): self.structure = deepcopy(new_structure) -class ComputationalResourcesWidget(AiiDACodeWidget): +class QEAppComputationalResourcesWidget(AiiDACodeWidget): nodes = traitlets.Int(default_value=1) cpus = traitlets.Int(default_value=1) @@ -723,7 +723,7 @@ def reset(self): self.npool.value = 1 -class PWscfWidget(ComputationalResourcesWidget): +class PWscfWidget(QEAppComputationalResourcesWidget): nodes = traitlets.Int(default_value=1) def __init__(self, **kwargs): diff --git a/src/aiidalab_qe/plugins/pdos/__init__.py b/src/aiidalab_qe/plugins/pdos/__init__.py index c96191078..8bc3fbd54 100644 --- a/src/aiidalab_qe/plugins/pdos/__init__.py +++ b/src/aiidalab_qe/plugins/pdos/__init__.py @@ -1,5 +1,5 @@ from aiidalab_qe.common.panel import OutlinePanel -from aiidalab_qe.common.widgets import ComputationalResourcesWidget +from aiidalab_qe.common.widgets import QEAppComputationalResourcesWidget from .result import Result from .setting import Setting @@ -11,12 +11,12 @@ class PdosOutline(OutlinePanel): help = """""" -dos_code = ComputationalResourcesWidget( +dos_code = QEAppComputationalResourcesWidget( description="dos.x", default_calc_job_plugin="quantumespresso.dos", ) -projwfc_code = ComputationalResourcesWidget( +projwfc_code = QEAppComputationalResourcesWidget( description="projwfc.x", default_calc_job_plugin="quantumespresso.projwfc", ) From 97c48ece53b1620e04bf642af717a886ffd639e4 Mon Sep 17 00:00:00 2001 From: superstar54 Date: Wed, 22 Nov 2023 15:10:39 +0000 Subject: [PATCH 08/21] only add blocker for selected codes --- src/aiidalab_qe/app/submission/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/aiidalab_qe/app/submission/__init__.py b/src/aiidalab_qe/app/submission/__init__.py index 7c8466cf5..57ffe0b97 100644 --- a/src/aiidalab_qe/app/submission/__init__.py +++ b/src/aiidalab_qe/app/submission/__init__.py @@ -156,6 +156,9 @@ def _identify_submission_blockers(self): # check if the QEAppComputationalResourcesWidget is used for name, code in self.codes.items(): + # skip if the code is not displayed, convenient for the plugin developer + if code.layout.display == "none": + continue if not isinstance(code, QEAppComputationalResourcesWidget): yield ( f"Error: hi, plugin developer, please use the QEAppComputationalResourcesWidget from aiidalab_qe.common.widgets for code {name}." From cb1ac30dbe02d1469609007f21dfd66c1780a770 Mon Sep 17 00:00:00 2001 From: superstar54 Date: Wed, 22 Nov 2023 15:18:39 +0000 Subject: [PATCH 09/21] update doc, ingore hidden codes --- docs/source/development/plugin.rst | 6 +++--- src/aiidalab_qe/app/submission/__init__.py | 6 +++++- src/aiidalab_qe/common/widgets.py | 2 ++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/source/development/plugin.rst b/docs/source/development/plugin.rst index 3dbd12692..d0310198c 100644 --- a/docs/source/development/plugin.rst +++ b/docs/source/development/plugin.rst @@ -224,7 +224,7 @@ The ``get_builder`` function will return a ``builder`` for the ``EOSWorkChain``, def get_builder(codes, structure, parameters, **kwargs): protocol = parameters["workchain"].pop('protocol', "fast") - pw_code = codes.get("pw") + pw_code = codes.get("pw")['code'] overrides = { "pw": parameters["advanced"], } @@ -333,9 +333,9 @@ Here is the example of the built-in `pdos` plugins with codes `dos.x` and `projw .. code-block:: python - from aiidalab_widgets_base import ComputationalResourcesWidget + from aiidalab_qe.common.widgets import QEAppComputationalResourcesWidget - dos_code = ComputationalResourcesWidget( + dos_code = QEAppComputationalResourcesWidget( description="dos.x", default_calc_job_plugin="quantumespresso.dos", ) diff --git a/src/aiidalab_qe/app/submission/__init__.py b/src/aiidalab_qe/app/submission/__init__.py index 57ffe0b97..54ad4a88f 100644 --- a/src/aiidalab_qe/app/submission/__init__.py +++ b/src/aiidalab_qe/app/submission/__init__.py @@ -276,7 +276,11 @@ def get_selected_codes(self): return: A dict with the code names as keys and the code UUIDs as values. """ - codes = {key: code.parameters for key, code in self.codes.items()} + codes = { + key: code.parameters + for key, code in self.codes.items() + if code.layout.display != "none" + } return codes def set_selected_codes(self, code_data): diff --git a/src/aiidalab_qe/common/widgets.py b/src/aiidalab_qe/common/widgets.py index 1de61f800..c27e7e894 100644 --- a/src/aiidalab_qe/common/widgets.py +++ b/src/aiidalab_qe/common/widgets.py @@ -724,6 +724,8 @@ def reset(self): class PWscfWidget(QEAppComputationalResourcesWidget): + """ComputationalResources Widget for the pw.x calculation.""" + nodes = traitlets.Int(default_value=1) def __init__(self, **kwargs): From 3e429a9945f8e3d5f98d3ed9a193c0a32038ce98 Mon Sep 17 00:00:00 2001 From: superstar54 Date: Mon, 22 Jan 2024 10:24:29 +0000 Subject: [PATCH 10/21] use composite method, add override for parallelization --- src/aiidalab_qe/common/widgets.py | 72 ++++++++++++++++------- src/aiidalab_qe/plugins/pdos/workchain.py | 5 +- tests/conftest.py | 6 +- 3 files changed, 57 insertions(+), 26 deletions(-) diff --git a/src/aiidalab_qe/common/widgets.py b/src/aiidalab_qe/common/widgets.py index 18675c11c..b14f9e729 100644 --- a/src/aiidalab_qe/common/widgets.py +++ b/src/aiidalab_qe/common/widgets.py @@ -18,7 +18,7 @@ from aiida.orm import CalcJobNode from aiida.orm import Data as orm_Data from aiida.orm import load_code, load_node -from aiidalab_widgets_base import ComputationalResourcesWidget as AiiDACodeWidget +from aiidalab_widgets_base import ComputationalResourcesWidget from aiidalab_widgets_base.utils import ( StatusHTML, list_to_string_range, @@ -620,26 +620,37 @@ def _select_periodicity(self, _=None): self.structure = deepcopy(new_structure) -class QEAppComputationalResourcesWidget(AiiDACodeWidget): +class QEAppComputationalResourcesWidget(ipw.VBox): + value = traitlets.Unicode(allow_none=True) nodes = traitlets.Int(default_value=1) cpus = traitlets.Int(default_value=1) - def __init__(self, max_num_nodes=1000, **kwargs): - """Widget for the selection of compute resources. - max_num_nodes: maximum number of nodes allowed. + def __init__(self, **kwargs): + """Widget to setup the compute resources, which include the code, + the number of nodes and the number of cpus. """ + self.code_selection = ComputationalResourcesWidget(**kwargs) + self.code_selection.layout.width = "70%" + self.num_nodes = ipw.BoundedIntText( - value=1, step=1, min=1, max=max_num_nodes, description="Nodes", width="10%" + value=1, step=1, min=1, max=1000, description="Nodes", width="10%" ) self.num_cpus = ipw.BoundedIntText( value=1, step=1, min=1, description="CPUs", width="10%" ) - super().__init__(**kwargs) - # add nodes and cpus into the children of the widget - self.children[0].children += ( - self.num_nodes, - self.num_cpus, - ) + # combine code, nodes and cpus + children = [ + ipw.HBox( + children=[ + self.code_selection, + self.num_nodes, + self.num_cpus, + ] + ) + ] + super().__init__(children=children, **kwargs) + + traitlets.link((self.code_selection, "value"), (self, "value")) @traitlets.observe("value") def _update_resources(self, change): @@ -673,7 +684,7 @@ def parameters(self): def get_parameters(self): """Return the parameters.""" return { - "code": self.value, + "code": self.code_selection.value, "nodes": self.num_nodes.value, "cpus": self.num_cpus.value, } @@ -684,7 +695,7 @@ def parameters(self, parameters): def set_parameters(self, parameters): """Set the parameters.""" - self.value = parameters["code"] + self.code_selection.value = parameters["code"] if "nodes" in parameters: self.num_nodes.value = parameters["nodes"] if "cpus" in parameters: @@ -697,7 +708,7 @@ class ParallelizationSettings(ipw.VBox): prompt = ipw.HTML( """

- Specify the number of k-points pools for the pw.x calculations. + Specify the number of k-points pools for the pw.x calculations (only for advanced user).

""" ) @@ -709,14 +720,29 @@ def __init__(self, **kwargs): self.npool = ipw.BoundedIntText( value=1, step=1, min=1, max=128, description="Number of k-pools", **extra ) + self.override = ipw.Checkbox( + escription="", + indent=False, + value=False, + layout=ipw.Layout(max_width="20px"), + ) + self.override.observe(self.set_visibility, "value") super().__init__( children=[ ipw.HBox( - children=[self.prompt, self.npool], - layout=ipw.Layout(justify_content="space-between"), + children=[self.override, self.prompt, self.npool], + layout=ipw.Layout(justify_content="flex-start"), ), ] ) + # set the default visibility of the widget + self.npool.layout.display = "none" + + def set_visibility(self, change): + if change["new"]: + self.npool.layout.display = "block" + else: + self.npool.layout.display = "none" def reset(self): """Reset the parallelization settings.""" @@ -738,14 +764,18 @@ def __init__(self, **kwargs): def get_parallelization(self): """Return the parallelization settings.""" - parallelization = { - "npool": self.parallelization.npool.value, - } + parallelization = ( + {"npool": self.parallelization.npool.value} + if self.parallelization.override.value + else {} + ) return parallelization def set_parallelization(self, parallelization): """Set the parallelization settings.""" - self.parallelization.npool.value = parallelization["npool"] + if "npool" in parallelization: + self.parallelization.override.value = True + self.parallelization.npool.value = parallelization["npool"] def get_parameters(self): """Return the parameters.""" diff --git a/src/aiidalab_qe/plugins/pdos/workchain.py b/src/aiidalab_qe/plugins/pdos/workchain.py index 6d54d2959..a614f3c3d 100644 --- a/src/aiidalab_qe/plugins/pdos/workchain.py +++ b/src/aiidalab_qe/plugins/pdos/workchain.py @@ -51,8 +51,9 @@ def update_resources(builder, codes): "num_machines": codes.get("projwfc")["nodes"], "num_mpiprocs_per_machine": codes.get("projwfc")["cpus"], } - npool = codes["pw"]["parallelization"]["npool"] - builder.projwfc.settings = orm.Dict(dict={"cmdline": ["-nk", str(npool)]}) + # disable the parallelization setting for projwfc + # npool = codes["pw"]["parallelization"]["npool"] + # builder.projwfc.settings = orm.Dict(dict={"cmdline": ["-nk", str(npool)]}) def get_builder(codes, structure, parameters, **kwargs): diff --git a/tests/conftest.py b/tests/conftest.py index 76420149d..fd5932a0d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -307,9 +307,9 @@ def app(pw_code, dos_code, projwfc_code): app.submit_step.sssp_installation_status.installed = True # set up codes - app.submit_step.pw_code.refresh() - app.submit_step.codes["dos"].refresh() - app.submit_step.codes["projwfc"].refresh() + app.submit_step.pw_code.code_selection.refresh() + app.submit_step.codes["dos"].code_selection.refresh() + app.submit_step.codes["projwfc"].code_selection.refresh() app.submit_step.pw_code.value = pw_code.uuid app.submit_step.codes["dos"].value = dos_code.uuid From 80727e5f0f9d13804d64d4117472240e4465d5ed Mon Sep 17 00:00:00 2001 From: superstar54 Date: Mon, 22 Jan 2024 10:45:48 +0000 Subject: [PATCH 11/21] fix test --- src/aiidalab_qe/common/widgets.py | 6 +----- .../test_create_builder_default.yml | 19 +++++-------------- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/src/aiidalab_qe/common/widgets.py b/src/aiidalab_qe/common/widgets.py index b14f9e729..bc67ca5f5 100644 --- a/src/aiidalab_qe/common/widgets.py +++ b/src/aiidalab_qe/common/widgets.py @@ -654,11 +654,7 @@ def __init__(self, **kwargs): @traitlets.observe("value") def _update_resources(self, change): - if change["new"] and ( - change["old"] is None - or load_code(change["new"]).computer.pk - != load_code(change["old"]).computer.pk - ): + if change["new"]: self.set_resource_defaults(load_code(change["new"]).computer) def set_resource_defaults(self, computer=None): diff --git a/tests/test_submit_qe_workchain/test_create_builder_default.yml b/tests/test_submit_qe_workchain/test_create_builder_default.yml index b2af426fc..fe6d4823d 100644 --- a/tests/test_submit_qe_workchain/test_create_builder_default.yml +++ b/tests/test_submit_qe_workchain/test_create_builder_default.yml @@ -1,8 +1,7 @@ bands: bands: pw: - parallelization: - npool: 1 + parallelization: {} parameters: CONTROL: calculation: bands @@ -34,8 +33,7 @@ bands: kpoints_distance: 0.12 kpoints_force_parity: false pw: - parallelization: - npool: 1 + parallelization: {} parameters: CONTROL: calculation: scf @@ -67,8 +65,7 @@ pdos: kpoints_distance: 0.1 kpoints_force_parity: false pw: - parallelization: - npool: 1 + parallelization: {} parameters: CONTROL: calculation: nscf @@ -93,16 +90,11 @@ pdos: parameters: PROJWFC: DeltaE: 0.02 - settings: - cmdline: - - -nk - - '1' scf: kpoints_distance: 0.12 kpoints_force_parity: false pw: - parallelization: - npool: 1 + parallelization: {} parameters: CONTROL: calculation: scf @@ -134,8 +126,7 @@ relax: kpoints_distance: 0.12 kpoints_force_parity: false pw: - parallelization: - npool: 1 + parallelization: {} parameters: CELL: cell_dofree: all From c7f1f597fcb1f8c24eceb8a12e7c201116687178 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 5 Apr 2024 16:57:00 +0000 Subject: [PATCH 12/21] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/aiidalab_qe/plugins/pdos/workchain.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/aiidalab_qe/plugins/pdos/workchain.py b/src/aiidalab_qe/plugins/pdos/workchain.py index 1fed10c27..0af03c892 100644 --- a/src/aiidalab_qe/plugins/pdos/workchain.py +++ b/src/aiidalab_qe/plugins/pdos/workchain.py @@ -94,7 +94,6 @@ def get_builder(codes, structure, parameters, **kwargs): # update resources update_resources(pdos, codes) - if ( scf_overrides["pw"]["parameters"]["SYSTEM"].get("tot_magnetization") is not None From a25abe440b118a76d2a7a75196b085ddae19ee8b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 23 Apr 2024 07:27:11 +0000 Subject: [PATCH 13/21] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/aiidalab_qe/app/submission/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/aiidalab_qe/app/submission/__init__.py b/src/aiidalab_qe/app/submission/__init__.py index 1301f8f2c..b2002c0ca 100644 --- a/src/aiidalab_qe/app/submission/__init__.py +++ b/src/aiidalab_qe/app/submission/__init__.py @@ -308,8 +308,8 @@ def _get_code_uuid(code): if _get_code_uuid(code_data.get(name)["code"]) in code_options: # get code uuid from code label in case of using DEFAULT_PARAMETERS code_data.get(name)["code"] = _get_code_uuid( - code_data.get(name)["code"] - ) + code_data.get(name)["code"] + ) code.parameters = code_data.get(name) def update_codes_display(self): From f8d6a85e93b9151ae008484feb321245a6ad2455 Mon Sep 17 00:00:00 2001 From: superstar54 Date: Fri, 5 Apr 2024 17:10:18 +0000 Subject: [PATCH 14/21] delete empty resource.py file --- src/aiidalab_qe/app/submission/resource.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/aiidalab_qe/app/submission/resource.py diff --git a/src/aiidalab_qe/app/submission/resource.py b/src/aiidalab_qe/app/submission/resource.py deleted file mode 100644 index e69de29bb..000000000 From 029e957b99dbca975bdd50ae6a069636790cd440 Mon Sep 17 00:00:00 2001 From: superstar54 Date: Tue, 23 Apr 2024 08:06:50 +0000 Subject: [PATCH 15/21] update XAS plugin --- src/aiidalab_qe/app/parameters/qeapp.yaml | 18 ++++++++++++------ src/aiidalab_qe/app/submission/__init__.py | 4 ++-- src/aiidalab_qe/plugins/xas/__init__.py | 4 ++-- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/aiidalab_qe/app/parameters/qeapp.yaml b/src/aiidalab_qe/app/parameters/qeapp.yaml index d7ac60571..f9556cb1d 100644 --- a/src/aiidalab_qe/app/parameters/qeapp.yaml +++ b/src/aiidalab_qe/app/parameters/qeapp.yaml @@ -25,9 +25,15 @@ advanced: ## Computational resources codes: - dos: dos-7.2@localhost - projwfc: projwfc-7.2@localhost - pw: pw-7.2@localhost - pp: pp-7.2@localhost - xspectra: xspectra-7.2@localhost - hp: hp-7.2@localhost + dos: + code: dos-7.2@localhost + projwfc: + code: projwfc-7.2@localhost + pw: + code: pw-7.2@localhost + pp: + code: pp-7.2@localhost + xspectra: + code: xspectra-7.2@localhost + hp: + code: hp-7.2@localhost diff --git a/src/aiidalab_qe/app/submission/__init__.py b/src/aiidalab_qe/app/submission/__init__.py index b2002c0ca..cde7638e4 100644 --- a/src/aiidalab_qe/app/submission/__init__.py +++ b/src/aiidalab_qe/app/submission/__init__.py @@ -201,7 +201,7 @@ def _auto_select_code(self, change): if not DEFAULT_PARAMETERS["codes"].get(name): continue try: - code.refresh() + code.code_selection.refresh() code.value = orm.load_code(DEFAULT_PARAMETERS["codes"][name]).uuid except NotExistent: pass @@ -304,7 +304,7 @@ def _get_code_uuid(code): # check if the code is installed and usable # note: if code is imported from another user, it is not usable and thus will not be # treated as an option in the ComputationalResourcesWidget. - code_options = [o[1] for o in code.code_select_dropdown.options] + code_options = [o[1] for o in code.code_selection.code_select_dropdown.options] if _get_code_uuid(code_data.get(name)["code"]) in code_options: # get code uuid from code label in case of using DEFAULT_PARAMETERS code_data.get(name)["code"] = _get_code_uuid( diff --git a/src/aiidalab_qe/plugins/xas/__init__.py b/src/aiidalab_qe/plugins/xas/__init__.py index 1ca6f4473..3d6debb89 100644 --- a/src/aiidalab_qe/plugins/xas/__init__.py +++ b/src/aiidalab_qe/plugins/xas/__init__.py @@ -1,7 +1,7 @@ from importlib import resources import yaml -from aiidalab_widgets_base import ComputationalResourcesWidget +from aiidalab_qe.common.widgets import QEAppComputationalResourcesWidget from aiidalab_qe.common.panel import OutlinePanel from aiidalab_qe.plugins import xas as xas_folder @@ -18,7 +18,7 @@ class XasOutline(OutlinePanel): help = """""" -xs_code = ComputationalResourcesWidget( +xs_code = QEAppComputationalResourcesWidget( description="xspectra.x", default_calc_job_plugin="quantumespresso.xspectra" ) From 56ab9bbceccad61af70f532e269dea843cbfb3f4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 23 Apr 2024 08:08:37 +0000 Subject: [PATCH 16/21] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/aiidalab_qe/app/parameters/qeapp.yaml | 12 ++++++------ src/aiidalab_qe/app/submission/__init__.py | 4 +++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/aiidalab_qe/app/parameters/qeapp.yaml b/src/aiidalab_qe/app/parameters/qeapp.yaml index f9556cb1d..c00c0f1c1 100644 --- a/src/aiidalab_qe/app/parameters/qeapp.yaml +++ b/src/aiidalab_qe/app/parameters/qeapp.yaml @@ -25,15 +25,15 @@ advanced: ## Computational resources codes: - dos: + dos: code: dos-7.2@localhost - projwfc: + projwfc: code: projwfc-7.2@localhost - pw: + pw: code: pw-7.2@localhost - pp: + pp: code: pp-7.2@localhost - xspectra: + xspectra: code: xspectra-7.2@localhost - hp: + hp: code: hp-7.2@localhost diff --git a/src/aiidalab_qe/app/submission/__init__.py b/src/aiidalab_qe/app/submission/__init__.py index cde7638e4..4aff30065 100644 --- a/src/aiidalab_qe/app/submission/__init__.py +++ b/src/aiidalab_qe/app/submission/__init__.py @@ -304,7 +304,9 @@ def _get_code_uuid(code): # check if the code is installed and usable # note: if code is imported from another user, it is not usable and thus will not be # treated as an option in the ComputationalResourcesWidget. - code_options = [o[1] for o in code.code_selection.code_select_dropdown.options] + code_options = [ + o[1] for o in code.code_selection.code_select_dropdown.options + ] if _get_code_uuid(code_data.get(name)["code"]) in code_options: # get code uuid from code label in case of using DEFAULT_PARAMETERS code_data.get(name)["code"] = _get_code_uuid( From ad0c844aa6dc6af4669d4d38ecd7a92dcd48899b Mon Sep 17 00:00:00 2001 From: superstar54 Date: Tue, 23 Apr 2024 08:59:24 +0000 Subject: [PATCH 17/21] add setup resource detail --- src/aiidalab_qe/app/submission/__init__.py | 3 +- src/aiidalab_qe/common/widgets.py | 88 ++++++++++++++++++- src/aiidalab_qe/plugins/bands/workchain.py | 6 +- src/aiidalab_qe/plugins/pdos/workchain.py | 12 ++- .../test_create_builder_default.yml | 21 +++-- 5 files changed, 115 insertions(+), 15 deletions(-) diff --git a/src/aiidalab_qe/app/submission/__init__.py b/src/aiidalab_qe/app/submission/__init__.py index 4aff30065..924530cfe 100644 --- a/src/aiidalab_qe/app/submission/__init__.py +++ b/src/aiidalab_qe/app/submission/__init__.py @@ -385,7 +385,8 @@ def _update_builder(self, builder, codes): # update resources builder.relax.base.pw.metadata.options.resources = { "num_machines": codes.get("pw")["nodes"], - "num_mpiprocs_per_machine": codes.get("pw")["cpus"], + "num_mpiprocs_per_machine": codes.get("pw")["ntasks_per_node"], + "num_cores_per_mpiproc": codes.get("pw")["cpus_per_task"], } builder.relax.base.pw.parallelization = orm.Dict( dict=codes["pw"]["parallelization"] diff --git a/src/aiidalab_qe/common/widgets.py b/src/aiidalab_qe/common/widgets.py index bc67ca5f5..4a94a36c9 100644 --- a/src/aiidalab_qe/common/widgets.py +++ b/src/aiidalab_qe/common/widgets.py @@ -630,7 +630,7 @@ def __init__(self, **kwargs): the number of nodes and the number of cpus. """ self.code_selection = ComputationalResourcesWidget(**kwargs) - self.code_selection.layout.width = "70%" + self.code_selection.layout.width = "80%" self.num_nodes = ipw.BoundedIntText( value=1, step=1, min=1, max=1000, description="Nodes", width="10%" @@ -638,6 +638,10 @@ def __init__(self, **kwargs): self.num_cpus = ipw.BoundedIntText( value=1, step=1, min=1, description="CPUs", width="10%" ) + self.btn_setup_resource_detail = ipw.ToggleButton(description="More") + self.btn_setup_resource_detail.observe(self._setup_resource_detail, "value") + self._setup_resource_detail_output = ipw.Output(layout={"width": "500px"}) + # combine code, nodes and cpus children = [ ipw.HBox( @@ -645,11 +649,15 @@ def __init__(self, **kwargs): self.code_selection, self.num_nodes, self.num_cpus, + self.btn_setup_resource_detail, ] - ) + ), + self._setup_resource_detail_output, ] super().__init__(children=children, **kwargs) + self.resource_detail = ResourceDetailSettings() + traitlets.dlink((self.num_cpus, "value"), (self.resource_detail.ntasks_per_node, "value")) traitlets.link((self.code_selection, "value"), (self, "value")) @traitlets.observe("value") @@ -679,11 +687,13 @@ def parameters(self): def get_parameters(self): """Return the parameters.""" - return { + parameters = { "code": self.code_selection.value, "nodes": self.num_nodes.value, "cpus": self.num_cpus.value, } + parameters.update(self.resource_detail.parameters) + return parameters @parameters.setter def parameters(self, parameters): @@ -696,7 +706,79 @@ def set_parameters(self, parameters): self.num_nodes.value = parameters["nodes"] if "cpus" in parameters: self.num_cpus.value = parameters["cpus"] + if "ntasks_per_node" in parameters: + self.resource_detail.ntasks_per_node = parameters["ntasks_per_node"] + if "cpus_per_task" in parameters: + self.resource_detail.cpus_per_task = parameters["cpus_per_task"] + + def _setup_resource_detail(self, _=None): + with self._setup_resource_detail_output: + clear_output() + if self.btn_setup_resource_detail.value: + self._setup_resource_detail_output.layout = { + "width": "500px", + "border": "1px solid gray", + } + + children = [ + self.resource_detail, + ] + display(*children) + else: + self._setup_resource_detail_output.layout = { + "width": "500px", + "border": "none", + } + + +class ResourceDetailSettings(ipw.VBox): + """Widget for setting the Resource detail.""" + + prompt = ipw.HTML( + """
+

+ Specify the parameters for the scheduler (only for advanced user). +

""" + ) + + def __init__(self, **kwargs): + self.ntasks_per_node = ipw.BoundedIntText( + value=1, step=1, min=1, max=1000, description="ntasks-per-node", + style={"description_width": "100px"}, + ) + self.cpus_per_task = ipw.BoundedIntText( + value=1, step=1, min=1, description="cpus-per-task", + style={"description_width": "100px"}, + ) + super().__init__( + children=[ + self.prompt, + self.ntasks_per_node, + self.cpus_per_task + ], + **kwargs + ) + + @property + def parameters(self): + return self.get_parameters() + + def get_parameters(self): + """Return the parameters.""" + return { + "ntasks_per_node": self.ntasks_per_node.value, + "cpus_per_task": self.cpus_per_task.value, + } + + @parameters.setter + def parameters(self, parameters): + self.ntasks_per_node.value = parameters.get("ntasks_per_node", 1) + self.cpus_per_task.value = parameters.get("cpus_per_task", 1) + def reset(self): + """Reset the settings.""" + self.ntasks_per_node.value = 1 + self.cpus_per_task.value = 1 class ParallelizationSettings(ipw.VBox): """Widget for setting the parallelization settings.""" diff --git a/src/aiidalab_qe/plugins/bands/workchain.py b/src/aiidalab_qe/plugins/bands/workchain.py index 7f68c1eb9..efa234028 100644 --- a/src/aiidalab_qe/plugins/bands/workchain.py +++ b/src/aiidalab_qe/plugins/bands/workchain.py @@ -175,12 +175,14 @@ def generate_kpath_2d(structure, kpoints_distance, kpath_2d): def update_resources(builder, codes): builder.scf.pw.metadata.options.resources = { "num_machines": codes.get("pw")["nodes"], - "num_mpiprocs_per_machine": codes.get("pw")["cpus"], + "num_mpiprocs_per_machine": codes.get("pw")["ntasks_per_node"], + "num_cores_per_mpiproc": codes.get("pw")["cpus_per_task"], } builder.scf.pw.parallelization = orm.Dict(dict=codes["pw"]["parallelization"]) builder.bands.pw.metadata.options.resources = { "num_machines": codes.get("pw")["nodes"], - "num_mpiprocs_per_machine": codes.get("pw")["cpus"], + "num_mpiprocs_per_machine": codes.get("pw")["ntasks_per_node"], + "num_cores_per_mpiproc": codes.get("pw")["cpus_per_task"], } builder.bands.pw.parallelization = orm.Dict(dict=codes["pw"]["parallelization"]) diff --git a/src/aiidalab_qe/plugins/pdos/workchain.py b/src/aiidalab_qe/plugins/pdos/workchain.py index b1181e798..6da26dda6 100644 --- a/src/aiidalab_qe/plugins/pdos/workchain.py +++ b/src/aiidalab_qe/plugins/pdos/workchain.py @@ -35,21 +35,25 @@ def check_codes(pw_code, dos_code, projwfc_code): def update_resources(builder, codes): builder.scf.pw.metadata.options.resources = { "num_machines": codes.get("pw")["nodes"], - "num_mpiprocs_per_machine": codes.get("pw")["cpus"], + "num_mpiprocs_per_machine": codes.get("pw")["ntasks_per_node"], + "num_cores_per_mpiproc": codes.get("pw")["cpus_per_task"], } builder.scf.pw.parallelization = orm.Dict(dict=codes["pw"]["parallelization"]) builder.nscf.pw.metadata.options.resources = { "num_machines": codes.get("pw")["nodes"], - "num_mpiprocs_per_machine": codes.get("pw")["cpus"], + "num_mpiprocs_per_machine": codes.get("pw")["ntasks_per_node"], + "num_cores_per_mpiproc": codes.get("pw")["cpus_per_task"], } builder.nscf.pw.parallelization = orm.Dict(dict=codes["pw"]["parallelization"]) builder.dos.metadata.options.resources = { "num_machines": codes.get("dos")["nodes"], - "num_mpiprocs_per_machine": codes.get("dos")["cpus"], + "num_mpiprocs_per_machine": codes.get("pw")["ntasks_per_node"], + "num_cores_per_mpiproc": codes.get("pw")["cpus_per_task"], } builder.projwfc.metadata.options.resources = { "num_machines": codes.get("projwfc")["nodes"], - "num_mpiprocs_per_machine": codes.get("projwfc")["cpus"], + "num_mpiprocs_per_machine": codes.get("pw")["ntasks_per_node"], + "num_cores_per_mpiproc": codes.get("pw")["cpus_per_task"], } # disable the parallelization setting for projwfc # npool = codes["pw"]["parallelization"]["npool"] diff --git a/tests/test_submit_qe_workchain/test_create_builder_default.yml b/tests/test_submit_qe_workchain/test_create_builder_default.yml index 2f9f23575..5a4add9d7 100644 --- a/tests/test_submit_qe_workchain/test_create_builder_default.yml +++ b/tests/test_submit_qe_workchain/test_create_builder_default.yml @@ -16,13 +16,24 @@ advanced: bands: kpath_2d: hexagonal codes: - xspectra: null + dos: + cpus: 1 + cpus_per_task: 1 + nodes: 1 + ntasks_per_node: 1 + projwfc: + cpus: 1 + cpus_per_task: 1 + nodes: 1 + ntasks_per_node: 1 + pw: + cpus: 2 + cpus_per_task: 1 + nodes: 1 + ntasks_per_node: 2 + parallelization: {} pdos: nscf_kpoints_distance: 0.1 -resources: - npools: 1 - num_machines: 1 - num_mpiprocs_per_machine: 2 workchain: electronic_type: metal properties: From 4a0cb832586cf6760c07a7c2e403f427051f724c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 23 Apr 2024 08:59:38 +0000 Subject: [PATCH 18/21] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/aiidalab_qe/common/widgets.py | 33 +++++++++++++---------- src/aiidalab_qe/plugins/pdos/workchain.py | 8 +++--- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/aiidalab_qe/common/widgets.py b/src/aiidalab_qe/common/widgets.py index 4a94a36c9..9ab8c1ffb 100644 --- a/src/aiidalab_qe/common/widgets.py +++ b/src/aiidalab_qe/common/widgets.py @@ -657,7 +657,9 @@ def __init__(self, **kwargs): super().__init__(children=children, **kwargs) self.resource_detail = ResourceDetailSettings() - traitlets.dlink((self.num_cpus, "value"), (self.resource_detail.ntasks_per_node, "value")) + traitlets.dlink( + (self.num_cpus, "value"), (self.resource_detail.ntasks_per_node, "value") + ) traitlets.link((self.code_selection, "value"), (self, "value")) @traitlets.observe("value") @@ -707,9 +709,9 @@ def set_parameters(self, parameters): if "cpus" in parameters: self.num_cpus.value = parameters["cpus"] if "ntasks_per_node" in parameters: - self.resource_detail.ntasks_per_node = parameters["ntasks_per_node"] + self.resource_detail.ntasks_per_node.value = parameters["ntasks_per_node"] if "cpus_per_task" in parameters: - self.resource_detail.cpus_per_task = parameters["cpus_per_task"] + self.resource_detail.cpus_per_task.value = parameters["cpus_per_task"] def _setup_resource_detail(self, _=None): with self._setup_resource_detail_output: @@ -743,33 +745,35 @@ class ResourceDetailSettings(ipw.VBox): def __init__(self, **kwargs): self.ntasks_per_node = ipw.BoundedIntText( - value=1, step=1, min=1, max=1000, description="ntasks-per-node", + value=1, + step=1, + min=1, + max=1000, + description="ntasks-per-node", style={"description_width": "100px"}, ) self.cpus_per_task = ipw.BoundedIntText( - value=1, step=1, min=1, description="cpus-per-task", + value=1, + step=1, + min=1, + description="cpus-per-task", style={"description_width": "100px"}, ) super().__init__( - children=[ - self.prompt, - self.ntasks_per_node, - self.cpus_per_task - ], - **kwargs + children=[self.prompt, self.ntasks_per_node, self.cpus_per_task], **kwargs ) - + @property def parameters(self): return self.get_parameters() - + def get_parameters(self): """Return the parameters.""" return { "ntasks_per_node": self.ntasks_per_node.value, "cpus_per_task": self.cpus_per_task.value, } - + @parameters.setter def parameters(self, parameters): self.ntasks_per_node.value = parameters.get("ntasks_per_node", 1) @@ -780,6 +784,7 @@ def reset(self): self.ntasks_per_node.value = 1 self.cpus_per_task.value = 1 + class ParallelizationSettings(ipw.VBox): """Widget for setting the parallelization settings.""" diff --git a/src/aiidalab_qe/plugins/pdos/workchain.py b/src/aiidalab_qe/plugins/pdos/workchain.py index 6da26dda6..18ddb5a49 100644 --- a/src/aiidalab_qe/plugins/pdos/workchain.py +++ b/src/aiidalab_qe/plugins/pdos/workchain.py @@ -47,13 +47,13 @@ def update_resources(builder, codes): builder.nscf.pw.parallelization = orm.Dict(dict=codes["pw"]["parallelization"]) builder.dos.metadata.options.resources = { "num_machines": codes.get("dos")["nodes"], - "num_mpiprocs_per_machine": codes.get("pw")["ntasks_per_node"], - "num_cores_per_mpiproc": codes.get("pw")["cpus_per_task"], + "num_mpiprocs_per_machine": codes.get("dos")["ntasks_per_node"], + "num_cores_per_mpiproc": codes.get("dos")["cpus_per_task"], } builder.projwfc.metadata.options.resources = { "num_machines": codes.get("projwfc")["nodes"], - "num_mpiprocs_per_machine": codes.get("pw")["ntasks_per_node"], - "num_cores_per_mpiproc": codes.get("pw")["cpus_per_task"], + "num_mpiprocs_per_machine": codes.get("projwfc")["ntasks_per_node"], + "num_cores_per_mpiproc": codes.get("projwfc")["cpus_per_task"], } # disable the parallelization setting for projwfc # npool = codes["pw"]["parallelization"]["npool"] From 14e6f7c7b08fde19389627e90c74285921804dbe Mon Sep 17 00:00:00 2001 From: superstar54 Date: Tue, 23 Apr 2024 13:15:39 +0000 Subject: [PATCH 19/21] rename PwCodeResourceSetupWidget, add test --- src/aiidalab_qe/app/submission/__init__.py | 4 ++-- src/aiidalab_qe/common/widgets.py | 2 +- tests/test_codes.py | 20 ++++++++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/aiidalab_qe/app/submission/__init__.py b/src/aiidalab_qe/app/submission/__init__.py index 924530cfe..f89979161 100644 --- a/src/aiidalab_qe/app/submission/__init__.py +++ b/src/aiidalab_qe/app/submission/__init__.py @@ -18,7 +18,7 @@ from aiidalab_qe.app.utils import get_entry_items from aiidalab_qe.common.setup_codes import QESetupWidget from aiidalab_qe.common.setup_pseudos import PseudosInstallWidget -from aiidalab_qe.common.widgets import PWscfWidget, QEAppComputationalResourcesWidget +from aiidalab_qe.common.widgets import PwCodeResourceSetupWidget, QEAppComputationalResourcesWidget from aiidalab_qe.workflows import QeAppWorkChain @@ -59,7 +59,7 @@ def __init__(self, qe_auto_setup=True, **kwargs): self.message_area = ipw.Output() self._submission_blocker_messages = ipw.HTML() - self.pw_code = PWscfWidget( + self.pw_code = PwCodeResourceSetupWidget( description="pw.x:", default_calc_job_plugin="quantumespresso.pw" ) diff --git a/src/aiidalab_qe/common/widgets.py b/src/aiidalab_qe/common/widgets.py index 9ab8c1ffb..44c2c20c0 100644 --- a/src/aiidalab_qe/common/widgets.py +++ b/src/aiidalab_qe/common/widgets.py @@ -832,7 +832,7 @@ def reset(self): self.npool.value = 1 -class PWscfWidget(QEAppComputationalResourcesWidget): +class PwCodeResourceSetupWidget(QEAppComputationalResourcesWidget): """ComputationalResources Widget for the pw.x calculation.""" nodes = traitlets.Int(default_value=1) diff --git a/tests/test_codes.py b/tests/test_codes.py index 37f46dd4c..ab2340be3 100644 --- a/tests/test_codes.py +++ b/tests/test_codes.py @@ -59,3 +59,23 @@ def test_identify_submission_blockers(app): submit.codes["dos"].value = dos_value blockers = list(submit._identify_submission_blockers()) assert len(blockers) == 0 + + +def test_qeapp_computational_resources_widget(): + """Test QEAppComputationalResourcesWidget.""" + from aiidalab_qe.app.submission import SubmitQeAppWorkChainStep + + new_submit_step = SubmitQeAppWorkChainStep(qe_auto_setup=False) + assert new_submit_step.codes['pw'].parallelization.npool.layout.display == 'none' + new_submit_step.codes['pw'].parallelization.override.value = True + new_submit_step.codes['pw'].parallelization.npool.value = 2 + assert new_submit_step.codes['pw'].parallelization.npool.layout.display == 'block' + assert new_submit_step.codes['pw'].parameters == {"code": None, + "cpus": 1, + "cpus_per_task": 1, + "nodes": 1, + "ntasks_per_node": 1, + "parallelization": {"npool": 2}, + } + + From 9a70a27026e810029371d43c1d7af6c4b889e271 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 23 Apr 2024 13:16:06 +0000 Subject: [PATCH 20/21] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/aiidalab_qe/app/submission/__init__.py | 5 ++++- tests/test_codes.py | 25 +++++++++++----------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/aiidalab_qe/app/submission/__init__.py b/src/aiidalab_qe/app/submission/__init__.py index f89979161..a5775a49c 100644 --- a/src/aiidalab_qe/app/submission/__init__.py +++ b/src/aiidalab_qe/app/submission/__init__.py @@ -18,7 +18,10 @@ from aiidalab_qe.app.utils import get_entry_items from aiidalab_qe.common.setup_codes import QESetupWidget from aiidalab_qe.common.setup_pseudos import PseudosInstallWidget -from aiidalab_qe.common.widgets import PwCodeResourceSetupWidget, QEAppComputationalResourcesWidget +from aiidalab_qe.common.widgets import ( + PwCodeResourceSetupWidget, + QEAppComputationalResourcesWidget, +) from aiidalab_qe.workflows import QeAppWorkChain diff --git a/tests/test_codes.py b/tests/test_codes.py index ab2340be3..f351df525 100644 --- a/tests/test_codes.py +++ b/tests/test_codes.py @@ -66,16 +66,15 @@ def test_qeapp_computational_resources_widget(): from aiidalab_qe.app.submission import SubmitQeAppWorkChainStep new_submit_step = SubmitQeAppWorkChainStep(qe_auto_setup=False) - assert new_submit_step.codes['pw'].parallelization.npool.layout.display == 'none' - new_submit_step.codes['pw'].parallelization.override.value = True - new_submit_step.codes['pw'].parallelization.npool.value = 2 - assert new_submit_step.codes['pw'].parallelization.npool.layout.display == 'block' - assert new_submit_step.codes['pw'].parameters == {"code": None, - "cpus": 1, - "cpus_per_task": 1, - "nodes": 1, - "ntasks_per_node": 1, - "parallelization": {"npool": 2}, - } - - + assert new_submit_step.codes["pw"].parallelization.npool.layout.display == "none" + new_submit_step.codes["pw"].parallelization.override.value = True + new_submit_step.codes["pw"].parallelization.npool.value = 2 + assert new_submit_step.codes["pw"].parallelization.npool.layout.display == "block" + assert new_submit_step.codes["pw"].parameters == { + "code": None, + "cpus": 1, + "cpus_per_task": 1, + "nodes": 1, + "ntasks_per_node": 1, + "parallelization": {"npool": 2}, + } From 5720107d5dfea8d54bb8ab0a2045c94163a52d93 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 23 Apr 2024 14:40:14 +0000 Subject: [PATCH 21/21] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/aiidalab_qe/common/widgets.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/aiidalab_qe/common/widgets.py b/src/aiidalab_qe/common/widgets.py index 2d100cee3..2d9b08f62 100644 --- a/src/aiidalab_qe/common/widgets.py +++ b/src/aiidalab_qe/common/widgets.py @@ -873,6 +873,7 @@ def set_parameters(self, parameters): if "parallelization" in parameters: self.set_parallelization(parameters["parallelization"]) + class HubbardWidget(ipw.VBox): """Widget for setting up Hubbard parameters."""