Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
179f0e7
Add output fields to the base calculation for storing the (optional) …
BTSpeake Nov 5, 2025
01a1880
Fix for string formatting in base calculation
BTSpeake Nov 5, 2025
9fa980d
Add labels and descriptions to output nodes
BTSpeake Nov 5, 2025
eea2c2b
Correctly add 'save_path' as a valid optimisation parameter
BTSpeake Nov 5, 2025
233d50b
Correct names for trajectory path files
BTSpeake Nov 5, 2025
6886e19
Create outline for clf workchain
BTSpeake Nov 18, 2025
7ffdc58
Fix for correct return of trajectory path outputs when 'save_path' op…
BTSpeake Nov 18, 2025
859ae18
Optionally port command line parameters for mpi running with the chem…
BTSpeake Nov 18, 2025
9908b20
Create calc job that runs a python script to split ChemShell path fil…
BTSpeake Nov 18, 2025
12289b3
Add exit code for when no trajectory files have been produced
BTSpeake Nov 18, 2025
17c1923
Update basic workflow outline to include a call to aiida-mlip for sin…
BTSpeake Nov 21, 2025
9df4c70
Update split_trajectory job to correctly generate required inputs for…
BTSpeake May 20, 2026
bfed416
Add the energy of each step in an optimisation as a result of the bas…
BTSpeake May 21, 2026
254e5a1
Add default labelling of subprocesses in a geometry optimisation work…
BTSpeake May 26, 2026
9171b6c
Enable fine-tuning of MLIP model as additional step to an optimisatio…
BTSpeake Jun 11, 2026
f032f39
Create a workchain for extracting and calculating isolated atomic ene…
BTSpeake Jun 17, 2026
c33f0c5
Simplify isolated atoms workflow and extract re-usable parts
BTSpeake Jun 18, 2026
ba2354b
Fully integrated mlip options in ChemShell optimisation workflow
BTSpeake Jun 18, 2026
5114fb4
Fix to make sure isolated atoms workchain only does the unique atom t…
BTSpeake Jun 22, 2026
53e321a
Fix for base calculation parser when collecting both the optimisation…
BTSpeake Jun 22, 2026
e543d60
Clarify auto-labelling of optimised structure file, it is now a cjson…
BTSpeake Jun 22, 2026
12966a6
Add additional validation for xyz path files when creating Janus trai…
BTSpeake Jun 22, 2026
c70d528
Add error if pyscf used for isolated atom energy workflow
BTSpeake Jun 24, 2026
579cf75
Make isolated atom workflow call in optimisation workflow use the opt…
BTSpeake Jun 24, 2026
0298c1d
Remove old clf-ultra.py workflow file
BTSpeake Jun 24, 2026
29cb1b4
Expose new calculations/workflows as aiida plugins
BTSpeake Jun 24, 2026
f5679ad
Remove basis quality input from optimisation workchain, will be handl…
BTSpeake Jun 24, 2026
6ccfd18
Correctly identify only unique elements from cjson based input structure
BTSpeake Jun 24, 2026
c740ff8
Fix spelling mistake
BTSpeake Jun 24, 2026
a18649a
Add label and description to create atomistic StructureData nodes in …
BTSpeake Jun 24, 2026
d2c6716
Add node labels to created nodes during isolated atoms workflow
BTSpeake Jun 24, 2026
bd5ce67
Remove validators for outputs which are breaking workchain
BTSpeake Jun 24, 2026
eb5a6af
Improve calling structure in Isolated Atom workchain
BTSpeake Jun 24, 2026
b6b73ab
Improve step labelling in optimisation workchain
BTSpeake Jun 24, 2026
a1e9bde
Fix tests
BTSpeake Jun 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 24 additions & 27 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
[build-system]
requires = ["setuptools",]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

[project]
version = "0.1.10"
name = "aiida-chemshell"
description = "AiiDA workflow plugin for the ChemShell chemical modelling software package"
authors = [
{name = "Dr. Benjamin T. Speake", email = "benjamin.speake@stfc.ac.uk"},
]
dependencies = [
"aiida-core >= 2.5",
{ name = "Dr. Benjamin T. Speake", email = "benjamin.speake@stfc.ac.uk" },
]
dependencies = ["aiida-core >= 2.5"]
readme = "README.md"
license = {file = "LICENSE"}
keywords = ["aiida", "workflows", "chemshell", ]
license = { file = "LICENSE" }
keywords = ["aiida", "workflows", "chemshell"]
classifiers = [
"Intended Audience :: Science/Research",
"Programming Language :: Python :: 3",
"Topic :: Scientific/Engineering",
"Topic :: Scientific/Engineering",
"Framework :: AiiDA",
"Development Status :: 5 - Production/Stable"
"Development Status :: 5 - Production/Stable",
]
requires-python = ">=3.10"

