Skip to content

Commit d058213

Browse files
BaseJobGroup, JobGroup, ColocatedJobGroup skeleton (#599)
BaseJobGroup, JobGroup and ColocatedJobGroup skeletons added. [ Committed by @amandarichardsonn ] [ Reviewed by @juliaputko ]
1 parent b64af80 commit d058213

File tree

9 files changed

+317
-54
lines changed

9 files changed

+317
-54
lines changed

smartsim/launchable/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@
2525
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2626

2727
from .basejob import BaseJob
28+
from .baseJobGroup import BaseJobGroup
29+
from .colocatedJobGroup import ColocatedJobGroup
2830
from .job import Job
31+
from .jobGroup import JobGroup
2932
from .launchable import Launchable
3033
from .mpmdjob import MPMDJob
3134
from .mpmdpair import MPMDPair
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import typing as t
2+
from abc import abstractmethod
3+
from collections.abc import MutableSequence
4+
from copy import deepcopy
5+
6+
from smartsim.launchable.launchable import Launchable
7+
8+
from .basejob import BaseJob
9+
10+
11+
class BaseJobGroup(Launchable, MutableSequence):
12+
"""Highest level ABC of a group of jobs that can be
13+
launched
14+
"""
15+
16+
def __init__(self) -> None:
17+
super().__init__()
18+
19+
@property
20+
@abstractmethod
21+
def jobs(self) -> t.List[BaseJob]:
22+
"""This property method returns a list of BaseJob objects.
23+
It represents the collection of jobs associated with an
24+
instance of the BaseJobGroup abstract class.
25+
"""
26+
pass
27+
28+
def insert(self, idx: int, value: BaseJob) -> None:
29+
"""Inserts the given value at the specified index (idx) in
30+
the list of jobs. If the index is out of bounds, the method
31+
prints an error message.
32+
"""
33+
self.jobs.insert(idx, value)
34+
35+
def __iter__(self) -> t.Iterator[BaseJob]:
36+
"""Allows iteration over the jobs in the collection."""
37+
return iter(self.jobs)
38+
39+
def __getitem__(self, idx: int) -> BaseJob:
40+
"""Retrieves the job at the specified index (idx)."""
41+
return self.jobs[idx]
42+
43+
def __setitem__(self, idx: int, value: BaseJob) -> None:
44+
"""Sets the job at the specified index (idx) to the given value."""
45+
self.jobs[idx] = deepcopy(value)
46+
47+
def __delitem__(self, idx: int) -> None:
48+
"""Deletes the job at the specified index (idx)."""
49+
del self.jobs[idx]
50+
51+
def __len__(self) -> int:
52+
"""Returns the total number of jobs in the collection."""
53+
return len(self.jobs)
54+
55+
def __str__(self): # pragma: no-cover
56+
"""Returns a string representation of the collection of jobs."""
57+
string = ""
58+
string += f"Jobs: {self.jobs}"

smartsim/launchable/basejob.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
class BaseJob(ABC, Launchable):
3434
"""The highest level abstract base class for a single job that can be launched"""
3535

36-
@abstractmethod
3736
def get_launch_steps(self) -> None: # TODO: -> LaunchSteps:
3837
"""Return the launch steps corresponding to the
3938
internal data.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import typing as t
2+
from copy import deepcopy
3+
4+
from .basejob import BaseJob
5+
from .baseJobGroup import BaseJobGroup
6+
7+
8+
class ColocatedJobGroup(BaseJobGroup):
9+
"""A colocated job group holds references to multiple jobs that
10+
will be executed all at the same time when resources
11+
permit. Execution is blocked until resources are available.
12+
"""
13+
14+
def __init__(
15+
self,
16+
jobs: t.List[BaseJob],
17+
) -> None:
18+
super().__init__()
19+
self._jobs = deepcopy(jobs)
20+
21+
@property
22+
def jobs(self) -> t.List[BaseJob]:
23+
"""This property method returns a list of BaseJob objects.
24+
It represents the collection of jobs associated with an
25+
instance of the BaseJobGroup abstract class.
26+
"""
27+
return self._jobs
28+
29+
def __str__(self): # pragma: no-cover
30+
"""Returns a string representation of the collection of
31+
colocated job groups.
32+
"""
33+
string = ""
34+
string += f"Colocated Jobs: {self.jobs}"

smartsim/launchable/jobGroup.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import typing as t
2+
from copy import deepcopy
3+
4+
from .basejob import BaseJob
5+
from .baseJobGroup import BaseJobGroup
6+
7+
8+
class JobGroup(BaseJobGroup):
9+
"""A job group holds references to multiple jobs that
10+
will be executed all at the same time when resources
11+
permit. Execution is blocked until resources are available.
12+
"""
13+
14+
def __init__(
15+
self,
16+
jobs: t.List[BaseJob],
17+
) -> None:
18+
super().__init__()
19+
self._jobs = deepcopy(jobs)
20+
21+
@property
22+
def jobs(self) -> t.List[BaseJob]:
23+
"""This property method returns a list of BaseJob objects.
24+
It represents the collection of jobs associated with an
25+
instance of the BaseJobGroup abstract class.
26+
"""
27+
return self._jobs
28+
29+
def __str__(self): # pragma: no-cover
30+
"""Returns a string representation of the collection of
31+
job groups.
32+
"""
33+
string = ""
34+
string += f"Job Groups: {self.jobs}"

smartsim/launchable/mpmdpair.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2525
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2626

27+
import copy
28+
2729
from smartsim.entity.entity import SmartSimEntity
2830
from smartsim.settings.base import RunSettings
2931

@@ -34,5 +36,5 @@ class MPMDPair:
3436
def __init__(
3537
self, entity: SmartSimEntity, launch_settings: RunSettings
3638
): # TODO: rename to LaunchSettings
37-
self.entity = entity
38-
self.launch_settings = launch_settings
39+
self.entity = copy.deepcopy(entity)
40+
self.launch_settings = copy.deepcopy(launch_settings)
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from smartsim.entity.model import Application
2+
from smartsim.launchable.basejob import BaseJob
3+
from smartsim.launchable.colocatedJobGroup import ColocatedJobGroup
4+
from smartsim.launchable.job import Job
5+
from smartsim.settings.base import RunSettings
6+
7+
# TODO replace with LaunchSettings
8+
app_1 = Application("app_1", "python", run_settings=RunSettings())
9+
app_2 = Application("app_2", "python", run_settings=RunSettings())
10+
app_3 = Application("app_3", "python", run_settings=RunSettings())
11+
12+
13+
def test_create_ColocatedJobGroup():
14+
job_1 = BaseJob()
15+
job_group = ColocatedJobGroup([job_1])
16+
assert len(job_group) == 1
17+
18+
19+
def test_getitem_ColocatedJobGroup():
20+
job_1 = Job(app_1, RunSettings())
21+
job_2 = Job(app_2, RunSettings())
22+
job_group = ColocatedJobGroup([job_1, job_2])
23+
get_value = job_group[0].entity.name
24+
assert get_value == job_1.entity.name
25+
26+
27+
def test_setitem_JobGroup():
28+
job_1 = Job(app_1, RunSettings())
29+
job_2 = Job(app_2, RunSettings())
30+
job_group = ColocatedJobGroup([job_1, job_2])
31+
job_3 = Job(app_3, RunSettings())
32+
job_group[1] = job_3
33+
assert len(job_group) == 2
34+
get_value = job_group[1].entity.name
35+
assert get_value == job_3.entity.name
36+
37+
38+
def test_delitem_ColocatedJobGroup():
39+
job_1 = BaseJob()
40+
job_2 = BaseJob()
41+
job_group = ColocatedJobGroup([job_1, job_2])
42+
assert len(job_group) == 2
43+
del job_group[1]
44+
assert len(job_group) == 1
45+
46+
47+
def test_len_ColocatedJobGroup():
48+
job_1 = BaseJob()
49+
job_2 = BaseJob()
50+
job_group = ColocatedJobGroup([job_1, job_2])
51+
assert len(job_group) == 2
52+
53+
54+
def test_insert_ColocatedJobGroup():
55+
job_1 = BaseJob()
56+
job_2 = BaseJob()
57+
job_group = ColocatedJobGroup([job_1, job_2])
58+
job_3 = BaseJob()
59+
job_group.insert(0, job_3)
60+
get_value = job_group[0]
61+
assert get_value == job_3

tests/temp_tests/test_jobGroup.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from smartsim.entity.model import Application
2+
from smartsim.launchable.basejob import BaseJob
3+
from smartsim.launchable.job import Job
4+
from smartsim.launchable.jobGroup import JobGroup
5+
from smartsim.settings.base import RunSettings
6+
7+
# TODO replace with LaunchSettings
8+
app_1 = Application("app_1", "python", RunSettings())
9+
app_2 = Application("app_2", "python", RunSettings())
10+
app_3 = Application("app_3", "python", RunSettings())
11+
12+
13+
def test_create_JobGroup():
14+
job_1 = BaseJob()
15+
job_group = JobGroup([job_1])
16+
assert len(job_group) == 1
17+
18+
19+
def test_getitem_JobGroup():
20+
job_1 = Job(app_1, RunSettings())
21+
job_2 = Job(app_2, RunSettings())
22+
job_group = JobGroup([job_1, job_2])
23+
get_value = job_group[0].entity.name
24+
assert get_value == job_1.entity.name
25+
26+
27+
def test_setitem_JobGroup():
28+
job_1 = Job(app_1, RunSettings())
29+
job_2 = Job(app_2, RunSettings())
30+
job_group = JobGroup([job_1, job_2])
31+
job_3 = Job(app_3, RunSettings())
32+
job_group[1] = job_3
33+
assert len(job_group) == 2
34+
get_value = job_group[1]
35+
assert get_value.entity.name == job_3.entity.name
36+
37+
38+
def test_delitem_JobGroup():
39+
job_1 = BaseJob()
40+
job_2 = BaseJob()
41+
job_group = JobGroup([job_1, job_2])
42+
assert len(job_group) == 2
43+
del job_group[1]
44+
assert len(job_group) == 1
45+
46+
47+
def test_len_JobGroup():
48+
job_1 = BaseJob()
49+
job_2 = BaseJob()
50+
job_group = JobGroup([job_1, job_2])
51+
assert len(job_group) == 2
52+
53+
54+
def test_insert_JobGroup():
55+
job_1 = BaseJob()
56+
job_2 = BaseJob()
57+
job_group = JobGroup([job_1, job_2])
58+
job_3 = BaseJob()
59+
job_group.insert(0, job_3)
60+
get_value = job_group[0]
61+
assert get_value == job_3

0 commit comments

Comments
 (0)