Source code for mdt.cli_scripts.mdt_create_protocol

#!/usr/bin/env python
# PYTHON_ARGCOMPLETE_OK
"""Create a protocol from a bvec and bval file.

MDT uses a protocol file (with extension .prtcl) to store all the acquisition related values.
This is a column based file which can hold, next to the b-values and gradient directions,
the big Delta, small delta, gradient amplitude G and more of these extra acquisition details.
"""
import argparse
import os

from argcomplete.completers import FilesCompleter
import textwrap
import mdt.protocols
from mdt.lib.shell_utils import BasicShellApplication
from mdt.protocols import load_bvec_bval

__author__ = 'Robbert Harms'
__date__ = "2015-08-18"
__maintainer__ = "Robbert Harms"
__email__ = "robbert@xkls.nl"


[docs]class CreateProtocol(BasicShellApplication): def __init__(self): super().__init__() self.parse_unknown_args = True def _get_arg_parser(self, doc_parser=False): description = textwrap.dedent(__doc__) examples = textwrap.dedent(''' mdt-create-protocol data.bvec data.bval mdt-create-protocol data.bvec data.bval -o my_protocol.prtcl mdt-create-protocol data.bvec data.bval mdt-create-protocol data.bvec data.bval --Delta 30 --delta 20 mdt-create-protocol data.bvec data.bval --sequence-timing-units 's' --Delta 0.03 mdt-create-protocol data.bvec data.bval --TE ../my_TE_file.txt ''') epilog = self._format_examples(doc_parser, examples) epilog += textwrap.dedent(""" Additional columns can be specified using the syntax: \"--{column_name} {value}\" structure. Please note that these additional values will not be auto-converted from ms to s. """) parser = argparse.ArgumentParser(description=description, epilog=epilog, formatter_class=argparse.RawTextHelpFormatter) parser.add_argument('bvec', help='the gradient vectors file').completer = FilesCompleter() parser.add_argument('bval', help='the gradient b-values').completer = FilesCompleter() parser.add_argument('-s', '--bval-scale-factor', type=float, help="We expect the b-values in the output protocol in units of s/m^2. " "Example use: 1 or 1e6. The default is autodetect.") parser.add_argument('-o', '--output_file', help='the output protocol, defaults to "<bvec_name>.prtcl" in the same ' 'directory as the bvec file.').completer = FilesCompleter() parser.add_argument('--sequence-timing-units', choices=('ms', 's'), default='ms', help="The units of the sequence timings. The default is 'ms' which we will convert to 's'.") parser.add_argument('--G', help="The gradient amplitudes in T/m.") parser.add_argument('--maxG', help="The maximum gradient amplitude in T/m. This is only useful if we need to guess " "big Delta and small delta. Default is 0.04 T/m") parser.add_argument('--Delta', help="The big Delta to use, either a single number or a file with either a single number " "or one number per gradient direction.") parser.add_argument('--delta', help="The small delta to use, either a single number or a file with either a single number " "or one number per gradient direction.") parser.add_argument('--TE', help="The TE to use, either a single number or a file with either a single number " "or one number per gradient direction.") parser.add_argument('--TR', help="The TR to use, either a single number or a file with either a single number " "or one number per gradient direction.") return parser
[docs] def run(self, args, extra_args): bvec = os.path.realpath(args.bvec) bval = os.path.realpath(args.bval) if args.output_file: output_prtcl = os.path.realpath(args.output_file) else: output_prtcl = os.path.join(os.path.dirname(bvec), os.path.splitext(os.path.basename(bvec))[0] + '.prtcl') if args.bval_scale_factor: bval_scale_factor = float(args.bval_scale_factor) else: bval_scale_factor = 'auto' protocol = load_bvec_bval(bvec=bvec, bval=bval, bval_scale=bval_scale_factor) if args.G is None and args.maxG is not None: if os.path.isfile(str(args.maxG)): protocol = protocol.with_added_column_from_file('maxG', os.path.realpath(str(args.maxG)), 1) else: protocol = protocol.with_new_column('maxG', float(args.maxG)) if args.Delta is not None: protocol = add_sequence_timing_column_to_protocol(protocol, 'Delta', args.Delta, args.sequence_timing_units) if args.delta is not None: protocol = add_sequence_timing_column_to_protocol(protocol, 'delta', args.delta, args.sequence_timing_units) if args.TE is not None: protocol = add_sequence_timing_column_to_protocol(protocol, 'TE', args.TE, args.sequence_timing_units) if args.TR is not None: protocol = add_sequence_timing_column_to_protocol(protocol, 'TR', args.TR, args.sequence_timing_units) if args.G is not None: protocol = add_column_to_protocol(protocol, 'G', args.G, 1) protocol = add_extra_columns(protocol, extra_args) mdt.protocols.write_protocol(protocol, output_prtcl)
[docs]def add_extra_columns(protocol, extra_args): key = None for element in extra_args: if '=' in element and element.startswith('--'): key, value = element[2:].split('=') protocol = add_column_to_protocol(protocol, key, value, 1) elif element.startswith('--'): key = element[2:] else: protocol = add_column_to_protocol(protocol, key, element, 1) return protocol
[docs]def add_column_to_protocol(protocol, column, value, mult_factor): if value is not None: if os.path.isfile(value): return protocol.with_added_column_from_file(column, os.path.realpath(value), mult_factor) else: return protocol.with_new_column(column, float(value) * mult_factor)
[docs]def add_sequence_timing_column_to_protocol(protocol, column, value, units): mult_factor = 1e-3 if units == 'ms' else 1 return add_column_to_protocol(protocol, column, value, mult_factor)
[docs]def get_doc_arg_parser(): return CreateProtocol().get_documentation_arg_parser()
if __name__ == '__main__': CreateProtocol().start()