Skip to content

Commit

Permalink
Added ChiRun and nonyaml functionality. Needs testing.
Browse files Browse the repository at this point in the history
  • Loading branch information
lamsoa729 committed Jan 11, 2024
1 parent a0f5874 commit dbe0269
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 83 deletions.
12 changes: 0 additions & 12 deletions chi_pet/chi.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
"""

# Basic
import shutil
import os
from pathlib import Path
# Main functions
Expand All @@ -24,26 +23,15 @@ class Chi(object):
def __init__(self, opts):

self.opts = opts
self.read_opts()
self.execute()

def read_opts(self):
if not self.opts.workdir:
self.opts.workdir = Path.cwd()

if not self.opts.states and self.opts.args_file:
with self.opts.args_file.open('r') as af:
yd = clib.load_yaml_in_order(af)
self.opts.states = list(yd.keys())

def execute(self):

if self.opts.command == 'create':
chi_root_node = ChiNode(self.opts.workdir, opts=self.opts)
chi_root_node.make_subnodes()

elif self.opts.command == 'run':
pass
c = ChiRun(self.opts)
c.run(self.opts)

Expand Down
26 changes: 20 additions & 6 deletions chi_pet/chi_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Email: [email protected]
Description:
"""
from shutil import rmtree
from shutil import rmtree, copy
from pathlib import Path
from copy import deepcopy
from .chi_param import ChiParam
Expand Down Expand Up @@ -33,14 +33,14 @@ def __init__(self, node_path: Path,
opts : _type_, optional
parser options, by default None
params : _type_, optional
_description_, by default None
_description_ TODO, by default None
Raises
------
TypeError
_description_
_description_ TODO
RuntimeError
_description_
_description_ TODO
"""
if isinstance(node_path, Path):
self._node_path = node_path
Expand Down Expand Up @@ -78,8 +78,7 @@ def make_node_dir(self, node_path: Path, overwrite: bool = False) -> None:
return

self._chi_dict.write_out_yaml_files(node_path)
# TODO initialize nonyaml files and test
# self.make_nonyaml_files(self._path)
self.make_nonyaml_files(node_path, self._opts.overwrite)
# self.make_analysis_dir(self._path)
# self.make_misc_dir(self._path)
# if len(self._chi_params):
Expand All @@ -88,6 +87,21 @@ def make_node_dir(self, node_path: Path, overwrite: bool = False) -> None:

self._chi_dict.write_out_yaml_files(node_path)

def make_nonyaml_files(self, dir_path: Path, overwrite: bool = False) -> None:
for nyf in self._opts.non_yaml:
if nyf.exists():
new_nyf = dir_path / nyf.name
if new_nyf.exists():
if overwrite:
new_nyf.unlink()
else:
raise RuntimeError(
f"Non-yaml file {new_nyf} already exists. Use the overwrite flag to overwrite.")
copy(nyf, new_nyf)
else:
raise RuntimeError(
f"Non-yaml file {nyf} does not exist.")

def make_data_dir(self, path: Path, overwrite: bool = False) -> None:
self._data_dir = path / "data"
return self.create_dir(self._data_dir, overwrite)
Expand Down
32 changes: 22 additions & 10 deletions chi_pet/chi_parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"""

from pathlib import Path
from . import chi_lib as clib


def parse_chi_options():
Expand Down Expand Up @@ -46,25 +47,24 @@ def parse_chi_options():
metavar='PARAM_FILE(S)', nargs='+', type=Path, default=[],
help='List of yaml files to be combined into a single yaml file and varied using Chi-Pet.')

# create_parser.add_argument('-A', '--algorithm', type=str, default='scan',
# help='Algorithm used to vary parameters. Options are "scan", "match", "particle_swarm", "genetic_algorithm".')

create_parser.add_argument('-r', '--replace', default=False, action='store_true',
help='Replace simulation file instead of throwing and error if file already exists.(Used with create parser only)')