Expand All @@ -29,36 +27,34 @@ Source = "https://github.com/stfc/aiida-chemshell"

[project.entry-points."aiida.calculations"]
"chemshell" = "aiida_chemshell.calculations.base:ChemShellCalculation"
"chemshell.file_conversion.mlip_training" = "aiida_chemshell.calculations.file_conversion:CreateJanusTrainingInputsCalcJob"

[project.entry-points."aiida.parsers"]
"chemshell" = "aiida_chemshell.parsers.base:ChemShellParser"
"chemshell.file_conversion.mlip_training" = "aiida_chemshell.parsers.file_conversion:CreateJanusTrainingInputsParser"

[project.entry-points."aiida.workflows"]
"chemshell.opt" = "aiida_chemshell.workflows.optimisation:GeometryOptimisationWorkChain"
"chemshell.atomic_energies" = "aiida_chemshell.workflows.isolated_atoms:IsolatedAtomicEnergiesWorkChain"

[tool.setuptools.packages.find]
where = ["src",]
where = ["src"]

[project.optional-dependencies]
dev = [
"aiida-core>=2.6", # Required to support aiida.tools.pytest_fixtures
"pytest>=8.0",
"pytest>=8.0",
"pytest-cov>=6.0",
"ruff>=0.11.0",
"pre-commit"
]
docs = [
"sphinx>=8.0.2",
"piccolo-theme>=0.14.0",
"sphinx-toolbox",
"numpydoc",
"pre-commit",
]
docs = ["sphinx>=8.0.2", "piccolo-theme>=0.14.0", "sphinx-toolbox", "numpydoc"]

[tool.ruff]
target-version = "py310"
line-length = 88
target-version = "py310"
line-length = 88
indent-width = 4
exclude = ["conf.py",]
exclude = ["conf.py"]

[tool.ruff.lint.per-file-ignores]
"tests/conftest.py" = ["B008"]
Expand All @@ -68,23 +64,24 @@ select = [
# flake8-bugbear
"B",
# pylint
"C", "R",
"C",
"R",
# pydocstyle
"D",
# pycodestyle
"E", "W",
"E",
"W",
# Pyflakes
"F", "FA",
"F",
"FA",
# isort
"I",
# pep8-naming
"N",
# pyupgrade
"UP",
]
ignore = [
"C901",
]
ignore = ["C901"]

[tool.ruff.lint.pydocstyle]
convention = "numpy"
Expand Down
99 changes: 85 additions & 14 deletions src/aiida_chemshell/calculations/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from aiida.engine import CalcJob, CalcJobProcessSpec, PortNamespace
from aiida.orm import ArrayData, Dict, Float, SinglefileData, StructureData

from aiida_chemshell.units import UnitsConverter
from aiida_chemshell.utils import ChemShellMMTheory, ChemShellQMTheory


Expand All @@ -23,6 +24,8 @@ class ChemShellCalculation(CalcJob):
FILE_DLFIND = "_dl_find.cjson"
FILE_TMP_STRUCTURE = "input_structure.xyz"
FILE_RESULTS = "result.json"
FILE_TRJPTH = "path.xyz"
FILE_TRJFRC = "path_force.xyz"

@classmethod
def define(cls, spec: CalcJobProcessSpec) -> None:
Expand All @@ -41,8 +44,8 @@ def define(cls, spec: CalcJobProcessSpec) -> None:
validator=cls.validate_structure_file,
required=True,
help=(
"The input structure for the ChemShell calculation either contained"
"within an '.xyz', '.pun' or '.cjson' file or as a StructureData"
"The input structure for the ChemShell calculation either contained "
"within an '.xyz', '.pun' or '.cjson' file or as a StructureData "
"instance."
),
)
Expand Down Expand Up @@ -131,6 +134,14 @@ def define(cls, spec: CalcJobProcessSpec) -> None:
"structure is contained within a ChemShell '.pun' file."
),
)
spec.output(
"optimisation_path",
valid_type=ArrayData,
required=False,
help=(
"Values calculated at each step of an optimisation based calculation."
),
)
spec.output(
"vibrational_energies",
valid_type=Dict,
Expand Down Expand Up @@ -160,10 +171,26 @@ def inputs_validator_wrapper(inputs, namespace):

spec.inputs.validator = inputs_validator_wrapper

spec.output(
"trajectory_path",
valid_type=SinglefileData,
required=False,
help="XYZ trajectory file for the geometry optimisation",
)
spec.output(
"trajectory_force",
valid_type=SinglefileData,
required=False,
help=(
"XYZ trajectory containing forces at each step of a geometry "
"optimisation"
),
)

## Metadata
spec.inputs["metadata"]["options"]["resources"].default = {
"num_machines": 1,
"num_mpiprocs_per_machine": 1,
"num_mpiprocs_per_machine": 4,
}
spec.inputs["metadata"]["options"]["parser_name"].default = "chemshell"

Expand Down Expand Up @@ -327,6 +354,7 @@ def get_valid_optimisation_parameter_keys(cls) -> tuple[str]:
"delta",
"tsrelative",
"thermal",
"save_path",
)

