def test_convert_beams(target): def check_positions(data): assert 'sample_position' not in data.coords assert ('source_position' in data.coords) == (target == 'scattered_beam') assert ('position' in data.coords) == (target == 'incident_beam') # A single sample position. original = make_test_data(coords=('position', 'sample_position', 'source_position')) converted = scn.convert(original, origin='position', target=target, scatter=True) check_positions(converted) assert sc.identical( converted.coords[target], make_incident_beam() if target == 'incident_beam' else make_scattered_beam()) # Two sample positions. original = make_test_data(coords=('position', 'source_position')) original.coords['sample_position'] = sc.vectors(dims=['spectrum'], values=[[1.0, 0.0, 0.2], [2.1, -0.3, 1.4]], unit='m') converted = scn.convert(original, origin='position', target=target, scatter=True) check_positions(converted) if target == 'incident_beam': assert sc.allclose(converted.coords['incident_beam'], sc.vectors(dims=['spectrum'], values=[[1.0, 0.0, 10.2], [2.1, -0.3, 11.4]], unit='m'), rtol=1e-14 * sc.units.one) if target == 'scattered_beam': assert sc.allclose(converted.coords['scattered_beam'], sc.vectors(dims=['spectrum'], values=[[0.0, 0.0, -0.2], [-2.0, 0.3, -0.4]], unit='m'), rtol=1e-14 * sc.units.one)
def _load_pixel_positions(detector_group: Group, detector_ids_size: int, nexus: LoadFromNexus) -> Optional[sc.Variable]: offsets_unit = nexus.get_unit( nexus.get_dataset_from_group(detector_group, "x_pixel_offset")) if offsets_unit == sc.units.dimensionless: warn(f"Skipped loading pixel positions as no units found on " f"x_pixel_offset dataset in {nexus.get_name(detector_group)}") return None try: x_positions = nexus.load_dataset_from_group_as_numpy_array( detector_group, "x_pixel_offset").flatten() y_positions = nexus.load_dataset_from_group_as_numpy_array( detector_group, "y_pixel_offset").flatten() except MissingDataset: return None try: z_positions = nexus.load_dataset_from_group_as_numpy_array( detector_group, "z_pixel_offset").flatten() except MissingDataset: # According to the NeXus standard z offsets are allowed to be # missing, in which case use zeros z_positions = np.zeros_like(x_positions) list_of_sizes = [ x_positions.size, y_positions.size, z_positions.size, detector_ids_size ] if list_of_sizes.count(list_of_sizes[0]) != len(list_of_sizes): warn(f"Skipped loading pixel positions as pixel offset and id " f"dataset sizes do not match in {nexus.get_name(detector_group)}") return None x_positions = _convert_array_to_metres(x_positions, offsets_unit) y_positions = _convert_array_to_metres(y_positions, offsets_unit) z_positions = _convert_array_to_metres(z_positions, offsets_unit) array = np.array([x_positions, y_positions, z_positions]).T data = sc.vectors(dims=[_detector_dimension], values=array, unit=sc.units.m) found_depends_on, _ = nexus.dataset_in_group(detector_group, "depends_on") if found_depends_on: data = (get_full_transformation_matrix(detector_group, nexus) * data) if isinstance(data, sc.DataArray): return data["time", 0].data else: return data
def get_detector_pos(ws, spectrum_dim): nHist = ws.getNumberHistograms() pos = np.zeros([nHist, 3]) spec_info = ws.spectrumInfo() for i in range(nHist): if spec_info.hasDetectors(i): p = spec_info.position(i) pos[i, 0] = p.X() pos[i, 1] = p.Y() pos[i, 2] = p.Z() else: pos[i, :] = [np.nan, np.nan, np.nan] return sc.vectors(dims=[spectrum_dim], values=pos, unit=sc.units.m)
def make_dataset_with_beamline(): positions = [[1, 0, 0], [0, 1, 0], [0, 0, 1], [-1, 0, 0]] d = sc.Dataset( data={'a': sc.Variable(dims=['position', 'tof'], values=np.random.rand(4, 9))}, coords={ 'tof': sc.Variable(dims=['tof'], values=np.arange(1000.0, 1010.0), unit=sc.units.us), 'position': sc.vectors(dims=['position'], values=positions, unit=sc.units.m) }) d.coords['source_position'] = sc.vector(value=np.array([0, 0, -10]), unit=sc.units.m) d.coords['sample_position'] = sc.vector(value=np.array([0, 0, 0]), unit=sc.units.m) return d
def get_detector_properties(ws, source_pos, sample_pos, spectrum_dim, advanced_geometry=False): if not advanced_geometry: return (get_detector_pos(ws, spectrum_dim), None, None) spec_info = ws.spectrumInfo() det_info = ws.detectorInfo() comp_info = ws.componentInfo() nspec = len(spec_info) det_rot = np.zeros([nspec, 3, 3]) det_bbox = np.zeros([nspec, 3]) if sample_pos is not None and source_pos is not None: total_detectors = spec_info.detectorCount() act_beam = (sample_pos - source_pos) rot = _rot_from_vectors(act_beam, sc.vector(value=[0, 0, 1])) inv_rot = _rot_from_vectors(sc.vector(value=[0, 0, 1]), act_beam) pos_d = sc.Dataset() # Create empty to hold position info for all spectra detectors pos_d["x"] = sc.zeros(dims=["detector"], shape=[total_detectors], unit=sc.units.m) pos_d["y"] = sc.zeros_like(pos_d["x"]) pos_d["z"] = sc.zeros_like(pos_d["x"]) pos_d.coords[spectrum_dim] = sc.array(dims=["detector"], values=np.empty(total_detectors)) spectrum_values = pos_d.coords[spectrum_dim].values x_values = pos_d["x"].values y_values = pos_d["y"].values z_values = pos_d["z"].values idx = 0 for i, spec in enumerate(spec_info): if spec.hasDetectors: definition = spec_info.getSpectrumDefinition(i) n_dets = len(definition) quats = [] bboxes = [] for j in range(n_dets): det_idx = definition[j][0] p = det_info.position(det_idx) r = det_info.rotation(det_idx) spectrum_values[idx] = i x_values[idx] = p.X() y_values[idx] = p.Y() z_values[idx] = p.Z() idx += 1 quats.append( np.array([r.imagI(), r.imagJ(), r.imagK(), r.real()])) if comp_info.hasValidShape(det_idx): s = comp_info.shape(det_idx) bboxes.append(s.getBoundingBox().width()) det_rot[ i, :] = sc.geometry.rotation_matrix_from_quaternion_coeffs( np.mean(quats, axis=0)) det_bbox[i, :] = np.sum(bboxes, axis=0) rot_pos = rot * sc.geometry.position(pos_d["x"].data, pos_d["y"].data, pos_d["z"].data) _to_spherical(rot_pos, pos_d) averaged = sc.groupby(pos_d, spectrum_dim, bins=sc.Variable(dims=[spectrum_dim], values=np.arange( -0.5, len(spec_info) + 0.5, 1.0))).mean("detector") sign = averaged["p-sign"].data / sc.abs(averaged["p-sign"].data) averaged["p"] = sign * ( (np.pi * sc.units.rad) - averaged["p-delta"].data) averaged["x"] = averaged["r"].data * sc.sin( averaged["t"].data) * sc.cos(averaged["p"].data) averaged["y"] = averaged["r"].data * sc.sin( averaged["t"].data) * sc.sin(averaged["p"].data) averaged["z"] = averaged["r"].data * sc.cos(averaged["t"].data) pos = sc.geometry.position(averaged["x"].data, averaged["y"].data, averaged["z"].data) return (inv_rot * pos, sc.spatial.linear_transforms(dims=[spectrum_dim], values=det_rot), sc.vectors(dims=[spectrum_dim], values=det_bbox, unit=sc.units.m)) else: pos = np.zeros([nspec, 3]) for i, spec in enumerate(spec_info): if spec.hasDetectors: definition = spec_info.getSpectrumDefinition(i) n_dets = len(definition) vec3s = [] quats = [] bboxes = [] for j in range(n_dets): det_idx = definition[j][0] p = det_info.position(det_idx) r = det_info.rotation(det_idx) vec3s.append([p.X(), p.Y(), p.Z()]) quats.append( np.array([r.imagI(), r.imagJ(), r.imagK(), r.real()])) if comp_info.hasValidShape(det_idx): s = comp_info.shape(det_idx) bboxes.append(s.getBoundingBox().width()) pos[i, :] = np.mean(vec3s, axis=0) det_rot[ i, :] = sc.geometry.rotation_matrix_from_quaternion_coeffs( np.mean(quats, axis=0)) det_bbox[i, :] = np.sum(bboxes, axis=0) else: pos[i, :] = [np.nan, np.nan, np.nan] det_rot[i, :] = [np.nan, np.nan, np.nan, np.nan] det_bbox[i, :] = [np.nan, np.nan, np.nan] return (sc.vectors(dims=[spectrum_dim], values=pos, unit=sc.units.m), sc.spatial.linear_transforms(dims=[spectrum_dim], values=det_rot), sc.vectors( dims=[spectrum_dim], values=det_bbox, unit=sc.units.m, ))
def make_scattered_beam(): return sc.vectors(dims=['spectrum'], values=[[1.0, 0.0, 0.0], [0.1, 0.0, 1.0]], unit='m')
def make_position(): return sc.vectors(dims=['spectrum'], values=[[1.0, 0.0, 0.0], [0.1, 0.0, 1.0]], unit='m')