Source code for reV.config.execution

# -*- coding: utf-8 -*-
"""
reV Configuration for Execution Options
"""
import logging

from reV.config.base_config import BaseConfig
from reV.utilities.exceptions import ConfigError

logger = logging.getLogger(__name__)


[docs]class BaseExecutionConfig(BaseConfig): """Base class to handle execution configuration""" def __init__(self, config_dict): """ Parameters ---------- config : str | dict File path to config json (str), serialized json object (str), or dictionary with pre-extracted config. """ self._default_option = 'local' self._default_nodes = 1 self._default_mem_util_lim = 0.4 super().__init__(config_dict) @property def option(self): """Get the hardware run option. Returns ------- option : str Execution control option, e.g. local, peregrine, eagle... """ return str(self.get('option', self._default_option)).lower() @property def nodes(self): """Get the number of nodes property. Returns ------- nodes : int Number of available nodes. Default is 1 node. """ return int(self.get('nodes', self._default_nodes)) @property def max_workers(self): """Get the max_workers property (1 runs in serial, None is all workers) Returns ------- max_workers : int | None Processes per node. Default is None max_workers (all available). """ return self.get('max_workers', None) @property def sites_per_worker(self): """Get the number of sites to run per worker. Returns ------- sites_per_worker : int | None Number of sites to run per worker in a parallel scheme. """ return self.get('sites_per_worker', None) @property def memory_utilization_limit(self): """Get the node memory utilization limit property. Key in the config json is "memory_utilization_limit". Returns ------- mem_util_lim : float Memory utilization limit (fractional). Key in the config json is "memory_utilization_limit". """ mem_util_lim = self.get('memory_utilization_limit', self._default_mem_util_lim) return mem_util_lim @property def sh_script(self): """Get the "sh_script" entry which is a string that contains extra shell script commands to run before the reV commands. Returns ------- str """ return self.get('sh_script', '')
[docs]class HPCConfig(BaseExecutionConfig): """Class to handle HPC configuration inputs.""" @property def allocation(self): """Get the HPC allocation property. Returns ------- hpc_alloc : str Name of the HPC allocation account for the specified job. """ return self.get('allocation', None) @property def feature(self): """Get feature request str. Returns ------- feature : str | NoneType Feature request string. For EAGLE, a full additional flag. Config should look like: ``"feature": "--depend=[state:job_id]"`` """ return self.get('feature', None) @property def module(self): """ Get module to load if given Returns ------- module : str Module to load on node """ return self.get('module', None) @property def conda_env(self): """ Get conda environment to activate Returns ------- conda_env : str Conda environment to activate """ return self.get('conda_env', None)
[docs]class SlurmConfig(HPCConfig): """Class to handle SLURM (Eagle) configuration inputs.""" def _preflight(self): """Run a preflight check on the config.""" if self.option in {'eagle', 'kestrel', 'slurm'}: if self.allocation is None: msg = 'HPC execution config must have an "allocation" input' logger.error(msg) raise ConfigError(msg) if self.walltime is None: msg = 'HPC execution config must have a "walltime" input' logger.error(msg) raise ConfigError(msg) super()._preflight() @property def memory(self): """Get the requested Eagle node "memory" value in GB or can be None. Returns ------- _hpc_node_mem : int | None Requested node memory in GB. """ return self.get('memory', None) @property def walltime(self): """Get the requested Eagle node "walltime" value. Returns ------- _hpc_walltime : int Requested single node job time in hours. """ return self.get('walltime', None)