@classmethod
Expand Down Expand Up @@ -565,7 +593,7 @@ def validate_mm_parameters(cls, value: Dict | None, _) -> str | None:
theory = value.get("theory", "").upper()
if theory not in ChemShellMMTheory.__members__:
return (
"The specified MM theory '{theory:s}' is not a "
f"The specified MM theory '{theory:s}' is not a "
"valid ChemShell MM interface within the AiiDA-ChemShell workflow."
)

Expand Down Expand Up @@ -664,22 +692,37 @@ def _build_process_label(self) -> str:
Defines the process label to be associated with the created ProcessNode
stored in the AiiDA database.

Returns
-------
str
The process label based on what inputs have been provided.
"""
return ChemShellCalculation.default_process_label(self)

@classmethod
def default_process_label(cls, node) -> str:
"""
AiiDA Process label definition (Class Method).

Defines the process label to be associated with the created ProcessNode
stored in the AiiDA database.

Returns
-------
str
The process label based on what inputs have been provided.
"""
theory_key = ""
if "qm_parameters" in self.inputs:
if "mm_parameters" in self.inputs:
if "qm_parameters" in node.inputs:
if "mm_parameters" in node.inputs:
theory_key = "_(QM/MM)"
else:
theory_key = "_(QM)"
else:
theory_key = "_(MM)"

if "optimisation_parameters" in self.inputs:
if self.inputs.optimisation_parameters.get("thermal", False):
if "optimisation_parameters" in node.inputs:
if node.inputs.optimisation_parameters.get("thermal", False):
return "ChemShell_Vibrational_Frequencies" + theory_key
return "ChemShell_Geometry_Optimisation" + theory_key

Expand All @@ -700,10 +743,19 @@ def chemsh_script_generator(self) -> str:

script = "from chemsh import Fragment\n"
if isinstance(self.inputs.structure, SinglefileData):
fname = self.inputs.structure.filename
script += (
f"structure = Fragment(coords='{self.inputs.structure.filename:s}')\n"
)
else:
fname = ChemShellCalculation.FILE_TMP_STRUCTURE
script += f"structure = Fragment(coords='{fname:s}')\n"
atom_names = [site.kind_name for site in self.inputs.structure.sites]
coords = [
[UnitsConverter.angstrom_to_bohr(r) for r in site.position]
for site in self.inputs.structure.sites
]
script += (
f"structure = Fragment(coords={str(coords):s}, names="
f"{str(atom_names):s})\n"
)

## Setup Theory objects

Expand Down Expand Up @@ -829,9 +881,21 @@ def prepare_for_submission(self, folder: Folder) -> CalcInfo:
# Define the AiiDA code parameters
code_info = CodeInfo()
code_info.code_uuid = self.inputs.code.uuid
code_info.cmdline_params = [
ChemShellCalculation.FILE_SCRIPT,
]
if "chemsh.x" in str(self.inputs.code.filepath_executable):
code_info.cmdline_params = [
ChemShellCalculation.FILE_SCRIPT,
]
else:
n_machines = self.inputs.metadata.options.resources.get("num_machines")
n_mpi_pm = self.inputs.metadata.options.resources.get(
"num_mpiprocs_per_machine"
)
tot_mpi = n_machines * n_mpi_pm
code_info.cmdline_params = [
"-np",
self.inputs.metadata.options.resources.get("tot_num_mpiprocs", tot_mpi),
ChemShellCalculation.FILE_SCRIPT,
]
code_info.stdout_name = ChemShellCalculation.FILE_STDOUT

# Setup the calculation information object
Expand Down Expand Up @@ -871,5 +935,12 @@ def prepare_for_submission(self, folder: Folder) -> CalcInfo:
# file containing the optimised structure
if "optimisation_parameters" in self.inputs:
calc_info.retrieve_list.append(ChemShellCalculation.FILE_DLFIND)
if self.inputs.optimisation_parameters.get("save_path", False):
calc_info.retrieve_list.append(
"_dl_find/" + ChemShellCalculation.FILE_TRJPTH
)
calc_info.retrieve_list.append(
"_dl_find/" + ChemShellCalculation.FILE_TRJFRC
)

return calc_info
Loading
Loading