hpcflow 0.1.15__py3-none-any.whl → 0.2.0a271__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 (275) hide show
  1. hpcflow/__init__.py +2 -11
  2. hpcflow/__pyinstaller/__init__.py +5 -0
  3. hpcflow/__pyinstaller/hook-hpcflow.py +40 -0
  4. hpcflow/_version.py +1 -1
  5. hpcflow/app.py +43 -0
  6. hpcflow/cli.py +2 -461
  7. hpcflow/data/demo_data_manifest/__init__.py +3 -0
  8. hpcflow/data/demo_data_manifest/demo_data_manifest.json +6 -0
  9. hpcflow/data/jinja_templates/test/test_template.txt +8 -0
  10. hpcflow/data/programs/hello_world/README.md +1 -0
  11. hpcflow/data/programs/hello_world/hello_world.c +87 -0
  12. hpcflow/data/programs/hello_world/linux/hello_world +0 -0
  13. hpcflow/data/programs/hello_world/macos/hello_world +0 -0
  14. hpcflow/data/programs/hello_world/win/hello_world.exe +0 -0
  15. hpcflow/data/scripts/__init__.py +1 -0
  16. hpcflow/data/scripts/bad_script.py +2 -0
  17. hpcflow/data/scripts/demo_task_1_generate_t1_infile_1.py +8 -0
  18. hpcflow/data/scripts/demo_task_1_generate_t1_infile_2.py +8 -0
  19. hpcflow/data/scripts/demo_task_1_parse_p3.py +7 -0
  20. hpcflow/data/scripts/do_nothing.py +2 -0
  21. hpcflow/data/scripts/env_specifier_test/input_file_generator_pass_env_spec.py +4 -0
  22. hpcflow/data/scripts/env_specifier_test/main_script_test_pass_env_spec.py +8 -0
  23. hpcflow/data/scripts/env_specifier_test/output_file_parser_pass_env_spec.py +4 -0
  24. hpcflow/data/scripts/env_specifier_test/v1/input_file_generator_basic.py +4 -0
  25. hpcflow/data/scripts/env_specifier_test/v1/main_script_test_direct_in_direct_out.py +7 -0
  26. hpcflow/data/scripts/env_specifier_test/v1/output_file_parser_basic.py +4 -0
  27. hpcflow/data/scripts/env_specifier_test/v2/main_script_test_direct_in_direct_out.py +7 -0
  28. hpcflow/data/scripts/generate_t1_file_01.py +7 -0
  29. hpcflow/data/scripts/import_future_script.py +7 -0
  30. hpcflow/data/scripts/input_file_generator_basic.py +3 -0
  31. hpcflow/data/scripts/input_file_generator_basic_FAIL.py +3 -0
  32. hpcflow/data/scripts/input_file_generator_test_stdout_stderr.py +8 -0
  33. hpcflow/data/scripts/main_script_test_direct_in.py +3 -0
  34. hpcflow/data/scripts/main_script_test_direct_in_direct_out.py +6 -0
  35. hpcflow/data/scripts/main_script_test_direct_in_direct_out_2.py +6 -0
  36. hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed.py +6 -0
  37. hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed_group.py +7 -0
  38. hpcflow/data/scripts/main_script_test_direct_in_direct_out_3.py +6 -0
  39. hpcflow/data/scripts/main_script_test_direct_in_direct_out_all_iters_test.py +15 -0
  40. hpcflow/data/scripts/main_script_test_direct_in_direct_out_env_spec.py +7 -0
  41. hpcflow/data/scripts/main_script_test_direct_in_direct_out_labels.py +8 -0
  42. hpcflow/data/scripts/main_script_test_direct_in_group_direct_out_3.py +6 -0
  43. hpcflow/data/scripts/main_script_test_direct_in_group_one_fail_direct_out_3.py +6 -0
  44. hpcflow/data/scripts/main_script_test_direct_sub_param_in_direct_out.py +6 -0
  45. hpcflow/data/scripts/main_script_test_hdf5_in_obj.py +12 -0
  46. hpcflow/data/scripts/main_script_test_hdf5_in_obj_2.py +12 -0
  47. hpcflow/data/scripts/main_script_test_hdf5_in_obj_group.py +12 -0
  48. hpcflow/data/scripts/main_script_test_hdf5_out_obj.py +11 -0
  49. hpcflow/data/scripts/main_script_test_json_and_direct_in_json_out.py +14 -0
  50. hpcflow/data/scripts/main_script_test_json_in_json_and_direct_out.py +17 -0
  51. hpcflow/data/scripts/main_script_test_json_in_json_out.py +14 -0
  52. hpcflow/data/scripts/main_script_test_json_in_json_out_labels.py +16 -0
  53. hpcflow/data/scripts/main_script_test_json_in_obj.py +12 -0
  54. hpcflow/data/scripts/main_script_test_json_out_FAIL.py +3 -0
  55. hpcflow/data/scripts/main_script_test_json_out_obj.py +10 -0
  56. hpcflow/data/scripts/main_script_test_json_sub_param_in_json_out_labels.py +16 -0
  57. hpcflow/data/scripts/main_script_test_shell_env_vars.py +12 -0
  58. hpcflow/data/scripts/main_script_test_std_out_std_err.py +6 -0
  59. hpcflow/data/scripts/output_file_parser_basic.py +3 -0
  60. hpcflow/data/scripts/output_file_parser_basic_FAIL.py +7 -0
  61. hpcflow/data/scripts/output_file_parser_test_stdout_stderr.py +8 -0
  62. hpcflow/data/scripts/parse_t1_file_01.py +4 -0
  63. hpcflow/data/scripts/script_exit_test.py +5 -0
  64. hpcflow/data/template_components/__init__.py +1 -0
  65. hpcflow/data/template_components/command_files.yaml +26 -0
  66. hpcflow/data/template_components/environments.yaml +13 -0
  67. hpcflow/data/template_components/parameters.yaml +14 -0
  68. hpcflow/data/template_components/task_schemas.yaml +139 -0
  69. hpcflow/data/workflows/workflow_1.yaml +5 -0
  70. hpcflow/examples.ipynb +1037 -0
  71. hpcflow/sdk/__init__.py +149 -0
  72. hpcflow/sdk/app.py +4266 -0
  73. hpcflow/sdk/cli.py +1479 -0
  74. hpcflow/sdk/cli_common.py +385 -0
  75. hpcflow/sdk/config/__init__.py +5 -0
  76. hpcflow/sdk/config/callbacks.py +246 -0
  77. hpcflow/sdk/config/cli.py +388 -0
  78. hpcflow/sdk/config/config.py +1410 -0
  79. hpcflow/sdk/config/config_file.py +501 -0
  80. hpcflow/sdk/config/errors.py +272 -0
  81. hpcflow/sdk/config/types.py +150 -0
  82. hpcflow/sdk/core/__init__.py +38 -0
  83. hpcflow/sdk/core/actions.py +3857 -0
  84. hpcflow/sdk/core/app_aware.py +25 -0
  85. hpcflow/sdk/core/cache.py +224 -0
  86. hpcflow/sdk/core/command_files.py +814 -0
  87. hpcflow/sdk/core/commands.py +424 -0
  88. hpcflow/sdk/core/element.py +2071 -0
  89. hpcflow/sdk/core/enums.py +221 -0
  90. hpcflow/sdk/core/environment.py +256 -0
  91. hpcflow/sdk/core/errors.py +1043 -0
  92. hpcflow/sdk/core/execute.py +207 -0
  93. hpcflow/sdk/core/json_like.py +809 -0
  94. hpcflow/sdk/core/loop.py +1320 -0
  95. hpcflow/sdk/core/loop_cache.py +282 -0
  96. hpcflow/sdk/core/object_list.py +933 -0
  97. hpcflow/sdk/core/parameters.py +3371 -0
  98. hpcflow/sdk/core/rule.py +196 -0
  99. hpcflow/sdk/core/run_dir_files.py +57 -0
  100. hpcflow/sdk/core/skip_reason.py +7 -0
  101. hpcflow/sdk/core/task.py +3792 -0
  102. hpcflow/sdk/core/task_schema.py +993 -0
  103. hpcflow/sdk/core/test_utils.py +538 -0
  104. hpcflow/sdk/core/types.py +447 -0
  105. hpcflow/sdk/core/utils.py +1207 -0
  106. hpcflow/sdk/core/validation.py +87 -0
  107. hpcflow/sdk/core/values.py +477 -0
  108. hpcflow/sdk/core/workflow.py +4820 -0
  109. hpcflow/sdk/core/zarr_io.py +206 -0
  110. hpcflow/sdk/data/__init__.py +13 -0
  111. hpcflow/sdk/data/config_file_schema.yaml +34 -0
  112. hpcflow/sdk/data/config_schema.yaml +260 -0
  113. hpcflow/sdk/data/environments_spec_schema.yaml +21 -0
  114. hpcflow/sdk/data/files_spec_schema.yaml +5 -0
  115. hpcflow/sdk/data/parameters_spec_schema.yaml +7 -0
  116. hpcflow/sdk/data/task_schema_spec_schema.yaml +3 -0
  117. hpcflow/sdk/data/workflow_spec_schema.yaml +22 -0
  118. hpcflow/sdk/demo/__init__.py +3 -0
  119. hpcflow/sdk/demo/cli.py +242 -0
  120. hpcflow/sdk/helper/__init__.py +3 -0
  121. hpcflow/sdk/helper/cli.py +137 -0
  122. hpcflow/sdk/helper/helper.py +300 -0
  123. hpcflow/sdk/helper/watcher.py +192 -0
  124. hpcflow/sdk/log.py +288 -0
  125. hpcflow/sdk/persistence/__init__.py +18 -0
  126. hpcflow/sdk/persistence/base.py +2817 -0
  127. hpcflow/sdk/persistence/defaults.py +6 -0
  128. hpcflow/sdk/persistence/discovery.py +39 -0
  129. hpcflow/sdk/persistence/json.py +954 -0
  130. hpcflow/sdk/persistence/pending.py +948 -0
  131. hpcflow/sdk/persistence/store_resource.py +203 -0
  132. hpcflow/sdk/persistence/types.py +309 -0
  133. hpcflow/sdk/persistence/utils.py +73 -0
  134. hpcflow/sdk/persistence/zarr.py +2388 -0
  135. hpcflow/sdk/runtime.py +320 -0
  136. hpcflow/sdk/submission/__init__.py +3 -0
  137. hpcflow/sdk/submission/enums.py +70 -0
  138. hpcflow/sdk/submission/jobscript.py +2379 -0
  139. hpcflow/sdk/submission/schedulers/__init__.py +281 -0
  140. hpcflow/sdk/submission/schedulers/direct.py +233 -0
  141. hpcflow/sdk/submission/schedulers/sge.py +376 -0
  142. hpcflow/sdk/submission/schedulers/slurm.py +598 -0
  143. hpcflow/sdk/submission/schedulers/utils.py +25 -0
  144. hpcflow/sdk/submission/shells/__init__.py +52 -0
  145. hpcflow/sdk/submission/shells/base.py +229 -0
  146. hpcflow/sdk/submission/shells/bash.py +504 -0
  147. hpcflow/sdk/submission/shells/os_version.py +115 -0
  148. hpcflow/sdk/submission/shells/powershell.py +352 -0
  149. hpcflow/sdk/submission/submission.py +1402 -0
  150. hpcflow/sdk/submission/types.py +140 -0
  151. hpcflow/sdk/typing.py +194 -0
  152. hpcflow/sdk/utils/arrays.py +69 -0
  153. hpcflow/sdk/utils/deferred_file.py +55 -0
  154. hpcflow/sdk/utils/hashing.py +16 -0
  155. hpcflow/sdk/utils/patches.py +31 -0
  156. hpcflow/sdk/utils/strings.py +69 -0
  157. hpcflow/tests/api/test_api.py +32 -0
  158. hpcflow/tests/conftest.py +123 -0
  159. hpcflow/tests/data/__init__.py +0 -0
  160. hpcflow/tests/data/benchmark_N_elements.yaml +6 -0
  161. hpcflow/tests/data/benchmark_script_runner.yaml +26 -0
  162. hpcflow/tests/data/multi_path_sequences.yaml +29 -0
  163. hpcflow/tests/data/workflow_1.json +10 -0
  164. hpcflow/tests/data/workflow_1.yaml +5 -0
  165. hpcflow/tests/data/workflow_1_slurm.yaml +8 -0
  166. hpcflow/tests/data/workflow_1_wsl.yaml +8 -0
  167. hpcflow/tests/data/workflow_test_run_abort.yaml +42 -0
  168. hpcflow/tests/jinja_templates/test_jinja_templates.py +161 -0
  169. hpcflow/tests/programs/test_programs.py +180 -0
  170. hpcflow/tests/schedulers/direct_linux/test_direct_linux_submission.py +12 -0
  171. hpcflow/tests/schedulers/sge/test_sge_submission.py +36 -0
  172. hpcflow/tests/schedulers/slurm/test_slurm_submission.py +14 -0
  173. hpcflow/tests/scripts/test_input_file_generators.py +282 -0
  174. hpcflow/tests/scripts/test_main_scripts.py +1361 -0
  175. hpcflow/tests/scripts/test_non_snippet_script.py +46 -0
  176. hpcflow/tests/scripts/test_ouput_file_parsers.py +353 -0
  177. hpcflow/tests/shells/wsl/test_wsl_submission.py +14 -0
  178. hpcflow/tests/unit/test_action.py +1066 -0
  179. hpcflow/tests/unit/test_action_rule.py +24 -0
  180. hpcflow/tests/unit/test_app.py +132 -0
  181. hpcflow/tests/unit/test_cache.py +46 -0
  182. hpcflow/tests/unit/test_cli.py +172 -0
  183. hpcflow/tests/unit/test_command.py +377 -0
  184. hpcflow/tests/unit/test_config.py +195 -0
  185. hpcflow/tests/unit/test_config_file.py +162 -0
  186. hpcflow/tests/unit/test_element.py +666 -0
  187. hpcflow/tests/unit/test_element_iteration.py +88 -0
  188. hpcflow/tests/unit/test_element_set.py +158 -0
  189. hpcflow/tests/unit/test_group.py +115 -0
  190. hpcflow/tests/unit/test_input_source.py +1479 -0
  191. hpcflow/tests/unit/test_input_value.py +398 -0
  192. hpcflow/tests/unit/test_jobscript_unit.py +757 -0
  193. hpcflow/tests/unit/test_json_like.py +1247 -0
  194. hpcflow/tests/unit/test_loop.py +2674 -0
  195. hpcflow/tests/unit/test_meta_task.py +325 -0
  196. hpcflow/tests/unit/test_multi_path_sequences.py +259 -0
  197. hpcflow/tests/unit/test_object_list.py +116 -0
  198. hpcflow/tests/unit/test_parameter.py +243 -0
  199. hpcflow/tests/unit/test_persistence.py +664 -0
  200. hpcflow/tests/unit/test_resources.py +243 -0
  201. hpcflow/tests/unit/test_run.py +286 -0
  202. hpcflow/tests/unit/test_run_directories.py +29 -0
  203. hpcflow/tests/unit/test_runtime.py +9 -0
  204. hpcflow/tests/unit/test_schema_input.py +372 -0
  205. hpcflow/tests/unit/test_shell.py +129 -0
  206. hpcflow/tests/unit/test_slurm.py +39 -0
  207. hpcflow/tests/unit/test_submission.py +502 -0
  208. hpcflow/tests/unit/test_task.py +2560 -0
  209. hpcflow/tests/unit/test_task_schema.py +182 -0
  210. hpcflow/tests/unit/test_utils.py +616 -0
  211. hpcflow/tests/unit/test_value_sequence.py +549 -0
  212. hpcflow/tests/unit/test_values.py +91 -0
  213. hpcflow/tests/unit/test_workflow.py +827 -0
  214. hpcflow/tests/unit/test_workflow_template.py +186 -0
  215. hpcflow/tests/unit/utils/test_arrays.py +40 -0
  216. hpcflow/tests/unit/utils/test_deferred_file_writer.py +34 -0
  217. hpcflow/tests/unit/utils/test_hashing.py +65 -0
  218. hpcflow/tests/unit/utils/test_patches.py +5 -0
  219. hpcflow/tests/unit/utils/test_redirect_std.py +50 -0
  220. hpcflow/tests/unit/utils/test_strings.py +97 -0
  221. hpcflow/tests/workflows/__init__.py +0 -0
  222. hpcflow/tests/workflows/test_directory_structure.py +31 -0
  223. hpcflow/tests/workflows/test_jobscript.py +355 -0
  224. hpcflow/tests/workflows/test_run_status.py +198 -0
  225. hpcflow/tests/workflows/test_skip_downstream.py +696 -0
  226. hpcflow/tests/workflows/test_submission.py +140 -0
  227. hpcflow/tests/workflows/test_workflows.py +564 -0
  228. hpcflow/tests/workflows/test_zip.py +18 -0
  229. hpcflow/viz_demo.ipynb +6794 -0
  230. hpcflow-0.2.0a271.dist-info/LICENSE +375 -0
  231. hpcflow-0.2.0a271.dist-info/METADATA +65 -0
  232. hpcflow-0.2.0a271.dist-info/RECORD +237 -0
  233. {hpcflow-0.1.15.dist-info → hpcflow-0.2.0a271.dist-info}/WHEEL +4 -5
  234. hpcflow-0.2.0a271.dist-info/entry_points.txt +6 -0
  235. hpcflow/api.py +0 -490
  236. hpcflow/archive/archive.py +0 -307
  237. hpcflow/archive/cloud/cloud.py +0 -45
  238. hpcflow/archive/cloud/errors.py +0 -9
  239. hpcflow/archive/cloud/providers/dropbox.py +0 -427
  240. hpcflow/archive/errors.py +0 -5
  241. hpcflow/base_db.py +0 -4
  242. hpcflow/config.py +0 -233
  243. hpcflow/copytree.py +0 -66
  244. hpcflow/data/examples/_config.yml +0 -14
  245. hpcflow/data/examples/damask/demo/1.run.yml +0 -4
  246. hpcflow/data/examples/damask/demo/2.process.yml +0 -29
  247. hpcflow/data/examples/damask/demo/geom.geom +0 -2052
  248. hpcflow/data/examples/damask/demo/load.load +0 -1
  249. hpcflow/data/examples/damask/demo/material.config +0 -185
  250. hpcflow/data/examples/damask/inputs/geom.geom +0 -2052
  251. hpcflow/data/examples/damask/inputs/load.load +0 -1
  252. hpcflow/data/examples/damask/inputs/material.config +0 -185
  253. hpcflow/data/examples/damask/profiles/_variable_lookup.yml +0 -21
  254. hpcflow/data/examples/damask/profiles/damask.yml +0 -4
  255. hpcflow/data/examples/damask/profiles/damask_process.yml +0 -8
  256. hpcflow/data/examples/damask/profiles/damask_run.yml +0 -5
  257. hpcflow/data/examples/damask/profiles/default.yml +0 -6
  258. hpcflow/data/examples/thinking.yml +0 -177
  259. hpcflow/errors.py +0 -2
  260. hpcflow/init_db.py +0 -37
  261. hpcflow/models.py +0 -2595
  262. hpcflow/nesting.py +0 -9
  263. hpcflow/profiles.py +0 -455
  264. hpcflow/project.py +0 -81
  265. hpcflow/scheduler.py +0 -322
  266. hpcflow/utils.py +0 -103
  267. hpcflow/validation.py +0 -166
  268. hpcflow/variables.py +0 -543
  269. hpcflow-0.1.15.dist-info/METADATA +0 -168
  270. hpcflow-0.1.15.dist-info/RECORD +0 -45
  271. hpcflow-0.1.15.dist-info/entry_points.txt +0 -8
  272. hpcflow-0.1.15.dist-info/top_level.txt +0 -1
  273. /hpcflow/{archive → data/jinja_templates}/__init__.py +0 -0
  274. /hpcflow/{archive/cloud → data/programs}/__init__.py +0 -0
  275. /hpcflow/{archive/cloud/providers → data/workflows}/__init__.py +0 -0
