Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
444e502
removed unused attrs from application, in progress
juliaputko Aug 20, 2024
71311ae
in progress rm attrs
juliaputko Aug 21, 2024
a8e852d
in progress
juliaputko Aug 22, 2024
40e782f
add files to ignore, refactor of application, fixing tests to accomod…
juliaputko Aug 23, 2024
1045f7e
Merge branch 'rmdeadattrs' into ensemblerefactor
juliaputko Aug 26, 2024
fba48d3
update to model
juliaputko Aug 26, 2024
20058b3
Merge branch 'rmdeadattrs' into ensemblerefactor
juliaputko Aug 26, 2024
a324c32
in progress ensemble refactor
juliaputko Aug 26, 2024
e48541d
pr review comments addressed
juliaputko Aug 27, 2024
8a85875
resolve merge onflicts
juliaputko Aug 27, 2024
cc22b54
doc strings and isort fixes
juliaputko Aug 28, 2024
6c80307
Merge branch 'rmdeadattrs' into ensemblerefactor
juliaputko Aug 28, 2024
20b5044
merge with smartsim-refactor
juliaputko Aug 28, 2024
8b72051
__str refactor; deepycopy changes; clean
juliaputko Aug 28, 2024
2330f7a
ensemble update and mypy changes
juliaputko Aug 28, 2024
15d4c90
merge in model attrs rm
juliaputko Aug 28, 2024
bb93bde
mypy error fix
juliaputko Aug 28, 2024
4f3d187
fixing tests
juliaputko Aug 28, 2024
172edb7
Merge branch 'rmdeadattrs' into ensemblerefactor
juliaputko Aug 28, 2024
0f0b263
remove unnecessary lines
juliaputko Aug 28, 2024
b3270ac
Merge branch 'rmdeadattrs' into ensemblerefactor
juliaputko Aug 28, 2024
202cb32
formatting fix
juliaputko Aug 28, 2024
9b46fc6
resolve merge conflicts
juliaputko Aug 29, 2024
6378593
added tests;format and type changes
juliaputko Aug 30, 2024
72b74a1
merge with ssmartsim-refactor
juliaputko Aug 30, 2024
1a44b33
file_params and exe_args are deepcopies
juliaputko Sep 3, 2024
b618b9a
formatting fix
juliaputko Sep 3, 2024
f913ce0
changed typing
juliaputko Sep 4, 2024
b1431a7
type fix
juliaputko Sep 4, 2024
ca8654f
formatting fix
juliaputko Sep 5, 2024
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
5 changes: 3 additions & 2 deletions smartsim/entity/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

from __future__ import annotations

