def check_workspaces_exist(run_no) -> bool: """ Check the vanadium workspaces are loaded into the ADS :return: True if both are present, false otherwise """ return Ads.doesExist(str(run_no) + '_' + PROCESSED_WORKSPACE_NAME) and Ads.doesExist( str(run_no) + '_' + INTEGRATED_WORKSPACE_NAME)
def _check_region_grouping_ws_exists(grouping_ws_name: str, inst_ws) -> bool: """ Check that the required grouping workspace for this focus exists, and if not present for a North/South bank focus, retrieve them from the user directories or create them (expected if first focus with loaded calibration) :param grouping_ws_name: Name of the grouping workspace whose presence in the ADS is being checked :param inst_ws: Workspace containing the instrument data for use in making a bank grouping workspace :return: True if the required workspace exists (or has just been loaded/created), False if not """ if not Ads.doesExist(grouping_ws_name): if "North" in grouping_ws_name: logger.notice( "NorthBank grouping workspace not present in ADS, loading") EnggUtils.get_bank_grouping_workspace(1, inst_ws) return True elif "South" in grouping_ws_name: logger.notice( "SouthBank grouping workspace not present in ADS, loading") EnggUtils.get_bank_grouping_workspace(2, inst_ws) return True else: logger.warning( f"Cannot focus as the grouping workspace \"{grouping_ws_name}\" is not present." ) return False return True
def __addNoise(self, mean=0.0, scale=0.1): """ Add some random background noise to the baseline using a normal distribution """ noise_gen = np.random.default_rng(self.noise_seed) self.assertTrue(AnalysisDataService.doesExist("Baseline")) basews = AnalysisDataService.retrieve("Baseline") y = basews.extractY() y = np.add(y, noise_gen.normal(mean, scale, self.resolution)) basews.setY(y)
def get_bank_grouping_workspace(bank: int, sample_raw): # -> GroupingWorkspace """ Retrieve the grouping workspace for the North/South bank from the user directories, or create a new one from the sample workspace instrument data if not found :param bank: integer denoting the bank, 1 or 2 for North/South respectively :param sample_raw: Workspace containing the instrument data that can be used to create a new grouping workspace :return: The loaded or created grouping workspace """ if bank == 1: try: if ADS.doesExist("NorthBank_grouping"): return ADS.retrieve("NorthBank_grouping") grp_ws = mantid.LoadDetectorsGroupingFile( InputFile="ENGINX_North_grouping.xml", OutputWorkspace="NorthBank_grouping") return grp_ws except ValueError: logger.notice( "NorthBank grouping file not found in user directories - creating one" ) bank_name = "NorthBank" elif bank == 2: try: if ADS.doesExist("SouthBank_grouping"): return ADS.retrieve("SouthBank_grouping") grp_ws = mantid.LoadDetectorsGroupingFile( InputFile="ENGINX_South_grouping.xml", OutputWorkspace="SouthBank_grouping") return grp_ws except ValueError: logger.notice( "SouthBank grouping file not found in user directories - creating one" ) bank_name = "SouthBank" else: raise ValueError("Invalid bank number given") ws_name = bank_name + "_grouping" grp_ws, _, _ = mantid.CreateGroupingWorkspace(InputWorkspace=sample_raw, GroupNames=bank_name, OutputWorkspace=ws_name) return grp_ws
def get_detector_ids_for_bank(bank): """ Find the detector IDs for an instrument bank. Note this is at this point specific to the ENGINX instrument. @param bank :: name/number as a string. @returns list of detector IDs corresponding to the specified Engg bank number """ import os grouping_file_path = os.path.join(mantid.config.getInstrumentDirectory(), 'Grouping', 'ENGINX_Grouping.xml') alg = AlgorithmManager.create('LoadDetectorsGroupingFile') alg.initialize() alg.setLogging(False) alg.setProperty('InputFile', grouping_file_path) group_name = '__EnginXGrouping' alg.setProperty('OutputWorkspace', group_name) alg.execute() # LoadDetectorsGroupingFile produces a 'Grouping' workspace. # PropertyWithValue<GroupingWorkspace> not working (GitHub issue 13437) # => cannot run as child and get outputworkspace property properly if not ADS.doesExist(group_name): raise RuntimeError( 'LoadDetectorsGroupingFile did not run correctly. Could not ' 'find its output workspace: ' + group_name) grouping = mtd[group_name] detector_ids = set() # less then zero indicates both banks, from line 98 bank_int = int(bank) if bank_int < 0: # both banks, north and south bank_int = [1, 2] else: # make into list so that the `if in` check works bank_int = [bank_int] for i in range(grouping.getNumberHistograms()): if grouping.readY(i)[0] in bank_int: detector_ids.add(grouping.getDetector(i).getID()) mantid.DeleteWorkspace(grouping) if len(detector_ids) == 0: raise ValueError('Could not find any detector for this bank: ' + bank + '. This looks like an unknown bank') return detector_ids
def _check_region_calib_ws_exists(region: str) -> bool: """ Check that the required workspace for use in focussing the provided region of interest exist in the ADS :param region: String describing region of interest :return: True if present, False if not """ region_ws_name = REGION_CALIB_WS_PREFIX + region present = Ads.doesExist(region_ws_name) if not present: logger.warning( f"Cannot focus as the region calibration workspace \"{region_ws_name}\" is not " f"present.") return present
def load_full_instrument_calibration(): if ADS.doesExist("full_inst_calib"): full_calib = ADS.retrieve("full_inst_calib") else: full_calib_path = get_setting( output_settings.INTERFACES_SETTINGS_GROUP, output_settings.ENGINEERING_PREFIX, "full_calibration") try: full_calib = Load(full_calib_path, OutputWorkspace="full_inst_calib") except ValueError: logger.error( "Error loading Full instrument calibration - this is set in the interface settings." ) return return full_calib
def __createRandPeaksWS(self, amplitude=1.0): """ Creates a test WS with random peaks added to the baseline function """ # Create a new generator, get a permutation of indices used to add peaks to the data. np.random.seed(self.rand_seed) peaklist = np.random.randint(self.peak_border_lim, self.resolution - self.peak_border_lim, self.npeaks) self.assertTrue(AnalysisDataService.doesExist("Baseline")) basews = AnalysisDataService.retrieve("Baseline") x = basews.extractX() y = basews.extractY() # Add a simple peak to the indices chosen by the random permutation for i in peaklist: y[0][i] = y[0][i] + amplitude * np.abs(np.sin(x[0][i])) CreateWorkspace(DataX=x, DataY=y, OutputWorkspace="PeakData")
def create_vanadium_corrections(vanadium_path: str, instrument: str): # -> Workspace, Workspace """ Runs the vanadium correction algorithm. :param vanadium_path: The path to the vanadium data. :return: The integrated workspace and the processed instrument workspace generated. """ try: run_no = path_handling.get_run_number_from_path( vanadium_path, instrument) van_ws = Load(Filename=vanadium_path, OutputWorkspace=str(run_no) + '_' + VANADIUM_INPUT_WORKSPACE_NAME) except Exception as e: logger.error( "Error when loading vanadium sample data. " "Could not run Load algorithm with vanadium run number: " + str(vanadium_path) + ". Error description: " + str(e)) raise RuntimeError # get full instrument calibration for instrument processing calculation if Ads.doesExist("full_inst_calib"): full_calib_ws = Ads.retrieve("full_inst_calib") else: full_calib_path = get_setting( output_settings.INTERFACES_SETTINGS_GROUP, output_settings.ENGINEERING_PREFIX, "full_calibration") try: full_calib_ws = Load(full_calib_path, OutputWorkspace="full_inst_calib") except ValueError: logger.error( "Error loading Full instrument calibration - this is set in the interface settings." ) return integral_ws = _calculate_vanadium_integral(van_ws, run_no) processed_ws = _calculate_vanadium_processed_instrument( van_ws, full_calib_ws, integral_ws, run_no) return integral_ws, processed_ws
def _get_van_curves_for_roi(region: str, van_processed_inst_ws, grouping_ws): # -> Workspace """ Retrieve vanadium curves for this roi from the ADS if they exist, create them if not :param region: String describing region of interest :param van_processed_inst_ws: Processed instrument workspace of this vanadium run :param grouping_ws: Grouping workspace for DiffractionFoucussing :return: Curves workspace for this roi """ curves_roi_name = CURVES_PREFIX + region # check if van curves for roi in ADS (should exist if not first run in session) if Ads.doesExist(curves_roi_name): return Ads.retrieve(curves_roi_name) else: # focus processed instrument ws over specified region of interest, iot produce vanadium curves for roi focused_curves = DiffractionFocussing( InputWorkspace=van_processed_inst_ws, OutputWorkspace=curves_roi_name, GroupingWorkspace=grouping_ws) EnggEstimateFocussedBackground(InputWorkspace=focused_curves, OutputWorkspace=focused_curves, NIterations='15', XWindow=0.03) return focused_curves
def _plotTimeCounts(self, wksp): """ Plot time/counts """ import datetime # Rebin events by pulse time try: # Get run start and run stop if wksp.getRun().hasProperty("run_start"): runstart = wksp.getRun().getProperty("run_start").value else: runstart = wksp.getRun().getProperty("proton_charge").times[0] runstop = wksp.getRun().getProperty("proton_charge").times[-1] runstart = str(runstart).split(".")[0].strip() runstop = str(runstop).split(".")[0].strip() t0 = datetime.datetime.strptime(runstart, "%Y-%m-%dT%H:%M:%S") tf = datetime.datetime.strptime(runstop, "%Y-%m-%dT%H:%M:%S") # Calcualte dt = tf - t0 timeduration = dt.days * 3600 * 24 + dt.seconds timeres = float(timeduration) / MAXTIMEBINSIZE if timeres < 1.0: timeres = 1.0 sumwsname = "_Summed_%s" % (str(wksp)) if AnalysisDataService.doesExist(sumwsname) is False: sumws = api.SumSpectra(InputWorkspace=wksp, OutputWorkspace=sumwsname) sumws = api.RebinByPulseTimes(InputWorkspace=sumws, OutputWorkspace=sumwsname, Params="%f" % (timeres)) sumws = api.ConvertToPointData(InputWorkspace=sumws, OutputWorkspace=sumwsname) else: sumws = AnalysisDataService.retrieve(sumwsname) except RuntimeError as e: return str(e) vecx = sumws.readX(0) vecy = sumws.readY(0) xmin = min(vecx) xmax = max(vecx) ymin = min(vecy) ymax = max(vecy) # Reset graph self.ui.mainplot.set_xlim(xmin, xmax) self.ui.mainplot.set_ylim(ymin, ymax) self.ui.mainplot.set_xlabel('Time (seconds)', fontsize=13) self.ui.mainplot.set_ylabel('Counts', fontsize=13) # Set up main line setp(self.mainline, xdata=vecx, ydata=vecy) # Reset slide newslidery = [min(vecy), max(vecy)] newleftx = xmin + (xmax - xmin) * self._leftSlideValue * 0.01 setp(self.leftslideline, xdata=[newleftx, newleftx], ydata=newslidery) newrightx = xmin + (xmax - xmin) * self._rightSlideValue * 0.01 setp(self.rightslideline, xdata=[newrightx, newrightx], ydata=newslidery) self.ui.graphicsView.draw() return
def _plotTimeCounts(self, wksp): """ Plot time/counts """ import datetime # Rebin events by pulse time try: # Get run start and run stop if wksp.getRun().hasProperty("run_start"): runstart = wksp.getRun().getProperty("run_start").value else: runstart = wksp.getRun().getProperty("proton_charge").times[0] runstop = wksp.getRun().getProperty("proton_charge").times[-1] runstart = str(runstart).split(".")[0].strip() runstop = str(runstop).split(".")[0].strip() t0 = datetime.datetime.strptime(runstart, "%Y-%m-%dT%H:%M:%S") tf = datetime.datetime.strptime(runstop, "%Y-%m-%dT%H:%M:%S") # Calcualte dt = tf-t0 timeduration = dt.days*3600*24 + dt.seconds timeres = float(timeduration)/MAXTIMEBINSIZE if timeres < 1.0: timeres = 1.0 sumwsname = "_Summed_%s"%(str(wksp)) if AnalysisDataService.doesExist(sumwsname) is False: sumws = api.SumSpectra(InputWorkspace=wksp, OutputWorkspace=sumwsname) sumws = api.RebinByPulseTimes(InputWorkspace=sumws, OutputWorkspace = sumwsname, Params="%f"%(timeres)) sumws = api.ConvertToPointData(InputWorkspace=sumws, OutputWorkspace=sumwsname) else: sumws = AnalysisDataService.retrieve(sumwsname) except RuntimeError as e: return str(e) vecx = sumws.readX(0) vecy = sumws.readY(0) xmin = min(vecx) xmax = max(vecx) ymin = min(vecy) ymax = max(vecy) # Reset graph self.ui.mainplot.set_xlim(xmin, xmax) self.ui.mainplot.set_ylim(ymin, ymax) self.ui.mainplot.set_xlabel('Time (seconds)', fontsize=13) self.ui.mainplot.set_ylabel('Counts', fontsize=13) # Set up main line setp(self.mainline, xdata=vecx, ydata=vecy) # Reset slide newslidery = [min(vecy), max(vecy)] newleftx = xmin + (xmax-xmin)*self._leftSlideValue*0.01 setp(self.leftslideline, xdata=[newleftx, newleftx], ydata=newslidery) newrightx = xmin + (xmax-xmin)*self._rightSlideValue*0.01 setp(self.rightslideline, xdata=[newrightx, newrightx], ydata=newslidery) self.ui.graphicsView.draw() return
def focus_run(self, sample_paths, banks, plot_output, instrument, rb_num, spectrum_numbers): """ Focus some data using the current calibration. :param sample_paths: The paths to the data to be focused. :param banks: The banks that should be focused. :param plot_output: True if the output should be plotted. :param instrument: The instrument that the data came from. :param rb_num: The experiment number, used to create directories. Can be None :param spectrum_numbers: The specific spectra that should be focused. Used instead of banks. """ if not Ads.doesExist(vanadium_corrections.INTEGRATED_WORKSPACE_NAME ) and not Ads.doesExist( vanadium_corrections.CURVES_WORKSPACE_NAME): return integration_workspace = Ads.retrieve( vanadium_corrections.INTEGRATED_WORKSPACE_NAME) curves_workspace = Ads.retrieve( vanadium_corrections.CURVES_WORKSPACE_NAME) output_workspaces = [] # List of collated workspaces to plot. full_calib_path = get_setting(path_handling.INTERFACES_SETTINGS_GROUP, path_handling.ENGINEERING_PREFIX, "full_calibration") if full_calib_path is not None and path.exists(full_calib_path): full_calib_workspace = LoadAscii(full_calib_path, OutputWorkspace="det_pos", Separator="Tab") else: full_calib_workspace = None if spectrum_numbers is None: for sample_path in sample_paths: sample_workspace = path_handling.load_workspace(sample_path) run_no = path_handling.get_run_number_from_path( sample_path, instrument) workspaces_for_run = [] for name in banks: output_workspace_name = str( run_no) + "_" + FOCUSED_OUTPUT_WORKSPACE_NAME + str( name) self._run_focus(sample_workspace, output_workspace_name, integration_workspace, curves_workspace, name, full_calib_workspace) workspaces_for_run.append(output_workspace_name) # Save the output to the file system. self._save_output(instrument, sample_path, name, output_workspace_name, rb_num) output_workspaces.append(workspaces_for_run) else: for sample_path in sample_paths: sample_workspace = path_handling.load_workspace(sample_path) run_no = path_handling.get_run_number_from_path( sample_path, instrument) output_workspace_name = str( run_no) + "_" + FOCUSED_OUTPUT_WORKSPACE_NAME + "cropped" self._run_focus(sample_workspace, output_workspace_name, integration_workspace, curves_workspace, None, full_calib_workspace, spectrum_numbers) output_workspaces.append([output_workspace_name]) self._save_output(instrument, sample_path, "cropped", output_workspace_name, rb_num) # Plot the output if plot_output: for ws_names in output_workspaces: self._plot_focused_workspaces(ws_names)
def check_workspaces_exist(): return Ads.doesExist(CURVES_WORKSPACE_NAME) and Ads.doesExist(INTEGRATED_WORKSPACE_NAME)
def _plotTimeCounts(self, wksp): """ Plot time/counts """ import datetime # Rebin events by pulse time try: # Get run start if wksp.getRun().hasProperty("run_start"): runstart = wksp.getRun().getProperty("run_start").value elif wksp.getRun().hasProperty("proton_charge"): runstart = wksp.getRun().getProperty("proton_charge").times[0] else: runstart = wksp.getRun().getProperty("start_time").value # get run stop if wksp.getRun().hasProperty("proton_charge"): runstop = wksp.getRun().getProperty("proton_charge").times[-1] runstop = str(runstop).split(".")[0].strip() tf = datetime.datetime.strptime(runstop, "%Y-%m-%dT%H:%M:%S") else: last_pulse = wksp.getPulseTimeMax().toISO8601String() tf = datetime.datetime.strptime(last_pulse[:19], "%Y-%m-%dT%H:%M:%S") tf += datetime.timedelta(0, wksp.getTofMax() / 1000000) runstart = str(runstart).split(".")[0].strip() t0 = datetime.datetime.strptime(runstart, "%Y-%m-%dT%H:%M:%S") # Calculate dt = tf - t0 timeduration = dt.days * 3600 * 24 + dt.seconds timeres = float(timeduration) / MAXTIMEBINSIZE if timeres < 1.0: timeres = 1.0 sumwsname = '_Summed_{}'.format(wksp) if not AnalysisDataService.doesExist(sumwsname): sumws = api.SumSpectra(InputWorkspace=wksp, OutputWorkspace=sumwsname) sumws = api.RebinByPulseTimes(InputWorkspace=sumws, OutputWorkspace=sumwsname, Params='{}'.format(timeres)) sumws = api.ConvertToPointData(InputWorkspace=sumws, OutputWorkspace=sumwsname) else: sumws = AnalysisDataService.retrieve(sumwsname) except RuntimeError as e: return str(e) vecx = sumws.readX(0) vecy = sumws.readY(0) # if there is only one xbin in the summed workspace, that means we have an evetn file without pulse, # and in this case we use the original workspace time limits if len(vecx) == 1: xmin = min(wksp.readX(0)) / 1000000 xmax = max(wksp.readX(0)) / 1000000 else: xmin = min(vecx) xmax = max(vecx) ymin = min(vecy) ymax = max(vecy) # Reset graph self.ui.mainplot.set_xlim(xmin, xmax) self.ui.mainplot.set_ylim(ymin, ymax) self.ui.mainplot.set_xlabel('Time (seconds)', fontsize=13) self.ui.mainplot.set_ylabel('Counts', fontsize=13) # Set up main line setp(self.mainline, xdata=vecx, ydata=vecy) # Reset slide newslidery = [min(vecy), max(vecy)] newleftx = xmin + (xmax - xmin) * self._leftSlideValue * 0.01 setp(self.leftslideline, xdata=[newleftx, newleftx], ydata=newslidery) newrightx = xmin + (xmax - xmin) * self._rightSlideValue * 0.01 setp(self.rightslideline, xdata=[newrightx, newrightx], ydata=newslidery) self.canvas.draw()
def focus_run(self, sample_paths: list, vanadium_path: str, plot_output: bool, instrument: str, rb_num: str, regions_dict: dict) -> None: """ Focus some data using the current calibration. :param sample_paths: The paths to the data to be focused. :param vanadium_path: Path to the vanadium file from the current calibration :param plot_output: True if the output should be plotted. :param instrument: The instrument that the data came from. :param rb_num: Number to signify the user who is running this focus :param regions_dict: dict region name -> grp_ws_name, defining region(s) of interest to focus over """ full_calib_path = get_setting( output_settings.INTERFACES_SETTINGS_GROUP, output_settings.ENGINEERING_PREFIX, "full_calibration") if not Ads.doesExist("full_inst_calib"): try: full_calib_workspace = Load(full_calib_path, OutputWorkspace="full_inst_calib") except RuntimeError: logger.error( "Error loading Full instrument calibration - this is set in the interface settings." ) return else: full_calib_workspace = Ads.retrieve("full_inst_calib") van_integration_ws, van_processed_inst_ws = vanadium_corrections.fetch_correction_workspaces( vanadium_path, instrument) # check correct region calibration(s) and grouping workspace(s) exists inst_ws = path_handling.load_workspace(sample_paths[0]) for region in regions_dict: calib_exists = self._check_region_calib_ws_exists(region) grouping_exists = self._check_region_grouping_ws_exists( regions_dict[region], inst_ws) if not (calib_exists and grouping_exists): return # loop over samples provided, focus each over region(s) specified in regions_dict output_workspaces = [] # List of collated workspaces to plot. self._last_focused_files = [] van_run_no = path_handling.get_run_number_from_path( vanadium_path, instrument) for sample_path in sample_paths: sample_workspace = path_handling.load_workspace(sample_path) run_no = path_handling.get_run_number_from_path( sample_path, instrument) # perform prefocus operations on whole instrument workspace prefocus_success = self._whole_inst_prefocus( sample_workspace, van_integration_ws, full_calib_workspace) if not prefocus_success: continue sample_plots = [ ] # if both banks focused, pass list with both so plotted on same figure for region, grouping_kwarg in regions_dict.items(): tof_output_name = str( run_no) + "_" + FOCUSED_OUTPUT_WORKSPACE_NAME + region dspacing_output_name = tof_output_name + "_dSpacing" region_calib_ws = self._get_region_calib_ws(region) curves = self._get_van_curves_for_roi(region, van_processed_inst_ws, grouping_kwarg) # perform focus over chosen region of interest self._run_focus(sample_workspace, tof_output_name, curves, grouping_kwarg, region_calib_ws) sample_plots.append(tof_output_name) self._save_output(instrument, run_no, van_run_no, region, tof_output_name, rb_num) self._save_output(instrument, run_no, van_run_no, region, dspacing_output_name, rb_num, unit="dSpacing") self._output_sample_logs(instrument, run_no, van_run_no, sample_workspace, rb_num) output_workspaces.append(sample_plots) DeleteWorkspace(sample_workspace) # remove created grouping workspace if present if Ads.doesExist("grp_ws"): DeleteWorkspace("grp_ws") # Plot the output if plot_output: for ws_names in output_workspaces: self._plot_focused_workspaces(ws_names)