hpcflow/scheduler.py DELETED
@@ -1,322 +0,0 @@
1
- """`hpcflow.scheduler.py`"""
2
-
3
- from datetime import datetime
4
- from subprocess import run, PIPE
5
-
6
- from hpcflow.config import Config as CONFIG
7
- from hpcflow._version import __version__
8
-
9
-
10
- class Scheduler(object):
11
-
12
- options = None
13
- output_dir = None
14
- error_dir = None
15
-
16
- def __repr__(self):
17
- out = ('{}('
18
- 'options={!r}, '
19
- 'output_dir={!r}, '
20
- 'error_dir={!r}'
21
- ')').format(
22
- self.__class__.__name__,
23
- self.options,
24
- self.output_dir,
25
- self.error_dir,
26
- )
27
- return out
28
-
29
- def __init__(self, options=None, output_dir=None, error_dir=None):
30
-
31
- self.output_dir = output_dir or CONFIG.get('default_output_dir')
32
- self.error_dir = error_dir or CONFIG.get('default_error_dir')
33
- self.options = options
34
-
35
-
36
- class SunGridEngine(Scheduler):
37
-
38
- _NAME = 'sge'
39
- SHEBANG = '#!/bin/bash --login'
40
-
41
- STATS_DELIM = '==============================================================\n'
42
-
43
- # Options that determine how to set the output/error directories:
44
- STDOUT_OPT = 'o'
45
- STDERR_OPT = 'e'
46
- STDOUT_OPT_FMT = '{}/'
47
- STDERR_OPT_FMT = '{}/'
48
-
49
- # Required options to ensure the job scripts work with hpcflow:
50
- REQ_OPT = ['cwd']
51
- REQ_PARAMETRISED_OPT = {}
52
-
53
- ALLOWED_USER_OPTS = [
54
- 'pe', # Parallel environment
55
- 'l', # Resource request
56
- 'tc', # Max running tasks
57
- 'P', # Project name (e.g. to which account jobs are accounted against)
58
- ]
59
-
60
- NUM_CORES_VAR = '$NSLOTS'
61
-
62
- def __init__(self, options=None, output_dir=None, error_dir=None):
63
-
64
- for i in options:
65
- if i not in SunGridEngine.ALLOWED_USER_OPTS:
66
- msg = ('Option "{}" is not allowed for scheduler "{}". Allowed options '
67
- 'are: {}.')
68
- raise ValueError(
69
- msg.format(i, SunGridEngine._NAME, SunGridEngine.ALLOWED_USER_OPTS))
70
-
71
- super().__init__(options=options, output_dir=output_dir, error_dir=error_dir)
72
-
73
- def get_formatted_options(self, max_num_tasks, task_step_size, user_opt=True,
74
- name=None):
75
-
76
- opts = ['#$ -{}'.format(i) for i in SunGridEngine.REQ_OPT]
77
- opts.append('#$ -{} {}'.format(
78
- SunGridEngine.STDOUT_OPT,
79
- SunGridEngine.STDOUT_OPT_FMT.format(self.output_dir)),
80
- )
81
- opts.append('#$ -{} {}'.format(
82
- SunGridEngine.STDERR_OPT,
83
- SunGridEngine.STDERR_OPT_FMT.format(self.error_dir)),
84
- )
85
- opts += ['#$ -{} {}'.format(i, j)
86
- for i, j in SunGridEngine.REQ_PARAMETRISED_OPT.items()]
87
-
88
- if name:
89
- opts += [f'#$ -N {name}']
90
-
91
- if user_opt:
92
- opts += ['#$ -{} {}'.format(k, v).strip()
93
- for k, v in sorted(self.options.items())]
94
-
95
- opts += ['', '#$ -t 1-{}:{}'.format(max_num_tasks, task_step_size)]
96
-
97
- return opts
98
-
99
- def write_jobscript(self, dir_path, workflow_directory, command_group_order,
100
- max_num_tasks, task_step_size, environment, archive,
101
- alternate_scratch_dir, command_group_submission_id, name):
102
- """Write the jobscript.
103
-
104
- Parameters
105
- ----------
106
- archive : bool
107
-
108
- """
109
-
110
- js_ext = CONFIG.get('jobscript_ext')
111
- js_name = 'js_{}'.format(command_group_order)
112
- js_fn = js_name + js_ext
113
- js_path = dir_path.joinpath(js_fn)
114
-
115
- cmd_name = 'cmd_{}'.format(command_group_order)
116
- cmd_fn = cmd_name + js_ext
117
-
118
- submit_dir_relative = dir_path.relative_to(workflow_directory).as_posix()
119
-
120
- wk_dirs_path = ('${{ITER_DIR}}/working_dirs_{}{}').format(
121
- command_group_order, CONFIG.get('working_dirs_file_ext'))
122
-
123
- dt_stamp = datetime.now().strftime(r'%Y.%m.%d at %H:%M:%S')
124
- about_msg = ['# --- jobscript generated by `hpcflow` (version: {}) '
125
- 'on {} ---'.format(__version__, dt_stamp)]
126
-
127
- define_dirs_A = [
128
- 'ROOT_DIR=`pwd`',
129
- 'SUBMIT_DIR=$ROOT_DIR/{}'.format(submit_dir_relative),
130
- 'ITER_DIR=$SUBMIT_DIR/iter_$ITER_IDX',
131
- 'LOG_PATH=$ITER_DIR/log_{}.$SGE_TASK_ID'.format(command_group_order),
132
- 'TASK_IDX=$((($SGE_TASK_ID - 1)/{}))'.format(task_step_size),
133
- ]
134
-
135
- write_cmd_exec = [(
136
- f'hpcflow write-runtime-files --directory $ROOT_DIR '
137
- f'--config-dir {CONFIG.get("config_dir")} '
138
- f'{command_group_submission_id} $TASK_IDX $ITER_IDX > $LOG_PATH 2>&1'
139
- )]
140
-
141
- define_dirs_B = [
142
- 'INPUTS_DIR_REL=`sed -n "${{SGE_TASK_ID}}p" {}`'.format(wk_dirs_path),
143
- 'INPUTS_DIR=$ROOT_DIR/$INPUTS_DIR_REL',
144
- ]
145
-
146
- if alternate_scratch_dir:
147
- alt_scratch_exc_path = '$ITER_DIR/{}_{}_$TASK_IDX{}'.format(
148
- CONFIG.get('alt_scratch_exc_file'),
149
- command_group_order,
150
- CONFIG.get('alt_scratch_exc_file_ext'),
151
- )
152
- define_dirs_B.append('ALT_SCRATCH_EXC=' + alt_scratch_exc_path)
153
- in_dir_scratch = 'INPUTS_DIR_SCRATCH={}/$INPUTS_DIR_REL'.format(
154
- alternate_scratch_dir)
155
- copy_to_alt = [
156
- ('rsync -avviz --exclude-from="${ALT_SCRATCH_EXC}" '
157
- '$INPUTS_DIR/ $INPUTS_DIR_SCRATCH >> $LOG_PATH 2>&1'),
158
- '',
159
- ]
160
- move_from_alt = [
161
- '',
162
- ('rsync -avviz $INPUTS_DIR_SCRATCH/ $INPUTS_DIR --remove-source-files'
163
- ' >> $LOG_PATH 2>&1'),
164
- '',
165
- ]
166
- else:
167
- in_dir_scratch = 'INPUTS_DIR_SCRATCH=$INPUTS_DIR'
168
- copy_to_alt = []
169
- move_from_alt = []
170
-
171
- define_dirs_B.append(in_dir_scratch)
172
-
173
- log_stuff = [
174
- r'printf "Jobscript variables:\n" >> $LOG_PATH 2>&1',
175
- r'printf "ITER_IDX:\t ${ITER_IDX}\n" >> $LOG_PATH 2>&1',
176
- r'printf "ROOT_DIR:\t ${ROOT_DIR}\n" >> $LOG_PATH 2>&1',
177
- r'printf "SUBMIT_DIR:\t ${SUBMIT_DIR}\n" >> $LOG_PATH 2>&1',
178
- r'printf "ITER_DIR:\t ${ITER_DIR}\n" >> $LOG_PATH 2>&1',
179
- r'printf "LOG_PATH:\t ${LOG_PATH}\n" >> $LOG_PATH 2>&1',
180
- r'printf "SGE_TASK_ID:\t ${SGE_TASK_ID}\n" >> $LOG_PATH 2>&1',
181
- r'printf "TASK_IDX:\t ${TASK_IDX}\n" >> $LOG_PATH 2>&1',
182
- r'printf "INPUTS_DIR_REL:\t ${INPUTS_DIR_REL}\n" >> $LOG_PATH 2>&1',
183
- r'printf "INPUTS_DIR:\t ${INPUTS_DIR}\n" >> $LOG_PATH 2>&1',
184
- r'printf "INPUTS_DIR_SCRATCH:\t ${INPUTS_DIR_SCRATCH}\n" >> $LOG_PATH 2>&1',
185
- ]
186
-
187
- if alternate_scratch_dir:
188
- log_stuff.append(
189
- r'printf "ALT_SCRATCH_EXC:\t ${ALT_SCRATCH_EXC}\n" >> $LOG_PATH 2>&1',
190
- )
191
-
192
- log_stuff.append(r'printf "\n" >> $LOG_PATH 2>&1')
193
-
194
- if environment:
195
- loads = [''] + environment + ['']
196
- else:
197
- loads = []
198
-
199
- set_task_args = (f'--directory $ROOT_DIR '
200
- f'--config-dir {CONFIG.get("config_dir")} '
201
- f'{command_group_submission_id} '
202
- f'$TASK_IDX $ITER_IDX >> $LOG_PATH 2>&1')
203
- cmd_exec = [
204
- f'hpcflow set-task-start {set_task_args}',
205
- f'',
206
- f'cd $INPUTS_DIR_SCRATCH',
207
- f'. $SUBMIT_DIR/{cmd_fn}',
208
- f'',
209
- f'hpcflow set-task-end {set_task_args}',
210
- ]
211
-
212
- arch_lns = []
213
- if archive:
214
- arch_lns = [
215
- (f'hpcflow archive --directory $ROOT_DIR '
216
- f'--config-dir {CONFIG.get("config_dir")} '
217
- f'{command_group_submission_id} '
218
- f'$TASK_IDX $ITER_IDX >> $LOG_PATH 2>&1'),
219
- ''
220
- ]
221
-
222
- js_lines = ([SunGridEngine.SHEBANG, ''] +
223
- about_msg + [''] +
224
- self.get_formatted_options(max_num_tasks, task_step_size, name=name) +
225
- [''] +
226
- define_dirs_A + [''] +
227
- write_cmd_exec + [''] +
228
- define_dirs_B + [''] +
229
- log_stuff + [''] +
230
- loads + [''] +
231
- copy_to_alt +
232
- cmd_exec +
233
- move_from_alt +
234
- arch_lns)
235
-
236
- # Write jobscript:
237
- with js_path.open('w') as handle:
238
- handle.write('\n'.join(js_lines))
239
-
240
- return js_path
241
-
242
- def write_stats_jobscript(self, dir_path, workflow_directory, command_group_order,
243
- max_num_tasks, task_step_size, command_group_submission_id,
244
- name):
245
-
246
- js_ext = CONFIG.get('jobscript_ext')
247
- js_name = 'st_{}'.format(command_group_order)
248
- js_fn = js_name + js_ext
249
- js_path = dir_path.joinpath(js_fn)
250
-
251
- dt_stamp = datetime.now().strftime(r'%Y.%m.%d at %H:%M:%S')
252
- about_msg = ['# --- jobscript generated by `hpcflow` (version: {}) '
253
- 'on {} ---'.format(__version__, dt_stamp)]
254
-
255
- submit_dir_relative = dir_path.relative_to(workflow_directory).as_posix()
256
-
257
- define_dirs = [
258
- 'ROOT_DIR=`pwd`',
259
- 'SUBMIT_DIR=$ROOT_DIR/{}'.format(submit_dir_relative),
260
- 'ITER_DIR=$SUBMIT_DIR/iter_$ITER_IDX',
261
- 'LOG_PATH=$ITER_DIR/log_{}.$SGE_TASK_ID'.format(command_group_order),
262
- 'TASK_IDX=$((($SGE_TASK_ID - 1)/{}))'.format(task_step_size),
263
- ]
264
-
265
- log_stuff = [
266
- r'printf "Jobscript variables:\n" >> $LOG_PATH 2>&1',
267
- r'printf "ITER_IDX:\t ${ITER_IDX}\n" >> $LOG_PATH 2>&1',
268
- r'printf "ROOT_DIR:\t ${ROOT_DIR}\n" >> $LOG_PATH 2>&1',
269
- r'printf "SUBMIT_DIR:\t ${SUBMIT_DIR}\n" >> $LOG_PATH 2>&1',
270
- r'printf "ITER_DIR:\t ${ITER_DIR}\n" >> $LOG_PATH 2>&1',
271
- r'printf "LOG_PATH:\t ${LOG_PATH}\n" >> $LOG_PATH 2>&1',
272
- r'printf "SGE_TASK_ID:\t ${SGE_TASK_ID}\n" >> $LOG_PATH 2>&1',
273
- r'printf "TASK_IDX:\t ${TASK_IDX}\n" >> $LOG_PATH 2>&1',
274
- ]
275
-
276
- cmd_exec = [(
277
- f'hpcflow get-scheduler-stats --directory $ROOT_DIR '
278
- f'--config-dir {CONFIG.get("config_dir")} '
279
- f'{command_group_submission_id} $TASK_IDX $ITER_IDX >> $LOG_PATH 2>&1'
280
- )]
281
-
282
- opt = self.get_formatted_options(max_num_tasks, task_step_size, user_opt=False,
283
- name=name)
284
- opt.append('#$ -l short') # Temp (should be a profile option)
285
-
286
- js_lines = ([SunGridEngine.SHEBANG, ''] +
287
- about_msg + [''] +
288
- opt + [''] +
289
- define_dirs + [''] +
290
- log_stuff + [''] +
291
- cmd_exec)
292
-
293
- # Write jobscript:
294
- with js_path.open('w') as handle:
295
- handle.write('\n'.join(js_lines))
296
-
297
- return js_path
298
-
299
- def get_scheduler_stats(self, scheduler_job_id, task_id):
300
-
301
- cmd = ['/opt/site/sge/bin/lx-amd64/qacct', '-j', str(scheduler_job_id)]
302
- proc = run(cmd, stdout=PIPE, stderr=PIPE)
303
- out = proc.stdout.decode().strip()
304
- _ = proc.stderr.decode().strip()
305
-
306
- info = {}
307
- qacct = out.split(SunGridEngine.STATS_DELIM)
308
- for i in qacct[1:]:
309
- keep = False
310
- for ln in i.splitlines():
311
- key, val = ln.strip().split(None, 1)
312
- val = val.strip()
313
- info.update({key: val})
314
- if key == 'taskid':
315
- if val == 'undefined' or int(val) == task_id:
316
- keep = True
317
- if keep:
318
- break
319
- else:
320
- info = {}
321
-
322
- return info
hpcflow/utils.py DELETED
@@ -1,103 +0,0 @@
1
- """`hpcflow.utils.py`
2
-
3
- Utility functions that are not particularly specific to `hpcflow`.
4
-
5
- """
6
-
7
- import random
8
-
9
-
10
- def coerce_same_length(all_lists):
11
- """
12
- TODO: add docstring and examples
13
-
14
- """
15
-
16
- all_len = [len(i) for i in all_lists]
17
- uniq_lens = set(all_len)
18
- num_uniq_lens = len(uniq_lens)
19
-
20
- if num_uniq_lens == 1:
21
- out = all_lists
22
-
23
- elif num_uniq_lens == 2:
24
-
25
- if min(uniq_lens) != 1:
26
- raise ValueError('bad!')
27
-
28
- max_len = max(uniq_lens)
29
- out = []
30
- for i in all_lists:
31
- if len(i) != max_len:
32
- i = i * max_len
33
- out.append(i)
34
-
35
- else:
36
- raise ValueError('bad!')
37
-
38
- return out
39
-
40
-
41
- def zeropad(num, largest):
42
- """Return a zero-padded string of a number, given the largest number.
43
-
44
- TODO: want to support floating-point numbers as well? Or rename function
45
- accordingly.
46
-
47
- Parameters
48
- ----------
49
- num : int
50
- The number to be formatted with zeros padding on the left.
51
- largest : int
52
- The number that determines the number of zeros to pad with.
53
-
54
- Returns
55
- -------
56
- padded : str
57
- The original number, `num`, formatted as a string with zeros added
58
- on the left.
59
-
60
- """
61
-
62
- num_digits = len('{:.0f}'.format(largest))
63
- padded = '{0:0{width}}'.format(num, width=num_digits)
64
-
65
- return padded
66
-
67
-
68
- def datetime_to_dict(dt):
69
- return {
70
- 'year': dt.year,
71
- 'month': dt.month,
72
- 'day': dt.day,
73
- 'hour': dt.hour,
74
- 'minute': dt.minute,
75
- 'second': dt.second,
76
- 'microsecond': dt.microsecond,
77
- }
78
-
79
-
80
- def timedelta_to_dict(td):
81
- return {
82
- 'days': td.days,
83
- 'seconds': td.seconds,
84
- 'microseconds': td.microseconds,
85
- }
86
-
87
-
88
- def format_time_delta(time_delta):
89
-
90
- days, days_rem = divmod(time_delta.total_seconds(), 3600 * 24)
91
- hours, hours_rem = divmod(days_rem, 3600)
92
- mins, seconds = divmod(hours_rem, 60)
93
-
94
- time_diff_fmt = '{:02.0f}:{:02.0f}:{:02.0f}'.format(hours, mins, round(seconds))
95
- if days > 0:
96
- days_str = 'day' if days == 1 else 'days'
97
- time_diff_fmt = '{} {}, '.format(int(days), days_str) + time_diff_fmt
98
-
99
- return time_diff_fmt
100
-
101
-
102
- def get_random_hex(n=10):
103
- return ''.join([random.choice('0123456789abcdef') for i in range(n)])
hpcflow/validation.py DELETED
@@ -1,166 +0,0 @@
1
- """`hpcflow.validation.py`
2
-
3
- These validation functions are invoked during initialisation of the `Workflow`
4
- and `CommandGroup` instances. They are extracted out as functions here to allow
5
- re-use by the `visualise` module, whose code may be invoked without necessarily
6
- constructing `Workflow` and `CommandGroup` instances.
7
-
8
- """
9
-
10
- from hpcflow.config import Config as CONFIG
11
-
12
-
13
- def validate_workflow(workflow_dict):
14
- """Validate the `nesting`, `order` and `num_tasks` for each in a list of
15
- workflow command groups."""
16
-
17
- return workflow_dict
18
-
19
-
20
- def validate_job_profile(job_profile):
21
- """Validate the keys of a job profile.
22
-
23
- Parameters
24
- ----------
25
- job_profile : dict
26
- Dictionary representing a job profile.
27
-
28
- Returns
29
- -------
30
- job_profile : dict
31
- Dictionary representing a job profile.
32
-
33
- """
34
-
35
- # Validate profile keys:
36
- keys = job_profile.keys()
37
- missing_keys = list(set(CONFIG.get('profile_keys_required')) - set(keys))
38
- bad_keys = list(set(keys) - set(CONFIG.get('profile_keys_allowed')))
39
-
40
- # Check required keys exist:
41
- if len(missing_keys) > 0:
42
- msg = ('Job profile is missing required key(s): {}')
43
- raise ValueError(msg.format(missing_keys))
44
-
45
- # Check for unknown keys:
46
- if len(bad_keys) > 0:
47
- msg = ('Job profile contains unknown key(s): {}')
48
- raise ValueError(msg.format(bad_keys))
49
-
50
- return job_profile
51
-
52
-
53
- def validate_job_profile_list(job_profiles):
54
- """Validate a list of job profiles and sort by `profile_order`.
55
-
56
- Parameters
57
- ----------
58
- job_profiles : list of dict
59
- List of dictionaries representing job profiles.
60
-
61
- Returns
62
- -------
63
- job_profiles : list of dict
64
- List of dictionaries representing job profiles, sorted by
65
- `profile_order`.
66
-
67
- """
68
-
69
- # Some validation:
70
- profile_orders = []
71
- profile_names = []
72
- for i in job_profiles:
73
-
74
- # Check all profiles have a name:
75
- if i.get('profile_name') is None:
76
- msg = ('`profile_name` must be set for each job profile.')
77
- raise ValueError(msg)
78
- else:
79
- profile_names.append(i['profile_name'])
80
-
81
- if len(job_profiles) > 1:
82
- # Check all profiles have an order:
83
- if i.get('profile_order') is None:
84
- msg = ('`profile_order` must be set for each profile if there '
85
- 'are multiple job profiles, but was not specified for '
86
- 'the job profile "{}"')
87
- raise ValueError(msg.format(i['profile_name']))
88
- else:
89
- profile_orders.append(i['profile_order'])
90
-
91
- if len(job_profiles) > 1:
92
- # Check distinct profile names:
93
- if len(set(profile_names)) < len(job_profiles):
94
- msg = ('Each job profile must have a distinct `profile_name` if '
95
- 'there are multiple job profiles, but job profile names '
96
- 'are: {}')
97
- raise ValueError(msg.format(profile_names))
98
-
99
- # Check distinct profile orders:
100
- if len(set(profile_orders)) < len(job_profiles):
101
- msg = ('Each job profile must have a distinct `profile_order` if '
102
- 'there are multiple job profiles, but job profile orders '
103
- 'are: {}')
104
- raise ValueError(msg.format(profile_orders))
105
-
106
- # Sort by profile order:
107
- job_profiles = sorted(job_profiles, key=lambda x: x['profile_order'])
108
-
109
- return job_profiles
110
-
111
-
112
- def validate_task_multiplicity(cmd_groups, common_err_msg='',
113
- max_num_channels=1):
114
- """Validate an ordered list of command groups that represent (part of) a
115
- Workflow.
116
-
117
- Parameters
118
- ----------
119
- cmd_groups : list of dict
120
- List of dicts representing command groups.
121
- common_err_msg : str, optional
122
- Optional error message to prepend to any exception raised in here. By
123
- default, empty.
124
- max_num_channels : int, optional
125
- Restrict the allowed number of channels to a given number.
126
-
127
- Returns
128
- -------
129
- cmd_groups : list of dict
130
- List of dicts representing command groups.
131
-
132
- """
133
-
134
- if not common_err_msg.endswith(' '):
135
- common_err_msg += ' '
136
-
137
- exec_orders_all = [i.get('exec_order') for i in cmd_groups]
138
- exec_orders = [i for i in exec_orders_all if i is not None]
139
-
140
- if exec_orders:
141
- # Check `exec_order` starts from zero and increases by 0 or 1:
142
- uniq_exec_orders = list(set(sorted(exec_orders)))
143
- if uniq_exec_orders != list(range(len(uniq_exec_orders))):
144
- msg = common_err_msg + ('If specified, `exec_order` must start at '
145
- 'zero and increase by zero or one across '
146
- 'command groups.')
147
- raise ValueError(msg)
148
-
149
- for i in uniq_exec_orders:
150
- # Get cmd_group indices that have this `exec_order`:
151
- exec_order_idx = [idx for idx, j in enumerate(exec_orders_all)
152
- if j == i]
153
-
154
- if len(exec_order_idx) > 1:
155
-
156
- if len(exec_order_idx) > max_num_channels:
157
- # Temporarily restrict number of channels to 1:
158
- msg = ('Multiple channels are not yet implemented.')
159
- raise NotImplementedError(msg)
160
-
161
- else:
162
- # Set execution orders for command groups:
163
- for i in range(len(cmd_groups)):
164
- cmd_groups[i]['exec_order'] = i
165
-
166
- return cmd_groups