idmtools-platform-comps 0.0.0.dev0__py3-none-any.whl → 0.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. idmtools_platform_comps/__init__.py +25 -8
  2. idmtools_platform_comps/cli/__init__.py +4 -0
  3. idmtools_platform_comps/cli/cli_functions.py +50 -0
  4. idmtools_platform_comps/cli/comps.py +492 -0
  5. idmtools_platform_comps/comps_cli.py +48 -0
  6. idmtools_platform_comps/comps_operations/__init__.py +6 -0
  7. idmtools_platform_comps/comps_operations/asset_collection_operations.py +263 -0
  8. idmtools_platform_comps/comps_operations/experiment_operations.py +569 -0
  9. idmtools_platform_comps/comps_operations/simulation_operations.py +678 -0
  10. idmtools_platform_comps/comps_operations/suite_operations.py +228 -0
  11. idmtools_platform_comps/comps_operations/workflow_item_operations.py +269 -0
  12. idmtools_platform_comps/comps_platform.py +309 -0
  13. idmtools_platform_comps/plugin_info.py +168 -0
  14. idmtools_platform_comps/ssmt_operations/__init__.py +6 -0
  15. idmtools_platform_comps/ssmt_operations/simulation_operations.py +77 -0
  16. idmtools_platform_comps/ssmt_operations/workflow_item_operations.py +73 -0
  17. idmtools_platform_comps/ssmt_platform.py +44 -0
  18. idmtools_platform_comps/ssmt_work_items/__init__.py +4 -0
  19. idmtools_platform_comps/ssmt_work_items/comps_work_order_task.py +29 -0
  20. idmtools_platform_comps/ssmt_work_items/comps_workitems.py +113 -0
  21. idmtools_platform_comps/ssmt_work_items/icomps_workflowitem.py +71 -0
  22. idmtools_platform_comps/ssmt_work_items/work_order.py +54 -0
  23. idmtools_platform_comps/utils/__init__.py +4 -0
  24. idmtools_platform_comps/utils/assetize_output/__init__.py +4 -0
  25. idmtools_platform_comps/utils/assetize_output/assetize_output.py +125 -0
  26. idmtools_platform_comps/utils/assetize_output/assetize_ssmt_script.py +144 -0
  27. idmtools_platform_comps/utils/base_singularity_work_order.json +6 -0
  28. idmtools_platform_comps/utils/download/__init__.py +4 -0
  29. idmtools_platform_comps/utils/download/download.py +178 -0
  30. idmtools_platform_comps/utils/download/download_ssmt.py +81 -0
  31. idmtools_platform_comps/utils/download_experiment.py +116 -0
  32. idmtools_platform_comps/utils/file_filter_workitem.py +519 -0
  33. idmtools_platform_comps/utils/general.py +358 -0
  34. idmtools_platform_comps/utils/linux_mounts.py +73 -0
  35. idmtools_platform_comps/utils/lookups.py +123 -0
  36. idmtools_platform_comps/utils/package_version.py +489 -0
  37. idmtools_platform_comps/utils/python_requirements_ac/__init__.py +4 -0
  38. idmtools_platform_comps/utils/python_requirements_ac/create_asset_collection.py +155 -0
  39. idmtools_platform_comps/utils/python_requirements_ac/install_requirements.py +109 -0
  40. idmtools_platform_comps/utils/python_requirements_ac/requirements_to_asset_collection.py +374 -0
  41. idmtools_platform_comps/utils/python_version.py +40 -0
  42. idmtools_platform_comps/utils/scheduling.py +154 -0
  43. idmtools_platform_comps/utils/singularity_build.py +491 -0
  44. idmtools_platform_comps/utils/spatial_output.py +76 -0
  45. idmtools_platform_comps/utils/ssmt_utils/__init__.py +6 -0
  46. idmtools_platform_comps/utils/ssmt_utils/common.py +70 -0
  47. idmtools_platform_comps/utils/ssmt_utils/file_filter.py +568 -0
  48. idmtools_platform_comps/utils/sweeping.py +162 -0
  49. idmtools_platform_comps-0.0.2.dist-info/METADATA +100 -0
  50. idmtools_platform_comps-0.0.2.dist-info/RECORD +62 -0
  51. idmtools_platform_comps-0.0.2.dist-info/entry_points.txt +9 -0
  52. idmtools_platform_comps-0.0.2.dist-info/licenses/LICENSE.TXT +3 -0
  53. {idmtools_platform_comps-0.0.0.dev0.dist-info → idmtools_platform_comps-0.0.2.dist-info}/top_level.txt +1 -0
  54. ssmt_image/Dockerfile +52 -0
  55. ssmt_image/Makefile +21 -0
  56. ssmt_image/__init__.py +6 -0
  57. ssmt_image/bootstrap.sh +30 -0
  58. ssmt_image/build_docker_image.py +161 -0
  59. ssmt_image/pip.conf +3 -0
  60. ssmt_image/push_docker_image.py +49 -0
  61. ssmt_image/requirements.txt +9 -0
  62. idmtools_platform_comps-0.0.0.dev0.dist-info/METADATA +0 -41
  63. idmtools_platform_comps-0.0.0.dev0.dist-info/RECORD +0 -5
  64. {idmtools_platform_comps-0.0.0.dev0.dist-info → idmtools_platform_comps-0.0.2.dist-info}/WHEEL +0 -0
