def _load_masks(self, hidra_file): """Load masks from Hidra project file Parameters ---------- hidra_file : pyrs.projectfile.file_object.HidraProjectFile Hidra project file instance Returns ------- """ # Check checkdatatypes.check_type('HIDRA project file', hidra_file, HidraProjectFile) # Default mask: get value and set default_mask = hidra_file.read_default_masks() if default_mask is not None: self.set_detector_mask(default_mask, True) # User specified mask mask_dict = dict() hidra_file.read_user_masks(mask_dict) for mask_name in mask_dict: self.set_detector_mask(mask_dict[mask_name], False, mask_name)
def init_session(self, session_name, hidra_ws=None): """ Initialize a new session of reduction and thus to store data according to session name :return: """ # Check inputs checkdatatypes.check_string_variable('Reduction session name', session_name) if session_name == '': raise RuntimeError('Session name {} is empty'.format(session_name)) elif session_name in self._session_dict: print( '[WARNING] Session {} is previously taken. The HidraWorkspace associated ' 'will be replaced if new HidraWorkspace is not None ({})' ''.format(session_name, hidra_ws is None)) if hidra_ws is None: # session is initialized without HidraWorkspace self._curr_workspace = workspaces.HidraWorkspace() else: # session starts with a HidraWorkspace checkdatatypes.check_type('HidraWorkspace', hidra_ws, workspaces.HidraWorkspace) self._curr_workspace = hidra_ws self._session_dict[session_name] = self._curr_workspace
def generate_mantid_workspace(hidra_workspace, workspace_name, mask_id=None): """ Generate a Mantid MatrixWorkspace from a HidraWorkspace :param hidra_workspace: :param workspace_name: string for output workspace name :param mask_id: Mask index for the reduced diffraction data in HidraWorkspace/HidraProjectFile :return: """ # Check inputs checkdatatypes.check_type('Hidra workspace', hidra_workspace, workspaces.HidraWorkspace) # workspace name: if workspace_name is None: workspace_name = hidra_workspace.name else: checkdatatypes.check_string_variable('Workspace name', workspace_name) # Get data from HiDRA Workspace two_theta_matrix, data_y_matrix, data_e_matrix = hidra_workspace.get_reduced_diffraction_data_set(mask_id) # Mantid (2019.11) does not accept NaN # Convert all NaN to zero. No good peak will have NaN or Zero data_y_matrix[np.where(np.isnan(data_y_matrix))] = 0. data_e_matrix[np.where(np.isnan(data_e_matrix))] = 0. # Create Mantid workspace matrix_ws = CreateWorkspace(DataX=two_theta_matrix, DataY=data_y_matrix, DataE=data_e_matrix, NSpec=data_y_matrix.shape[0], OutputWorkspace=workspace_name, EnableLogging=False) return matrix_ws
def load_hidra_project(self, hidra_file, load_raw_counts, load_reduced_diffraction): """ Load HIDRA project file :param hidra_file: HIDRA project file instance (not file name) :param load_raw_counts: Flag to load raw counts :param load_reduced_diffraction: Flag to load reduced diffraction data :return: """ # Check input checkdatatypes.check_type('HIDRA project file', hidra_file, HidraProjectFile) self._project_file_name = hidra_file.name self._project_file = hidra_file # create the spectrum map - must exist before loading the counts array self._sample_logs.subruns = hidra_file.read_sub_runs() # load raw detector counts and load instrument if load_raw_counts: self._load_raw_counts(hidra_file) self._load_instrument(hidra_file) # load reduced diffraction if load_reduced_diffraction: self._load_reduced_diffraction_data(hidra_file) # load sample logs self._load_sample_logs(hidra_file) # load masks self._load_masks(hidra_file) # load the wave length self._load_wave_length(hidra_file)
def convert_opt_operations(opt_opts): """ Convert a 7-tuple list (long-name, short-name, target name, type, default value, is mandatory, document) :param opt_opts: list of operation :return: (1) operation_dict key as either long name --xxx, or short name -x), value = parameter name, value type (removed: default value, mandatory) (2) list of mandatory parameters (3) optional default value dictionary: key = parameter name, value = default default value (4) dictionary for helping message: key = parameter name, value = short name, long name, document """ checkdatatypes.check_type('Command options', opt_opts, list) # split a 4 tuple to 2 3-tuples opt_dict = dict() man_param_list = list() default_param_dict = dict() info_dict = dict() for t4 in opt_opts: if len(t4) != 7: raise RuntimeError( 'Item {} is not defined properly. 7 and only 7 items are allowed' ) long_name_i, short_name_i, target_name_i, type_i, default_i, mandatory_i, doc_i = t4 # long/full opt name if long_name_i is not None: if len(long_name_i) < 2: raise RuntimeError( 'Long name {} in {} is not allowed. At least 2 letters' ''.format(long_name_i, t4)) opt_dict['--{}'.format( long_name_i )] = target_name_i, type_i # , default_i, mandatory_i # short opt name if short_name_i is not None: if len(short_name_i) != 1: raise RuntimeError( 'Short name {} in {} is not allowed. 1 and only 1 letter' ''.format(short_name_i, t4)) opt_dict['-{}'.format( short_name_i )] = target_name_i, type_i # , default_i, mandatory_i # Mandatory if mandatory_i: man_param_list.append(target_name_i) else: default_param_dict[target_name_i] = default_i # Information info_dict[ target_name_i] = short_name_i, long_name_i, doc_i, mandatory_i, default_i # END-FOR return opt_dict, man_param_list, default_param_dict, info_dict
def save_reduced_diffraction_data(self, hidra_project): """ Export reduced diffraction data to project :param hidra_project: HidraProjectFile instance :return: """ checkdatatypes.check_type('HIDRA project file', hidra_project, HidraProjectFile) hidra_project.write_reduced_diffraction_data_set( self._2theta_matrix, self._diff_data_set, self._var_data_set)
def _load_instrument(self, hidra_file): """ Load instrument setup from HIDRA file :param hidra_file: HIDRA project file instance :return: """ # Check checkdatatypes.check_type('HIDRA project file', hidra_file, HidraProjectFile) # Get values self._instrument_setup = hidra_file.read_instrument_geometry()
def set_geometry_calibration(self, geometry_calibration): """ Load and apply calibration file :param geometry_calibration: :return: """ # TODO FIXME - #81 NOWNOW - Still not sure how to apply! checkdatatypes.check_type( 'Geometry calibration', geometry_calibration, instrument_geometry.AnglerCameraDetectorShift) self._geometry_calibration = geometry_calibration
def _load_sample_logs(self, hidra_file): """ Load sample logs. Note: this method can clear all the sample logs added previously. But it is not an issue in the real use cases. :param hidra_file: HIDRA project file instance :return: """ checkdatatypes.check_type('HIDRA project file', hidra_file, HidraProjectFile) # overwrite the existing sample logs self._sample_logs = hidra_file.read_sample_logs()
def _load_raw_counts(self, hidra_file): """ Load raw detector counts from HIDRA file :param hidra_file: :return: """ checkdatatypes.check_type('HIDRA project file', hidra_file, HidraProjectFile) for sub_run_i in self._sample_logs.subruns: counts_vec_i = hidra_file.read_raw_counts(sub_run_i) self._raw_counts[sub_run_i] = counts_vec_i # END-FOR return
def build_instrument(self, calibration): """ Build an instrument for each pixel's position in cartesian coordinate :param calibration: DENEXDetectorShift from geometry calibration :return: 2D numpy array """ if calibration is not None: checkdatatypes.check_type('Instrument geometry calibrated shift', calibration, instrument_geometry.DENEXDetectorShift) self._instrument.build_instrument(self._detector_2theta, self._detector_l2, instrument_calibration=calibration) return
def _load_wave_length(self, hidra_file): """Load wave length from HidraProject file Parameters ---------- hidra_file : pyrs.projectfile.file_object.HidraProjectFile Project file (instance) Returns ------- None """ checkdatatypes.check_type('HIDRA project file', hidra_file, HidraProjectFile) # reset the wave length (dictionary) from HIDRA project file self._wave_length = hidra_file.read_wavelengths()
def write_instrument_geometry(self, instrument_setup): """ Add instrument geometry and wave length information to project file """ # check inputs self._validate_write_operation() checkdatatypes.check_type('Instrument geometry setup', instrument_setup, HidraSetup) # write value to instrument instrument_group = self._project_h5[HidraConstants.INSTRUMENT] # write attributes instrument_group.attrs['name'] = instrument_setup.name # get the entry for raw instrument setup detector_group = instrument_group['geometry setup']['detector'] raw_geometry = instrument_setup.get_instrument_geometry(False) detector_group.create_dataset('L2', data=numpy.array( raw_geometry.arm_length)) det_size = numpy.array( instrument_setup.get_instrument_geometry(False).detector_size) detector_group.create_dataset('detector size', data=det_size) pixel_dimension = list( instrument_setup.get_instrument_geometry(False).pixel_dimension) detector_group.create_dataset('pixel dimension', data=numpy.array(pixel_dimension)) # wave length wavelength_group = instrument_group[HidraConstants.GEOMETRY_SETUP][ HidraConstants.WAVELENGTH] try: wl = instrument_setup.get_wavelength(None) except (NotImplementedError, RuntimeError) as run_err: # No wave length from workspace: do nothing self._log.error(str(run_err)) wl = None # Set wave length if wl is not None: wavelength_group.create_dataset('Calibrated', data=numpy.array([wl]))
def __init__(self, detector_setup): """Initialization Initialization HB2B instrument setup Parameters ---------- detector_setup """ # check inputs checkdatatypes.check_type('Detector geometry setup', detector_setup, DENEXDetectorGeometry) # set for original instrument setup defined by engineering self._geometry_setup = detector_setup self._single_wave_length = None self._geometry_shift = None self._calibrated_wave_length = None # calibration state self._calibration_applied = False
def __init__(self, instrument_setup): """ initialization :param instrument_setup: """ # check input checkdatatypes.check_type('Instrument setup', instrument_setup, instrument_geometry.DENEXDetectorGeometry) # Instrument geometry parameters self._instrument_geom_params = instrument_setup # Pixels' positions without calibration. It is kept stable upon calibration values (shifts) and arm (000 plane) self._raw_pixel_matrix = self._set_uncalibrated_pixels( ) # never been used for external client: len(shape) = 3 self._pixel_matrix = None # used by external after build_instrument: matrix for pixel positions self._pixel_2theta_matrix = None # matrix for pixel's 2theta value self._pixel_eta_matrix = None # matrix for pixel's eta value self._wave_length = None return
def save_reduced_diffraction_data(self, hidra_project, sub_runs): """Save reduced diffraction data to HiDRA project file Parameters ---------- hidra_project: HidraProjectFile reference to a HyDra project file sub_runs: None or list/ndarray(1D) None for exporting all or the specified sub runs Returns ------- None """ checkdatatypes.check_type('HIDRA project file', hidra_project, HidraProjectFile) if len(self._raw_counts.keys()) == len(sub_runs): hidra_project.write_reduced_diffraction_data_set( self._2theta_matrix, self._diff_data_set, self._var_data_set) else: if type(sub_runs) is list: sub_runs = numpy.array(sub_runs) diff_key = list(self._diff_data_set.keys())[0] _diff_data_temp = {} _var_data_temp = {} # sub_runs - 1 is used to convert sub_run naming into a numpy index _diff_data_temp[diff_key] = self._diff_data_set[diff_key][sub_runs - 1] _var_data_temp[diff_key] = self._var_data_set[diff_key][sub_runs - 1] hidra_project.write_reduced_diffraction_data_set( self._2theta_matrix[sub_runs - 1], _diff_data_temp, _var_data_temp)
def apply_shift(self, geometry_shift): checkdatatypes.check_type('Detector geometry shift', geometry_shift, DENEXDetectorShift) self._arm_length += geometry_shift.center_shift_z
def build_instrument(self, two_theta: float, l2: Optional[float] = None, instrument_calibration=None): """ build instrument considering calibration step 1: rotate instrument according to the calibration step 2: rotate instrument about 2theta :param two_theta :param l2 :param instrument_calibration: DENEXDetectorShift or None (no calibration) :return: """ # Check input two_theta = to_float('2theta', two_theta) # Check or set L2 if l2 is None: l2 = self._instrument_geom_params.arm_length else: l2 = to_float('L2', l2, 1E-2) # print('[DB...L101] Build instrument: 2theta = {}, arm = {} (diff to default = {})' # ''.format(two_theta, l2, l2 - self._instrument_geom_params.arm_length)) # make a copy from raw (constant position) self._pixel_matrix = self._raw_pixel_matrix.copy() # Check and set instrument calibration if instrument_calibration is not None: # check type checkdatatypes.check_type('Instrument calibration', instrument_calibration, instrument_geometry.DENEXDetectorShift) # shift center self._pixel_matrix[:, :, 0] += instrument_calibration.center_shift_x self._pixel_matrix[:, :, 1] += instrument_calibration.center_shift_y # rotation around instrument center # get rotation matrix at origin (for flip, spin and vertical): all data from calibration value rot_x_flip = instrument_calibration.rotation_x * np.pi / 180. rot_y_flip = instrument_calibration.rotation_y * np.pi / 180. rot_z_spin = instrument_calibration.rotation_z * np.pi / 180. calib_matrix = self.generate_rotation_matrix( rot_x_flip, rot_y_flip, rot_z_spin) # print ('[DB...BAT] Calibration rotation matrix:\n{}'.format(calib_matrix)) # and rotate at origin self._pixel_matrix = self._rotate_detector(self._pixel_matrix, calib_matrix) # shift two_theta by offset two_theta += instrument_calibration.two_theta_0 # END-IF-ELSE # push to +Z at length of detector arm arm_l2 = l2 if instrument_calibration is not None: # Apply the shift on Z (arm length) arm_l2 += instrument_calibration.center_shift_z # END-IF self._pixel_matrix[:, :, 2] += arm_l2 # rotate detector (2theta) if it is not zero self.rotate_detector_2theta(two_theta) return self._pixel_matrix
def _load_reduced_diffraction_data(self, hidra_file): """ Load reduced diffraction data from HIDRA file :param hidra_file: HidraProjectFile instance :return: """ # Check inputs checkdatatypes.check_type('HIDRA project file', hidra_file, HidraProjectFile) # get 2theta value try: vec_2theta = hidra_file.read_diffraction_2theta_array() except KeyError as key_err: print( '[INFO] Unable to load 2theta vector from HidraProject file due to {}.' 'It is very likely that no reduced data is recorded.' ''.format(key_err)) return # TRY-CATCH # Get number of spectra num_spec = len(hidra_file.read_sub_runs()) # Promote to 2theta from vector to array if len(vec_2theta.shape) == 1: # convert from 1D array to 2D tth_size = vec_2theta.shape[0] matrix_2theta = numpy.repeat(vec_2theta.reshape(1, tth_size), num_spec, axis=0) else: matrix_2theta = vec_2theta # Set value self._2theta_matrix = numpy.copy(matrix_2theta) # initialize data set for reduced diffraction patterns diff_mask_list = hidra_file.read_diffraction_masks() for mask_name in diff_mask_list: if mask_name == 'main': mask_name = None self._diff_data_set[mask_name] = numpy.ndarray( shape=(num_spec, vec_2theta.shape[0]), dtype='float') # END-FOR # Load data: all including masks / ROI for mask_name in diff_mask_list: # force to None if mask_name == 'main': mask_name = None self._diff_data_set[ mask_name] = hidra_file.read_diffraction_intensity_vector( mask_id=mask_name, sub_run=None) # Load data: all including masks / ROI for mask_name in diff_mask_list: # force to None if mask_name == 'main': mask_name = None self._var_data_set[ mask_name] = hidra_file.read_diffraction_variance_vector( mask_id=mask_name, sub_run=None) if self._var_data_set[mask_name] is None: self._var_data_set[mask_name] = numpy.sqrt( self._diff_data_set[mask_name]) print('[INFO] Loaded diffraction data from {} includes : {}' ''.format(self._project_file_name, self._diff_data_set.keys()))