1 | # Copyright 2014 Diamond Light Source Ltd. |
||
2 | # |
||
3 | # Licensed under the Apache License, Version 2.0 (the "License"); |
||
4 | # you may not use this file except in compliance with the License. |
||
5 | # You may obtain a copy of the License at |
||
6 | # |
||
7 | # http://www.apache.org/licenses/LICENSE-2.0 |
||
8 | # |
||
9 | # Unless required by applicable law or agreed to in writing, software |
||
10 | # distributed under the License is distributed on an "AS IS" BASIS, |
||
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||
12 | # See the License for the specific language governing permissions and |
||
13 | # limitations under the License. |
||
14 | |||
15 | """ |
||
16 | .. module:: pre-run |
||
17 | :platform: Unix |
||
18 | :synopsis: Runner for the Savu framework during a pre-run |
||
19 | |||
20 | .. moduleauthor:: Jacob Williamson <[email protected]> |
||
21 | |||
22 | """ |
||
23 | |||
24 | import tempfile # this import is required for pyFAI - DO NOT REMOVE! |
||
25 | import argparse |
||
26 | import traceback |
||
27 | import sys |
||
28 | import os |
||
29 | |||
30 | import h5py as h5 |
||
31 | from mpi4py import MPI |
||
32 | from savu.version import __version__ |
||
33 | |||
34 | import savu.core.utils as cu |
||
35 | from scripts.citation_extractor import citation_extractor |
||
36 | from savu.core.basic_plugin_runner import BasicPluginRunner |
||
37 | from savu.core.plugin_runner import PluginRunner |
||
38 | #from scripts.config_generator.savu_config import internal_config |
||
39 | |||
40 | |||
41 | def __option_parser(doc=True): |
||
42 | """ Option parser for command line arguments. |
||
43 | """ |
||
44 | version = "%(prog)s " + __version__ |
||
45 | parser = argparse.ArgumentParser(prog='savu') |
||
46 | hide = argparse.SUPPRESS |
||
47 | |||
48 | parser.add_argument('in_file', help='Input data file.') |
||
49 | parser.add_argument('out_folder', help='Output folder.') |
||
50 | parser.add_argument('--version', action='version', version=version) |
||
51 | parser.add_argument("-f", "--folder", help="Override output folder name") |
||
52 | |||
53 | tmp_help = "Store intermediate files in a temp directory." |
||
54 | parser.add_argument("-d", "--tmp", help=tmp_help) |
||
55 | |||
56 | template_help = "Pass a template file of plugin input parameters." |
||
57 | parser.add_argument("-t", "--template", help=template_help, default=None) |
||
58 | |||
59 | log_help = "Store full log file in a separate location" |
||
60 | parser.add_argument("-l", "--log", help=log_help) |
||
61 | |||
62 | v_help = "Display all debug log messages" |
||
63 | parser.add_argument("-v", "--verbose", help=v_help, action="store_true", |
||
64 | default=False) |
||
65 | parser.add_argument("-q", "--quiet", action="store_true", dest="quiet", |
||
66 | help="Display only Errors and Info.", default=False) |
||
67 | # temporary flag to fix lustre issue |
||
68 | parser.add_argument("--lustre_workaround", action="store_true", |
||
69 | dest="lustre", help="Avoid lustre segmentation fault", |
||
70 | default=False) |
||
71 | sys_params_help = "Override default path to Savu system parameters file." |
||
72 | parser.add_argument("--system_params", help=sys_params_help, default=None) |
||
73 | |||
74 | # Set stats off |
||
75 | parser.add_argument("--stats", help="Turn stats 'on' or 'off'.", default="on", choices=["on", "off"]) |
||
76 | |||
77 | # Hidden arguments |
||
78 | # process names |
||
79 | parser.add_argument("-n", "--names", help=hide, default="CPU0") |
||
80 | # transport mechanism |
||
81 | parser.add_argument("--transport", help=hide, default="hdf5") |
||
82 | |||
83 | # Set logging to cluster mode |
||
84 | parser.add_argument("-c", "--cluster", action="store_true", help=hide, |
||
85 | default=False) |
||
86 | # Facility email for errors |
||
87 | parser.add_argument("--facility_email", dest="femail", help=hide, |
||
88 | default=None) |
||
89 | # Send an email on completion |
||
90 | parser.add_argument("-e", "--email", dest="email", help=hide, default=None) |
||
91 | |||
92 | parser.add_argument("--bllog", dest="bllog", help=hide, default=None) |
||
93 | # Location of syslog server |
||
94 | |||
95 | # Location of syslog server |
||
96 | parser.add_argument("-s", "--syslog", dest="syslog", help=hide, |
||
97 | default='localhost') |
||
98 | # Port to connect to syslog server on |
||
99 | parser.add_argument("-p", "--syslog_port", dest="syslog_port", |
||
100 | help=hide, default=514, type=int) |
||
101 | parser.add_argument("--test_state", dest="test_state", default='False', |
||
102 | action='store_true', help=hide) |
||
103 | |||
104 | if doc==False: |
||
105 | args = parser.parse_args() |
||
106 | return args |
||
107 | else: |
||
108 | return parser |
||
109 | |||
110 | View Code Duplication | def _set_options(args): |
|
0 ignored issues
–
show
Duplication
introduced
by
![]() |
|||
111 | """ Set run specific information in options dictionary. |
||
112 | |||
113 | :params dict opt: input optional arguments (or defaults) |
||
114 | :params args: input required arguments |
||
115 | :returns options: optional and required arguments |
||
116 | :rtype: dict |
||
117 | """ |
||
118 | options = {} |
||
119 | options['data_file'] = args.in_file |
||
120 | options['process_file'] = 'savu/data/stats/pre_run.nxs' |
||
121 | options["process_file_name"] = options["process_file"].split("/")[-1] |
||
122 | options["post_pre_run"] = False |
||
123 | options['mode'] = 'full' |
||
124 | options['template'] = args.template |
||
125 | options['transport'] = args.transport |
||
126 | options['process_names'] = args.names |
||
127 | options['verbose'] = args.verbose |
||
128 | options['quiet'] = args.quiet |
||
129 | options['cluster'] = args.cluster |
||
130 | options['syslog_server'] = args.syslog |
||
131 | options['syslog_port'] = args.syslog_port |
||
132 | options['test_state'] = args.test_state |
||
133 | options['lustre'] = args.lustre |
||
134 | options['bllog'] = args.bllog |
||
135 | options['email'] = args.email |
||
136 | options['femail'] = args.femail |
||
137 | options['system_params'] = args.system_params |
||
138 | options['stats'] = 'on' |
||
139 | options['pre_run'] = True |
||
140 | options['checkpoint'] = None |
||
141 | |||
142 | if args.folder: |
||
143 | out_folder_name = os.path.basename(args.folder) |
||
144 | else: |
||
145 | out_folder_name = __create_folder_name(options['data_file']) |
||
146 | |||
147 | out_folder_path = __create_output_folder(args.out_folder, out_folder_name) |
||
148 | |||
149 | options['out_folder'] = out_folder_name |
||
150 | options['out_path'] = out_folder_path |
||
151 | |||
152 | basename = os.path.basename(args.in_file) |
||
153 | options['datafile_name'] = os.path.splitext(basename)[0] if basename \ |
||
154 | else args.in_file.split(os.sep)[-2] |
||
155 | |||
156 | inter_folder_path = __create_output_folder(args.tmp, out_folder_name) \ |
||
157 | if args.tmp else out_folder_path |
||
158 | |||
159 | options['inter_path'] = inter_folder_path |
||
160 | options['log_path'] = args.log if args.log else options['inter_path'] |
||
161 | options['nProcesses'] = len(options["process_names"].split(',')) |
||
162 | |||
163 | command_str = " ".join([str(i) for i in sys.argv[1:]]) |
||
164 | command_full = f"savu {command_str}" |
||
165 | options["command"] = command_full |
||
166 | |||
167 | return options |
||
168 | |||
169 | View Code Duplication | def __create_folder_name(dpath): |
|
0 ignored issues
–
show
|
|||
170 | if os.path.isfile(dpath): |
||
171 | dpath = os.path.splitext(dpath)[0] |
||
172 | elif os.path.isdir(dpath): |
||
173 | dpath = os.path.dirname(dpath) |
||
174 | import time |
||
175 | MPI.COMM_WORLD.barrier() |
||
176 | timestamp = time.strftime("%Y%m%d%H%M%S") |
||
177 | MPI.COMM_WORLD.barrier() |
||
178 | return "_".join([timestamp, os.path.basename(dpath)]) |
||
179 | |||
180 | |||
181 | def __create_output_folder(path, folder_name): |
||
182 | folder = os.path.join(path, folder_name) |
||
183 | if MPI.COMM_WORLD.rank == 0: |
||
184 | if not os.path.exists(folder): |
||
185 | os.makedirs(folder) |
||
186 | return folder |
||
187 | |||
188 | def __get_beamline(options): |
||
189 | try: |
||
190 | with h5.File(options["data_file"], "r") as h5file: |
||
191 | beamline = h5file['entry1/instrument/name'][()] |
||
192 | return beamline |
||
193 | except KeyError: |
||
194 | return None |
||
195 | |||
196 | #def _edit_process_list(options, beamline): |
||
197 | # # Only 'open', 'set', 'mod' and 'save' should be used. |
||
198 | # if beamline == "i23": |
||
199 | # commands = [f"open {options['process_file']}", |
||
200 | # f"set 2 on", |
||
201 | # f"save {options['process_file']}"] |
||
202 | # else: |
||
203 | # commands = [f"open {options['process_file']}", |
||
204 | # f"set 2 off", |
||
205 | # f"save {options['process_file']}"] |
||
206 | # plugin_list = internal_config(*commands) |
||
207 | # active_plugins = [] |
||
208 | # for plugin in plugin_list: |
||
209 | # if plugin["active"]: |
||
210 | # active_plugins.append(plugin["name"]) |
||
211 | # return active_plugins |
||
212 | |||
213 | def _choose_process_list(options, beamline): |
||
214 | # Only 'open', 'set', 'mod' and 'save' should be used. |
||
215 | if beamline == "i23": |
||
216 | options['process_file'] = 'savu/data/stats/pre_run_i23.nxs' |
||
217 | options["process_file_name"] = options["process_file"].split("/")[-1] |
||
218 | |||
219 | |||
220 | def main(input_args=None): |
||
221 | args = __option_parser(doc=False) |
||
222 | |||
223 | if input_args: |
||
224 | args = input_args |
||
225 | |||
226 | options = _set_options(args) |
||
227 | |||
228 | pRunner = PluginRunner if options['mode'] == 'full' else BasicPluginRunner |
||
229 | |||
230 | try: |
||
231 | beamline = __get_beamline(options) |
||
232 | _choose_process_list(options, beamline) |
||
233 | plugin_runner = pRunner(options) |
||
234 | plugin_runner._run_plugin_list() |
||
235 | plugin_runner.exp._save_pre_run_log() |
||
236 | if options['process'] == 0: |
||
237 | in_file = plugin_runner.exp.meta_data['nxs_filename'] |
||
238 | citation_extractor.main(in_file=in_file, quiet=True) |
||
239 | except Exception: |
||
240 | # raise the error in the user log |
||
241 | trace = traceback.format_exc() |
||
242 | cu.user_message(trace) |
||
243 | if options['nProcesses'] == 1: |
||
244 | sys.exit(1) |
||
245 | else: |
||
246 | # Kill all MPI processes |
||
247 | MPI.COMM_WORLD.Abort(1) |
||
248 | |||
249 | if __name__ == '__main__': |
||
250 | main() |
||
251 |