@@ -0,0 +1,309 @@
1
+ """idmtools COMPSPlatform.
2
+
3
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
4
+ """
5
+ # flake8: noqa E402
6
+ import copy
7
+ import logging
8
+ from idmtools.entities import Suite
9
+ from idmtools.entities.experiment import Experiment
10
+ from idmtools.entities.simulation import Simulation
11
+
12
+ HANDLERS = copy.copy(logging.getLogger().handlers)
13
+ LEVEL = logging.getLogger().level
14
+ from COMPS import Client
15
+
16
+ comps_logger = logging.getLogger('COMPS')
17
+ logging.root.handlers = HANDLERS
18
+ logging.getLogger().setLevel(LEVEL)
19
+ comps_logger.propagate = False
20
+ comps_logger.handlers = [h for h in comps_logger.handlers if isinstance(h, logging.FileHandler)]
21
+ from COMPS.Data import Simulation as COMPSSimulation
22
+ from COMPS.Data import WorkItem as COMPSWorkItem
23
+ from COMPS.Data import AssetCollection as COMPSAssetCollection
24
+ from COMPS.Data import Experiment as COMPSExperiment
25
+ from COMPS.Data import Suite as COMPSSuite
26
+ from COMPS.Data.Simulation import SimulationState
27
+ from COMPS.Data.WorkItem import WorkItemState
28
+ from idmtools.assets.asset_collection import AssetCollection
29
+ from idmtools.core.interfaces.ientity import IEntity
30
+ from idmtools.entities.iplatform_default import AnalyzerManagerPlatformDefault, IPlatformDefault
31
+ from idmtools.entities.iworkflow_item import IWorkflowItem
32
+ from dataclasses import dataclass, field
33
+ from typing import Union, Dict, Set
34
+ from functools import partial
35
+ from typing import List
36
+ from enum import Enum
37
+ from idmtools.core import CacheEnabled, ItemType, EntityStatus
38
+ from idmtools.entities.iplatform import IPlatform
39
+ from idmtools.entities.platform_requirements import PlatformRequirements
40
+ from idmtools_platform_comps.comps_operations.asset_collection_operations import CompsPlatformAssetCollectionOperations
41
+ from idmtools_platform_comps.comps_operations.experiment_operations import CompsPlatformExperimentOperations
42
+ from idmtools_platform_comps.comps_operations.simulation_operations import CompsPlatformSimulationOperations
43
+ from idmtools_platform_comps.comps_operations.suite_operations import CompsPlatformSuiteOperations
44
+ from idmtools_platform_comps.comps_operations.workflow_item_operations import CompsPlatformWorkflowItemOperations
45
+ from idmtools_platform_comps.cli.cli_functions import environment_list, validate_range
46
+
47
+ logger = logging.getLogger(__name__)
48
+
49
+
50
+ class COMPSPriority(Enum):
51
+ Lowest = "Lowest"
52
+ BelowNormal = "BelowNormal"
53
+ Normal = "Normal"
54
+ AboveNormal = "AboveNormal"
55
+ Highest = "Highest"
56
+
57
+
58
+ op_defaults = dict(default=None, compare=False, metadata=dict(pickle_ignore=True))
59
+
60
+ # We use this to track os. It would be nice to do that in server
61
+ SLURM_ENVS = ['calculon', 'slurmstage', "slurmdev", "nibbler"]
62
+ supported_types = [PlatformRequirements.PYTHON, PlatformRequirements.SHELL, PlatformRequirements.NativeBinary]
63
+ PLATFORM_DEFAULTS = [AnalyzerManagerPlatformDefault(max_workers=24)]
64
+
65
+
66
+ @dataclass(repr=False)
67
+ class COMPSPlatform(IPlatform, CacheEnabled):
68
+ """
69
+ Represents the platform allowing to run simulations on COMPS.
70
+ """
71
+
72
+ MAX_SUBDIRECTORY_LENGTH = 35 # avoid maxpath issues on COMPS
73
+
74
+ endpoint: str = field(default="https://comps.idmod.org", metadata={"help": "URL of the COMPS endpoint to use"})
75
+ environment: str = field(default="Calculon",
76
+ metadata=dict(help="Name of the COMPS environment to target", callback=environment_list))
77
+ priority: str = field(default=COMPSPriority.Lowest.value,
78
+ metadata=dict(help="Priority of the job", choices=[p.value for p in COMPSPriority]))
79
+ simulation_root: str = field(default="$COMPS_PATH(USER)\\output", metadata=dict(help="Location of the outputs"))
80
+ node_group: str = field(default=None, metadata=dict(help="Node group to target"))
81
+ num_retries: int = field(default=0, metadata=dict(help="How retries if the simulation fails",
82
+ validate=partial(validate_range, min=0, max=10)))
83
+ num_cores: int = field(default=1, metadata=dict(help="How many cores per simulation",
84
+ validate=partial(validate_range, min=1, max=32)))
85
+ max_workers: int = field(default=16, metadata=dict(help="How many processes to spawn locally",
86
+ validate=partial(validate_range, min=1, max=32)))
87
+ batch_size: int = field(default=10, metadata=dict(help="How many simulations per batch",
88
+ validate=partial(validate_range, min=1, max=100)))
89
+ min_time_between_commissions: int = field(default=15, metadata=dict(
90
+ help="How many seconds between commission calls on an experiment",
91
+ validate=partial(validate_range, min=10, max=300)))
92
+ exclusive: bool = field(default=False,
93
+ metadata=dict(help="Enable exclusive mode? (one simulation per node on the cluster)"))
94
+ docker_image: str = field(default=None, metadata={"help": "Docker image to use for simulations"})
95
+
96
+ _platform_supports: List[PlatformRequirements] = field(default_factory=lambda: copy.deepcopy(supported_types),
97
+ repr=False, init=False)
98
+ _platform_defaults: List[IPlatformDefault] = field(default_factory=lambda: copy.deepcopy(PLATFORM_DEFAULTS))
99
+
100
+ _experiments: CompsPlatformExperimentOperations = field(**op_defaults, repr=False, init=False)
101
+ _simulations: CompsPlatformSimulationOperations = field(**op_defaults, repr=False, init=False)
102
+ _suites: CompsPlatformSuiteOperations = field(**op_defaults, repr=False, init=False)
103
+ _workflow_items: CompsPlatformWorkflowItemOperations = field(**op_defaults, repr=False, init=False)
104
+ _assets: CompsPlatformAssetCollectionOperations = field(**op_defaults, repr=False, init=False)
105
+ _skip_login: bool = field(default=False, repr=False)
106
+
107
+ def __post_init__(self):
108
+ self.__init_interfaces()
109
+ self.supported_types = {ItemType.EXPERIMENT, ItemType.SIMULATION, ItemType.SUITE, ItemType.ASSETCOLLECTION,
110
+ ItemType.WORKFLOW_ITEM}
111
+ super().__post_init__()
112
+ # set platform requirements based on environment
113
+ if self.environment.lower() in SLURM_ENVS:
114
+ self._platform_supports.append(PlatformRequirements.LINUX)
115
+ else:
116
+ self._platform_supports.append(PlatformRequirements.WINDOWS)
117
+
118
+ def __init_interfaces(self):
119
+ if not self._skip_login:
120
+ self._login()
121
+ self._experiments = CompsPlatformExperimentOperations(platform=self)
122
+ self._simulations = CompsPlatformSimulationOperations(platform=self)
123
+ self._suites = CompsPlatformSuiteOperations(platform=self)
124
+ self._workflow_items = CompsPlatformWorkflowItemOperations(platform=self)
125
+ self._assets = CompsPlatformAssetCollectionOperations(platform=self)
126
+
127
+ def _login(self):
128
+ # ensure logging is initialized
129
+ from idmtools.core.logging import exclude_logging_classes
130
+ exclude_logging_classes()
131
+ Client.login(self.endpoint)
132
+
133
+ def post_setstate(self):
134
+ self.__init_interfaces()
135
+
136
+ def get_workitem_link(self, work_item: IWorkflowItem):
137
+ return f"{self.endpoint}/#explore/WorkItems?filters=Id={work_item.uid}"
138
+
139
+ def get_asset_collection_link(self, asset_collection: AssetCollection):
140
+ return f"{self.endpoint}/#explore/AssetCollections?filters=Id={asset_collection.uid}"
141
+
142
+ def get_username(self):
143
+ return Client.auth_manager()._username
144
+
145
+ def is_windows_platform(self, item: IEntity = None) -> bool:
146
+ if isinstance(item, IWorkflowItem):
147
+ return False
148
+ return super().is_windows_platform(item)
149
+
150
+ def validate_item_for_analysis(self, item: object, analyze_failed_items=False):
151
+ """
152
+ Check if item is valid for analysis.
153
+
154
+ Args:
155
+ item: which item to flatten
156
+ analyze_failed_items: bool
157
+
158
+ Returns: bool
159
+ """
160
+ result = False
161
+ if isinstance(item, COMPSSimulation):
162
+ if item.state == SimulationState.Succeeded:
163
+ result = True
164
+ else:
165
+ if analyze_failed_items and item.state == SimulationState.Failed:
166
+ result = True
167
+ elif isinstance(item, COMPSWorkItem):
168
+ if item.state == WorkItemState.Succeeded:
169
+ result = True
170
+ else:
171
+ if analyze_failed_items and item.state == WorkItemState.Failed:
172
+ result = True
173
+ elif isinstance(item, (Simulation, IWorkflowItem)):
174
+ if item.succeeded:
175
+ result = True
176
+ else:
177
+ if analyze_failed_items and item.status == EntityStatus.FAILED:
178
+ result = True
179
+
180
+ return result
181
+
182
+ def get_files(self, item: IEntity, files: Union[Set[str], List[str]], output: str = None, **kwargs) -> \
183
+ Union[Dict[str, Dict[str, bytearray]], Dict[str, bytearray]]:
184
+ """
185
+ Get files for a platform entity.
186
+
187
+ Args:
188
+ item: Item to fetch files for
189
+ files: List of asset filenames to retrieve from each simulation
190
+ output: save files to
191
+ kwargs: Platform arguments
192
+
193
+ Returns:
194
+ For simulations, this returns a dictionary with filename as key and values being binary data from file or a
195
+ dict.
196
+
197
+ For experiments, this returns a dictionary with key as sim id and then the values as a dict of the
198
+ simulations described above
199
+ """
200
+ file_data = super().get_files(self._normalized_item_fields(item), files, output, **kwargs)
201
+ return file_data
202
+
203
+ def flatten_item(self, item: object, raw: bool = False, **kwargs) -> List[object]:
204
+ """
205
+ Flatten an item: resolve the children until getting to the leaves.
206
+
207
+ For example, for an experiment, will return all the simulations.
208
+ For a suite, will return all the simulations contained in the suites experiments.
209
+
210
+ Args:
211
+ item: Which item to flatten
212
+ raw: If True, returns raw platform objects, False, return local objects
213
+ kwargs: Extra parameters for conversion
214
+
215
+ Returns:
216
+ List of leaf items, which can be from either the local platform or a COMPS server:
217
+ - Simulations (either local Simulation or COMPSSimulation),
218
+ - WorkItems (local or COMPSWorkItem),
219
+ - or AssetCollections (local or COMPSAssetCollection).
220
+ """
221
+ if not isinstance(item, (Simulation, IWorkflowItem, AssetCollection, COMPSSuite, COMPSExperiment,
222
+ COMPSSimulation, COMPSWorkItem, COMPSAssetCollection, Suite, Experiment)):
223
+ raise Exception(f'Item Type: {type(item)} is not supported!')
224
+
225
+ # Return directly if item is already in leaf and raw = False
226
+ if not raw and isinstance(item, (Simulation, IWorkflowItem, AssetCollection)):
227
+ return [item]
228
+
229
+ # Handle platform object conversion if needed
230
+ if not isinstance(item, (COMPSSuite, COMPSExperiment, COMPSSimulation,
231
+ COMPSWorkItem, COMPSAssetCollection)):
232
+ return self.flatten_item(item.get_platform_object(), raw=raw, **kwargs)
233
+
234
+ # Process type COMPSSuite
235
+ if isinstance(item, COMPSSuite):
236
+ children = self._get_children_for_platform_item(item, children=["tags", "configuration"])
237
+ # Handle leaf types
238
+ return [leaf
239
+ for child in children
240
+ for leaf in self.flatten_item(child, raw=raw, **kwargs)]
241
+ # Process type COMPSExperiment
242
+ elif isinstance(item, COMPSExperiment):
243
+ if type(self) is COMPSPlatform:
244
+ children = self._get_children_for_platform_item(item, children=["tags", "configuration"])
245
+ else:
246
+ children = self._get_children_for_platform_item(item,
247
+ children=["tags", "configuration", "hpc_jobs"])
248
+ # Assign server experiment to child.experiment to avoid recreating child's parent
249
+ item = self._normalized_item_fields(item)
250
+ for child in children:
251
+ child.experiment = item
252
+ # Handle leaf types
253
+ return [leaf
254
+ for child in children
255
+ for leaf in self.flatten_item(child, raw=raw, **kwargs)]
256
+
257
+ # Handle leaf types
258
+ elif isinstance(item, (COMPSSimulation, COMPSWorkItem, COMPSAssetCollection)):
259
+ item = self._normalized_item_fields(item)
260
+
261
+ if not raw:
262
+ parent = item.experiment if isinstance(item, COMPSSimulation) else None
263
+ item = self._convert_platform_item_to_entity(item, parent=parent, **kwargs)
264
+
265
+ return [item]
266
+
267
+ def _ensure_simulation_experiment(self, simulation: COMPSSimulation) -> None:
268
+ """
269
+ Ensure the given simulation has a valid experiment attached.
270
+
271
+ If the simulation's 'experiment' attribute is missing or uninitialized,
272
+ fetch the experiment from the server using its ID and normalize it.
273
+
274
+ Args:
275
+ simulation (COMPSSimulation): The simulation object to validate.
276
+ Raises:
277
+ ValueError: If 'experiment_id' is missing or invalid.
278
+ """
279
+ experiment = getattr(simulation, "experiment", None)
280
+
281
+ if experiment is None or getattr(experiment, "configuration", None) is None:
282
+ if not hasattr(simulation, "experiment_id") or simulation.experiment_id is None:
283
+ raise ValueError("simulation.experiment_id is missing or None; cannot retrieve experiment.")
284
+
285
+ experiment = self.get_item(simulation.experiment_id,
286
+ item_type=ItemType.EXPERIMENT,
287
+ raw=True)
288
+ simulation.experiment = self._normalized_item_fields(experiment)
289
+
290
+ def _normalized_item_fields(self, item):
291
+ """
292
+ Add extra fields to item.
293
+ Args:
294
+ item: Item (COMPS item)
295
+ """
296
+ if not isinstance(item, (COMPSSuite, COMPSExperiment, COMPSSimulation,
297
+ COMPSWorkItem, COMPSAssetCollection)):
298
+ item = item.get_platform_object()
299
+ if isinstance(item, COMPSSimulation):
300
+ self._ensure_simulation_experiment(item)
301
+ item.uid = item.id
302
+ item._id = str(item.id)
303
+ if type(item).__name__ == "WorkItem":
304
+ item.item_type = ItemType.WORKFLOW_ITEM
305
+ elif type(item).__name__ == "AssetCollection":
306
+ item.item_type = ItemType.ASSETCOLLECTION
307
+ else:
308
+ item.item_type = ItemType(type(item).__name__)
309
+ return item
@@ -0,0 +1,168 @@
1
+ """idmtools comps platform plugin definition.
2
+
3
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
4
+ """
5
+ from logging import getLogger
6
+ from typing import Type, List, Dict
7
+ from idmtools.registry.platform_specification import example_configuration_impl, get_platform_impl, \
8
+ get_platform_type_impl, PlatformSpecification
9
+ from idmtools.registry.plugin_specification import get_description_impl
10
+ from idmtools_platform_comps.comps_platform import COMPSPlatform
11
+ from idmtools_platform_comps.ssmt_platform import SSMTPlatform
12
+
13
+ COMPS_EXAMPLE_CONFIG = """
14
+ [COMPSPLATFORM]
15
+ endpoint = https://comps2.idmod.org
16
+ environment = Bayesian
17
+ priority = Lowest
18
+ simulation_root = $COMPS_PATH(USER)\\output
19
+ node_group = emod_abcd
20
+ num_retries = 0
21
+ num_cores = 1
22
+ max_workers = 16
23
+ batch_size = 10
24
+ min_time_between_commissions = 20
25
+ exclusive = False
26
+ # Optional config option. It is recommended you only use this in advanced scenarios. Otherwise
27
+ # leave it unset
28
+ docker_image = docker-staging.packages.idmod.org/idmtools/comps_ssmt_worker:1.0.0
29
+ """
30
+
31
+ logger = getLogger(__name__)
32
+
33
+
34
+ class COMPSPlatformSpecification(PlatformSpecification):
35
+ """Provide the plugin definition for COMPSPlatform."""
36
+
37
+ def __init__(self):
38
+ """Constructor."""
39
+ logger.debug("Initializing COMPS Specification")
40
+
41
+ @get_description_impl
42
+ def get_description(self) -> str:
43
+ """Get description."""
44
+ return "Provides access to the COMPS Platform to idmtools"
45
+
46
+ @get_platform_impl
47
+ def get(self, **configuration) -> COMPSPlatform:
48
+ """Get COMPSPlatform object with configuration."""
49
+ return COMPSPlatform(**configuration)
50
+
51
+ @example_configuration_impl
52
+ def example_configuration(self):
53
+ """Get example config."""
54
+ return COMPS_EXAMPLE_CONFIG
55
+
56
+ @get_platform_type_impl
57
+ def get_type(self) -> Type[COMPSPlatform]:
58
+ """Get COMPSPlatform type."""
59
+ return COMPSPlatform
60
+
61
+ def get_example_urls(self) -> List[str]:
62
+ """Get Comps examples."""
63
+ from idmtools_platform_comps import __version__
64
+ examples = [f'examples/{example}' for example in ['ssmt', 'workitem', 'vistools']]
65
+ return [self.get_version_url(f'v{__version__}', x) for x in examples]
66
+
67
+ def get_version(self) -> str:
68
+ """
69
+ Returns the version of the plugin.
70
+
71
+ Returns:
72
+ Plugin Version
73
+ """
74
+ from idmtools_platform_comps import __version__
75
+ return __version__
76
+
77
+ def get_configuration_aliases(self) -> Dict[str, Dict]:
78
+ """Provides configuration aliases that exist in COMPS."""
79
+ config_aliases = dict(
80
+ CALCULON=dict(
81
+ endpoint="https://comps.idmod.org",
82
+ environment="Calculon"
83
+ ),
84
+ IDMCLOUD=dict(
85
+ endpoint="https://comps.idmod.org",
86
+ environment="IDMcloud"
87
+ ),
88
+ NDCLOUD=dict(
89
+ endpoint="https://comps.idmod.org",
90
+ environment="NDcloud"
91
+ ),
92
+ BMGF_IPMCLOUD=dict(
93
+ endpoint="https://comps.idmod.org",
94
+ environment="BMGF_IPMcloud"
95
+ ),
96
+ QSTART=dict(
97
+ endpoint="https://comps.idmod.org",
98
+ environment="Qstart"
99
+ ),
100
+ NIBBLER=dict(
101
+ endpoint="https://comps.idmod.org",
102
+ environment="Nibbler"
103
+ ),
104
+ SLURMSTAGE=dict(
105
+ endpoint="https://comps2.idmod.org",
106
+ environment="SlurmStage"
107
+ ),
108
+ CUMULUS=dict(
109
+ endpoint="https://comps2.idmod.org",
110
+ environment="Cumulus"
111
+ )
112
+ )
113
+ config_aliases['SLURM'] = config_aliases['CALCULON']
114
+ config_aliases['SLURM2'] = config_aliases['SLURMSTAGE']
115
+ # Friendly names for dev/staging environments from @clorton
116
+ config_aliases['BOXY'] = config_aliases['SLURMSTAGE']
117
+ return config_aliases
118
+
119
+
120
+ class SSMTPlatformSpecification(COMPSPlatformSpecification):
121
+ """Provides the plugic spec for SSMTPlatform."""
122
+
123
+ def __init__(self):
124
+ """Constructor."""
125
+ logger.debug("Initializing SSMT Specification")
126
+
127
+ @get_description_impl
128
+ def get_description(self) -> str:
129
+ """Provide description of SSMT plugin."""
130
+ return "Provides access to the SSMT Platform to idmtools"
131
+
132
+ @get_platform_impl
133
+ def get(self, **configuration) -> SSMTPlatform:
134
+ """Get an instance of SSMTPlatform using the configuration."""
135
+ return SSMTPlatform(**configuration)
136
+
137
+ @example_configuration_impl
138
+ def example_configuration(self):
139
+ """Get example config."""
140
+ # TODO determine different config and how we handle remotely
141
+ return COMPS_EXAMPLE_CONFIG
142
+
143
+ @get_platform_type_impl
144
+ def get_type(self) -> Type[SSMTPlatform]:
145
+ """Get SSMT type."""
146
+ return SSMTPlatform
147
+
148
+ def get_example_urls(self) -> List[str]:
149
+ """Get SSMT example urls."""
150
+ from idmtools_platform_comps import __version__
151
+ examples = [f'examples/{example}' for example in ['ssmt', 'vistools']]
152
+ return [self.get_version_url(f'v{__version__}', x) for x in examples]
153
+
154
+ def get_version(self) -> str:
155
+ """
156
+ Returns the version of the plugin.
157
+
158
+ Returns:
159
+ Plugin Version
160
+ """
161
+ from idmtools_platform_comps import __version__
162
+ return __version__
163
+
164
+ def get_configuration_aliases(self) -> Dict[str, Dict]:
165
+ """Provides configuration aliases that exist in COMPS."""
166
+ config_aliases = super().get_configuration_aliases()
167
+ ssmt_config_aliases = {f"{a}_SSMT": p for a, p in config_aliases.items()}
168
+ return ssmt_config_aliases
@@ -0,0 +1,6 @@
1
+ """idmtools ssmt operations.
2
+
3
+ Since SSMT is the same as comps, we only derive the simulation and workfitem operations to do local file access.
4
+
5
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
6
+ """
@@ -0,0 +1,77 @@
1
+ """idmtools simulation operations for ssmt.
2
+
3
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
4
+ """
5
+ import os
6
+ from uuid import UUID
7
+ from typing import List, Dict, Optional
8
+ from idmtools.entities.simulation import Simulation
9
+ from idmtools_platform_comps.comps_operations.simulation_operations import CompsPlatformSimulationOperations
10
+ from COMPS.Data.Simulation import Simulation as COMPSSimulation
11
+ from COMPS.Data import QueryCriteria
12
+ from logging import getLogger, DEBUG
13
+
14
+ logger = getLogger(__name__)
15
+
16
+
17
+ class SSMTPlatformSimulationOperations(CompsPlatformSimulationOperations):
18
+ """
19
+ SSMTPlatformSimulationOperations provides Simulation operations to SSMT.
20
+
21
+ In this case, we only have to redefine get_assets to optimize file usage.
22
+ """
23
+
24
+ def get(self, simulation_id: UUID, columns: Optional[List[str]] = None, load_children: Optional[List[str]] = None,
25
+ query_criteria: Optional[QueryCriteria] = None, **kwargs) -> COMPSSimulation:
26
+ """
27
+ Get Simulation from Comps.
28
+
29
+ Args:
30
+ simulation_id: ID
31
+ columns: Optional list of columns to load. Defaults to "id", "name", "experiment_id", "state"
32
+ load_children: Optional children to load. Defaults to "tags", "configuration"
33
+ query_criteria: Optional query_criteria object to use your own custom criteria object
34
+ **kwargs:
35
+
36
+ Returns:
37
+ COMPSSimulation
38
+ """
39
+ # ensure hpc_jobs is in children
40
+ if load_children:
41
+ load_children.append('hpc_jobs')
42
+ # when query criteria is specified, we need to ensure our desired criteria are followed
43
+ elif query_criteria is not None:
44
+ if 'hpc_jobs' not in query_criteria._children:
45
+ query_criteria._children.append('hpc_jobs')
46
+ else:
47
+ load_children = ['hpc_jobs']
48
+
49
+ return super().get(simulation_id, load_children=load_children, query_criteria=query_criteria)
50
+
51
+ def get_assets(self, simulation: Simulation, files: List[str], **kwargs) -> Dict[str, bytearray]:
52
+ """
53
+ Get assets for Simulation.
54
+
55
+ Args:
56
+ simulation: Simulation to fetch
57
+ files: Files to get
58
+ **kwargs: Any keyword arguments
59
+
60
+ Returns:
61
+ Files fetched
62
+ """
63
+ files = [f.replace("\\", '/') for f in files]
64
+ working_directory = simulation.hpc_jobs[0].working_directory
65
+ results = dict()
66
+ for file in files:
67
+ full_path = os.path.join(working_directory, file)
68
+ full_path = full_path.replace("\\", '/')
69
+ if not os.path.exists(full_path):
70
+ msg = f"Cannot find the file {file} at {full_path}"
71
+ logger.error(msg)
72
+ raise FileNotFoundError(msg)
73
+ if logger.isEnabledFor(DEBUG):
74
+ logger.debug(full_path)
75
+ with open(full_path, 'rb') as fin:
76
+ results[file] = fin.read()
77
+ return results
@@ -0,0 +1,73 @@
1
+ """idmtools workflow item operations for ssmt.
2
+
3
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
4
+ """
5
+ import os
6
+ from dataclasses import dataclass
7
+ from uuid import UUID
8
+ from typing import List, Dict, Optional
9
+ from idmtools.entities.iworkflow_item import IWorkflowItem
10
+ from idmtools_platform_comps.comps_operations.workflow_item_operations import CompsPlatformWorkflowItemOperations
11
+ from COMPS.Data.WorkItem import WorkItem as COMPSWorkItem
12
+ from COMPS.Data import QueryCriteria
13
+ from logging import getLogger, DEBUG
14
+
15
+ logger = getLogger(__name__)
16
+
17
+
18
+ @dataclass
19
+ class SSMTPlatformWorkflowItemOperations(CompsPlatformWorkflowItemOperations):
20
+ """SSMTPlatformWorkflowItemOperations provides IWorkflowItem actions for SSMT Platform.
21
+
22
+ In IWorkflowItem's case, we just need to change how get_assets works.
23
+ """
24
+
25
+ def get(self, workflow_item_id: UUID, columns: Optional[List[str]] = None, load_children: Optional[List[str]] = None,
26
+ query_criteria: Optional[QueryCriteria] = None, **kwargs) -> \
27
+ COMPSWorkItem:
28
+ """
29
+ Get COMPSWorkItem.
30
+
31
+ Args:
32
+ workflow_item_id: Item id
33
+ columns: Optional columns to load. Defaults to "id", "name", "state", "environment_name", "working_directory"
34
+ load_children: Optional list of COMPS Children objects to load. Defaults to "Tags"
35
+ query_criteria: Optional QueryCriteria
36
+ **kwargs:
37
+
38
+ Returns:
39
+ COMPSWorkItem
40
+ """
41
+ columns = columns or ["id", "name", "state", "environment_name", "working_directory"]
42
+ if "working_directory" not in columns:
43
+ columns.append("working_directory")
44
+
45
+ return super().get(workflow_item_id, columns=columns, load_children=load_children, query_criteria=query_criteria)
46
+
47
+ def get_assets(self, workflow_item: IWorkflowItem, files: List[str], **kwargs) -> Dict[str, bytearray]:
48
+ """
49
+ Get Assets for workflow_item.
50
+
51
+ Args:
52
+ workflow_item: WorkflowItem
53
+ files: Files to get
54
+ **kwargs:
55
+
56
+ Returns:
57
+ Files requested
58
+ """
59
+ files = [f.replace("\\", '/') for f in files]
60
+ working_directory = workflow_item.working_directory
61
+ results = dict()
62
+ for file in files:
63
+ full_path = os.path.join(working_directory, file)
64
+ full_path = full_path.replace("\\", '/')
65
+ if not os.path.exists(full_path):
66
+ msg = f"Cannot find the file {file} at {full_path}"
67
+ logger.error(msg)
68
+ raise FileNotFoundError(msg)
69
+ if logger.isEnabledFor(DEBUG):
70
+ logger.debug(full_path)
71
+ with open(full_path, 'rb') as fin:
72
+ results[file] = fin.read()
73
+ return results
@@ -0,0 +1,44 @@
1
+ """define the ssmt platform.
2
+
3
+ SSMT platform is the same as the COMPS platform but file access is local.
4
+
5
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
6
+ """
7
+ from dataclasses import dataclass, field
8
+ from idmtools_platform_comps.comps_operations.asset_collection_operations import CompsPlatformAssetCollectionOperations
9
+ from idmtools_platform_comps.comps_operations.experiment_operations import CompsPlatformExperimentOperations
10
+ from idmtools_platform_comps.comps_operations.suite_operations import CompsPlatformSuiteOperations
11
+ from idmtools_platform_comps.comps_platform import COMPSPlatform, op_defaults
12
+ from idmtools_platform_comps.ssmt_operations.simulation_operations import SSMTPlatformSimulationOperations
13
+ from idmtools_platform_comps.ssmt_operations.workflow_item_operations import SSMTPlatformWorkflowItemOperations
14
+
15
+
16
+ @dataclass
17
+ class SSMTPlatform(COMPSPlatform):
18
+ """
19
+ Represents the platform allowing to run simulations on SSMT.
20
+ """
21
+
22
+ _simulations: SSMTPlatformSimulationOperations = field(**op_defaults)
23
+ _workflow_items: SSMTPlatformWorkflowItemOperations = field(**op_defaults)
24
+
25
+ def __post_init__(self):
26
+ """
27
+ Post method after SSMTPlatform creation.
28
+
29
+ Returns: None
30
+ """
31
+ super().__post_init__()
32
+ self.__init_interfaces()
33
+
34
+ def __init_interfaces(self):
35
+ """
36
+ Initialize intefaces.
37
+
38
+ Returns: None
39
+ """
40
+ self._experiments = CompsPlatformExperimentOperations(platform=self)
41
+ self._simulations = SSMTPlatformSimulationOperations(platform=self)
42
+ self._suites = CompsPlatformSuiteOperations(platform=self)
43
+ self._workflow_items = SSMTPlatformWorkflowItemOperations(platform=self)
44
+ self._assets = CompsPlatformAssetCollectionOperations(platform=self)
@@ -0,0 +1,4 @@
1
+ """idmtools ssmt work items.
2
+
3
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
4
+ """