Test Failed
Push — master ( 63d02b...e26e75 )
by Nicola
01:17 queued 15s
created

savu.tomo_recon   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 237
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 151
dl 0
loc 237
rs 10
c 0
b 0
f 0
wmc 23

6 Functions

Rating   Name   Duplication   Size   Complexity  
A __create_output_folder() 0 6 3
B _set_options() 0 56 6
A __check_conditions() 0 6 3
B main() 0 24 6
B __option_parser() 0 83 2
A __create_folder_name() 0 10 3
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:: tomo_recon
17
   :platform: Unix
18
   :synopsis: Runner for the Savu framework
19
20
.. moduleauthor:: Mark Basham <[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
from mpi4py import MPI
30
from savu.version import __version__
31
32
import savu.core.utils as cu
33
from scripts.citation_extractor import citation_extractor
34
from savu.core.basic_plugin_runner import BasicPluginRunner
35
from savu.core.plugin_runner import PluginRunner
36
37
38
def __option_parser(doc=True):
39
    """ Option parser for command line arguments.
40
    """
41
    version = "%(prog)s " + __version__
42
    parser = argparse.ArgumentParser(prog='savu')
43
    hide = argparse.SUPPRESS
44
45
    parser.add_argument('in_file', help='Input data file.')
46
    process_str = 'Process list, created with the savu configurator.'
47
    parser.add_argument('process_list', help=process_str)
48
    parser.add_argument('out_folder', help='Output folder.')
49
    parser.add_argument('--version', action='version', version=version)
50
    parser.add_argument("-f", "--folder", help="Override output folder name")
51
52
    tmp_help = "Store intermediate files in a temp directory."
53
    parser.add_argument("-d", "--tmp", help=tmp_help)
54
55
    template_help = "Pass a template file of plugin input parameters."
56
    parser.add_argument("-t", "--template", help=template_help, default=None)
57
58
    log_help = "Store full log file in a separate location"
59
    parser.add_argument("-l", "--log", help=log_help)
60
61
    v_help = "Display all debug log messages"
62
    parser.add_argument("-v", "--verbose", help=v_help, action="store_true",
63
                        default=False)
64
    parser.add_argument("-q", "--quiet", action="store_true", dest="quiet",
65
                        help="Display only Errors and Info.", default=False)
66
    # temporary flag to fix lustre issue
67
    parser.add_argument("--lustre_workaround", action="store_true",
68
                        dest="lustre", help="Avoid lustre segmentation fault",
69
                        default=False)
70
    sys_params_help = "Override default path to Savu system parameters file."
71
    parser.add_argument("--system_params", help=sys_params_help, default=None)
72
73
    # Hidden arguments
74
    # process names
75
    parser.add_argument("-n", "--names", help=hide, default="CPU0")
76
    # transport mechanism
77
    parser.add_argument("--transport", help=hide, default="hdf5")
78
    # Set Savu mode
79
    parser.add_argument("-m", "--mode", help=hide, default="full",
80
                        choices=['basic', 'full'])
81
    # Set logging to cluster mode
82
    parser.add_argument("-c", "--cluster", action="store_true", help=hide,
83
                        default=False)
84
    # Send an email on completion
85
    parser.add_argument("-e", "--email", dest="email", help=hide, default=None)
86
    # Facility email for errors
87
    parser.add_argument("--facility_email", dest="femail", help=hide,
88
                        default=None)
89
    # Set beamline log file (for online processing)
90
    parser.add_argument("--bllog", dest="bllog", help=hide, default=None)
91
    # Location of syslog server
92
    parser.add_argument("-s", "--syslog", dest="syslog", help=hide,
93
                        default='localhost')
94
    # Port to connect to syslog server on
95
    parser.add_argument("-p", "--syslog_port", dest="syslog_port",
96
                        help=hide, default=514, type=int)
97
    parser.add_argument("--test_state", dest="test_state", default='False',
98
                        action='store_true', help=hide)
99
100
    # DosNa related parameters
101
    parser.add_argument("--dosna_backend", dest="dosna_backend", help=hide,
102
                        default=None)
103
    parser.add_argument("--dosna_engine", dest="dosna_engine", help=hide,
104
                        default=None)
105
    parser.add_argument("--dosna_connection", dest="dosna_connection",
106
                        help=hide, default=None)
107
    parser.add_argument("--dosna_connection_options",
108
                        dest="dosna_connection_options", help=hide,
109
                        nargs='+', default=[])
110
111
    check_help = "Continue Savu processing from a checkpoint."
112
    choices = ['plugin', 'subplugin']
113
    parser.add_argument("--checkpoint", nargs="?", choices=choices,
114
                        const='plugin', help=check_help, default=None)
115
    if doc==False:
116
        args = parser.parse_args()
117
        __check_conditions(parser, args)
118
        return args
119
    else:
120
        return parser
121
122
123
def __check_conditions(parser, args):
124
    if args.checkpoint and not args.folder:
125
        msg = "--checkpoint flag requires '-f folder_name', where folder_name"\
126
              " contains the partially completed Savu job.  The out_folder"\
127
              " should be the path to this folder."
128
        parser.error(msg)
129
130
131
def _set_options(args):
132
    """ Set run specific information in options dictionary.
133
134
    :params dict opt: input optional arguments (or defaults)
135
    :params args: input required arguments
136
    :returns options: optional and required arguments
137
    :rtype: dict
138
    """
139
    options = {}
140
    options['data_file'] = args.in_file
141
    options['process_file'] = args.process_list
142
    options['mode'] = args.mode
143
    options['template'] = args.template
144
    options['transport'] = 'basic' if args.mode == 'basic' else args.transport
145
    options['process_names'] = args.names
146
    options['verbose'] = args.verbose
147
    options['quiet'] = args.quiet
148
    options['cluster'] = args.cluster
149
    options['syslog_server'] = args.syslog
150
    options['syslog_port'] = args.syslog_port
151
    options['test_state'] = args.test_state
152
    options['lustre'] = args.lustre
153
    options['bllog'] = args.bllog
154
    options['email'] = args.email
155
    options['femail'] = args.femail
156
    options['system_params'] = args.system_params
157
158
    if args.folder:
159
        out_folder_name = os.path.basename(args.folder)
160
    else:
161
        out_folder_name = __create_folder_name(options['data_file'])
162
163
    out_folder_path = __create_output_folder(args.out_folder, out_folder_name)
164
165
    options['out_folder'] = out_folder_name
166
    options['out_path'] = out_folder_path
167
168
    basename = os.path.basename(args.in_file)
169
    options['datafile_name'] = os.path.splitext(basename)[0] if basename \
170
        else args.in_file.split(os.sep)[-2]
171
172
    inter_folder_path = __create_output_folder(args.tmp, out_folder_name)\
173
        if args.tmp else out_folder_path
174
175
    options['inter_path'] = inter_folder_path
176
    options['log_path'] = args.log if args.log else options['inter_path']
177
    options['nProcesses'] = len(options["process_names"].split(','))
178
    # DosNa related options
179
    options["dosna_backend"] = args.dosna_backend
180
    options["dosna_engine"] = args.dosna_engine
181
    options["dosna_connection"] = args.dosna_connection
182
    options["dosna_connection_options"] = args.dosna_connection_options
183
184
    options['checkpoint'] = args.checkpoint
185
186
    return options
187
188
189
def __create_folder_name(dpath):
190
    if os.path.isfile(dpath):
191
        dpath = os.path.splitext(dpath)[0]
192
    elif os.path.isdir(dpath):
193
        dpath = os.path.dirname(dpath)
194
    import time
195
    MPI.COMM_WORLD.barrier()
196
    timestamp = time.strftime("%Y%m%d%H%M%S")
197
    MPI.COMM_WORLD.barrier()
198
    return "_".join([timestamp, os.path.basename(dpath)])
199
200
201
def __create_output_folder(path, folder_name):
202
    folder = os.path.join(path, folder_name)
203
    if MPI.COMM_WORLD.rank == 0:
204
        if not os.path.exists(folder):
205
            os.makedirs(folder)
206
    return folder
207
208
209
def main(input_args=None):
210
    args = __option_parser(doc=False)
211
212
    if input_args:
213
        args = input_args
214
215
    options = _set_options(args)
216
    pRunner = PluginRunner if options['mode'] == 'full' else BasicPluginRunner
217
218
    try:
219
        plugin_runner = pRunner(options)
220
        plugin_runner._run_plugin_list()
221
        if options['process'] == 0:
222
            in_file = plugin_runner.exp.meta_data['nxs_filename']
223
            citation_extractor.main(in_file=in_file, quiet=True)
224
    except Exception:
225
        # raise the error in the user log
226
        trace = traceback.format_exc()
227
        cu.user_message(trace)
228
        if options['nProcesses'] == 1:
229
            sys.exit(1)
230
        else:
231
            # Kill all MPI processes
232
            MPI.COMM_WORLD.Abort(1)
233
234
235
if __name__ == '__main__':
236
    main()
237