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,569 @@
1
+ """idmtools comps experiment operations.
2
+
3
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
4
+ """
5
+ import copy
6
+ import os
7
+ from dataclasses import dataclass, field
8
+ from itertools import tee
9
+ from logging import getLogger, DEBUG
10
+ from typing import List, Dict, Type, Generator, NoReturn, Optional, TYPE_CHECKING
11
+ from uuid import UUID
12
+ from COMPS.Data import Experiment as COMPSExperiment, QueryCriteria, Configuration, Suite as COMPSSuite, \
13
+ Simulation as COMPSSimulation
14
+ from COMPS.Data.Simulation import SimulationState
15
+ from idmtools import IdmConfigParser
16
+ from idmtools.assets import AssetCollection, Asset
17
+ from idmtools.core import ItemType, EntityStatus
18
+ from idmtools.core.experiment_factory import experiment_factory
19
+ from idmtools.core.logging import SUCCESS
20
+ from idmtools.entities import CommandLine
21
+ from idmtools.entities.experiment import Experiment
22
+ from idmtools.entities.iplatform_ops.iplatform_experiment_operations import IPlatformExperimentOperations
23
+ from idmtools.entities.templated_simulation import TemplatedSimulations
24
+ from idmtools.utils.collections import ExperimentParentIterator
25
+ from idmtools.utils.info import get_doc_base_url
26
+ from idmtools.utils.time import timestamp
27
+ from idmtools_platform_comps.utils.general import clean_experiment_name, convert_comps_status
28
+
29
+ if TYPE_CHECKING: # pragma: no cover
30
+ from idmtools_platform_comps.comps_platform import COMPSPlatform
31
+
32
+ logger = getLogger(__name__)
33
+ user_logger = getLogger('user')
34
+
35
+
36
+ @dataclass
37
+ class CompsPlatformExperimentOperations(IPlatformExperimentOperations):
38
+ """
39
+ Provides Experiment operations to the COMPSPlatform.
40
+ """
41
+ platform: 'COMPSPlatform' # noqa F821
42
+ platform_type: Type = field(default=COMPSExperiment)
43
+
44
+ def get(self, experiment_id: UUID, columns: Optional[List[str]] = None, load_children: Optional[List[str]] = None,
45
+ query_criteria: Optional[QueryCriteria] = None, **kwargs) -> COMPSExperiment:
46
+ """
47
+ Fetch experiments from COMPS.
48
+
49
+ Args:
50
+ experiment_id: Experiment ID
51
+ columns: Optional Columns. If not provided, id, name, and suite_id are fetched
52
+ load_children: Optional Children. If not provided, tags and configuration are specified
53
+ query_criteria: Optional QueryCriteria
54
+ **kwargs:
55
+
56
+ Returns:
57
+ COMPSExperiment with items
58
+ """
59
+ columns = columns or ["id", "name", "suite_id"]
60
+ comps_children = load_children if load_children is not None else ["tags", "configuration"]
61
+ query_criteria = query_criteria or QueryCriteria().select(columns).select_children(comps_children)
62
+ try:
63
+ result = COMPSExperiment.get(
64
+ id=experiment_id,
65
+ query_criteria=query_criteria
66
+ )
67
+ except AttributeError as e:
68
+ user_logger.error(f"The id {experiment_id} could not be converted to an UUID. Please verify your id")
69
+ raise e
70
+
71
+ return result
72
+
73
+ def pre_create(self, experiment: Experiment, **kwargs) -> NoReturn:
74
+ """
75
+ Pre-create for Experiment. At moment, validation related to COMPS is all that is done.
76
+
77
+ Args:
78
+ experiment: Experiment to run pre-create for
79
+ **kwargs:
80
+
81
+ Returns:
82
+ None
83
+ """
84
+ if experiment.name is None:
85
+ raise ValueError("Experiment name is required on COMPS")
86
+ super().pre_create(experiment, **kwargs)
87
+
88
+ def platform_create(self, experiment: Experiment, num_cores: Optional[int] = None,
89
+ executable_path: Optional[str] = None,
90
+ command_arg: Optional[str] = None, priority: Optional[str] = None,
91
+ check_command: bool = True, use_short_path: bool = False, **kwargs) -> COMPSExperiment:
92
+ """
93
+ Create Experiment on the COMPS Platform.
94
+
95
+ Args:
96
+ experiment: IDMTools Experiment to create
97
+ num_cores: Optional num of cores to allocate using MPI
98
+ executable_path: Executable path
99
+ command_arg: Command Argument
100
+ priority: Priority of command
101
+ check_command: Run task hooks on item
102
+ use_short_path: When set to true, simulation roots will be set to "$COMPS_PATH(USER)
103
+ **kwargs: Keyword arguments used to expand functionality. At moment these are usually not used
104
+
105
+ Returns:
106
+ COMPSExperiment that was created
107
+ """
108
+ # TODO check experiment task supported
109
+
110
+ # Cleanup the name
111
+ experiment.name = clean_experiment_name(experiment.name)
112
+
113
+ # Define the subdirectory
114
+ subdirectory = experiment.name[0:self.platform.MAX_SUBDIRECTORY_LENGTH] + '_' + timestamp()
115
+
116
+ if use_short_path:
117
+ logger.debug("Setting Simulation Root to $COMPS_PATH(USER)")
118
+ simulation_root = "$COMPS_PATH(USER)"
119
+ subdirectory = 'rac' + '_' + timestamp() # also shorten subdirectory
120
+ else:
121
+ simulation_root = self.platform.simulation_root
122
+
123
+ # Get the experiment command line
124
+ exp_command: CommandLine = self._get_experiment_command_line(check_command, experiment)
125
+
126
+ if command_arg is None and exp_command is not None:
127
+ command_arg = exp_command.arguments + " " + exp_command.options
128
+
129
+ if executable_path is None and exp_command is not None:
130
+ executable_path = exp_command.executable
131
+
132
+ # create initial configuration object
133
+ comps_config = dict(
134
+ environment_name=self.platform.environment,
135
+ simulation_input_args=command_arg.strip() if command_arg is not None else None,
136
+ working_directory_root=os.path.join(simulation_root, subdirectory).replace('\\', '/'),
137
+ executable_path=executable_path,
138
+ node_group_name=self.platform.node_group,
139
+ maximum_number_of_retries=self.platform.num_retries,
140
+ priority=self.platform.priority if priority is None else priority,
141
+ min_cores=self.platform.num_cores if num_cores is None else num_cores,
142
+ max_cores=self.platform.num_cores if num_cores is None else num_cores,
143
+ exclusive=self.platform.exclusive
144
+ )
145
+
146
+ if isinstance(experiment.simulations.items, TemplatedSimulations):
147
+ scheduling = getattr(experiment.simulations.items.base_simulation, 'scheduling', False)
148
+ elif isinstance(experiment.simulations.items, List):
149
+ scheduling = getattr(experiment.simulations.items[0], 'scheduling', False)
150
+ else:
151
+ scheduling = False
152
+
153
+ # kwargs.get("scheduling", False) case is for adding work_order file during sweeping call back which is too late
154
+ # to detect the scheduling flag from the simulation
155
+ if scheduling or kwargs.get("scheduling", False):
156
+ import copy
157
+ # save a copy of default config
158
+ setattr(self.platform, 'comps_config', copy.deepcopy(comps_config))
159
+ # clear some not-supported parameters
160
+ comps_config.update(executable_path=None, node_group_name=None, min_cores=None, max_cores=None,
161
+ exclusive=None, simulation_input_args=None)
162
+
163
+ if logger.isEnabledFor(DEBUG):
164
+ logger.debug(f'COMPS Experiment Configs: {str(comps_config)}')
165
+
166
+ config = Configuration(**comps_config)
167
+
168
+ e = COMPSExperiment(name=experiment.name,
169
+ configuration=config,
170
+ suite_id=experiment.parent_id)
171
+
172
+ # Add tags if present
173
+ if experiment.tags:
174
+ e.set_tags(experiment.tags)
175
+
176
+ # Save the experiment
177
+ e.save()
178
+
179
+ # Set the ID back in the object
180
+ experiment.uid = e.id
181
+
182
+ # Send the assets for the experiment
183
+ self.send_assets(experiment)
184
+ return e
185
+
186
+ def platform_modify_experiment(self, experiment: Experiment, regather_common_assets: bool = False,
187
+ **kwargs) -> Experiment:
188
+ """
189
+ Executed when an Experiment is being ran that is already in Created, Done, In Progress, or Failed State.
190
+
191
+ Args:
192
+ experiment: Experiment to modify
193
+ regather_common_assets: Triggers a new AC to be associated with experiment.
194
+ It is important to note that when using this feature, ensure the previous simulations have finished provisioning.
195
+ Failure to do so can lead to unexpected behaviour.
196
+
197
+ Returns:
198
+ Modified experiment.
199
+ """
200
+ if logger.isEnabledFor(DEBUG):
201
+ logger.debug(
202
+ f"Experiment Status: {experiment.status}. "
203
+ f"Modifying experiment: {experiment.id}. "
204
+ f"Asset Editable: {experiment.assets.is_editable()}. "
205
+ f"Regather assets: {regather_common_assets}."
206
+ )
207
+ if experiment.status is not None and experiment.assets.is_editable() and regather_common_assets:
208
+ experiment.pre_creation(self.platform, gather_assets=regather_common_assets)
209
+ self.send_assets(experiment)
210
+ else:
211
+ user_logger.warning(
212
+ f"Not gathering common assets again since experiment exists on platform. "
213
+ f"If you need to add additional common assets, see "
214
+ f"{get_doc_base_url()}cookbook/asset_collections.html#modifying-asset-collection"
215
+ )
216
+ return experiment
217
+
218
+ def _get_experiment_command_line(self, check_command: bool, experiment: Experiment) -> CommandLine:
219
+ """
220
+ Get the command line for COMPS.
221
+
222
+ Args:
223
+ check_command: Should we run the platform task hooks on comps?
224
+ experiment: Experiment to get command line for
225
+
226
+ Returns:
227
+ Command line for Experiment
228
+ """
229
+ from idmtools_platform_comps.utils.python_version import platform_task_hooks
230
+
231
+ if isinstance(experiment.simulations, Generator):
232
+ if logger.isEnabledFor(DEBUG):
233
+ logger.debug("Simulations generator detected. Copying generator and using first task as command")
234
+ sim_gen1, sim_gen2 = tee(experiment.simulations)
235
+ experiment.simulations = sim_gen2
236
+ sim = next(sim_gen1)
237
+ if check_command:
238
+ task = platform_task_hooks(sim.task, self.platform)
239
+ # run pre-creation in case task use it to produce the command line dynamically
240
+ task.pre_creation(sim, self.platform)
241
+ exp_command = task.command
242
+ elif isinstance(experiment.simulations, ExperimentParentIterator) and isinstance(experiment.simulations.items,
243
+ TemplatedSimulations):
244
+ if logger.isEnabledFor(DEBUG):
245
+ logger.debug("ParentIterator/TemplatedSimulations detected. Using base_task for command")
246
+ from idmtools.entities.simulation import Simulation
247
+ task = experiment.simulations.items.base_task
248
+ if check_command:
249
+ task = platform_task_hooks(task, self.platform)
250
+ # run pre-creation in case task use it to produce the command line dynamically
251
+ task.pre_creation(Simulation(task=task), self.platform)
252
+ exp_command = task.command
253
+ else:
254
+ if logger.isEnabledFor(DEBUG):
255
+ logger.debug("List of simulations detected. Using base_task for command")
256
+ task = experiment.simulations[0].task
257
+ if check_command:
258
+ task = platform_task_hooks(task, self.platform)
259
+ # run pre-creation in case task use it to produce the command line dynamically
260
+ task.pre_creation(experiment.simulations[0], self.platform)
261
+ exp_command = task.command
262
+ return exp_command
263
+
264
+ def post_create(self, experiment: Experiment, **kwargs) -> NoReturn:
265
+ """
266
+ Post create of experiment.
267
+
268
+ The default behaviour is to display the experiment url if output is enabled.
269
+ """
270
+ if IdmConfigParser.is_output_enabled():
271
+ user_logger.log(SUCCESS, f"\nThe created experiment can be viewed at {self.platform.endpoint}/#explore/"
272
+ f"Simulations?filters=ExperimentId={experiment.uid}\nSimulations are still being created\n"
273
+ )
274
+ super().post_create(experiment, **kwargs)
275
+
276
+ def post_run_item(self, experiment: Experiment, **kwargs):
277
+ """
278
+ Ran after experiment. Nothing is done on comps other that alerting the user to the item.
279
+
280
+ Args:
281
+ experiment: Experiment to run post run item
282
+ **kwargs:
283
+
284
+ Returns:
285
+ None
286
+ """
287
+ super().post_run_item(experiment, **kwargs)
288
+
289
+ def get_children(self, experiment: COMPSExperiment, columns: Optional[List[str]] = None,
290
+ children: Optional[List[str]] = None, **kwargs) -> List[COMPSSimulation]:
291
+ """
292
+ Get children for a COMPSExperiment.
293
+
294
+ Args:
295
+ experiment: Experiment to get children of Comps Experiment
296
+ columns: Columns to fetch. If not provided, id, name, experiment_id, and state will be loaded
297
+ children: Children to load. If not provided, Tags will be loaded
298
+ **kwargs:
299
+
300
+ Returns:
301
+ Simulations belonging to the Experiment
302
+ """
303
+ columns = columns or ["id", "name", "experiment_id", "state"]
304
+ children = children if children is not None else ["tags", "configuration", "files"]
305
+
306
+ children = experiment.get_simulations(query_criteria=QueryCriteria().select(columns).select_children(children))
307
+ return children
308
+
309
+ def get_parent(self, experiment: COMPSExperiment, **kwargs) -> COMPSSuite:
310
+ """
311
+ Get Parent of experiment.
312
+
313
+ Args:
314
+ experiment: Experiment to get parent of
315
+ **kwargs:
316
+
317
+ Returns:
318
+ Suite of the experiment
319
+ """
320
+ if experiment.suite_id is None:
321
+ return None
322
+ return self.platform._suites.get(experiment.suite_id, **kwargs)
323
+
324
+ def platform_run_item(self, experiment: Experiment, **kwargs):
325
+ """
326
+ Run experiment on COMPS. Here we commission the experiment.
327
+
328
+ Args:
329
+ experiment: Experiment to run
330
+ **kwargs:
331
+
332
+ Returns:
333
+ None
334
+ """
335
+ if logger.isEnabledFor(DEBUG):
336
+ logger.debug(f'Commissioning experiment: {experiment.uid}')
337
+ # commission only if rules we have items in created or none.
338
+ # TODO add new status to entity status to track commissioned as well instead of raw comps
339
+ if any([s.status in [None, EntityStatus.CREATED] for s in experiment.simulations]) and any(
340
+ [s.get_platform_object().state in [SimulationState.Created] for s in experiment.simulations]):
341
+ po = experiment.get_platform_object()
342
+ po.commission()
343
+ # for now, we update here in the comps objects to reflect the new state
344
+ for sim in experiment.simulations:
345
+ spo = sim.get_platform_object()
346
+ spo._state = SimulationState.CommissionRequested
347
+
348
+ def send_assets(self, experiment: Experiment, **kwargs):
349
+ """
350
+ Send assets related to the experiment.
351
+
352
+ Args:
353
+ experiment: Experiment to send assets for
354
+
355
+ **kwargs:
356
+
357
+ Returns:
358
+ None
359
+ """
360
+ if experiment.assets.count == 0:
361
+ logger.warning('Experiment has no assets to send')
362
+ return
363
+ ac = self.platform._assets.create(experiment.assets)
364
+
365
+ if logger.isEnabledFor(DEBUG):
366
+ logger.debug(f'Asset collection for experiment: {experiment.id} is: {ac.id}')
367
+
368
+ # associate the assets with the experiment in COMPS
369
+ e = COMPSExperiment.get(id=experiment.uid)
370
+ e.configuration = Configuration(asset_collection_id=ac.id)
371
+ e.save()
372
+
373
+ def refresh_status(self, experiment: Experiment, **kwargs):
374
+ """
375
+ Reload status for experiment(load simulations).
376
+
377
+ Args:
378
+ experiment: Experiment to load status for
379
+ **kwargs:
380
+
381
+ Returns:
382
+ None
383
+ """
384
+ simulations = self.get_children(experiment.get_platform_object(), force=True, columns=["id", "state"],
385
+ load_children=[])
386
+ for s in simulations:
387
+ experiment.simulations.set_status_for_item(s.id, convert_comps_status(s.state))
388
+
389
+ def to_entity(self, experiment: COMPSExperiment, parent: Optional[COMPSSuite] = None, children: bool = True,
390
+ **kwargs) -> Experiment:
391
+ """
392
+ Converts a COMPSExperiment to an idmtools Experiment.
393
+
394
+ Args:
395
+ experiment: COMPS Experiment objet to convert
396
+ parent: Optional suite parent
397
+ children: Should we load children objects?
398
+ **kwargs:
399
+
400
+ Returns:
401
+ Experiment
402
+ """
403
+ # Recreate the suite if needed
404
+ if experiment.suite_id is None:
405
+ suite = kwargs.get('suite')
406
+ else:
407
+ if parent:
408
+ suite = parent
409
+ else:
410
+ suite = kwargs.get('suite') or self.platform.get_item(experiment.suite_id, item_type=ItemType.SUITE)
411
+
412
+ # Create an experiment
413
+ obj = experiment_factory.create("idmtools.entities.experiment.Experiment", tags=experiment.tags, name=experiment.name,
414
+ fallback=Experiment)
415
+ obj.platform = self.platform
416
+ obj._platform_object = experiment
417
+ # Set parent
418
+ obj.parent = suite
419
+ # Set the correct attributes
420
+ obj.uid = experiment.id
421
+ obj.task_type = experiment.tags.get("task_type") if experiment.tags is not None else ""
422
+ # load assets first so children can access during their load
423
+ obj.assets = self.get_assets_from_comps_experiment(experiment)
424
+ if obj.assets is None:
425
+ obj.assets = AssetCollection()
426
+
427
+ # if we are loading the children, convert them
428
+ if children:
429
+ # Convert all simulations
430
+ comps_sims = experiment.get_simulations(
431
+ QueryCriteria().select(
432
+ ["id", "name", "experiment_id", "state"]
433
+ ).select_children(
434
+ ["tags", "files", "configuration"]
435
+ )
436
+ )
437
+ obj.simulations = []
438
+ for s in comps_sims:
439
+ obj.simulations.append(
440
+ self.platform._simulations.to_entity(s, parent=obj, **kwargs)
441
+ )
442
+ return obj
443
+
444
+ def get_assets_from_comps_experiment(self, experiment: COMPSExperiment) -> Optional[AssetCollection]:
445
+ """
446
+ Get assets for a comps experiment.
447
+
448
+ Args:
449
+ experiment: Experiment to get asset collection for.
450
+
451
+ Returns:
452
+ AssetCollection if configuration is set and configuration.asset_collection_id is set.
453
+ """
454
+ if experiment.configuration and experiment.configuration.asset_collection_id:
455
+ return self.platform.get_item(experiment.configuration.asset_collection_id, ItemType.ASSETCOLLECTION)
456
+ return None
457
+
458
+ def platform_list_asset(self, experiment: Experiment, **kwargs) -> List[Asset]:
459
+ """
460
+ List assets for an experiment.
461
+
462
+ Args:
463
+ experiment: Experiment to list assets for.
464
+ **kwargs:
465
+
466
+ Returns:
467
+ List of assets
468
+ """
469
+ assets = []
470
+ if experiment.assets is None:
471
+ po: COMPSExperiment = experiment.get_platform_object()
472
+ ac = self.get_assets_from_comps_experiment(po)
473
+ if ac:
474
+ assets = ac.assets
475
+ else:
476
+ assets = copy.deepcopy(experiment.assets.assets)
477
+ return assets
478
+
479
+ def create_sim_directory_map(self, experiment_id: str) -> Dict:
480
+ """
481
+ Build simulation working directory mapping.
482
+ Args:
483
+ experiment_id: experiment id
484
+
485
+ Returns:
486
+ Dict of simulation id as key and working dir as value
487
+ """
488
+ from idmtools_platform_comps.utils.linux_mounts import set_linux_mounts, clear_linux_mounts
489
+ set_linux_mounts(self.platform)
490
+ comps_exp = self.platform.get_item(experiment_id, ItemType.EXPERIMENT, raw=True, force=True)
491
+ comps_sims = comps_exp.get_simulations(QueryCriteria().select(['id', 'state']).select_children('hpc_jobs'))
492
+ sim_map = {str(sim.id): sim.hpc_jobs[-1].working_directory for sim in comps_sims if sim.hpc_jobs}
493
+ clear_linux_mounts(self.platform)
494
+ return sim_map
495
+
496
+ def platform_delete(self, experiment_id: str) -> None:
497
+ """
498
+ Delete platform experiment.
499
+ Args:
500
+ experiment_id: experiment id
501
+ Returns:
502
+ None
503
+ """
504
+ comps_exp = self.platform.get_item(experiment_id, ItemType.EXPERIMENT, raw=True)
505
+ try:
506
+ comps_exp.delete()
507
+ except RuntimeError:
508
+ logger.info(f"Could not delete the experiment ({comps_exp.id})...")
509
+ return
510
+
511
+ def platform_cancel(self, experiment_id: str) -> None:
512
+ """
513
+ Cancel platform experiment.
514
+ Args:
515
+ experiment_id: experiment id
516
+ Returns:
517
+ None
518
+ """
519
+
520
+ def experiment_is_running(comps_exp):
521
+ from COMPS.Data.Simulation import SimulationState
522
+ for sim in comps_exp.get_simulations():
523
+ if sim.state not in (SimulationState.Succeeded, SimulationState.Failed,
524
+ SimulationState.Canceled, SimulationState.Created,
525
+ SimulationState.CancelRequested):
526
+ return True
527
+ return False
528
+
529
+ comps_experiment = self.platform.get_item(experiment_id, ItemType.EXPERIMENT, raw=True)
530
+ if comps_experiment and experiment_is_running(comps_experiment):
531
+ comps_experiment.cancel()
532
+
533
+ def get_assets(self, experiment: Experiment, files: List[str], include_experiment_assets: bool = True, **kwargs) -> Dict[str, bytearray]:
534
+ """
535
+ Fetch the files associated with an experiment and its simulations.
536
+
537
+ Args:
538
+ experiment (Experiment): The experiment object.
539
+ files (List[str]): A list of filenames to retrieve.
540
+ include_experiment_assets (bool): Whether to include experiment-level assets. Defaults to True.
541
+ **kwargs: Additional platform-specific options.
542
+
543
+ Returns:
544
+ Dict[str, Dict[str, Dict[str, Union[str, bytearray]]]]: A nested dictionary in the format::
545
+
546
+ {
547
+ "experiment_id": {
548
+ "simulation_id": {
549
+ "filename1": file_content,
550
+ "filename2": file_content,
551
+ ...
552
+ },
553
+ ...
554
+ }
555
+ }
556
+
557
+ File content may be either a decoded string or a bytearray.
558
+ """
559
+ ret = dict()
560
+ if isinstance(experiment, COMPSExperiment):
561
+ comps_exp = experiment
562
+ else:
563
+ comps_exp = experiment.get_platform_object()
564
+ simulations = self.platform.flatten_item(comps_exp, raw=True)
565
+ for sim in simulations:
566
+ ret[sim.id] = self.platform._simulations.get_assets(sim, files,
567
+ include_experiment_assets=include_experiment_assets,
568
+ **kwargs)
569
+ return ret