def test_load_via_exact_match(): make_dynamic_algorithm_without_fileproperty("DummyLoader") # scn.load will need to check file exists # DummyLoader simply returns a TableWorkspace with tempfile.NamedTemporaryFile() as fp: scn.load(fp.name, mantid_alg="DummyLoader") # Sanity check corrupt full path will fail with pytest.raises(ValueError): scn.load("fictional_" + fp.name, mantid_alg="DummyLoader")
def test_extract_energy_initial(): from mantid.simpleapi import mtd mtd.clear() ds = scn.load(scn.data.get_path("CNCS_51936_event.nxs"), mantid_args={"SpectrumMax": 1}) assert sc.identical(ds.coords["incident_energy"], sc.scalar(value=3.0, unit=sc.Unit("meV")))
def test_fit(self): """ Tests that the fit executes, and the outputs are moved into the dataset. Does not check the fit values. """ from mantid.simpleapi import mtd mtd.clear() data = scn.load(scn.data.get_path("iris26176_graphite002_sqw.nxs")) params, diff = scn.fit(data['Q', 0], mantid_args={ 'Function': 'name=LinearBackground,A0=0,A1=1', 'StartX': 0, 'EndX': 3 }) # check that no workspaces have been leaked in the ADS assert len(mtd) == 0 assert 'data' in diff assert 'calculated' in diff assert 'diff' in diff assert 'status' in params.coords assert 'function' in params.coords assert 'cost_function' in params.coords assert 'chi^2/d.o.f.' in params.coords
def process_event_data(file, lambda_binning): """ Load and reduce event data (used for Vanadium and Empty instrument) file: Nexus file to be loaded and its data reduced in this script lambda_binning: lambda_min, lamba_max, number_of_bins """ # load nexus file event_data = scn.load(file, advanced_geometry=True, load_pulse_times=False, mantid_args={'LoadMonitors': True}) # ################################ # Monitor correction # extract monitor and convert from tof to wavelength mon4_lambda = scn.convert(event_data.attrs['monitor4'].values, 'tof', 'wavelength', scatter=False) mon4_smooth = smooth_data(mon4_lambda, dim='wavelength', NPoints=40) del mon4_lambda # ################################ # vana and EC # convert to lambda event_lambda = scn.convert(event_data, 'tof', 'wavelength', scatter=True) # normalize to monitor lambda_min, lambda_max, number_bins = lambda_binning edges_lambda = sc.Variable(['wavelength'], unit=sc.units.angstrom, values=np.linspace(lambda_min, lambda_max, num=number_bins)) mon_rebin = sc.rebin(mon4_smooth, 'wavelength', edges_lambda) del mon4_smooth event_lambda_norm = event_lambda.bins / sc.lookup(func=mon_rebin, dim='wavelength') del mon_rebin, event_lambda return event_lambda_norm
def test_EventWorkspace_with_monitors(self): from mantid.simpleapi import mtd mtd.clear() ds = scn.load(scn.data.get_path("CNCS_51936_event.nxs"), mantid_args={ "LoadMonitors": True, "SpectrumMax": 1 }) self.assertEqual(len(mtd), 0, mtd.getObjectNames()) attrs = [str(key) for key in ds.attrs.keys()] expected_monitor_attrs = {"monitor2", "monitor3"} assert expected_monitor_attrs.issubset(attrs) for monitor_name in expected_monitor_attrs: monitor = ds.attrs[monitor_name].value assert isinstance(monitor, sc.DataArray) assert monitor.shape == [200001] self.check_monitor_metadata(monitor)
def test_Workspace2D_with_include_monitors(self): from mantid.simpleapi import mtd mtd.clear() # This test would use 20 GB of memory if "SpectrumMax" was not set ds = scn.load(scn.data.get_path("WISH00016748.raw"), mantid_args={ "LoadMonitors": "Include", "SpectrumMax": 100 }) self.assertEqual(len(mtd), 0, mtd.getObjectNames()) attrs = [str(key) for key in ds.attrs.keys()] expected_monitor_attrs = { "monitor1", "monitor2", "monitor3", "monitor4", "monitor5" } assert expected_monitor_attrs.issubset(attrs) for monitor_name in expected_monitor_attrs: monitor = ds.attrs[monitor_name].value assert isinstance(monitor, sc.DataArray) assert monitor.shape == [4471] self.check_monitor_metadata(monitor)
def test_load_error_when_file_not_found_via_exact_match(): make_dynamic_algorithm_without_fileproperty("DummyLoader") with pytest.raises(ValueError): # DummyLoader has no FileProperty and forces # load to evaluate the path given as an absolute path scn.load("fictional.nxs", mantid_alg="DummyLoader")
def test_load_error_when_file_not_found_via_fuzzy_match(): with pytest.raises(ValueError): scn.load("fictional.nxs")
def setup(self): da = scn.load(scn.data.get_path('PG3_4844_event.nxs')) self.var_tof = da self.var_wavelength = scn.convert(self.var_tof, "tof", "wavelength", False) self.var_energy = scn.convert(self.var_tof, "tof", "energy", False)
def powder_reduction(sample='sample.nxs', calibration=None, vanadium=None, empty_instr=None, lambda_binning=(0.7, 10.35, 5615), **absorp): """ Simple WISH reduction workflow Note ---- The sample data were not recorded using the same layout of WISH as the Vanadium and empty instrument. That's why: - loading calibration for Vanadium used a different IDF - the Vanadium correction involved cropping the sample data to the first 5 groups (panels) ---- Corrections applied: - Vanadium correction - Absorption correction - Normalization by monitors - Conversion considering calibration - Masking and grouping detectors into panels Parameters ---------- sample: Nexus event file calibration: .cal file following Mantid's standards The columns correspond to detectors' IDs, offset, selection of detectors and groups vanadium: Nexus event file empty_instr: Nexus event file lambda_binning: min, max and number of steps for binning in wavelength min and max are in Angstroms **absorp: dictionary containing information to correct absorption for Sample and Vanadium. There could be only up to two elements related to the correction for Vanadium: the radius and height of the cylindrical sample shape. To distinguish them from the inputs related to the sample, their names in the dictionary are 'CylinderVanadiumRadius' and 'CylinderVanadiumHeight'. The other keysof the 'absorp' dictionary follow Mantid's syntax and are related to the sample data only. See help of Mantid's algorithm CylinderAbsorption for details https://docs.mantidproject.org/nightly/algorithms/CylinderAbsorption-v1.html Returns ------- Scipp dataset containing reduced data in d-spacing Hints ----- To plot the output data, one can histogram in d-spacing and sum according to groups using scipp.histogram and sc.sum, respectively. """ # Load counts sample_data = scn.load(sample, advanced_geometry=True, load_pulse_times=False, mantid_args={'LoadMonitors': True}) # Load calibration if calibration is not None: input_load_cal = {"InstrumentName": "WISH"} cal = load_calibration(calibration, mantid_args=input_load_cal) # Merge table with detector->spectrum mapping from sample # (implicitly checking that detectors between sample and calibration # are the same) cal_sample = sc.merge(cal, sample_data.coords['detector_info'].value) # Compute spectrum mask from detector mask mask = sc.groupby(cal_sample['mask'], group='spectrum').any('detector') # Compute spectrum groups from detector groups g = sc.groupby(cal_sample['group'], group='spectrum') group = g.min('detector') assert sc.identical(group, g.max('detector')), \ "Calibration table has mismatching group for detectors in same spectrum" sample_data.coords['group'] = group.data sample_data.masks['mask'] = mask.data del cal # Correct 4th monitor spectrum # There are 5 monitors for WISH. Only one, the fourth one, is selected for # correction (like in the real WISH workflow). # Select fourth monitor and convert from tof to wavelength mon4_lambda = scn.convert(sample_data.attrs['monitor4'].values, 'tof', 'wavelength', scatter=False) # Spline background # mon4_spline_background = bspline_background(mon4_lambda, # sc.Dim('wavelength'), # smoothing_factor=70) # Smooth monitor mon4_smooth = smooth_data( mon4_lambda, # mon4_spline_background, dim='wavelength', NPoints=40) # Delete intermediate data del mon4_lambda # , mon4_spline_background # Correct data # 1. Normalize to monitor # Convert to wavelength (counts) sample_lambda = scn.convert(sample_data, 'tof', 'wavelength', scatter=True) del sample_data # Rebin monitors' data lambda_min, lambda_max, number_bins = lambda_binning edges_lambda = sc.Variable(['wavelength'], unit=sc.units.angstrom, values=np.linspace(lambda_min, lambda_max, num=number_bins)) mon_rebin = sc.rebin(mon4_smooth, 'wavelength', edges_lambda) # Realign sample data sample_lambda = sample_lambda.bins / sc.lookup(func=mon_rebin, dim='wavelength') del mon_rebin, mon4_smooth # 2. absorption correction if bool(absorp): # Copy dictionary of absorption parameters absorp_sample = absorp.copy() # Remove input related to Vanadium if present in absorp dictionary found_vana_info = [ key for key in absorp_sample.keys() if 'Vanadium' in key ] for item in found_vana_info: absorp_sample.pop(item, None) # Calculate absorption correction for sample data correction = absorption_correction(sample, lambda_binning, **absorp_sample) # the 3 following lines of code are to place info about source and # sample position at the right place in the correction dataArray in # order to proceed to the normalization del correction.coords['source_position'] del correction.coords['sample_position'] del correction.coords['position'] correction_rebin = sc.rebin(correction, 'wavelength', edges_lambda) del correction sample_lambda = sample_lambda.bins / sc.lookup(func=correction_rebin, dim='wavelength') # 3. Convert to d-spacing with option of taking calibration into account if calibration is None: # No calibration data, use standard convert algorithm sample_dspacing = scn.convert(sample_lambda, 'tof', 'dspacing') else: # Calculate dspacing from calibration file sample_dspacing = convert_with_calibration(sample_lambda, cal_sample) del cal_sample del sample_lambda # 4. Focus panels # Assuming sample is in d-spacing: Focus into groups focused = sc.groupby(sample_dspacing, group='group').bins.concatenate('spectrum') del sample_dspacing # 5. Vanadium correction (requires Vanadium and Empty instrument) if vanadium is not None and empty_instr is not None: print("Proceed with reduction of Vanadium data ") vana_red_focused = process_vanadium_data(vanadium, empty_instr, lambda_binning, calibration, **absorp) # The following selection of groups depends on the loaded data for # Sample, Vanadium and Empty instrument focused = focused['group', 0:5].copy() # histogram vanadium for normalizing + cleaning 'metadata' d_min, d_max, number_dbins = (1., 10., 2000) edges_dspacing = sc.Variable(['dspacing'], unit=sc.units.angstrom, values=np.linspace(d_min, d_max, num=number_dbins)) vana_histo = sc.histogram(vana_red_focused, edges_dspacing) del vana_red_focused vana_histo.coords['detector_info'] = focused.coords[ 'detector_info'].copy() # del vana_histo.coords['source_position'] # del vana_histo.coords['sample_position'] # normalize by vanadium result = focused.bins / sc.lookup(func=vana_histo, dim='dspacing') del vana_histo, focused return result