Changeset 4cbb2f5 in sasview for src/sas/sascalc/dataloader/readers


Ignore:
Timestamp:
Feb 21, 2019 5:23:13 PM (6 years ago)
Author:
Paul Kienzle <pkienzle@…>
Branches:
master, magnetic_scatt, release-4.2.2, ticket-1009, ticket-1094-headless, ticket-1242-2d-resolution, ticket-1249
Children:
1342f6a, dbfd307
Parents:
e4e9162
Message:

pull conflicting changes from master

File:
1 edited

Legend:

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

    re090ba90 r4cbb2f5  
    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 
     17try: 
     18  basestring 
     19except NameError:  # CRUFT: python 2 support 
     20  basestring = str 
     21 
     22 
    1823def h5attr(node, key, default=None): 
    1924    return decode(node.attrs.get(key, default)) 
    2025 
     26 
    2127class Reader(FileReader): 
    2228    """ 
    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 
     29    A class for reading in NXcanSAS data files. The current implementation has 
     30    been tested to load data generated by multiple facilities, all of which are 
     31    known to produce NXcanSAS standards compliant data. Any number of data sets 
     32    may be present within the file and any dimensionality of data may be used. 
     33    Currently 1D and 2D SAS data sets are supported, but should be immediately 
     34    extensible to SESANS data. 
     35 
     36    Any number of SASdata groups  may be present in a SASentry and the data 
     37    within each SASdata group can be a single 1D I(Q), multi-framed 1D I(Q), 
     38    2D I(Qx, Qy) or multi-framed 2D I(Qx, Qy). 
    3339 
    3440    :Dependencies: 
    35         The CanSAS HDF5 reader requires h5py => v2.5.0 or later. 
     41        The NXcanSAS HDF5 reader requires h5py => v2.5.0 or later. 
    3642    """ 
    3743 
    3844    # CanSAS version 
    3945    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 
    5046    # Data type name 
    51     type_name = "CanSAS 2.0" 
     47    type_name = "NXcanSAS" 
    5248    # Wildcards 
    53     type = ["CanSAS 2.0 HDF5 Files (*.h5)|*.h5"] 
     49    type = ["NXcanSAS HDF5 Files (*.h5)|*.h5|"] 
    5450    # List of allowed extensions 
    5551    ext = ['.h5', '.H5'] 
     
    8177                except Exception as e: 
    8278                    if extension not in self.ext: 
    83                         msg = "CanSAS2.0 HDF5 Reader could not load file {}".format(basename + extension) 
     79                        msg = "NXcanSAS Reader could not load file {}".format( 
     80                            basename + extension) 
    8481                        raise DefaultReaderException(msg) 
    8582                    raise FileContentsException(e.message) 
     
    9592                    self.raw_data.close() 
    9693 
    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.") 
     94                for data_set in self.output: 
     95                    if isinstance(data_set, Data1D): 
     96                        if data_set.x.size < 5: 
     97                            exception = FileContentsException( 
     98                                "Fewer than 5 data points found.") 
     99                            data_set.errors.append(exception) 
    102100 
    103101    def reset_state(self): 
     
    109107        self.data2d = [] 
    110108        self.raw_data = None 
    111         self.errors = set() 
     109        self.multi_frame = False 
     110        self.data_frames = [] 
     111        self.data_uncertainty_frames = [] 
     112        self.errors = [] 
    112113        self.logging = [] 
     114        self.q_names = [] 
     115        self.mask_name = u'' 
     116        self.i_name = u'' 
     117        self.i_node = u'' 
     118        self.i_uncertainties_name = u'' 
     119        self.q_uncertainty_names = [] 
     120        self.q_resolution_names = [] 
    113121        self.parent_class = u'' 
    114122        self.detector = Detector() 
     
    131139            value = data.get(key) 
    132140            class_name = h5attr(value, u'canSAS_class') 
     141            if isinstance(class_name, (list, tuple, np.ndarray)): 
     142                class_name = class_name[0] 
    133143            if class_name is None: 
    134144                class_name = h5attr(value, u'NX_class') 
     
    140150            if isinstance(value, h5py.Group): 
    141151                # Set parent class before recursion 
     152                last_parent_class = self.parent_class 
    142153                self.parent_class = class_name 
    143154                parent_list.append(key) 
     
    147158                    self.add_data_set(key) 
    148159                elif class_prog.match(u'SASdata'): 
    149                     self._initialize_new_data_set(parent_list) 
     160                    self._find_data_attributes(value) 
     161                    self._initialize_new_data_set(value) 
    150162                # Recursion step to access data within the group 
    151163                self.read_children(value, parent_list) 
     164                self.add_intermediate() 
    152165                # Reset parent class when returning from recursive method 
    153                 self.parent_class = class_name 
    154                 self.add_intermediate() 
     166                self.parent_class = last_parent_class 
    155167                parent_list.remove(key) 
    156168 
    157169            elif isinstance(value, h5py.Dataset): 
    158170                # If this is a dataset, store the data appropriately 
    159                 data_set = data[key][:] 
     171                data_set = value.value 
    160172                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 
    224173 
    225174                for data_point in data_set: 
     
    231180                    # Top Level Meta Data 
    232181                    if key == u'definition': 
    233                         self.current_datainfo.meta_data['reader'] = data_point 
     182                        if isinstance(data_set, basestring): 
     183                            self.current_datainfo.meta_data['reader'] = data_set 
     184                            break 
     185                        else: 
     186                            self.current_datainfo.meta_data[ 
     187                                'reader'] = data_point 
     188                    # Run 
    234189                    elif key == u'run': 
    235                         self.current_datainfo.run.append(data_point) 
    236190                        try: 
    237191                            run_name = h5attr(value, 'name') 
    238                             run_dict = {data_point: run_name} 
     192                            run_dict = {data_set: run_name} 
    239193                            self.current_datainfo.run_name = run_dict 
    240194                        except Exception: 
    241195                            pass 
     196                        if isinstance(data_set, basestring): 
     197                            self.current_datainfo.run.append(data_set) 
     198                            break 
     199                        else: 
     200                            self.current_datainfo.run.append(data_point) 
     201                    # Title 
    242202                    elif key == u'title': 
    243                         self.current_datainfo.title = data_point 
     203                        if isinstance(data_set, basestring): 
     204                            self.current_datainfo.title = data_set 
     205                            break 
     206                        else: 
     207                            self.current_datainfo.title = data_point 
     208                    # Note 
    244209                    elif key == u'SASnote': 
    245                         self.current_datainfo.notes.append(data_point) 
    246  
     210                        self.current_datainfo.notes.append(data_set) 
     211                        break 
    247212                    # 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  
     213                    elif self.parent_class == u'SASsample': 
     214                        self.process_sample(data_point, key) 
    282215                    # Instrumental Information 
    283216                    elif (key == u'name' 
    284217                          and self.parent_class == u'SASinstrument'): 
    285218                        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  
     219                    # Detector 
     220                    elif self.parent_class == u'SASdetector': 
     221                        self.process_detector(data_point, key, unit) 
     222                    # Collimation 
     223                    elif self.parent_class == u'SAScollimation': 
     224                        self.process_collimation(data_point, key, unit) 
     225                    # Aperture 
     226                    elif self.parent_class == u'SASaperture': 
     227                        self.process_aperture(data_point, key) 
    346228                    # 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  
     229                    elif self.parent_class == u'SASprocess': # CanSAS 2.0 
     230                        self.process_process(data_point, key) 
    363231                    # 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  
     232                    elif self.parent_class == u'SASsource': 
     233                        self.process_source(data_point, key, unit) 
    404234                    # Everything else goes in meta_data 
     235                    elif self.parent_class == u'SASdata': 
     236                        if isinstance(self.current_dataset, plottable_2D): 
     237                            self.process_2d_data_object(data_set, key, unit) 
     238                        else: 
     239                            self.process_1d_data_object(data_set, key, unit) 
     240 
     241                        break 
     242                    elif self.parent_class == u'SAStransmission_spectrum': 
     243                        self.process_trans_spectrum(data_set, key) 
     244                        break 
    405245                    else: 
    406246                        new_key = self._create_unique_key( 
     
    410250            else: 
    411251                # I don't know if this reachable code 
    412                 self.errors.add("ShouldNeverHappenException") 
     252                self.errors.append("ShouldNeverHappenException") 
     253 
     254    def process_1d_data_object(self, data_set, key, unit): 
     255        """ 
     256        SASdata processor method for 1d data items 
     257        :param data_set: data from HDF5 file 
     258        :param key: canSAS_class attribute 
     259        :param unit: unit attribute 
     260        """ 
     261        if key == self.i_name: 
     262            if self.multi_frame: 
     263                for x in range(0, data_set.shape[0]): 
     264                    self.data_frames.append(data_set[x].flatten()) 
     265            else: 
     266                self.current_dataset.y = data_set.flatten() 
     267                self.current_dataset.yaxis("Intensity", unit) 
     268        elif key == self.i_uncertainties_name: 
     269            if self.multi_frame: 
     270                for x in range(0, data_set.shape[0]): 
     271                    self.data_uncertainty_frames.append(data_set[x].flatten()) 
     272            self.current_dataset.dy = data_set.flatten() 
     273        elif key in self.q_names: 
     274            self.current_dataset.xaxis("Q", unit) 
     275            self.current_dataset.x = data_set.flatten() 
     276        elif key in self.q_resolution_names: 
     277            if (len(self.q_resolution_names) > 1 
     278                    and np.where(self.q_resolution_names == key)[0] == 0): 
     279                self.current_dataset.dxw = data_set.flatten() 
     280            elif (len(self.q_resolution_names) > 1 
     281                  and np.where(self.q_resolution_names == key)[0] == 1): 
     282                self.current_dataset.dxl = data_set.flatten() 
     283            else: 
     284                self.current_dataset.dx = data_set.flatten() 
     285        elif key in self.q_uncertainty_names: 
     286            if (len(self.q_uncertainty_names) > 1 
     287                    and np.where(self.q_uncertainty_names == key)[0] == 0): 
     288                self.current_dataset.dxw = data_set.flatten() 
     289            elif (len(self.q_uncertainty_names) > 1 
     290                  and np.where(self.q_uncertainty_names == key)[0] == 1): 
     291                self.current_dataset.dxl = data_set.flatten() 
     292            else: 
     293                self.current_dataset.dx = data_set.flatten() 
     294        elif key == self.mask_name: 
     295            self.current_dataset.mask = data_set.flatten() 
     296        elif key == u'wavelength': 
     297            self.current_datainfo.source.wavelength = data_set[0] 
     298            self.current_datainfo.source.wavelength_unit = unit 
     299 
     300    def process_2d_data_object(self, data_set, key, unit): 
     301        if key == self.i_name: 
     302            self.current_dataset.data = data_set 
     303            self.current_dataset.zaxis("Intensity", unit) 
     304        elif key == self.i_uncertainties_name: 
     305            self.current_dataset.err_data = data_set.flatten() 
     306        elif key in self.q_names: 
     307            self.current_dataset.xaxis("Q_x", unit) 
     308            self.current_dataset.yaxis("Q_y", unit) 
     309            if self.q_names[0] == self.q_names[1]: 
     310                # All q data in a single array 
     311                self.current_dataset.qx_data = data_set[0] 
     312                self.current_dataset.qy_data = data_set[1] 
     313            elif self.q_names.index(key) == 0: 
     314                self.current_dataset.qx_data = data_set 
     315            elif self.q_names.index(key) == 1: 
     316                self.current_dataset.qy_data = data_set 
     317        elif key in self.q_uncertainty_names or key in self.q_resolution_names: 
     318            if ((self.q_uncertainty_names[0] == self.q_uncertainty_names[1]) or 
     319                    (self.q_resolution_names[0] == self.q_resolution_names[1])): 
     320                # All q data in a single array 
     321                self.current_dataset.dqx_data = data_set[0].flatten() 
     322                self.current_dataset.dqy_data = data_set[1].flatten() 
     323            elif (self.q_uncertainty_names.index(key) == 0 or 
     324                  self.q_resolution_names.index(key) == 0): 
     325                self.current_dataset.dqx_data = data_set.flatten() 
     326            elif (self.q_uncertainty_names.index(key) == 1 or 
     327                  self.q_resolution_names.index(key) == 1): 
     328                self.current_dataset.dqy_data = data_set.flatten() 
     329                self.current_dataset.yaxis("Q_y", unit) 
     330        elif key == self.mask_name: 
     331            self.current_dataset.mask = data_set.flatten() 
     332        elif key == u'Qy': 
     333            self.current_dataset.yaxis("Q_y", unit) 
     334            self.current_dataset.qy_data = data_set.flatten() 
     335        elif key == u'Qydev': 
     336            self.current_dataset.dqy_data = data_set.flatten() 
     337        elif key == u'Qx': 
     338            self.current_dataset.xaxis("Q_x", unit) 
     339            self.current_dataset.qx_data = data_set.flatten() 
     340        elif key == u'Qxdev': 
     341            self.current_dataset.dqx_data = data_set.flatten() 
     342 
     343    def process_trans_spectrum(self, data_set, key): 
     344        """ 
     345        SAStransmission_spectrum processor 
     346        :param data_set: data from HDF5 file 
     347        :param key: canSAS_class attribute 
     348        """ 
     349        if key == u'T': 
     350            self.trans_spectrum.transmission = data_set.flatten() 
     351        elif key == u'Tdev': 
     352            self.trans_spectrum.transmission_deviation = data_set.flatten() 
     353        elif key == u'lambda': 
     354            self.trans_spectrum.wavelength = data_set.flatten() 
     355 
     356    def process_sample(self, data_point, key): 
     357        """ 
     358        SASsample processor 
     359        :param data_point: Single point from an HDF5 data file 
     360        :param key: class name data_point was taken from 
     361        """ 
     362        if key == u'Title': 
     363            self.current_datainfo.sample.name = data_point 
     364        elif key == u'name': 
     365            self.current_datainfo.sample.name = data_point 
     366        elif key == u'ID': 
     367            self.current_datainfo.sample.name = data_point 
     368        elif key == u'thickness': 
     369            self.current_datainfo.sample.thickness = data_point 
     370        elif key == u'temperature': 
     371            self.current_datainfo.sample.temperature = data_point 
     372        elif key == u'transmission': 
     373            self.current_datainfo.sample.transmission = data_point 
     374        elif key == u'x_position': 
     375            self.current_datainfo.sample.position.x = data_point 
     376        elif key == u'y_position': 
     377            self.current_datainfo.sample.position.y = data_point 
     378        elif key == u'pitch': 
     379            self.current_datainfo.sample.orientation.x = data_point 
     380        elif key == u'yaw': 
     381            self.current_datainfo.sample.orientation.y = data_point 
     382        elif key == u'roll': 
     383            self.current_datainfo.sample.orientation.z = data_point 
     384        elif key == u'details': 
     385            self.current_datainfo.sample.details.append(data_point) 
     386 
     387    def process_detector(self, data_point, key, unit): 
     388        """ 
     389        SASdetector processor 
     390        :param data_point: Single point from an HDF5 data file 
     391        :param key: class name data_point was taken from 
     392        :param unit: unit attribute from data set 
     393        """ 
     394        if key == u'name': 
     395            self.detector.name = data_point 
     396        elif key == u'SDD': 
     397            self.detector.distance = float(data_point) 
     398            self.detector.distance_unit = unit 
     399        elif key == u'slit_length': 
     400            self.detector.slit_length = float(data_point) 
     401            self.detector.slit_length_unit = unit 
     402        elif key == u'x_position': 
     403            self.detector.offset.x = float(data_point) 
     404            self.detector.offset_unit = unit 
     405        elif key == u'y_position': 
     406            self.detector.offset.y = float(data_point) 
     407            self.detector.offset_unit = unit 
     408        elif key == u'pitch': 
     409            self.detector.orientation.x = float(data_point) 
     410            self.detector.orientation_unit = unit 
     411        elif key == u'roll': 
     412            self.detector.orientation.z = float(data_point) 
     413            self.detector.orientation_unit = unit 
     414        elif key == u'yaw': 
     415            self.detector.orientation.y = float(data_point) 
     416            self.detector.orientation_unit = unit 
     417        elif key == u'beam_center_x': 
     418            self.detector.beam_center.x = float(data_point) 
     419            self.detector.beam_center_unit = unit 
     420        elif key == u'beam_center_y': 
     421            self.detector.beam_center.y = float(data_point) 
     422            self.detector.beam_center_unit = unit 
     423        elif key == u'x_pixel_size': 
     424            self.detector.pixel_size.x = float(data_point) 
     425            self.detector.pixel_size_unit = unit 
     426        elif key == u'y_pixel_size': 
     427            self.detector.pixel_size.y = float(data_point) 
     428            self.detector.pixel_size_unit = unit 
     429 
     430    def process_collimation(self, data_point, key, unit): 
     431        """ 
     432        SAScollimation processor 
     433        :param data_point: Single point from an HDF5 data file 
     434        :param key: class name data_point was taken from 
     435        :param unit: unit attribute from data set 
     436        """ 
     437        if key == u'distance': 
     438            self.collimation.length = data_point 
     439            self.collimation.length_unit = unit 
     440        elif key == u'name': 
     441            self.collimation.name = data_point 
     442 
     443    def process_aperture(self, data_point, key): 
     444        """ 
     445        SASaperture processor 
     446        :param data_point: Single point from an HDF5 data file 
     447        :param key: class name data_point was taken from 
     448        """ 
     449        if key == u'shape': 
     450            self.aperture.shape = data_point 
     451        elif key == u'x_gap': 
     452            self.aperture.size.x = data_point 
     453        elif key == u'y_gap': 
     454            self.aperture.size.y = data_point 
     455 
     456    def process_source(self, data_point, key, unit): 
     457        """ 
     458        SASsource processor 
     459        :param data_point: Single point from an HDF5 data file 
     460        :param key: class name data_point was taken from 
     461        :param unit: unit attribute from data set 
     462        """ 
     463        if key == u'incident_wavelength': 
     464            self.current_datainfo.source.wavelength = data_point 
     465            self.current_datainfo.source.wavelength_unit = unit 
     466        elif key == u'wavelength_max': 
     467            self.current_datainfo.source.wavelength_max = data_point 
     468            self.current_datainfo.source.wavelength_max_unit = unit 
     469        elif key == u'wavelength_min': 
     470            self.current_datainfo.source.wavelength_min = data_point 
     471            self.current_datainfo.source.wavelength_min_unit = unit 
     472        elif key == u'incident_wavelength_spread': 
     473            self.current_datainfo.source.wavelength_spread = data_point 
     474            self.current_datainfo.source.wavelength_spread_unit = unit 
     475        elif key == u'beam_size_x': 
     476            self.current_datainfo.source.beam_size.x = data_point 
     477            self.current_datainfo.source.beam_size_unit = unit 
     478        elif key == u'beam_size_y': 
     479            self.current_datainfo.source.beam_size.y = data_point 
     480            self.current_datainfo.source.beam_size_unit = unit 
     481        elif key == u'beam_shape': 
     482            self.current_datainfo.source.beam_shape = data_point 
     483        elif key == u'radiation': 
     484            self.current_datainfo.source.radiation = data_point 
     485 
     486    def process_process(self, data_point, key): 
     487        """ 
     488        SASprocess processor 
     489        :param data_point: Single point from an HDF5 data file 
     490        :param key: class name data_point was taken from 
     491        """ 
     492        term_match = re.compile(u'^term[0-9]+$') 
     493        if key == u'Title':  # CanSAS 2.0 
     494            self.process.name = data_point 
     495        elif key == u'name':  # NXcanSAS 
     496            self.process.name = data_point 
     497        elif key == u'description': 
     498            self.process.description = data_point 
     499        elif key == u'date': 
     500            self.process.date = data_point 
     501        elif term_match.match(key): 
     502            self.process.term.append(data_point) 
     503        else: 
     504            self.process.notes.append(data_point) 
    413505 
    414506    def add_intermediate(self): 
     
    440532                self.data2d.append(self.current_dataset) 
    441533            elif isinstance(self.current_dataset, plottable_1D): 
    442                 self.data1d.append(self.current_dataset) 
     534                if self.multi_frame: 
     535                    for x in range(0, len(self.data_frames)): 
     536                        self.current_dataset.y = self.data_frames[x] 
     537                        if len(self.data_uncertainty_frames) > x: 
     538                            self.current_dataset.dy = \ 
     539                                self.data_uncertainty_frames[x] 
     540                        self.data1d.append(self.current_dataset) 
     541                else: 
     542                    self.data1d.append(self.current_dataset) 
    443543 
    444544    def final_data_cleanup(self): 
     
    452552            spectrum_list = [] 
    453553            for spectrum in self.current_datainfo.trans_spectrum: 
    454                 spectrum.transmission = np.delete(spectrum.transmission, [0]) 
    455554                spectrum.transmission = spectrum.transmission.astype(np.float64) 
    456                 spectrum.transmission_deviation = np.delete( 
    457                     spectrum.transmission_deviation, [0]) 
    458555                spectrum.transmission_deviation = \ 
    459556                    spectrum.transmission_deviation.astype(np.float64) 
    460                 spectrum.wavelength = np.delete(spectrum.wavelength, [0]) 
    461557                spectrum.wavelength = spectrum.wavelength.astype(np.float64) 
    462558                if len(spectrum.transmission) > 0: 
     
    466562        # Append errors to dataset and reset class errors 
    467563        self.current_datainfo.errors = self.errors 
    468         self.errors.clear() 
     564        self.errors = [] 
    469565 
    470566        # Combine all plottables with datainfo and append each to output 
    471567        # Type cast data arrays to float64 and find min/max as appropriate 
    472568        for dataset in self.data2d: 
    473             zeros = np.ones(dataset.data.size, dtype=bool) 
    474             try: 
    475                 for i in range(0, dataset.mask.size - 1): 
    476                     zeros[i] = dataset.mask[i] 
    477             except Exception as exc: 
    478                 self.errors.add(exc) 
    479             dataset.mask = zeros 
    480569            # Calculate the actual Q matrix 
    481570            try: 
     
    484573                                             * dataset.qx_data 
    485574                                             + dataset.qy_data 
    486                                              * dataset.qy_data) 
     575                                             * dataset.qy_data).flatten() 
    487576            except: 
    488577                dataset.q_data = None 
    489578 
    490579            if dataset.data.ndim == 2: 
    491                 (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] 
     580                dataset.y_bins = np.unique(dataset.qy_data.flatten()) 
     581                dataset.x_bins = np.unique(dataset.qx_data.flatten()) 
    494582                dataset.data = dataset.data.flatten() 
     583                dataset.qx_data = dataset.qx_data.flatten() 
     584                dataset.qy_data = dataset.qy_data.flatten() 
     585 
     586            try: 
     587                iter(dataset.mask) 
     588                dataset.mask = np.invert(np.asarray(dataset.mask, dtype=bool)) 
     589            except TypeError: 
     590                dataset.mask = np.ones(dataset.data.shape, dtype=bool) 
    495591            self.current_dataset = dataset 
    496592            self.send_to_output() 
     
    511607        if self.current_datainfo and self.current_dataset: 
    512608            self.final_data_cleanup() 
     609        self.data_frames = [] 
     610        self.data_uncertainty_frames = [] 
    513611        self.data1d = [] 
    514612        self.data2d = [] 
    515613        self.current_datainfo = DataInfo() 
    516614 
    517  
    518     def _initialize_new_data_set(self, parent_list=None): 
     615    def _initialize_new_data_set(self, value=None): 
    519616        """ 
    520617        A private class method to generate a new 1D or 2D data object based on 
     
    524621        :param parent_list: List of names of parent elements 
    525622        """ 
    526  
    527         if parent_list is None: 
    528             parent_list = [] 
    529         if self._find_intermediate(parent_list, "Qx"): 
     623        if self._is_2d_not_multi_frame(value): 
    530624            self.current_dataset = plottable_2D() 
    531625        else: 
     
    535629        self.current_datainfo.filename = self.raw_data.filename 
    536630 
    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 
     631    @staticmethod 
     632    def as_list_or_array(iterable): 
     633        """ 
     634        Return value as a list if not already a list or array. 
     635        :param iterable: 
     636        :return: 
     637        """ 
     638        if not (isinstance(iterable, np.ndarray) or isinstance(iterable, list)): 
     639            iterable = iterable.split(",") if isinstance(iterable, basestring)\ 
     640                else [iterable] 
     641        return iterable 
     642 
     643    def _find_data_attributes(self, value): 
     644        """ 
     645        A class to find the indices for Q, the name of the Qdev and Idev, and 
     646        the name of the mask. 
     647        :param value: SASdata/NXdata HDF5 Group 
     648        """ 
     649        # Initialize values to base types 
     650        self.mask_name = u'' 
     651        self.i_name = u'' 
     652        self.i_node = u'' 
     653        self.i_uncertainties_name = u'' 
     654        self.q_names = [] 
     655        self.q_uncertainty_names = [] 
     656        self.q_resolution_names = [] 
     657        # Get attributes 
     658        attrs = value.attrs 
     659        signal = attrs.get("signal", "I") 
     660        i_axes = attrs.get("I_axes", ["Q"]) 
     661        q_indices = attrs.get("Q_indices", [0]) 
     662        i_axes = self.as_list_or_array(i_axes) 
     663        keys = value.keys() 
     664        # Assign attributes to appropriate class variables 
     665        self.q_names = [i_axes[int(v)] for v in self.as_list_or_array(q_indices)] 
     666        self.mask_name = attrs.get("mask") 
     667        self.i_name = signal 
     668        self.i_node = value.get(self.i_name) 
     669        for item in self.q_names: 
     670            if item in keys: 
     671                q_vals = value.get(item) 
     672                if q_vals.attrs.get("uncertainties") is not None: 
     673                    self.q_uncertainty_names = q_vals.attrs.get("uncertainties") 
     674                elif q_vals.attrs.get("uncertainty") is not None: 
     675                    self.q_uncertainty_names = q_vals.attrs.get("uncertainty") 
     676                if isinstance(self.q_uncertainty_names, basestring): 
     677                    self.q_uncertainty_names = self.q_uncertainty_names.split(",") 
     678                if q_vals.attrs.get("resolutions") is not None: 
     679                    self.q_resolution_names = q_vals.attrs.get("resolutions") 
     680                if isinstance(self.q_resolution_names, basestring): 
     681                    self.q_resolution_names = self.q_resolution_names.split(",") 
     682        if self.i_name in keys: 
     683            i_vals = value.get(self.i_name) 
     684            self.i_uncertainties_name = i_vals.attrs.get("uncertainties") 
     685            if self.i_uncertainties_name is None: 
     686                self.i_uncertainties_name = i_vals.attrs.get("uncertainty") 
     687 
     688    def _is_2d_not_multi_frame(self, value, i_base="", q_base=""): 
     689        """ 
     690        A private class to determine if the data set is 1d or 2d. 
     691 
     692        :param value: Nexus/NXcanSAS data group 
    543693        :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 
     694        :return: True if 2D, otherwise false 
     695        """ 
     696        i_basename = i_base if i_base != "" else self.i_name 
     697        i_vals = value.get(i_basename) 
     698        q_basename = q_base if q_base != "" else self.q_names 
     699        q_vals = value.get(q_basename[0]) 
     700        self.multi_frame = (i_vals is not None and q_vals is not None 
     701                            and len(i_vals.shape) != 1 
     702                            and len(q_vals.shape) == 1) 
     703        return (i_vals is not None and len(i_vals.shape) != 1 
     704                and not self.multi_frame) 
    557705 
    558706    def _create_unique_key(self, dictionary, name, numb=0): 
     
    583731        if unit is None: 
    584732            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}" 
    590733        return unit 
Note: See TracChangeset for help on using the changeset viewer.