- Timestamp:
- Feb 21, 2019 5:23:13 PM (6 years ago)
- Branches:
- master, magnetic_scatt, release-4.2.2, ticket-1009, ticket-1094-headless, ticket-1242-2d-resolution, ticket-1249
- Children:
- 1342f6a, dbfd307
- Parents:
- e4e9162
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/sascalc/dataloader/readers/cansas_reader_HDF5.py
re090ba90 r4cbb2f5 1 1 """ 2 CanSAS 2Ddata reader for reading HDF5 formatted CanSAS files.2 NXcanSAS data reader for reading HDF5 formatted CanSAS files. 3 3 """ 4 4 … … 12 12 Data1D, Data2D, DataInfo, Process, Aperture, Collimation, \ 13 13 TransmissionSpectrum, Detector 14 from ..data_info import combine_data_info_with_plottable15 14 from ..loader_exceptions import FileContentsException, DefaultReaderException 16 15 from ..file_reader_base_class import FileReader, decode 17 16 17 try: 18 basestring 19 except NameError: # CRUFT: python 2 support 20 basestring = str 21 22 18 23 def h5attr(node, key, default=None): 19 24 return decode(node.attrs.get(key, default)) 20 25 26 21 27 class Reader(FileReader): 22 28 """ 23 A class for reading in CanSAS v2.0 data files. The existing iteration opens24 Mantid generated HDF5 formatted files with file extension .h5/.H5. Any25 number of data sets may be present within the file and any dimensionality26 of data may be used. Currently 1D and 2D SAS data sets are supported, but27 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 files29 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). 33 39 34 40 :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. 36 42 """ 37 43 38 44 # CanSAS version 39 45 cansas_version = 2.0 40 # Logged warnings or messages41 logging = None42 # List of errors for the current data set43 errors = None44 # Raw file contents to be processed45 raw_data = None46 # List of plottable1D objects that should be linked to the current_datainfo47 data1d = None48 # List of plottable2D objects that should be linked to the current_datainfo49 data2d = None50 46 # Data type name 51 type_name = " CanSAS 2.0"47 type_name = "NXcanSAS" 52 48 # Wildcards 53 type = [" CanSAS 2.0 HDF5 Files (*.h5)|*.h5"]49 type = ["NXcanSAS HDF5 Files (*.h5)|*.h5|"] 54 50 # List of allowed extensions 55 51 ext = ['.h5', '.H5'] … … 81 77 except Exception as e: 82 78 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) 84 81 raise DefaultReaderException(msg) 85 82 raise FileContentsException(e.message) … … 95 92 self.raw_data.close() 96 93 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) 102 100 103 101 def reset_state(self): … … 109 107 self.data2d = [] 110 108 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 = [] 112 113 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 = [] 113 121 self.parent_class = u'' 114 122 self.detector = Detector() … … 131 139 value = data.get(key) 132 140 class_name = h5attr(value, u'canSAS_class') 141 if isinstance(class_name, (list, tuple, np.ndarray)): 142 class_name = class_name[0] 133 143 if class_name is None: 134 144 class_name = h5attr(value, u'NX_class') … … 140 150 if isinstance(value, h5py.Group): 141 151 # Set parent class before recursion 152 last_parent_class = self.parent_class 142 153 self.parent_class = class_name 143 154 parent_list.append(key) … … 147 158 self.add_data_set(key) 148 159 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) 150 162 # Recursion step to access data within the group 151 163 self.read_children(value, parent_list) 164 self.add_intermediate() 152 165 # 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 155 167 parent_list.remove(key) 156 168 157 169 elif isinstance(value, h5py.Dataset): 158 170 # If this is a dataset, store the data appropriately 159 data_set = data[key][:]171 data_set = value.value 160 172 unit = self._get_unit(value) 161 162 # I and Q Data163 if key == u'I':164 if isinstance(self.current_dataset, plottable_2D):165 self.current_dataset.data = data_set166 self.current_dataset.zaxis("Intensity", unit)167 else:168 self.current_dataset.y = data_set.flatten()169 self.current_dataset.yaxis("Intensity", unit)170 continue171 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 continue177 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 continue184 elif key == u'Qdev':185 self.current_dataset.dx = data_set.flatten()186 continue187 elif key == u'dQw':188 self.current_dataset.dxw = data_set.flatten()189 continue190 elif key == u'dQl':191 self.current_dataset.dxl = data_set.flatten()192 continue193 elif key == u'Qy':194 self.current_dataset.yaxis("Q_y", unit)195 self.current_dataset.qy_data = data_set.flatten()196 continue197 elif key == u'Qydev':198 self.current_dataset.dqy_data = data_set.flatten()199 continue200 elif key == u'Qx':201 self.current_dataset.xaxis("Q_x", unit)202 self.current_dataset.qx_data = data_set.flatten()203 continue204 elif key == u'Qxdev':205 self.current_dataset.dqx_data = data_set.flatten()206 continue207 elif key == u'Mask':208 self.current_dataset.mask = data_set.flatten()209 continue210 # Transmission Spectrum211 elif (key == u'T'212 and self.parent_class == u'SAStransmission_spectrum'):213 self.trans_spectrum.transmission = data_set.flatten()214 continue215 elif (key == u'Tdev'216 and self.parent_class == u'SAStransmission_spectrum'):217 self.trans_spectrum.transmission_deviation = \218 data_set.flatten()219 continue220 elif (key == u'lambda'221 and self.parent_class == u'SAStransmission_spectrum'):222 self.trans_spectrum.wavelength = data_set.flatten()223 continue224 173 225 174 for data_point in data_set: … … 231 180 # Top Level Meta Data 232 181 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 234 189 elif key == u'run': 235 self.current_datainfo.run.append(data_point)236 190 try: 237 191 run_name = h5attr(value, 'name') 238 run_dict = {data_ point: run_name}192 run_dict = {data_set: run_name} 239 193 self.current_datainfo.run_name = run_dict 240 194 except Exception: 241 195 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 242 202 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 244 209 elif key == u'SASnote': 245 self.current_datainfo.notes.append(data_ point)246 210 self.current_datainfo.notes.append(data_set) 211 break 247 212 # 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) 282 215 # Instrumental Information 283 216 elif (key == u'name' 284 217 and self.parent_class == u'SASinstrument'): 285 218 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) 346 228 # 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) 363 231 # 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) 404 234 # 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 405 245 else: 406 246 new_key = self._create_unique_key( … … 410 250 else: 411 251 # 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) 413 505 414 506 def add_intermediate(self): … … 440 532 self.data2d.append(self.current_dataset) 441 533 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) 443 543 444 544 def final_data_cleanup(self): … … 452 552 spectrum_list = [] 453 553 for spectrum in self.current_datainfo.trans_spectrum: 454 spectrum.transmission = np.delete(spectrum.transmission, [0])455 554 spectrum.transmission = spectrum.transmission.astype(np.float64) 456 spectrum.transmission_deviation = np.delete(457 spectrum.transmission_deviation, [0])458 555 spectrum.transmission_deviation = \ 459 556 spectrum.transmission_deviation.astype(np.float64) 460 spectrum.wavelength = np.delete(spectrum.wavelength, [0])461 557 spectrum.wavelength = spectrum.wavelength.astype(np.float64) 462 558 if len(spectrum.transmission) > 0: … … 466 562 # Append errors to dataset and reset class errors 467 563 self.current_datainfo.errors = self.errors 468 self.errors .clear()564 self.errors = [] 469 565 470 566 # Combine all plottables with datainfo and append each to output 471 567 # Type cast data arrays to float64 and find min/max as appropriate 472 568 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 = zeros480 569 # Calculate the actual Q matrix 481 570 try: … … 484 573 * dataset.qx_data 485 574 + dataset.qy_data 486 * dataset.qy_data) 575 * dataset.qy_data).flatten() 487 576 except: 488 577 dataset.q_data = None 489 578 490 579 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()) 494 582 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) 495 591 self.current_dataset = dataset 496 592 self.send_to_output() … … 511 607 if self.current_datainfo and self.current_dataset: 512 608 self.final_data_cleanup() 609 self.data_frames = [] 610 self.data_uncertainty_frames = [] 513 611 self.data1d = [] 514 612 self.data2d = [] 515 613 self.current_datainfo = DataInfo() 516 614 517 518 def _initialize_new_data_set(self, parent_list=None): 615 def _initialize_new_data_set(self, value=None): 519 616 """ 520 617 A private class method to generate a new 1D or 2D data object based on … … 524 621 :param parent_list: List of names of parent elements 525 622 """ 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): 530 624 self.current_dataset = plottable_2D() 531 625 else: … … 535 629 self.current_datainfo.filename = self.raw_data.filename 536 630 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 543 693 :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) 557 705 558 706 def _create_unique_key(self, dictionary, name, numb=0): … … 583 731 if unit is None: 584 732 unit = h5attr(value, u'unit') 585 # Convert the unit formats586 if unit == "1/A":587 unit = "A^{-1}"588 elif unit == "1/cm":589 unit = "cm^{-1}"590 733 return unit
Note: See TracChangeset
for help on using the changeset viewer.