import collections
import copy
import textwrap
import typing as t
Expand Down Expand Up @@ -262,7 +263,7 @@ def _build_exe_args(exe_args: t.Union[str, t.Sequence[str], None]) -> t.List[str
if not (
isinstance(exe_args, str)
or (
isinstance(exe_args, list)
isinstance(exe_args, collections.abc.Sequence)
and all(isinstance(arg, str) for arg in exe_args)
)
):
Expand All @@ -271,7 +272,7 @@ def _build_exe_args(exe_args: t.Union[str, t.Sequence[str], None]) -> t.List[str
if isinstance(exe_args, str):
return exe_args.split()

return exe_args
return list(exe_args)

def print_attached_files(self) -> None:
"""Print a table of the attached files on std out"""
Expand Down
176 changes: 168 additions & 8 deletions smartsim/entity/ensemble.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
import os.path
import typing as t

from smartsim.entity import _mock, entity, strategies
from smartsim.entity import entity, strategies
from smartsim.entity.application import Application
from smartsim.entity.files import EntityFiles
from smartsim.entity.strategies import ParamSet
Expand All @@ -59,23 +59,183 @@ def __init__(
max_permutations: int = -1,
replicas: int = 1,
) -> None:
"""Initialize an ``Ensemble`` of application instances

:param name: name of the ensemble
:param exe: executable to run
:param exe_args: executable arguments
:param exe_arg_parameters: parameters and values to be used when configuring entities
:param files: files to be copied, symlinked, and/or configured prior to
execution
:param file_parameters: parameters and values to be used when configuring
files
:param permutation_strategy: strategy to control how the param values are applied to the Ensemble
:param max_permutations: max parameter permutations to set for the ensemble
:param replicas: number of identical entities to create within an Ensemble
"""
self.name = name
self.exe = os.fspath(exe)
"""The name of the ensemble"""
self._exe = os.fspath(exe)
"""The executable to run"""
self.exe_args = list(exe_args) if exe_args else []
self.exe_arg_parameters = (
"""The executable arguments"""
self._exe_arg_parameters = (
copy.deepcopy(exe_arg_parameters) if exe_arg_parameters else {}
)
self.files = copy.deepcopy(files) if files else EntityFiles()
self.file_parameters = dict(file_parameters) if file_parameters else {}
self.permutation_strategy = permutation_strategy
self.max_permutations = max_permutations
self.replicas = replicas
"""The parameters and values to be used when configuring entities"""
self._files = copy.deepcopy(files) if files else EntityFiles()
"""The files to be copied, symlinked, and/or configured prior to execution"""
self._file_parameters = (
copy.deepcopy(file_parameters) if file_parameters else {}
)
"""The parameters and values to be used when configuring files"""
self._permutation_strategy = permutation_strategy
"""The strategy to control how the param values are applied to the Ensemble"""
self._max_permutations = max_permutations
"""The maximum number of entities to come out of the permutation strategy"""
self._replicas = replicas
"""How many identical entities to create within an Ensemble"""

@property
def exe(self) -> str:
"""Return executable to run.

:returns: application executable to run
"""
return self._exe

@exe.setter
def exe(self, value: str | os.PathLike[str]) -> None:
"""Set executable to run.

:param value: executable to run
"""
self._exe = os.fspath(value)

@property
def exe_args(self) -> t.List[str]:
"""Return a list of attached executable arguments.

:returns: application executable arguments
"""
return self._exe_args

@exe_args.setter
def exe_args(self, value: t.Sequence[str]) -> None:
"""Set the executable arguments.

:param value: executable arguments
"""
self._exe_args = list(value)

@property
def exe_arg_parameters(self) -> t.Mapping[str, t.Sequence[t.Sequence[str]]]:
"""Return the executable argument parameters

:returns: executable arguments parameters
"""
return self._exe_arg_parameters

@exe_arg_parameters.setter
def exe_arg_parameters(
self, value: t.Mapping[str, t.Sequence[t.Sequence[str]]]
) -> None:
"""Set the executable arguments.

:param value: executable arguments
"""
self._exe_arg_parameters = copy.deepcopy(value)

@property
def files(self) -> EntityFiles:
"""Return files to be copied, symlinked, and/or configured prior to
execution.

:returns: files
"""
return self._files

@files.setter
def files(self, value: EntityFiles) -> None:
"""Set files to be copied, symlinked, and/or configured prior to
execution.

:param value: files
"""
self._files = copy.deepcopy(value)

@property
def file_parameters(self) -> t.Mapping[str, t.Sequence[str]]:
"""Return file parameters.

:returns: application file parameters
"""
return self._file_parameters

@file_parameters.setter
def file_parameters(self, value: t.Mapping[str, t.Sequence[str]]) -> None:
"""Set the file parameters.

:param value: file parameters
"""
self._file_parameters = dict(value)

@property
def permutation_strategy(self) -> str | strategies.PermutationStrategyType:
"""Return the permutation strategy

:return: permutation strategy
"""
return self._permutation_strategy

@permutation_strategy.setter
def permutation_strategy(
self, value: str | strategies.PermutationStrategyType
) -> None:
"""Set the permutation strategy

:param value: permutation strategy
"""
self._permutation_strategy = value

@property
def max_permutations(self) -> int:
"""Return the maximum permutations

:return: max permutations
"""
return self._max_permutations

@max_permutations.setter
def max_permutations(self, value: int) -> None:
"""Set the maximum permutations

:param value: the maxpermutations
"""
self._max_permutations = value

@property
def replicas(self) -> int:
"""Return the number of replicas

:return: number of replicas
"""
return self._replicas

@replicas.setter
def replicas(self, value: int) -> None:
"""Set the number of replicas

:return: the number of replicas
"""
self._replicas = value

def _create_applications(self) -> tuple[Application, ...]:
"""Concretize the ensemble attributes into a collection of
application instances.
"""
permutation_strategy = strategies.resolve(self.permutation_strategy)

combinations = permutation_strategy(
self.file_parameters, self.exe_arg_parameters, self.max_permutations
)
Expand Down
52 changes: 51 additions & 1 deletion tests/test_ensemble.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@

import itertools
import typing as t
from glob import glob
from os import path as osp

import pytest

from smartsim.entity import _mock
from smartsim.entity.ensemble import Ensemble
from smartsim.entity.files import EntityFiles
from smartsim.entity.strategies import ParamSet
from smartsim.settings.launchSettings import LaunchSettings

Expand All @@ -40,6 +42,54 @@
_2x2_EXE_ARG = {"EXE": [["a"], ["b", "c"]], "ARGS": [["d"], ["e", "f"]]}


@pytest.fixture
def get_gen_configure_dir(fileutils):
yield fileutils.get_test_conf_path(osp.join("generator_files", "tag_dir_template"))


def test_exe_property():
e = Ensemble(name="test", exe="path/to/example_simulation_program")
exe = e.exe
assert exe == e.exe


def test_exe_args_property():
e = Ensemble("test", exe="path/to/example_simulation_program", exe_args="sleepy.py")
exe_args = e.exe_args
assert exe_args == e.exe_args


def test_exe_arg_parameters_property():
exe_arg_parameters = {"-N": 2}
e = Ensemble(
"test",
exe="path/to/example_simulation_program",
exe_arg_parameters=exe_arg_parameters,
)
exe_arg_parameters = e.exe_arg_parameters
assert exe_arg_parameters == e.exe_arg_parameters


def test_files_property(get_gen_configure_dir):
tagged_files = sorted(glob(get_gen_configure_dir + "/*"))
files = EntityFiles(tagged=tagged_files)
e = Ensemble("test", exe="path/to/example_simulation_program", files=files)
files = e.files
assert files == e.files


def test_file_parameters_property():
file_parameters = {"h": [5, 6, 7, 8]}
e = Ensemble(
"test",
exe="path/to/example_simulation_program",
file_parameters=file_parameters,
)
file_parameters = e.file_parameters

assert file_parameters == e.file_parameters


def user_created_function(
file_params: t.Mapping[str, t.Sequence[str]],
exe_arg_params: t.Mapping[str, t.Sequence[t.Sequence[str]]],
Expand Down