from __future__ import annotations
import argparse
import logging
import os
import traceback
from multiprocessing import Pool
from pathlib import Path
from typing import TYPE_CHECKING, NamedTuple, List
import yaml
from nrel.hive.app.run import run_sim
from nrel.hive.util import fs
if TYPE_CHECKING:
pass
parser = argparse.ArgumentParser(description="run hive")
parser.add_argument("batch_config", help="which batch config file to use?")
log = logging.getLogger("hive")
[docs]class BatchConfig(NamedTuple):
scenario_files: List[Path]
[docs] @classmethod
def from_dict(cls, d: dict) -> BatchConfig:
if "scenario_files" not in d:
raise KeyError("must specify scenario_files in the batch config")
scenario_files = [fs.find_scenario(f) for f in d["scenario_files"]]
return BatchConfig(scenario_files)
[docs]class SimArgs(NamedTuple):
scenario_file: Path
[docs]def safe_sim(sim_args: SimArgs) -> int:
try:
return run_sim(sim_args.scenario_file)
except Exception:
log.error(f"{sim_args.scenario_file} failed, see traceback:")
log.error(traceback.format_exc())
return -1
[docs]def run() -> int:
"""
entry point for a hive application run
:return: 0 if success, 1 if error
"""
_welcome_to_hive()
# parse arguments
args = parser.parse_args()
# main application
config_file = Path(args.batch_config)
if not config_file.is_file():
raise FileNotFoundError(f"couldn't find config file: {config_file}")
with config_file.open("r") as stream:
d = yaml.safe_load(stream)
config = BatchConfig.from_dict(d)
sim_args = [SimArgs(f) for f in config.scenario_files]
# check to make sure we don't exceed system CPU
os_cpu = os.cpu_count()
if os_cpu is None:
max_cpu = 1
else:
max_cpu = os_cpu
if len(config.scenario_files) > max_cpu:
cpu = max_cpu
else:
cpu = len(config.scenario_files)
with Pool(cpu) as p:
results = p.map(safe_sim, sim_args)
return 0
[docs]def _welcome_to_hive():
welcome = """
## ## #### ## ## #######
## ## ## ## ## ##
######### ## ## ## ######
## ## ## ## ## ##
## ## #### ### #######
.' '. __
. . . (__\_
. . . -{{_(|8)
' . . ' ' . . ' (__/
"""
log.info(welcome)
if __name__ == "__main__":
run()