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

Feature decouple somd 3 #29

Open
wants to merge 8 commits into
base: feature-decouple-somd-3
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 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
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ python -m pip install --no-deps .
- Activate your a3fe conda environment
- Create a base directory for the calculation and create an directory called `input` within this
- Move your input files into the the input directory. For example, if you have parameterised AMBER-format input files, name these bound_param.rst7, bound_param.prm7, free_param.rst7, and free_param.prm7. For more details see the documentation. Alternatively, copy the example input files from a3fe/a3fe/data/example_run_dir to your input directory.
- Copy run template_config.cfg from a3fe/a3fe/data/example_run_dir to your `input` directory.
- In the calculation base directory, run the following python code, either through ipython or as a python script (you will likely want to run the script with `nohup`or use ipython through tmux to ensure that the calculation is not killed when you lose connection)

```python
Expand Down
2 changes: 1 addition & 1 deletion a3fe/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
enums,
)

from .configuration import SystemPreparationConfig, SlurmConfig
from .configuration import SystemPreparationConfig, SlurmConfig, SomdConfig

_sys.modules["EnsEquil"] = _sys.modules["a3fe"]

Expand Down
1 change: 1 addition & 0 deletions a3fe/configuration/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@

from .system_prep_config import SystemPreparationConfig
from .slurm_config import SlurmConfig
from .engine_config import SomdConfig
139 changes: 139 additions & 0 deletions a3fe/configuration/_engine_runner_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
"""Abstract base class for engine configurations."""

from __future__ import annotations

import copy as _copy
import logging as _logging
import yaml as _yaml
from abc import ABC, abstractmethod
from typing import Any as _Any
from typing import Dict as _Dict

from ..run._logging_formatters import _A3feStreamFormatter


class EngineRunnerConfig(ABC):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inherit from base model please.

"""An abstract base class for engine configurations."""

def __init__(
self,
stream_log_level: int = _logging.INFO,
) -> None:
"""
Initialize the engine configuration.

Parameters
----------
stream_log_level : int, Optional, default: logging.INFO
Logging level to use for the steam file handlers.
"""
# Set up logging
self._stream_log_level = stream_log_level
self._set_up_logging()

def _set_up_logging(self) -> None:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can remove logging as it's not used. Thanks

"""Set up logging for the configuration."""
# If logger exists, remove it and start again
if hasattr(self, "_logger"):
handlers = self._logger.handlers[:]
for handler in handlers:
self._logger.removeHandler(handler)
handler.close()
del self._logger

# Create a new logger
self._logger = _logging.getLogger(f"{self.__class__.__name__}")
self._logger.propagate = False
self._logger.setLevel(_logging.DEBUG)

# For the stream handler, we want to log at the user-specified level
stream_handler = _logging.StreamHandler()
stream_handler.setFormatter(_A3feStreamFormatter())
stream_handler.setLevel(self._stream_log_level)
self._logger.addHandler(stream_handler)

@abstractmethod
def get_config(self) -> _Dict[str, _Any]:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And instead replace call with self.model_dump() in dump() please.

"""
Get the configuration dictionary.

Returns
-------
config : Dict[str, Any]
The configuration dictionary.
"""
pass

def dump(self, file_path: str) -> None:
"""
Dump the configuration to a YAML file.

Parameters
----------
file_path : str
Path to dump the configuration to.
"""
config = self.get_config()
with open(file_path, "w") as f:
_yaml.safe_dump(config, f, default_flow_style=False)
self._logger.info(f"Configuration dumped to {file_path}")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can probably remove, thanks


@classmethod
def load(cls, file_path: str) -> EngineRunnerConfig:
"""
Load a configuration from a YAML file.

Parameters
----------
file_path : str
Path to load the configuration from.

Returns
-------
config : EngineRunnerConfig
The loaded configuration.
"""
with open(file_path, "r") as f:
config_dict = _yaml.safe_load(f)
return cls(**config_dict)

@abstractmethod
def get_file_name(self) -> str:
"""
Get the name of the configuration file.

Returns
-------
file_name : str
The name of the configuration file.
"""
pass

def __eq__(self, other: object) -> bool:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to define if this derived from pdyantic base model.

"""
Check if two configurations are equal.

Parameters
----------
other : object
The other configuration to compare with.

Returns
-------
equal : bool
Whether the configurations are equal.
"""
if not isinstance(other, EngineRunnerConfig):
return NotImplemented
return self.get_config() == other.get_config()

def copy(self) -> EngineRunnerConfig:
"""
Create a deep copy of the configuration.

Returns
-------
config : EngineRunnerConfig
A deep copy of the configuration.
"""
return _copy.deepcopy(self)
Loading