Ignore:
Timestamp:
Nov 15, 2018 12:09:18 PM (5 years ago)
Author:
Jeff Krzywon <jkrzywon@…>
Branches:
master, magnetic_scatt, release-4.2.2, ticket-1009, ticket-1094-headless, ticket-1242-2d-resolution, ticket-1243, ticket-1249
Children:
9220e89c
Parents:
a165bee (diff), f560e23 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' into ticket-1111

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/sas/sascalc/dataloader/readers/cansas_reader_HDF5.py

    r61f329f0 ra165bee  
    11""" 
    2     CanSAS 2D data reader for reading HDF5 formatted CanSAS files. 
     2    NXcanSAS data reader for reading HDF5 formatted CanSAS files. 
    33""" 
    44 
     
    1212    Data1D, Data2D, DataInfo, Process, Aperture, Collimation, \ 
    1313    TransmissionSpectrum, Detector 
    14 from ..data_info import combine_data_info_with_plottable 
    1514from ..loader_exceptions import FileContentsException, DefaultReaderException 
    1615from ..file_reader_base_class import FileReader, decode 
    1716 
     17 
    1818def h5attr(node, key, default=None): 
    1919    return decode(node.attrs.get(key, default)) 
    2020 
     21 
    2122class Reader(FileReader): 
    2223    """ 
    23     A class for reading in CanSAS v2.0 data files. The existing iteration opens 
    24     Mantid generated HDF5 formatted files with file extension .h5/.H5. Any 
    25     number of data sets may be present within the file and any dimensionality 
    26     of data may be used. Currently 1D and 2D SAS data sets are supported, but 
    27     future implementations will include 1D and 2D SESANS data. 
    28  
    29     Any number of SASdata sets may be present in a SASentry and the data within 
    30     can be either 1D I(Q) or 2D I(Qx, Qy). 
    31  
    32     Also supports reading NXcanSAS formatted HDF5 files 
     24    A class for reading in NXcanSAS data files. The current implementation has 
     25    been tested to load data generated by multiple facilities, all of which are 
     26    known to produce NXcanSAS standards compliant data. Any number of data sets 
     27    may be present within the file and any dimensionality of data may be used. 
     28    Currently 1D and 2D SAS data sets are supported, but should be immediately 
     29    extensible to SESANS data. 
     30 
     31    Any number of SASdata groups  may be present in a SASentry and the data 
     32    within each SASdata group can be a single 1D I(Q), multi-framed 1D I(Q), 
     33    2D I(Qx, Qy) or multi-framed 2D I(Qx, Qy). 
    3334 
    3435    :Dependencies: 
    35         The CanSAS HDF5 reader requires h5py => v2.5.0 or later. 
     36        The NXcanSAS HDF5 reader requires h5py => v2.5.0 or later. 
    3637    """ 
    3738 
    3839    # CanSAS version 
    3940    cansas_version = 2.0 
    40     # Logged warnings or messages 
    41     logging = None 
    42     # List of errors for the current data set 
    43     errors = None 
    44     # Raw file contents to be processed 
    45     raw_data = None 
    46     # List of plottable1D objects that should be linked to the current_datainfo 
    47     data1d = None 
    48     # List of plottable2D objects that should be linked to the current_datainfo 
    49     data2d = None 
    5041    # Data type name 
    51     type_name = "CanSAS 2.0" 
     42    type_name = "NXcanSAS" 
    5243    # Wildcards 
    53     type = ["CanSAS 2.0 HDF5 Files (*.h5)|*.h5"] 
     44    type = ["NXcanSAS HDF5 Files (*.h5)|*.h5|"] 
    5445    # List of allowed extensions 
    5546    ext = ['.h5', '.H5'] 
     
    8172                except Exception as e: 
    8273                    if extension not in self.ext: 
    83                         msg = "CanSAS2.0 HDF5 Reader could not load file {}".format(basename + extension) 
     74                        msg = "NXcanSAS Reader could not load file {}".format( 
     75                            basename + extension) 
    8476                        raise DefaultReaderException(msg) 
    8577                    raise FileContentsException(e.message) 
     
    9587                    self.raw_data.close() 
    9688 
    97                 for dataset in self.output: 
    98                     if isinstance(dataset, Data1D): 
    99                         if dataset.x.size < 5: 
    100                             self.output = [] 
    101                             raise FileContentsException("Fewer than 5 data points found.") 
     89                for data_set in self.output: 
     90                    if isinstance(data_set, Data1D): 
     91                        if data_set.x.size < 5: 
     92                            exception = FileContentsException( 
     93                                "Fewer than 5 data points found.") 
     94                            data_set.errors.append(exception) 
    10295 
    10396    def reset_state(self): 
     
    109102        self.data2d = [] 
    110103        self.raw_data = None 
    111         self.errors = set() 
     104        self.multi_frame = False 
     105        self.data_frames = [] 
     106        self.data_uncertainty_frames = [] 
     107        self.errors = [] 
    112108        self.logging = [] 
     109        self.q_names = [] 
     110        self.mask_name = u'' 
     111        self.i_name = u'' 
     112        self.i_node = u'' 
     113        self.i_uncertainties_name = u'' 
     114        self.q_uncertainty_names = [] 
     115        self.q_resolution_names = [] 
    113116        self.parent_class = u'' 
    114117        self.detector = Detector() 
     
    131134            value = data.get(key) 
    132135            class_name = h5attr(value, u'canSAS_class') 
     136            if isinstance(class_name, (list, tuple, np.ndarray)): 
     137                class_name = class_name[0] 
    133138            if class_name is None: 
    134139                class_name = h5attr(value, u'NX_class') 
     
    140145            if isinstance(value, h5py.Group): 
    141146                # Set parent class before recursion 
     147                last_parent_class = self.parent_class 
    142148                self.parent_class = class_name 
    143149                parent_list.append(key) 
     
    147153                    self.add_data_set(key) 
    148154                elif class_prog.match(u'SASdata'): 
    149                     self._initialize_new_data_set(parent_list) 
     155                    self._find_data_attributes(value) 
     156                    self._initialize_new_data_set(value) 
    150157                # Recursion step to access data within the group 
    151158                self.read_children(value, parent_list) 
     159                self.add_intermediate() 
    152160                # Reset parent class when returning from recursive method 
    153                 self.parent_class = class_name 
    154                 self.add_intermediate() 
     161                self.parent_class = last_parent_class 
    155162                parent_list.remove(key) 
    156163 
    157164            elif isinstance(value, h5py.Dataset): 
    158165                # If this is a dataset, store the data appropriately 
    159                 data_set = data[key][:] 
     166                data_set = value.value 
    160167                unit = self._get_unit(value) 
    161  
    162                 # I and Q Data 
    163                 if key == u'I': 
    164                     if isinstance(self.current_dataset, plottable_2D): 
    165                         self.current_dataset.data = data_set 
    166                         self.current_dataset.zaxis("Intensity", unit) 
    167                     else: 
    168                         self.current_dataset.y = data_set.flatten() 
    169                         self.current_dataset.yaxis("Intensity", unit) 
    170                     continue 
    171                 elif key == u'Idev': 
    172                     if isinstance(self.current_dataset, plottable_2D): 
    173                         self.current_dataset.err_data = data_set.flatten() 
    174                     else: 
    175                         self.current_dataset.dy = data_set.flatten() 
    176                     continue 
    177                 elif key == u'Q': 
    178                     self.current_dataset.xaxis("Q", unit) 
    179                     if isinstance(self.current_dataset, plottable_2D): 
    180                         self.current_dataset.q = data_set.flatten() 
    181                     else: 
    182                         self.current_dataset.x = data_set.flatten() 
    183                     continue 
    184                 elif key == u'Qdev': 
    185                     self.current_dataset.dx = data_set.flatten() 
    186                     continue 
    187                 elif key == u'dQw': 
    188                     self.current_dataset.dxw = data_set.flatten() 
    189                     continue 
    190                 elif key == u'dQl': 
    191                     self.current_dataset.dxl = data_set.flatten() 
    192                     continue 
    193                 elif key == u'Qy': 
    194                     self.current_dataset.yaxis("Q_y", unit) 
    195                     self.current_dataset.qy_data = data_set.flatten() 
    196                     continue 
    197                 elif key == u'Qydev': 
    198                     self.current_dataset.dqy_data = data_set.flatten() 
    199                     continue 
    200                 elif key == u'Qx': 
    201                     self.current_dataset.xaxis("Q_x", unit) 
    202                     self.current_dataset.qx_data = data_set.flatten() 
    203                     continue 
    204                 elif key == u'Qxdev': 
    205                     self.current_dataset.dqx_data = data_set.flatten() 
    206                     continue 
    207                 elif key == u'Mask': 
    208                     self.current_dataset.mask = data_set.flatten() 
    209                     continue 
    210                 # Transmission Spectrum 
    211                 elif (key == u'T' 
    212                       and self.parent_class == u'SAStransmission_spectrum'): 
    213                     self.trans_spectrum.transmission = data_set.flatten() 
    214                     continue 
    215                 elif (key == u'Tdev' 
    216                       and self.parent_class == u'SAStransmission_spectrum'): 
    217                     self.trans_spectrum.transmission_deviation = \ 
    218                         data_set.flatten() 
    219                     continue 
    220                 elif (key == u'lambda' 
    221                       and self.parent_class == u'SAStransmission_spectrum'): 
    222                     self.trans_spectrum.wavelength = data_set.flatten() 
    223                     continue 
    224168 
    225169                for data_point in data_set: 
     
    231175                    # Top Level Meta Data 
    232176                    if key == u'definition': 
    233                         self.current_datainfo.meta_data['reader'] = data_point 
     177                        if isinstance(data_set, basestring): 
     178                            self.current_datainfo.meta_data['reader'] = data_set 
     179                            break 
     180                        else: 
     181                            self.current_datainfo.meta_data[ 
     182                                'reader'] = data_point 
     183                    # Run 
    234184                    elif key == u'run': 
    235                         self.current_datainfo.run.append(data_point) 
    236185                        try: 
    237186                            run_name = h5attr(value, 'name') 
    238                             run_dict = {data_point: run_name} 
     187                            run_dict = {data_set: run_name} 
    239188                            self.current_datainfo.run_name = run_dict 
    240189                        except Exception: 
    241190                            pass 
     191                        if isinstance(data_set, basestring): 
     192                            self.current_datainfo.run.append(data_set) 
     193                            break 
     194                        else: 
     195                            self.current_datainfo.run.append(data_point) 
     196                    # Title 
    242197                    elif key == u'title': 
    243                         self.current_datainfo.title = data_point 
     198                        if isinstance(data_set, basestring): 
     199                            self.current_datainfo.title = data_set 
     200                            break 
     201                        else: 
     202                            self.current_datainfo.title = data_point 
     203                    # Note 
    244204                    elif key == u'SASnote': 
    245                         self.current_datainfo.notes.append(data_point) 
    246  
     205                        self.current_datainfo.notes.append(data_set) 
     206                        break 
    247207                    # Sample Information 
    248                     # CanSAS 2.0 format 
    249                     elif key == u'Title' and self.parent_class == u'SASsample': 
    250                         self.current_datainfo.sample.name = data_point 
    251                     # NXcanSAS format 
    252                     elif key == u'name' and self.parent_class == u'SASsample': 
    253                         self.current_datainfo.sample.name = data_point 
    254                     # NXcanSAS format 
    255                     elif key == u'ID' and self.parent_class == u'SASsample': 
    256                         self.current_datainfo.sample.name = data_point 
    257                     elif (key == u'thickness' 
    258                           and self.parent_class == u'SASsample'): 
    259                         self.current_datainfo.sample.thickness = data_point 
    260                     elif (key == u'temperature' 
    261                           and self.parent_class == u'SASsample'): 
    262                         self.current_datainfo.sample.temperature = data_point 
    263                     elif (key == u'transmission' 
    264                           and self.parent_class == u'SASsample'): 
    265                         self.current_datainfo.sample.transmission = data_point 
    266                     elif (key == u'x_position' 
    267                           and self.parent_class == u'SASsample'): 
    268                         self.current_datainfo.sample.position.x = data_point 
    269                     elif (key == u'y_position' 
    270                           and self.parent_class == u'SASsample'): 
    271                         self.current_datainfo.sample.position.y = data_point 
    272                     elif key == u'pitch' and self.parent_class == u'SASsample': 
    273                         self.current_datainfo.sample.orientation.x = data_point 
    274                     elif key == u'yaw' and self.parent_class == u'SASsample': 
    275                         self.current_datainfo.sample.orientation.y = data_point 
    276                     elif key == u'roll' and self.parent_class == u'SASsample': 
    277                         self.current_datainfo.sample.orientation.z = data_point 
    278                     elif (key == u'details' 
    279                           and self.parent_class == u'SASsample'): 
    280                         self.current_datainfo.sample.details.append(data_point) 
    281  
     208                    elif self.parent_class == u'SASsample': 
     209                        self.process_sample(data_point, key) 
    282210                    # Instrumental Information 
    283211                    elif (key == u'name' 
    284212                          and self.parent_class == u'SASinstrument'): 
    285213                        self.current_datainfo.instrument = data_point 
    286                     elif key == u'name' and self.parent_class == u'SASdetector': 
    287                         self.detector.name = data_point 
    288                     elif key == u'SDD' and self.parent_class == u'SASdetector': 
    289                         self.detector.distance = float(data_point) 
    290                         self.detector.distance_unit = unit 
    291                     elif (key == u'slit_length' 
    292                           and self.parent_class == u'SASdetector'): 
    293                         self.detector.slit_length = float(data_point) 
    294                         self.detector.slit_length_unit = unit 
    295                     elif (key == u'x_position' 
    296                           and self.parent_class == u'SASdetector'): 
    297                         self.detector.offset.x = float(data_point) 
    298                         self.detector.offset_unit = unit 
    299                     elif (key == u'y_position' 
    300                           and self.parent_class == u'SASdetector'): 
    301                         self.detector.offset.y = float(data_point) 
    302                         self.detector.offset_unit = unit 
    303                     elif (key == u'pitch' 
    304                           and self.parent_class == u'SASdetector'): 
    305                         self.detector.orientation.x = float(data_point) 
    306                         self.detector.orientation_unit = unit 
    307                     elif key == u'roll' and self.parent_class == u'SASdetector': 
    308                         self.detector.orientation.z = float(data_point) 
    309                         self.detector.orientation_unit = unit 
    310                     elif key == u'yaw' and self.parent_class == u'SASdetector': 
    311                         self.detector.orientation.y = float(data_point) 
    312                         self.detector.orientation_unit = unit 
    313                     elif (key == u'beam_center_x' 
    314                           and self.parent_class == u'SASdetector'): 
    315                         self.detector.beam_center.x = float(data_point) 
    316                         self.detector.beam_center_unit = unit 
    317                     elif (key == u'beam_center_y' 
    318                           and self.parent_class == u'SASdetector'): 
    319                         self.detector.beam_center.y = float(data_point) 
    320                         self.detector.beam_center_unit = unit 
    321                     elif (key == u'x_pixel_size' 
    322                           and self.parent_class == u'SASdetector'): 
    323                         self.detector.pixel_size.x = float(data_point) 
    324                         self.detector.pixel_size_unit = unit 
    325                     elif (key == u'y_pixel_size' 
    326                           and self.parent_class == u'SASdetector'): 
    327                         self.detector.pixel_size.y = float(data_point) 
    328                         self.detector.pixel_size_unit = unit 
    329                     elif (key == u'distance' 
    330                           and self.parent_class == u'SAScollimation'): 
    331                         self.collimation.length = data_point 
    332                         self.collimation.length_unit = unit 
    333                     elif (key == u'name' 
    334                           and self.parent_class == u'SAScollimation'): 
    335                         self.collimation.name = data_point 
    336                     elif (key == u'shape' 
    337                           and self.parent_class == u'SASaperture'): 
    338                         self.aperture.shape = data_point 
    339                     elif (key == u'x_gap' 
    340                           and self.parent_class == u'SASaperture'): 
    341                         self.aperture.size.x = data_point 
    342                     elif (key == u'y_gap' 
    343                           and self.parent_class == u'SASaperture'): 
    344                         self.aperture.size.y = data_point 
    345  
     214                    # Detector 
     215                    elif self.parent_class == u'SASdetector': 
     216                        self.process_detector(data_point, key, unit) 
     217                    # Collimation 
     218                    elif self.parent_class == u'SAScollimation': 
     219                        self.process_collimation(data_point, key, unit) 
     220                    # Aperture 
     221                    elif self.parent_class == u'SASaperture': 
     222                        self.process_aperture(data_point, key) 
    346223                    # Process Information 
    347                     elif (key == u'Title' 
    348                           and self.parent_class == u'SASprocess'): # CanSAS 2.0 
    349                         self.process.name = data_point 
    350                     elif (key == u'name' 
    351                           and self.parent_class == u'SASprocess'): # NXcanSAS 
    352                         self.process.name = data_point 
    353                     elif (key == u'description' 
    354                           and self.parent_class == u'SASprocess'): 
    355                         self.process.description = data_point 
    356                     elif key == u'date' and self.parent_class == u'SASprocess': 
    357                         self.process.date = data_point 
    358                     elif key == u'term' and self.parent_class == u'SASprocess': 
    359                         self.process.term = data_point 
    360                     elif self.parent_class == u'SASprocess': 
    361                         self.process.notes.append(data_point) 
    362  
     224                    elif self.parent_class == u'SASprocess': # CanSAS 2.0 
     225                        self.process_process(data_point, key) 
    363226                    # Source 
    364                     elif (key == u'wavelength' 
    365                           and self.parent_class == u'SASdata'): 
    366                         self.current_datainfo.source.wavelength = data_point 
    367                         self.current_datainfo.source.wavelength_unit = unit 
    368                     elif (key == u'incident_wavelength' 
    369                           and self.parent_class == 'SASsource'): 
    370                         self.current_datainfo.source.wavelength = data_point 
    371                         self.current_datainfo.source.wavelength_unit = unit 
    372                     elif (key == u'wavelength_max' 
    373                           and self.parent_class == u'SASsource'): 
    374                         self.current_datainfo.source.wavelength_max = data_point 
    375                         self.current_datainfo.source.wavelength_max_unit = unit 
    376                     elif (key == u'wavelength_min' 
    377                           and self.parent_class == u'SASsource'): 
    378                         self.current_datainfo.source.wavelength_min = data_point 
    379                         self.current_datainfo.source.wavelength_min_unit = unit 
    380                     elif (key == u'incident_wavelength_spread' 
    381                           and self.parent_class == u'SASsource'): 
    382                         self.current_datainfo.source.wavelength_spread = \ 
    383                             data_point 
    384                         self.current_datainfo.source.wavelength_spread_unit = \ 
    385                             unit 
    386                     elif (key == u'beam_size_x' 
    387                           and self.parent_class == u'SASsource'): 
    388                         self.current_datainfo.source.beam_size.x = data_point 
    389                         self.current_datainfo.source.beam_size_unit = unit 
    390                     elif (key == u'beam_size_y' 
    391                           and self.parent_class == u'SASsource'): 
    392                         self.current_datainfo.source.beam_size.y = data_point 
    393                         self.current_datainfo.source.beam_size_unit = unit 
    394                     elif (key == u'beam_shape' 
    395                           and self.parent_class == u'SASsource'): 
    396                         self.current_datainfo.source.beam_shape = data_point 
    397                     elif (key == u'radiation' 
    398                           and self.parent_class == u'SASsource'): 
    399                         self.current_datainfo.source.radiation = data_point 
    400                     elif (key == u'transmission' 
    401                           and self.parent_class == u'SASdata'): 
    402                         self.current_datainfo.sample.transmission = data_point 
    403  
     227                    elif self.parent_class == u'SASsource': 
     228                        self.process_source(data_point, key, unit) 
    404229                    # Everything else goes in meta_data 
     230                    elif self.parent_class == u'SASdata': 
     231                        if isinstance(self.current_dataset, plottable_2D): 
     232                            self.process_2d_data_object(data_set, key, unit) 
     233                        else: 
     234                            self.process_1d_data_object(data_set, key, unit) 
     235 
     236                        break 
     237                    elif self.parent_class == u'SAStransmission_spectrum': 
     238                        self.process_trans_spectrum(data_set, key) 
     239                        break 
    405240                    else: 
    406241                        new_key = self._create_unique_key( 
     
    410245            else: 
    411246                # I don't know if this reachable code 
    412                 self.errors.add("ShouldNeverHappenException") 
     247                self.errors.append("ShouldNeverHappenException") 
     248 
     249    def process_1d_data_object(self, data_set, key, unit): 
     250        """ 
     251        SASdata processor method for 1d data items 
     252        :param data_set: data from HDF5 file 
     253        :param key: canSAS_class attribute 
     254        :param unit: unit attribute 
     255        """ 
     256        if key == self.i_name: 
     257            if self.multi_frame: 
     258                for x in range(0, data_set.shape[0]): 
     259                    self.data_frames.append(data_set[x].flatten()) 
     260            else: 
     261                self.current_dataset.y = data_set.flatten() 
     262                self.current_dataset.yaxis("Intensity", unit) 
     263        elif key == self.i_uncertainties_name: 
     264            if self.multi_frame: 
     265                for x in range(0, data_set.shape[0]): 
     266                    self.data_uncertainty_frames.append(data_set[x].flatten()) 
     267            self.current_dataset.dy = data_set.flatten() 
     268        elif key in self.q_names: 
     269            self.current_dataset.xaxis("Q", unit) 
     270            self.current_dataset.x = data_set.flatten() 
     271        elif key in self.q_resolution_names: 
     272            if (len(self.q_resolution_names) > 1 
     273                    and np.where(self.q_resolution_names == key)[0] == 0): 
     274                self.current_dataset.dxw = data_set.flatten() 
     275            elif (len(self.q_resolution_names) > 1 
     276                  and np.where(self.q_resolution_names == key)[0] == 1): 
     277                self.current_dataset.dxl = data_set.flatten() 
     278            else: 
     279                self.current_dataset.dx = data_set.flatten() 
     280        elif key in self.q_uncertainty_names: 
     281            if (len(self.q_uncertainty_names) > 1 
     282                    and np.where(self.q_uncertainty_names == key)[0] == 0): 
     283                self.current_dataset.dxw = data_set.flatten() 
     284            elif (len(self.q_uncertainty_names) > 1 
     285                  and np.where(self.q_uncertainty_names == key)[0] == 1): 
     286                self.current_dataset.dxl = data_set.flatten() 
     287            else: 
     288                self.current_dataset.dx = data_set.flatten() 
     289        elif key == self.mask_name: 
     290            self.current_dataset.mask = data_set.flatten() 
     291        elif key == u'wavelength': 
     292            self.current_datainfo.source.wavelength = data_set[0] 
     293            self.current_datainfo.source.wavelength_unit = unit 
     294 
     295    def process_2d_data_object(self, data_set, key, unit): 
     296        if key == self.i_name: 
     297            self.current_dataset.data = data_set 
     298            self.current_dataset.zaxis("Intensity", unit) 
     299        elif key == self.i_uncertainties_name: 
     300            self.current_dataset.err_data = data_set.flatten() 
     301        elif key in self.q_names: 
     302            self.current_dataset.xaxis("Q_x", unit) 
     303            self.current_dataset.yaxis("Q_y", unit) 
     304            if self.q_names[0] == self.q_names[1]: 
     305                # All q data in a single array 
     306                self.current_dataset.qx_data = data_set[0] 
     307                self.current_dataset.qy_data = data_set[1] 
     308            elif self.q_names.index(key) == 0: 
     309                self.current_dataset.qx_data = data_set 
     310            elif self.q_names.index(key) == 1: 
     311                self.current_dataset.qy_data = data_set 
     312        elif key in self.q_uncertainty_names or key in self.q_resolution_names: 
     313            if ((self.q_uncertainty_names[0] == self.q_uncertainty_names[1]) or 
     314                    (self.q_resolution_names[0] == self.q_resolution_names[1])): 
     315                # All q data in a single array 
     316                self.current_dataset.dqx_data = data_set[0].flatten() 
     317                self.current_dataset.dqy_data = data_set[1].flatten() 
     318            elif (self.q_uncertainty_names.index(key) == 0 or 
     319                  self.q_resolution_names.index(key) == 0): 
     320                self.current_dataset.dqx_data = data_set.flatten() 
     321            elif (self.q_uncertainty_names.index(key) == 1 or 
     322                  self.q_resolution_names.index(key) == 1): 
     323                self.current_dataset.dqy_data = data_set.flatten() 
     324                self.current_dataset.yaxis("Q_y", unit) 
     325        elif key == self.mask_name: 
     326            self.current_dataset.mask = data_set.flatten() 
     327        elif key == u'Qy': 
     328            self.current_dataset.yaxis("Q_y", unit) 
     329            self.current_dataset.qy_data = data_set.flatten() 
     330        elif key == u'Qydev': 
     331            self.current_dataset.dqy_data = data_set.flatten() 
     332        elif key == u'Qx': 
     333            self.current_dataset.xaxis("Q_x", unit) 
     334            self.current_dataset.qx_data = data_set.flatten() 
     335        elif key == u'Qxdev': 
     336            self.current_dataset.dqx_data = data_set.flatten() 
     337 
     338    def process_trans_spectrum(self, data_set, key): 
     339        """ 
     340        SAStransmission_spectrum processor 
     341        :param data_set: data from HDF5 file 
     342        :param key: canSAS_class attribute 
     343        """ 
     344        if key == u'T': 
     345            self.trans_spectrum.transmission = data_set.flatten() 
     346        elif key == u'Tdev': 
     347            self.trans_spectrum.transmission_deviation = data_set.flatten() 
     348        elif key == u'lambda': 
     349            self.trans_spectrum.wavelength = data_set.flatten() 
     350 
     351    def process_sample(self, data_point, key): 
     352        """ 
     353        SASsample processor 
     354        :param data_point: Single point from an HDF5 data file 
     355        :param key: class name data_point was taken from 
     356        """ 
     357        if key == u'Title': 
     358            self.current_datainfo.sample.name = data_point 
     359        elif key == u'name': 
     360            self.current_datainfo.sample.name = data_point 
     361        elif key == u'ID': 
     362            self.current_datainfo.sample.name = data_point 
     363        elif key == u'thickness': 
     364            self.current_datainfo.sample.thickness = data_point 
     365        elif key == u'temperature': 
     366            self.current_datainfo.sample.temperature = data_point 
     367        elif key == u'transmission': 
     368            self.current_datainfo.sample.transmission = data_point 
     369        elif key == u'x_position': 
     370            self.current_datainfo.sample.position.x = data_point 
     371        elif key == u'y_position': 
     372            self.current_datainfo.sample.position.y = data_point 
     373        elif key == u'pitch': 
     374            self.current_datainfo.sample.orientation.x = data_point 
     375        elif key == u'yaw': 
     376            self.current_datainfo.sample.orientation.y = data_point 
     377        elif key == u'roll': 
     378            self.current_datainfo.sample.orientation.z = data_point 
     379        elif key == u'details': 
     380            self.current_datainfo.sample.details.append(data_point) 
     381 
     382    def process_detector(self, data_point, key, unit): 
     383        """ 
     384        SASdetector processor 
     385        :param data_point: Single point from an HDF5 data file 
     386        :param key: class name data_point was taken from 
     387        :param unit: unit attribute from data set 
     388        """ 
     389        if key == u'name': 
     390            self.detector.name = data_point 
     391        elif key == u'SDD': 
     392            self.detector.distance = float(data_point) 
     393            self.detector.distance_unit = unit 
     394        elif key == u'slit_length': 
     395            self.detector.slit_length = float(data_point) 
     396            self.detector.slit_length_unit = unit 
     397        elif key == u'x_position': 
     398            self.detector.offset.x = float(data_point) 
     399            self.detector.offset_unit = unit 
     400        elif key == u'y_position': 
     401            self.detector.offset.y = float(data_point) 
     402            self.detector.offset_unit = unit 
     403        elif key == u'pitch': 
     404            self.detector.orientation.x = float(data_point) 
     405            self.detector.orientation_unit = unit 
     406        elif key == u'roll': 
     407            self.detector.orientation.z = float(data_point) 
     408            self.detector.orientation_unit = unit 
     409        elif key == u'yaw': 
     410            self.detector.orientation.y = float(data_point) 
     411            self.detector.orientation_unit = unit 
     412        elif key == u'beam_center_x': 
     413            self.detector.beam_center.x = float(data_point) 
     414            self.detector.beam_center_unit = unit 
     415        elif key == u'beam_center_y': 
     416            self.detector.beam_center.y = float(data_point) 
     417            self.detector.beam_center_unit = unit 
     418        elif key == u'x_pixel_size': 
     419            self.detector.pixel_size.x = float(data_point) 
     420            self.detector.pixel_size_unit = unit 
     421        elif key == u'y_pixel_size': 
     422            self.detector.pixel_size.y = float(data_point) 
     423            self.detector.pixel_size_unit = unit 
     424 
     425    def process_collimation(self, data_point, key, unit): 
     426        """ 
     427        SAScollimation processor 
     428        :param data_point: Single point from an HDF5 data file 
     429        :param key: class name data_point was taken from 
     430        :param unit: unit attribute from data set 
     431        """ 
     432        if key == u'distance': 
     433            self.collimation.length = data_point 
     434            self.collimation.length_unit = unit 
     435        elif key == u'name': 
     436            self.collimation.name = data_point 
     437 
     438    def process_aperture(self, data_point, key): 
     439        """ 
     440        SASaperture processor 
     441        :param data_point: Single point from an HDF5 data file 
     442        :param key: class name data_point was taken from 
     443        """ 
     444        if key == u'shape': 
     445            self.aperture.shape = data_point 
     446        elif key == u'x_gap': 
     447            self.aperture.size.x = data_point 
     448        elif key == u'y_gap': 
     449            self.aperture.size.y = data_point 
     450 
     451    def process_source(self, data_point, key, unit): 
     452        """ 
     453        SASsource processor 
     454        :param data_point: Single point from an HDF5 data file 
     455        :param key: class name data_point was taken from 
     456        :param unit: unit attribute from data set 
     457        """ 
     458        if key == u'incident_wavelength': 
     459            self.current_datainfo.source.wavelength = data_point 
     460            self.current_datainfo.source.wavelength_unit = unit 
     461        elif key == u'wavelength_max': 
     462            self.current_datainfo.source.wavelength_max = data_point 
     463            self.current_datainfo.source.wavelength_max_unit = unit 
     464        elif key == u'wavelength_min': 
     465            self.current_datainfo.source.wavelength_min = data_point 
     466            self.current_datainfo.source.wavelength_min_unit = unit 
     467        elif key == u'incident_wavelength_spread': 
     468            self.current_datainfo.source.wavelength_spread = data_point 
     469            self.current_datainfo.source.wavelength_spread_unit = unit 
     470        elif key == u'beam_size_x': 
     471            self.current_datainfo.source.beam_size.x = data_point 
     472            self.current_datainfo.source.beam_size_unit = unit 
     473        elif key == u'beam_size_y': 
     474            self.current_datainfo.source.beam_size.y = data_point 
     475            self.current_datainfo.source.beam_size_unit = unit 
     476        elif key == u'beam_shape': 
     477            self.current_datainfo.source.beam_shape = data_point 
     478        elif key == u'radiation': 
     479            self.current_datainfo.source.radiation = data_point 
     480 
     481    def process_process(self, data_point, key): 
     482        """ 
     483        SASprocess processor 
     484        :param data_point: Single point from an HDF5 data file 
     485        :param key: class name data_point was taken from 
     486        """ 
     487        term_match = re.compile(u'^term[0-9]+$') 
     488        if key == u'Title':  # CanSAS 2.0 
     489            self.process.name = data_point 
     490        elif key == u'name':  # NXcanSAS 
     491            self.process.name = data_point 
     492        elif key == u'description': 
     493            self.process.description = data_point 
     494        elif key == u'date': 
     495            self.process.date = data_point 
     496        elif term_match.match(key): 
     497            self.process.term.append(data_point) 
     498        else: 
     499            self.process.notes.append(data_point) 
    413500 
    414501    def add_intermediate(self): 
     
    440527                self.data2d.append(self.current_dataset) 
    441528            elif isinstance(self.current_dataset, plottable_1D): 
    442                 self.data1d.append(self.current_dataset) 
     529                if self.multi_frame: 
     530                    for x in range(0, len(self.data_frames)): 
     531                        self.current_dataset.y = self.data_frames[x] 
     532                        if len(self.data_uncertainty_frames) > x: 
     533                            self.current_dataset.dy = \ 
     534                                self.data_uncertainty_frames[x] 
     535                        self.data1d.append(self.current_dataset) 
     536                else: 
     537                    self.data1d.append(self.current_dataset) 
    443538 
    444539    def final_data_cleanup(self): 
     
    452547            spectrum_list = [] 
    453548            for spectrum in self.current_datainfo.trans_spectrum: 
    454                 spectrum.transmission = np.delete(spectrum.transmission, [0]) 
    455549                spectrum.transmission = spectrum.transmission.astype(np.float64) 
    456                 spectrum.transmission_deviation = np.delete( 
    457                     spectrum.transmission_deviation, [0]) 
    458550                spectrum.transmission_deviation = \ 
    459551                    spectrum.transmission_deviation.astype(np.float64) 
    460                 spectrum.wavelength = np.delete(spectrum.wavelength, [0]) 
    461552                spectrum.wavelength = spectrum.wavelength.astype(np.float64) 
    462553                if len(spectrum.transmission) > 0: 
     
    466557        # Append errors to dataset and reset class errors 
    467558        self.current_datainfo.errors = self.errors 
    468         self.errors.clear() 
     559        self.errors = [] 
    469560 
    470561        # Combine all plottables with datainfo and append each to output 
     
    476567                    zeros[i] = dataset.mask[i] 
    477568            except: 
    478                 self.errors.add(sys.exc_value) 
     569                self.errors.append(sys.exc_value) 
    479570            dataset.mask = zeros 
    480571            # Calculate the actual Q matrix 
     
    490581            if dataset.data.ndim == 2: 
    491582                (n_rows, n_cols) = dataset.data.shape 
    492                 dataset.y_bins = dataset.qy_data[0::n_cols] 
    493                 dataset.x_bins = dataset.qx_data[:n_cols] 
     583                flat_qy = dataset.qy_data[0::n_cols].flatten() 
     584                # For 2D arrays of Qx and Qy, the Q value should be constant 
     585                # along each row -OR- each column. The direction is not 
     586                # specified in the NXcanSAS standard. 
     587                if flat_qy[0] == flat_qy[1]: 
     588                    flat_qy = np.transpose(dataset.qy_data)[0::n_cols].flatten() 
     589                dataset.y_bins = np.unique(flat_qy) 
     590                flat_qx = dataset.qx_data[0::n_rows].flatten() 
     591                # For 2D arrays of Qx and Qy, the Q value should be constant 
     592                # along each row -OR- each column. The direction is not 
     593                # specified in the NXcanSAS standard. 
     594                if flat_qx[0] == flat_qx[1]: 
     595                    flat_qx = np.transpose(dataset.qx_data)[0::n_rows].flatten() 
     596                dataset.x_bins = np.unique(flat_qx) 
    494597                dataset.data = dataset.data.flatten() 
     598                dataset.qx_data = dataset.qx_data.flatten() 
     599                dataset.qy_data = dataset.qy_data.flatten() 
    495600            self.current_dataset = dataset 
    496601            self.send_to_output() 
     
    511616        if self.current_datainfo and self.current_dataset: 
    512617            self.final_data_cleanup() 
     618        self.data_frames = [] 
     619        self.data_uncertainty_frames = [] 
    513620        self.data1d = [] 
    514621        self.data2d = [] 
    515622        self.current_datainfo = DataInfo() 
    516623 
    517  
    518     def _initialize_new_data_set(self, parent_list=None): 
     624    def _initialize_new_data_set(self, value=None): 
    519625        """ 
    520626        A private class method to generate a new 1D or 2D data object based on 
     
    524630        :param parent_list: List of names of parent elements 
    525631        """ 
    526  
    527         if parent_list is None: 
    528             parent_list = [] 
    529         if self._find_intermediate(parent_list, "Qx"): 
     632        if self._is2d(value): 
    530633            self.current_dataset = plottable_2D() 
    531634        else: 
     
    535638        self.current_datainfo.filename = self.raw_data.filename 
    536639 
    537     def _find_intermediate(self, parent_list, basename=""): 
    538         """ 
    539         A private class used to find an entry by either using a direct key or 
    540         knowing the approximate basename. 
    541  
    542         :param parent_list: List of parents nodes in the HDF5 file 
     640    @staticmethod 
     641    def check_is_list_or_array(iterable): 
     642        try: 
     643            iter(iterable) 
     644            if (not isinstance(iterable, np.ndarray) and not isinstance( 
     645                    iterable, list)) or (isinstance(iterable, basestring)): 
     646                raise TypeError 
     647        except TypeError: 
     648            if isinstance(iterable, basestring): 
     649                iterable = iterable.split(",") 
     650            else: 
     651                iterable = [iterable] 
     652        return iterable 
     653 
     654    def _find_data_attributes(self, value): 
     655        """ 
     656        A class to find the indices for Q, the name of the Qdev and Idev, and 
     657        the name of the mask. 
     658        :param value: SASdata/NXdata HDF5 Group 
     659        """ 
     660        # Initialize values to base types 
     661        self.mask_name = u'' 
     662        self.i_name = u'' 
     663        self.i_node = u'' 
     664        self.i_uncertainties_name = u'' 
     665        self.q_names = [] 
     666        self.q_uncertainty_names = [] 
     667        self.q_resolution_names = [] 
     668        # Get attributes 
     669        attrs = value.attrs 
     670        signal = attrs.get("signal", "I") 
     671        i_axes = attrs.get("I_axes", ["Q"]) 
     672        q_indices = attrs.get("Q_indices", [0]) 
     673        q_indices = map(int, self.check_is_list_or_array(q_indices)) 
     674        i_axes = self.check_is_list_or_array(i_axes) 
     675        keys = value.keys() 
     676        # Assign attributes to appropriate class variables 
     677        self.mask_name = attrs.get("mask") 
     678        for val in q_indices: 
     679            self.q_names.append(i_axes[val]) 
     680        self.i_name = signal 
     681        self.i_node = value.get(self.i_name) 
     682        for item in self.q_names: 
     683            if item in keys: 
     684                q_vals = value.get(item) 
     685                if q_vals.attrs.get("uncertainties") is not None: 
     686                    self.q_uncertainty_names = q_vals.attrs.get("uncertainties") 
     687                elif q_vals.attrs.get("uncertainty") is not None: 
     688                    self.q_uncertainty_names = q_vals.attrs.get("uncertainty") 
     689                if isinstance(self.q_uncertainty_names, basestring): 
     690                    self.q_uncertainty_names = self.q_uncertainty_names.split(",") 
     691                if q_vals.attrs.get("resolutions") is not None: 
     692                    self.q_resolution_names = q_vals.attrs.get("resolutions") 
     693                if isinstance(self.q_resolution_names, basestring): 
     694                    self.q_resolution_names = self.q_resolution_names.split(",") 
     695        if self.i_name in keys: 
     696            i_vals = value.get(self.i_name) 
     697            self.i_uncertainties_name = i_vals.attrs.get("uncertainties") 
     698            if self.i_uncertainties_name is None: 
     699                self.i_uncertainties_name = i_vals.attrs.get("uncertainty") 
     700 
     701    def _is2d(self, value, i_base="", q_base=[]): 
     702        """ 
     703        A private class to determine if the data set is 1d or 2d. 
     704 
     705        :param value: Nexus/NXcanSAS data group 
    543706        :param basename: Approximate name of an entry to search for 
    544         :return: 
    545         """ 
    546  
    547         entry = False 
    548         key_prog = re.compile(basename) 
    549         top = self.raw_data 
    550         for parent in parent_list: 
    551             top = top.get(parent) 
    552         for key in top.keys(): 
    553             if key_prog.match(key): 
    554                 entry = True 
    555                 break 
    556         return entry 
     707        :return: True if 2D, otherwise false 
     708        """ 
     709        i_basename = i_base if i_base != "" else self.i_name 
     710        i_vals = value.get(i_basename) 
     711        q_basename = q_base if q_base != [] else self.q_names 
     712        q_vals = value.get(q_basename[0]) 
     713        self.multi_frame = True if (i_vals is not None and q_vals is not None 
     714                                    and len(i_vals.shape) != 1 
     715                                    and len(q_vals.shape) == 1) else False 
     716        return (i_vals is not None and i_vals.shape is not None 
     717                and len(i_vals.shape) != 1 and not self.multi_frame) 
    557718 
    558719    def _create_unique_key(self, dictionary, name, numb=0): 
     
    583744        if unit is None: 
    584745            unit = h5attr(value, u'unit') 
    585         # Convert the unit formats 
    586         if unit == "1/A": 
    587             unit = "A^{-1}" 
    588         elif unit == "1/cm": 
    589             unit = "cm^{-1}" 
    590746        return unit 
Note: See TracChangeset for help on using the changeset viewer.