[35488b2] | 1 | import os |
---|
| 2 | import wx |
---|
| 3 | from sas.sascalc.data_util.calcthread import CalcThread |
---|
| 4 | from sas.sascalc.dataloader.data_info import Data2D |
---|
| 5 | from sas.sascalc.file_converter.bsl_loader import BSLLoader |
---|
| 6 | from sas.sascalc.dataloader.readers.red2d_reader import Reader as Red2DWriter |
---|
| 7 | |
---|
| 8 | class ConvertBSLThread(CalcThread): |
---|
| 9 | |
---|
| 10 | def __init__(self, parent, in_file, out_file, |
---|
| 11 | updatefn=None, completefn=None): |
---|
| 12 | CalcThread.__init__(self, updatefn=updatefn, completefn=completefn) |
---|
| 13 | self.parent = parent |
---|
| 14 | self.in_file = in_file |
---|
| 15 | self.out_file = out_file |
---|
| 16 | |
---|
| 17 | def compute(self): |
---|
| 18 | self.ready(delay=0.0) |
---|
| 19 | self.update(msg="Extracting data...") |
---|
| 20 | |
---|
| 21 | try: |
---|
| 22 | x, y, frame_data = self._extract_bsl_data(self.in_file) |
---|
| 23 | except Exception as e: |
---|
| 24 | self.ready() |
---|
| 25 | self.update(exception=e) |
---|
| 26 | self.complete(success=False) |
---|
| 27 | return |
---|
| 28 | |
---|
| 29 | if x == None and y == None and frame_data == None: |
---|
| 30 | # Cancelled by user |
---|
| 31 | self.ready() |
---|
| 32 | self.update(msg="Conversion cancelled") |
---|
| 33 | self.complete(success=False) |
---|
| 34 | return |
---|
| 35 | |
---|
| 36 | if self.isquit(): |
---|
| 37 | self.complete(success=False) |
---|
| 38 | return |
---|
| 39 | |
---|
| 40 | self.ready(delay=0.0) |
---|
| 41 | self.update(msg="Exporting data...") |
---|
| 42 | |
---|
| 43 | try: |
---|
| 44 | completed = self._convert_to_red2d(self.out_file, x, y, frame_data) |
---|
| 45 | except Exception as e: |
---|
| 46 | self.ready() |
---|
| 47 | self.update(exception=e) |
---|
| 48 | self.complete(success=False) |
---|
| 49 | return |
---|
| 50 | |
---|
| 51 | self.complete(success=completed) |
---|
| 52 | |
---|
| 53 | |
---|
| 54 | def _extract_bsl_data(self, filename): |
---|
| 55 | """ |
---|
| 56 | Extracts data from a 2D BSL file |
---|
| 57 | |
---|
| 58 | :param filename: The header file to extract the data from |
---|
| 59 | :return x_data: A 1D array containing all the x coordinates of the data |
---|
| 60 | :return y_data: A 1D array containing all the y coordinates of the data |
---|
| 61 | :return frame_data: A dictionary of the form frame_number: data, where |
---|
| 62 | data is a 2D numpy array containing the intensity data |
---|
| 63 | """ |
---|
| 64 | loader = BSLLoader(filename) |
---|
| 65 | frames = [0] |
---|
| 66 | should_continue = True |
---|
| 67 | |
---|
| 68 | if loader.n_frames > 1: |
---|
| 69 | params = self.parent.ask_frame_range(loader.n_frames) |
---|
| 70 | frames = params['frames'] |
---|
| 71 | elif loader.n_rasters == 1 and loader.n_frames == 1: |
---|
| 72 | message = ("The selected file is an OTOKO file. Please select the " |
---|
| 73 | "'OTOKO 1D' option if you wish to convert it.") |
---|
| 74 | dlg = wx.MessageDialog(self.parent, |
---|
| 75 | message, |
---|
| 76 | 'Error!', |
---|
| 77 | wx.OK | wx.ICON_WARNING) |
---|
| 78 | dlg.ShowModal() |
---|
| 79 | should_continue = False |
---|
| 80 | dlg.Destroy() |
---|
| 81 | else: |
---|
| 82 | message = ("The selected data file only has 1 frame, it might be" |
---|
| 83 | " a multi-frame OTOKO file.\nContinue conversion?") |
---|
| 84 | dlg = wx.MessageDialog(self.parent, |
---|
| 85 | message, |
---|
| 86 | 'Warning!', |
---|
| 87 | wx.YES_NO | wx.ICON_WARNING) |
---|
| 88 | should_continue = (dlg.ShowModal() == wx.ID_YES) |
---|
| 89 | dlg.Destroy() |
---|
| 90 | |
---|
| 91 | if not should_continue: |
---|
| 92 | return None, None, None |
---|
| 93 | |
---|
| 94 | frame_data = {} |
---|
| 95 | |
---|
| 96 | for frame in frames: |
---|
| 97 | loader.frame = frame |
---|
| 98 | frame_data[frame] = loader.load_data() |
---|
| 99 | |
---|
| 100 | # TODO: Tidy this up |
---|
| 101 | # Prepare axes values (arbitrary scale) |
---|
| 102 | x_data = [] |
---|
| 103 | y_data = range(loader.n_pixels) * loader.n_rasters |
---|
| 104 | for i in range(loader.n_rasters): |
---|
| 105 | x_data += [i] * loader.n_pixels |
---|
| 106 | |
---|
| 107 | return x_data, y_data, frame_data |
---|
| 108 | |
---|
| 109 | def _convert_to_red2d(self, filepath, x, y, frame_data): |
---|
| 110 | """ |
---|
| 111 | Writes Data2D objects to Red2D .dat files. If more than one frame is |
---|
| 112 | provided, the frame number will be appended to the filename of each |
---|
| 113 | file written. |
---|
| 114 | |
---|
| 115 | :param filepath: The filepath to write to |
---|
| 116 | :param x: The x column of the data |
---|
| 117 | :param y: The y column of the data |
---|
| 118 | :param frame_data: A dictionary of the form frame_number: data, where |
---|
| 119 | data is a 2D numpy array containing the intensity data |
---|
| 120 | |
---|
| 121 | :return: True if export completed, False if export cancelled by user |
---|
| 122 | """ |
---|
| 123 | filename = os.path.split(filepath)[-1] |
---|
| 124 | filepath = os.path.split(filepath)[0] |
---|
| 125 | writer = Red2DWriter() |
---|
| 126 | |
---|
| 127 | for i, frame in frame_data.iteritems(): |
---|
| 128 | # If more than 1 frame is being exported, append the frame |
---|
| 129 | # number to the filename |
---|
| 130 | if self.isquit(): |
---|
| 131 | return False |
---|
| 132 | |
---|
| 133 | if len(frame_data) > 1: |
---|
| 134 | frame_filename = filename.split('.') |
---|
| 135 | frame_filename[0] += str(i+1) |
---|
| 136 | frame_filename = '.'.join(frame_filename) |
---|
| 137 | else: |
---|
| 138 | frame_filename = filename |
---|
| 139 | |
---|
| 140 | data_i = frame.reshape((len(x),1)) |
---|
| 141 | data_info = Data2D(data=data_i, qx_data=x, qy_data=y) |
---|
| 142 | writer.write(os.path.join(filepath, frame_filename), data_info) |
---|
| 143 | self.ready() |
---|
| 144 | self.update(msg="Written file: {}".format(frame_filename)) |
---|
| 145 | |
---|
| 146 | return True |
---|