Skip to content

Commit

Permalink
Merge pull request #192 from ispg-group/reorganize-workflows
Browse files Browse the repository at this point in the history
  • Loading branch information
danielhollas authored May 30, 2023
2 parents 69a2326 + 15ce23c commit a95a8d5
Show file tree
Hide file tree
Showing 25 changed files with 650 additions and 602 deletions.
2 changes: 2 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
63d994fa6294d87eead1f8502d1476eca3a84148 # apply new pre-commit rules
b20a1b955f654202f2014a29ab834ec1f3915e35 # reorganize workflows
20 changes: 5 additions & 15 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,27 +1,17 @@
repos:
- repo: https://github.com/psf/black
rev: 22.12.0
rev: 23.3.0
hooks:
- id: black
language_version: python3 # Should be a command that runs python3.6+

- repo: https://github.com/pycqa/flake8
rev: '6.0.0'
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.0.270
hooks:
- id: flake8
args: [--count, --show-source, --statistics, --version]
additional_dependencies:
- flake8-bugbear
- flake8-builtins
- flake8-comprehensions
- id: ruff
args: [--show-source]

- repo: https://github.com/kynan/nbstripout
rev: 0.6.1
hooks:
- id: nbstripout

- repo: https://github.com/asottile/pyupgrade
rev: v3.3.0
hooks:
- id: pyupgrade
args: [--py39-plus]
9 changes: 3 additions & 6 deletions aiidalab_ispg/app/atmospec_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@
import traitlets

from aiida.engine import submit, ProcessState
from aiida.orm import Bool, StructureData, TrajectoryData, WorkChainNode
from aiida.orm import Bool
from aiida.orm import load_code, load_node
from aiida.plugins import WorkflowFactory

from aiidalab_widgets_base import WizardAppWidgetStep

from .input_widgets import (
ExcitedStateMethod,
Expand Down Expand Up @@ -335,9 +334,8 @@ def submit(self, _=None):
nroots=bp.nstates,
)
else:
raise NotImplementedError(
f"Excited method {bp.excited_method} not implemented"
)
msg = f"Excited method {bp.excited_method} not implemented"
raise NotImplementedError(msg)

builder.optimize = bp.optimize
builder.opt.orca.parameters = gs_opt_parameters
Expand Down Expand Up @@ -454,7 +452,6 @@ def _observe_status(self, change):


class ViewAtmospecAppWorkChainStatusAndResultsStep(ViewWorkChainStatusStep):

workflow_status = traitlets.Instance(AtmospecWorkflowStatus, allow_none=True)

def __init__(self, **kwargs):
Expand Down
9 changes: 6 additions & 3 deletions aiidalab_ispg/app/conformers.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ class FFMethod(Enum):


class ConformerSmilesWidget(SmilesWidget):

structure = Union(
[Instance(Atoms), Instance(StructureData), Instance(TrajectoryData)],
allow_none=True,
Expand Down Expand Up @@ -232,7 +231,10 @@ def _filter_and_sort_conformers(self, conformers, energies):
selected_energies.append(shifted_energy)
return selected_conformers, selected_energies

def _rdkit_opt(self, smiles, steps, algo=RDKitMethod.ETKDGV1, opt_algo=None):
# TODO: Refactor this to smaller functions
def _rdkit_opt( # noqa: C901
self, smiles, steps, algo=RDKitMethod.ETKDGV1, opt_algo=None
):
"""Optimize a molecule using force field and rdkit (needed for complex SMILES)."""

if self.debug:
Expand Down Expand Up @@ -273,7 +275,8 @@ def _rdkit_opt(self, smiles, steps, algo=RDKitMethod.ETKDGV1, opt_algo=None):
mol, numConfs=num_confs, params=params
)
if len(conf_ids) == 0:
raise ValueError("Failed to generate conformers with RDKit")
msg = "Failed to generate conformers with RDKit"
raise ValueError(msg)

ffenergies = None
if opt_algo == FFMethod.UFF and AllChem.UFFHasAllMoleculeParams(mol):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# ruff: noqa: INP001
# This script needs to be run with `verdi run`
import argparse
from pprint import pprint
Expand All @@ -7,6 +8,9 @@
import numpy as np
from rdkit import Chem

from aiida.orm import QueryBuilder
from aiida.plugins import DataFactory

XyData = DataFactory("array.xy")


Expand All @@ -33,15 +37,16 @@ def parse_cmd():
def canonicalize_smiles(smiles):
mol = Chem.MolFromSmiles(smiles, sanitize=True)
if mol is None:
raise ValueError("RDkit ERROR: Invalid SMILES string")
msg = "RDkit ERROR: Invalid SMILES string"
raise ValueError(msg)
canonical_smiles = Chem.MolToSmiles(mol, isomericSmiles=True, canonical=True)
if not canonical_smiles:
raise ValueError("RDKit: Could not canonicalize SMILES")
msg = "RDKit: Could not canonicalize SMILES"
raise ValueError(msg)
return canonical_smiles