create_parser.add_argument('-ny', '--non_yaml', nargs='+', default=[], type=Path,
create_parser.add_argument('-ny', '--non_yaml', nargs='+', type=Path, default=[],
help='Will add non-yaml files to seed directories when creating directory structure. (Used with create parser only)')

# RUN options
run_parser = subparsers.add_parser(
'run', parents=[parent_parser], help='Run a simulation pipeline defined in args yaml file in a singular seed directory. Requires the --args_file option defined.')

if opts.command == 'run':
if opts.args_file is None:
parser.error("'run' requires the '--args_file' option.")

# LAUNCH options
launch_parser = subparsers.add_parser(
'launch', parents=[parent_parser], help='Launch or create launching script to run simulations in seed directories.')

# parser.add_argument('-L', '--launch', nargs='*', default='NOLAUNCH', type=str, metavar='DIRS',
# help='Launches all the seed directories in DIRS list. If no list is\
# given all sim directories in the "simulations" directory will be launched.')

# parser.add_argument('-PSC', '--particleswarmcreate', metavar='PARAM_FILE',
# nargs='+', type=str, default=[],
# help='Particle Swarm Optimization Creation. Creates seed directories with simulation structure that can be launched with ChiLaunch.py. PARAM_FILEs are copied into seed directories with ChiParams chosen according to the random distribution specified. Need -n to specify the number of random population members (default=10).')
Expand All @@ -75,7 +75,19 @@ def parse_chi_options():

opts = parser.parse_args()

if opts.command == 'run' and opts.args_file is None:
parser.error("'run' requires the '--args_file' option.")
if not opts.workdir:
opts.workdir = Path.cwd()
elif not opts.workdir.exists():
parser.error("Work directory '{opts.workdir}' does not exists.")

if opts.args_file:
assert opts.args_file.exists(
), f"Args file {opts.args_file} does not exist."

with opts.args_file.open('r') as f:
opts.args_dict = clib.load_yaml_in_order(f)

if not opts.states:
opts.states = list(opts.args_dict.keys())

return opts
57 changes: 4 additions & 53 deletions chi_pet/chi_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,75 +3,26 @@
import os
from subprocess import run
from .chi_lib import load_yaml_in_order, dump_yaml_in_order
import argparse
from pathlib import Path
from .chi_parse import parse_chi_options

'''
Name: ChiMain.py
Description: Main control program for xi(chi)-launcher. Runs all newagebob code.
Input: To view type ChiRun.py -h
Output: Runs seed (singular) simulations
Name: chi_run.py
Description:
'''


def run_args(workdir, state, args):
action = state + '-ing'
action_file = Path('.' + action)
print("Started {} sim using args {}".format(action, args))
sys.stdout.flush()
if workdir.exists():
os.chdir(workdir)
action_file.touch()
status = run(args)
action_file.unlink()
if status.returncode:
print(f"Run failed: State {state} did not succeed.")
return status.returncode
else:
print(
f"Run failed: could not find work directory {workdir} to do action {state}.")
return 1


class ChiRun(object):
def __init__(self, opts):
self._opts = opts

def run(self):
"""Run simulation pipeline defined in the the args.yaml file defined as self.opts.args_file.
Parameters
----------
opts : _type_
_description_
"""Run simulation pipeline defined in the the args.yaml file defined as self._opts.args_file.
Raises
------
FileNotFoundError
_description_
FileNotFoundError
_description_
"""

# TODO NEXT Make these more useful for running simulations
if not self._opts.workdir.exists():
raise FileNotFoundError(
"Run failed. Directory {} does not exists.".format(
self._opts.workdir))

elif not self._opts._args_file.exists():
raise FileNotFoundError(
"Run failed. args.yaml file not found in {self._opts.workdir}.".format(
))
else:
with self._opts.args_file.open('r') as f:
args_dict = load_yaml_in_order(f)

# print(dump_yaml_in_order(args_dict, default_flow_style=False))
# Loop through all states in args.yaml.
# TODO Add option to see if sim_action file exists and only run those states.
for run_state, vals in args_dict.items():
for run_state, vals in self._opts.args_dict.items():
args = [str(a) for a in vals]
sim_action = Path('sim.{}'.format(run_state))

Expand Down
11 changes: 10 additions & 1 deletion tests/test_chi_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ def test_chi_node_matched_scanned_subnode_creation(mock_yaml_dict, mock_create_o
@pytest.mark.parametrize("chi_param_2_str",
["ChiParam(name='pB', format_str='pB{:.1f}', values=[.1,.2,.3,.4], alg='match', param_grp='alpha')",
"ChiParam(name='pB', format_str='pB{:.1f}', values=[.1,.2,.3], alg='match')"])
def test_chi_node_matched_creation_rt_error(mock_yaml_dict, mock_create_opts, chi_param_2_str):
def test_chi_node_matched_creation_runtime_error(mock_yaml_dict, mock_create_opts, chi_param_2_str):
# Set path for creating node
root_path = Path.cwd() / 'tests/mock_root'

Expand All @@ -207,3 +207,12 @@ def test_chi_node_matched_creation_rt_error(mock_yaml_dict, mock_create_opts, ch
cnode.make_node_dir(root_path)
with pytest.raises(RuntimeError):
cnode.make_subnodes()


def test_chi_node_nonyaml_create(mock_root_dir, mock_create_opts):
"""!Test to make sure subnodes are generated properly.
"""
root_path = mock_root_dir
mock_create_opts.param_files = list(root_path.glob('*.yaml'))
# TODO NEXT TEST Make sure nonyaml files are created
pass
23 changes: 22 additions & 1 deletion tests/test_chi_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,27 @@
"""Tests for `chi_run` module of `chi_pet` package."""

from pathlib import Path
from chi_pet.chi_run import ChiRun
import pytest

# TODO NTEST add tests for chi_run.py

@pytest.fixture()
def mock_args_dict(mock_chi_dict, mock_create_opts):
"""Create a mock of ChiNode to use in testing
Returns
-------
opts
Mock opts object with args_dict attribute
"""
pass


# TODO NEXT TEST add tests for chi_run.py
def test_chi_run_pipeline():
"""Test chi_run."""
assert True
# Mock an opts object
# Make a ChiRun object
# Run the pipeline
# Make sure action is carried out

0 comments on commit dbe0269

Please sign in to comment.