Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgraded to qcio Generics data structures. #58

Merged
merged 1 commit into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ repos:
hooks:
- id: isort
- repo: https://github.com/psf/black
rev: 23.3.0
rev: 24.4.2
hooks:
- id: black
- repo: https://github.com/charliermarsh/ruff-pre-commit
Expand Down
1 change: 1 addition & 0 deletions chemcloud/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""ChemCloud python client. Scalable compute, easy to learn, fast to code."""

# https://github.com/python-poetry/poetry/pull/2366#issuecomment-652418094
from importlib import metadata

Expand Down
7 changes: 4 additions & 3 deletions chemcloud/http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@
import tomli_w
from qcio.utils import json_dumps

from chemcloud.models import FutureOutput, FutureOutputGroup, QCIOInputs
from chemcloud.models import FutureOutput, FutureOutputGroup

from .config import Settings, settings
from .models import QCIOInputsOrList


class _RequestsClient:
Expand Down Expand Up @@ -280,14 +281,14 @@ def _result_id_to_future_result(self, input_data, result_id):

def compute(
self,
inp_obj: QCIOInputs,
inp_obj: QCIOInputsOrList,
params: Optional[Dict[str, Any]] = None,
) -> Union[FutureOutput, FutureOutputGroup]:
"""Submit a computation to ChemCloud"""
result_id = self._authenticated_request(
"post",
"/compute",
data=json_dumps(inp_obj),
data=json_dumps(inp_obj), # type: ignore
params=params or {},
)
return self._result_id_to_future_result(inp_obj, result_id)
Expand Down
30 changes: 15 additions & 15 deletions chemcloud/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,18 @@

from pydantic import field_validator
from pydantic.main import BaseModel
from qcio import (
DualProgramInput,
FileInput,
FileOutput,
OptimizationOutput,
ProgramFailure,
ProgramInput,
SinglePointOutput,
)
from qcio import DualProgramInput, FileInput, ProgramInput, ProgramOutput
from typing_extensions import TypeAlias

from .exceptions import TimeoutError

GROUP_ID_PREFIX = "group-"

# Convenience types
QCIOInputs = Union[ProgramInput, FileInput, DualProgramInput]
QCIOInputsOrList = Union[QCIOInputs, List[QCIOInputs]]
QCIOOutputs = Union[FileOutput, SinglePointOutput, OptimizationOutput, ProgramFailure]
QCIOOutputsOrList = Union[QCIOOutputs, List[QCIOOutputs]]
QCIOInputs: TypeAlias = Union[ProgramInput, FileInput, DualProgramInput]
QCIOInputsOrList: TypeAlias = Union[QCIOInputs, List[QCIOInputs]]
QCIOOutputs: TypeAlias = ProgramOutput
QCIOOutputsOrList: TypeAlias = Union[QCIOOutputs, List[QCIOOutputs]]


class TaskStatus(str, Enum):
Expand All @@ -33,6 +26,7 @@ class TaskStatus(str, Enum):
#: Task state is unknown (assumed pending since you know the id).
PENDING = "PENDING"
COMPLETE = "COMPLETE"
FAILURE = "FAILURE"


class FutureOutputBase(BaseModel, ABC):
Expand Down Expand Up @@ -60,7 +54,7 @@ def get(
self,
timeout: Optional[float] = None, # in seconds
interval: float = 1.0,
) -> QCIOOutputsOrList:
) -> Optional[QCIOOutputsOrList]:
"""Block until a calculation is complete and return the result.

Parameters:
Expand All @@ -80,7 +74,13 @@ def get(

start_time = time()

while not self.result:
# self._state check prevents 401 errors from ChemCloud when the job completed
# but the server failed to return a result (e.g., due to .program_output not)
# being set correctly by qcio/BigChem.
# TODO: Make a clearer contract between Server and Client re: states. This got
# a bit messy as I switched mimicking celery states to the more simplified setup
# I have now. This can be simplified further.
while not self.result and self._state not in {"COMPLETE", "FAILURE"}:
# Calling self.status returns status and sets self.result if task complete
self.status
if timeout:
Expand Down
5 changes: 5 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## [unreleased]

### Changed

- Upgraded to `qcio` Generics data structures.
- Upgraded `black` from `^23.0.0` to `^24.0.0`.

## [0.8.3] - 2023-10-20

### Changed
Expand Down
20 changes: 12 additions & 8 deletions examples/energy.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from qcio import Molecule, ProgramInput, SinglePointOutput
from qcio import Molecule, ProgramInput, ProgramOutput

from chemcloud import CCClient

Expand All @@ -19,11 +19,15 @@
calctype="energy", # Or "gradient" or "hessian"
keywords={},
)
future_result = client.compute("psi4", prog_inp, collect_files=True)
output: SinglePointOutput = future_result.get()
# SinglePointOutput object containing all returned data
print(output.stdout)
print(output)
future_result = client.compute("terachem", prog_inp, collect_files=True)
prog_output: ProgramOutput = future_result.get()
# ProgramOutput object containing all returned data
print(prog_output.stdout)
print(prog_output)
# The energy value requested
print(output.return_result)
print(output.files.keys())