def main(input_file, dry_run=True):

with open(opts.input_file) as f:
data = yaml.safe_load(f)

Expand Down
6 changes: 1 addition & 5 deletions aiidalab_ispg/app/input_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ class ExcitedStateMethod(Enum):


class MolecularGeometrySettings(ipw.VBox):

title = ipw.HTML(
"""<div style="padding-top: 0px; padding-bottom: 0px">
<h4>Molecular geometry</h4></div>"""
Expand Down Expand Up @@ -234,14 +233,13 @@ def _observe_excited_method(self, change):
self.tddft_functional.disabled = False

def reset(self):
self.excited_method.value = _DEFAULT_EXCITED_METHOD
self.excited_method.value = self._DEFAULT_EXCITED_METHOD
self.method.value = self._DEFAULT_FUNCTIONAL
self.basis.value = self._DEFAULT_BASIS
self.nstate.value = self._DEFAULT_NSTATES


class WignerSamplingSettings(ipw.VBox):

disabled = traitlets.Bool(default=False)

title = ipw.HTML(
Expand Down Expand Up @@ -296,7 +294,6 @@ def reset(self):


class CodeSettings(ipw.VBox):

codes_title = ipw.HTML(
"""<div style="padding-top: 10px; padding-bottom: 0px">
<h4>Codes</h4></div>"""
Expand All @@ -311,7 +308,6 @@ class CodeSettings(ipw.VBox):
_DEFAULT_ORCA_CODES = ("orca@slurm", "orca@localhost")

def __init__(self, **kwargs):

self.orca = ComputationalResourcesWidget(
default_calc_job_plugin="orca.orca",
description="ORCA program",
Expand Down
9 changes: 1 addition & 8 deletions aiidalab_ispg/app/optimization_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,10 @@
import traitlets

from aiida.engine import submit, ProcessState
from aiida.orm import Bool, StructureData, TrajectoryData, WorkChainNode
from aiida.orm import Bool
from aiida.orm import load_code, load_node
from aiida.plugins import WorkflowFactory

from aiidalab_widgets_base import (
WizardAppWidgetStep,
AiidaNodeViewWidget,
ProcessMonitor,
ProcessNodesTreeWidget,
)

from .input_widgets import (
ResourceSelectionWidget,
Expand All @@ -27,7 +21,6 @@
)
from .widgets import TrajectoryDataViewer, spinner
from .steps import SubmitWorkChainStepBase, ViewWorkChainStatusStep
from .utils import MEMORY_PER_CPU

ConformerOptimizationWorkChain = WorkflowFactory("ispg.conformer_opt")

Expand Down
1 change: 0 additions & 1 deletion aiidalab_ispg/app/qeapp/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

import ipywidgets as ipw
import traitlets as tl
from aiida import orm
from aiida.tools.query.calculation import CalculationQueryBuilder


Expand Down
7 changes: 2 additions & 5 deletions aiidalab_ispg/app/qeapp/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@


class RollingOutput(ipw.VBox):

style = (
"background-color: #253239; color: #cdd3df; line-height: normal; custom=test"
)
Expand Down Expand Up @@ -107,7 +106,8 @@ def _default_tooltip(self):
return "Download"

def __on_click(self, _):
digest = hashlib.md5(self.payload).hexdigest() # bypass browser cache
# bypass browser cache
digest = hashlib.md5(self.payload).hexdigest() # noqa: S324
payload = base64.b64encode(self.payload).decode()

link_id = f"dl_{digest}"
Expand All @@ -134,7 +134,6 @@ def __on_click(self, _):


class FilenameDisplayWidget(ipw.Box):

value = traitlets.Unicode()

def __init__(self, max_width=None, **kwargs):
Expand All @@ -158,7 +157,6 @@ def _observe_filename(self, change):


class LogOutputWidget(ipw.VBox):

filename = traitlets.Unicode()
value = traitlets.Unicode()

Expand Down Expand Up @@ -236,7 +234,6 @@ def _observe_value(self, change):


class CalcJobOutputFollower(traitlets.HasTraits):

calcjob_uuid = traitlets.Unicode(allow_none=True)
filename = traitlets.Unicode(allow_none=True)
output = traitlets.List(trait=traitlets.Unicode)
Expand Down
12 changes: 7 additions & 5 deletions aiidalab_ispg/app/spectrum.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ def get_spectrum(
elif kernel is BroadeningKernel.LORENTZ:
self._calc_lorentzian_spectrum(x, y, width)
else:
raise ValueError(f"Invalid broadening kernel {kernel}")
msg = f"Invalid broadening kernel {kernel}"
raise ValueError(msg)

# Conversion factor from eV to given energy unit
if x_unit == EnergyUnit.NM:
Expand All @@ -170,7 +171,6 @@ def _convert_to_nanometers(self, x, y):


class SpectrumWidget(ipw.VBox):

disabled = traitlets.Bool(default=True)
conformer_transitions = traitlets.List(
trait=traitlets.Dict, allow_none=True, default=None
Expand Down Expand Up @@ -645,7 +645,8 @@ def _validate_conformers(self, change):
if not all(
self._validate_transitions(c["transitions"]) for c in conformer_transitions
):
raise ValueError("Invalid conformer transitions")
msg = "Invalid conformer transitions"
raise ValueError(msg)
return conformer_transitions

@traitlets.validate("conformer_structures")
Expand All @@ -659,7 +660,8 @@ def _validate_conformer_structures(self, change):
elif isinstance(structures, StructureData):
return TrajectoryData(structurelist=(structures,))
else:
raise ValueError(f"Unsupported type {type(structures)}")
msg = f"Unsupported type {type(structures)}"
raise ValueError(msg)

@traitlets.observe("selected_conformer_id")
def _observe_selected_conformer(self, change):
Expand Down Expand Up @@ -704,7 +706,7 @@ def find_experimental_spectrum_by_smiles(self, smiles: str):
and plot it if it is available in our DB"""

self.set_trait("experimental_spectrum_uuid", None)
if smiles is None or smiles == "":
if not smiles:
return

qb = QueryBuilder()
Expand Down
10 changes: 4 additions & 6 deletions aiidalab_ispg/app/spectrum_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,13 @@
"""

from dataclasses import dataclass
from enum import Enum, unique

import bokeh.plotting as plt
import bokeh.palettes
from bokeh.models import ColumnDataSource, Scatter

import ipywidgets as ipw
import traitlets
import scipy
from scipy import constants
import numpy as np

from .utils import BokehFigureContext
Expand Down Expand Up @@ -105,8 +102,8 @@ def _init_figure(self, *args, **kwargs) -> BokehFigureContext:
"""Initialize Bokeh figure. Arguments are passed to bokeh.plt.figure()"""
figure = BokehFigureContext(plt.figure(*args, **kwargs))
f = figure.get_figure()
f.xaxis.axis_label = f"Excitation Energy (eV)"
f.yaxis.axis_label = f"Oscillator strength (-)"
f.xaxis.axis_label = "Excitation Energy (eV)"
f.yaxis.axis_label = "Oscillator strength (-)"
return figure

@traitlets.observe("conformer_transitions")
Expand All @@ -130,7 +127,8 @@ def _update_density_plot(self, plot_type: str):
elif plot_type == "DENSITY":
self.plot_density(energies, osc_strengths)
else:
raise ValueError(f"Unexpected value for toggle: {plot_type}")
msg = f"Unexpected value for toggle: {plot_type}"
raise ValueError(msg)

def _flatten_transitions(self):
# Flatten transitions for all conformers.
Expand Down
10 changes: 3 additions & 7 deletions aiidalab_ispg/app/steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,12 @@
* Daniel Hollas <daniel.hollas@durham.ac.uk>
"""
import ipywidgets as ipw
import numpy as np
import re
import traitlets

from aiida.common import MissingEntryPointError, LinkType
from aiida.engine import ProcessState, submit
from aiida.engine import ProcessState
from aiida.orm import load_node
from aiida.orm import WorkChainNode, StructureData, TrajectoryData
from aiida.plugins import WorkflowFactory

from aiidalab_widgets_base import (
AiidaNodeViewWidget,
Expand Down Expand Up @@ -87,7 +84,8 @@ def _on_submit_button_clicked(self, _):

def submit(self):
"""Submit workflow, implementation must be provided by the the child class"""
raise NotImplementedError("FATAL: submit method not implemented")
msg = "FATAL: submit method not implemented"
raise NotImplementedError(msg)

def _get_state(self):
# Process is already running.
Expand Down Expand Up @@ -212,11 +210,9 @@ def _update_workflow_state(self, _=None):
"""To be implemented by child workflows
to power the workflow-specific progress bar
"""
pass

def _display_results(self, _=None):
"""Optional function to be called when the process is finished"""
pass

@traitlets.observe("process_uuid")
def _observe_process(self, change):
Expand Down
4 changes: 3 additions & 1 deletion aiidalab_ispg/app/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
# https://github.com/pzarabadip/aiida-orca/issues/45
MEMORY_PER_CPU = 3000 # Mb


# TODO: Use numpy here? Measure the speed...
# Energies expected in kJ / mole, Absolute temperature in Kelvins
def calc_boltzmann_weights(energies, T):
Expand All @@ -48,7 +49,8 @@ def get_formula(data_node):
elif isinstance(data_node, CifData):
return data_node.get_ase().get_chemical_formula()
else:
raise ValueError(f"Cannot get formula from node {type(data_node)}")
msg = f"Cannot get formula from node {type(data_node)}"
raise ValueError(msg)


# https://stackoverflow.com/a/3382369
Expand Down
Loading

0 comments on commit a95a8d5

Please sign in to comment.