if prog_output.success:
print(prog_output.results.energy)
print(prog_output.files.keys())
else:
print(prog_output.traceback)
6 changes: 3 additions & 3 deletions examples/energy_batch.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@
keywords={},
)
future_result = client.compute("psi4", [prog_inp] * 2)
output = future_result.get()
# Array of SinglePointOutput objects containing all returned data
print(output)
prog_output = future_result.get()
# Array of ProgramOutput objects containing all returned data
print(prog_output)
14 changes: 7 additions & 7 deletions examples/energy_wfn_input.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from qcio import Molecule, ProgramInput, SinglePointOutput
from qcio import Molecule, ProgramInput, ProgramOutput

from chemcloud import CCClient

Expand All @@ -23,10 +23,10 @@
},
)
future_result = client.compute("terachem", prog_inp)
output: SinglePointOutput = future_result.get()
# SinglePointOutput object containing all returned data
print(output.stdout)
print(output)
prog_output: ProgramOutput = future_result.get()
# ProgramOutput object containing all returned data
print(prog_output.stdout)
print(prog_output)
# The energy value requested
print(output.return_result)
print(output.files.keys())
print(prog_output.return_result)
print(prog_output.files.keys())
8 changes: 4 additions & 4 deletions examples/optimization_batch.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@
prog_inp = DualProgramInput(
molecule=water,
calctype="optimization",
keywords={"maxiter": 3},
keywords={"maxiter": 25},
subprogram="psi4",
subprogram_args={"model": {"method": "b3lyp", "basis": "6-31g"}},
)


# Submit calculation
future_result = client.compute("geometric", [prog_inp] * 2)
output = future_result.get()
future_result = client.compute("geometric", prog_inp)
prog_output = future_result.get()

# Array of OptimizationOutput objects
print(output)
print(prog_output)
14 changes: 7 additions & 7 deletions examples/parallel_frequency_analysis.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from qcio import DualProgramInput, Molecule, SinglePointOutput
from qcio import DualProgramInput, Molecule, ProgramOutput

from chemcloud import CCClient

Expand All @@ -23,10 +23,10 @@

# Submit calculation
future_result = client.compute("bigchem", prog_inp)
output: SinglePointOutput = future_result.get()
prog_output: ProgramOutput = future_result.get()

# SinglePointOutput object containing all returned data
print(output)
print(f"Wavenumbers: {output.results.freqs_wavenumber}")
print(output.results.normal_modes_cartesian)
print(output.results.gibbs_free_energy)
# ProgramOutput object containing all returned data
print(prog_output)
print(f"Wavenumbers: {prog_output.results.freqs_wavenumber}")
print(prog_output.results.normal_modes_cartesian)
print(prog_output.results.gibbs_free_energy)
16 changes: 8 additions & 8 deletions examples/parallel_hessian.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from qcio import DualProgramInput, Molecule, SinglePointOutput
from qcio import DualProgramInput, Molecule, ProgramOutput

from chemcloud import CCClient

Expand All @@ -23,12 +23,12 @@

# Submit calculation
future_result = client.compute("bigchem", prog_inp)
output: SinglePointOutput = future_result.get()
prog_output: ProgramOutput = future_result.get()

# SinglePointOutput object containing all returned data
print(output)
print(output.results.hessian)
# ProgramOutput object containing all returned data
print(prog_output)
print(prog_output.results.hessian)
# Frequency data always included too
print(f"Wavenumbers: {output.results.freqs_wavenumber}")
print(output.results.normal_modes_cartesian)
print(output.results.gibbs_free_energy)
print(f"Wavenumbers: {prog_output.results.freqs_wavenumber}")
print(prog_output.results.normal_modes_cartesian)
print(prog_output.results.gibbs_free_energy)
Loading
Loading