diff --git a/src/mslice/cli/_mslice_commands.py b/src/mslice/cli/_mslice_commands.py index 0dc70ec8..53e7ad21 100644 --- a/src/mslice/cli/_mslice_commands.py +++ b/src/mslice/cli/_mslice_commands.py @@ -16,6 +16,7 @@ from mslice.cli.helperfunctions import (_string_to_integration_axis, _process_axis, _check_workspace_name, _check_workspace_type, _correct_intensity) from mslice.workspace.pixel_workspace import PixelWorkspace +from mslice.workspace.helperfunctions import WorkspaceNameHandler from mslice.util.qt.qapp import QAppThreadCall, mainloop from six import string_types from mslice.workspace.histogram_workspace import HistogramWorkspace @@ -87,7 +88,7 @@ def Load(Filename, OutputWorkspace=None): if OutputWorkspace is not None: old_name = ospath.splitext(ospath.basename(Filename))[0] if merge: - old_name = old_name + '_merged' + old_name = WorkspaceNameHandler(old_name).get_name(merged=True) name = rename_workspace(workspace=old_name, new_name=OutputWorkspace).name return get_workspace_handle(name) diff --git a/src/mslice/models/cut/cut_algorithm.py b/src/mslice/models/cut/cut_algorithm.py index 84883c83..39b70197 100644 --- a/src/mslice/models/cut/cut_algorithm.py +++ b/src/mslice/models/cut/cut_algorithm.py @@ -12,6 +12,7 @@ from mslice.models.units import EnergyUnits from mslice.workspace.helperfunctions import attribute_to_log from .cut_normalisation import normalize_workspace +from mslice.workspace.helperfunctions import WorkspaceNameHandler class Cut(PythonAlgorithm): @@ -87,17 +88,17 @@ def _compute_cut_nonPSD(selected_workspace, cut_axis, integration_axis, emode, a integration_axis.end_meV))) idx = 0 if 'Rebin' in algo else 1 unit = 'DeltaE' - name = '__MSL_EnergyTransfer' + name = WorkspaceNameHandler('_EnergyTransfer').get_name(hide_from_ADS=True, mslice_signature=True) if is_momentum(cut_axis.units): ws_out = _cut_nonPSD_momentum(cut_binning, int_binning, emode, selected_workspace, algo) idx = 1 unit = 'MomentumTransfer' - name = '__MSL_|Q|' + name = WorkspaceNameHandler('_|Q|').get_name(hide_from_ADS=True, mslice_signature=True) elif is_twotheta(cut_axis.units): ws_out = _cut_nonPSD_theta(int_binning, cut_binning, selected_workspace, algo) idx = 1 if 'Rebin' in algo else 0 unit = 'Degrees' - name = '__MSL_Theta' + name = WorkspaceNameHandler('_Theta').get_name(hide_from_ADS=True, mslice_signature=True) elif integration_axis.units == '|Q|': ws_out = _cut_nonPSD_momentum(int_binning, cut_binning, emode, selected_workspace, algo) else: diff --git a/src/mslice/models/intensity_correction_algs.py b/src/mslice/models/intensity_correction_algs.py index a0dc837e..7b35ed7e 100644 --- a/src/mslice/models/intensity_correction_algs.py +++ b/src/mslice/models/intensity_correction_algs.py @@ -15,6 +15,7 @@ from mslice.models.cut.cut_algorithm import _cut_nonPSD_general from math import trunc, ceil +from mslice.workspace.helperfunctions import WorkspaceNameHandler KB_MEV = constants.value('Boltzmann constant in eV/K') * 1000 E_TO_K = np.sqrt(2 * constants.neutron_mass * constants.elementary_charge / 1000) / constants.hbar @@ -141,7 +142,7 @@ def _cut_compute_gdos(scattering_data, sample_temp, q_axis, e_axis, rotated, nor def _cut_compute_gdos_pixel(scattering_data, sample_temp, q_axis, e_axis, rotated, norm_to_one, algorithm, is_icut): pixel_ws = get_workspace_handle(scattering_data.parent) if is_icut: - slice_ws = get_workspace_handle("__" + scattering_data.parent) + slice_ws = get_workspace_handle(WorkspaceNameHandler(scattering_data.parent).get_name(hide_from_ADS=True)) slice_rotated = not _is_momentum_or_two_theta(slice_ws.raw_ws.getXDimension().getUnits()) # fn arg rotated refers to cut. else: slice_rotated = not _is_momentum_or_two_theta(pixel_ws.raw_ws.getXDimension().getUnits()) # no pre existing slice, use pixel ws. diff --git a/src/mslice/models/slice/slice_functions.py b/src/mslice/models/slice/slice_functions.py index 4e375a3f..d854bb8e 100644 --- a/src/mslice/models/slice/slice_functions.py +++ b/src/mslice/models/slice/slice_functions.py @@ -11,11 +11,13 @@ from mslice.workspace.pixel_workspace import PixelWorkspace from mslice.workspace.workspace import Workspace +from mslice.workspace.helperfunctions import WorkspaceNameHandler def compute_slice(selected_workspace, x_axis, y_axis, norm_to_one, store_in_ADS=True): workspace = get_workspace_handle(selected_workspace) - slice = mantid_algorithms.Slice(OutputWorkspace='__' + workspace.name, InputWorkspace=workspace, + output_name = WorkspaceNameHandler(workspace.name).get_name(hide_from_ADS=True) + slice = mantid_algorithms.Slice(OutputWorkspace=output_name, InputWorkspace=workspace, XAxis=x_axis.to_dict(), YAxis=y_axis.to_dict(), PSD=workspace.is_PSD, EMode=workspace.e_mode, NormToOne=norm_to_one, StoreInADS=store_in_ADS) propagate_properties(workspace, slice) diff --git a/src/mslice/models/workspacemanager/workspace_algorithms.py b/src/mslice/models/workspacemanager/workspace_algorithms.py index 89843590..ea684335 100644 --- a/src/mslice/models/workspacemanager/workspace_algorithms.py +++ b/src/mslice/models/workspacemanager/workspace_algorithms.py @@ -25,6 +25,7 @@ from mslice.workspace.pixel_workspace import PixelWorkspace from mslice.workspace.histogram_workspace import HistogramWorkspace from mslice.workspace.workspace import Workspace +from mslice.workspace.helperfunctions import WorkspaceNameHandler from .file_io import save_ascii, save_matlab, save_nexus, save_nxspe @@ -198,18 +199,18 @@ def combine_workspace(selected_workspaces, new_name): def add_workspace_runs(selected_ws): - out_ws_name = selected_ws[0] + '_sum' - sum_ws = MergeRuns(OutputWorkspace=out_ws_name, InputWorkspaces=selected_ws) + sum_ws = MergeRuns(OutputWorkspace=WorkspaceNameHandler(selected_ws[0]).get_name(summed=True), + InputWorkspaces=selected_ws) propagate_properties(get_workspace_handle(selected_ws[0]), sum_ws) def subtract(workspaces, background_ws, ssf): - scaled_bg_ws = Scale(OutputWorkspace=str(background_ws) + '_scaled', + scaled_bg_ws = Scale(OutputWorkspace=WorkspaceNameHandler(background_ws).get_name(scaling_factor=ssf, scaled=True), InputWorkspace=str(background_ws), Factor=ssf, store=False) try: for ws_name in workspaces: - result = Minus(OutputWorkspace=ws_name + '_subtracted', LHSWorkspace=ws_name, - RHSWorkspace=scaled_bg_ws) + result = Minus(OutputWorkspace=WorkspaceNameHandler(ws_name).get_name(scaling_factor=ssf, subtracted=True), + LHSWorkspace=ws_name, RHSWorkspace=scaled_bg_ws) propagate_properties(get_workspace_handle(ws_name), result) except ValueError as e: raise ValueError(e) @@ -217,8 +218,8 @@ def subtract(workspaces, background_ws, ssf): def rebose_single(ws, from_temp, to_temp): ws = get_workspace_handle(ws) - results = Rebose(InputWorkspace=ws, CurrentTemperature=from_temp, TargetTemperature=to_temp, - OutputWorkspace=ws.name+'_bosed') + results = Rebose(OutputWorkspace=WorkspaceNameHandler(ws.name).get_name(rebosed=True), + InputWorkspace=ws, CurrentTemperature=from_temp, TargetTemperature=to_temp) propagate_properties(ws, results) return results @@ -232,7 +233,8 @@ def scale_workspaces(workspaces, scale_factor=None, from_temp=None, to_temp=None else: for ws_name in workspaces: ws = get_workspace_handle(ws_name) - result = Scale(InputWorkspace=ws.raw_ws, Factor=scale_factor, OutputWorkspace=ws_name+'_scaled') + result = Scale(OutputWorkspace=WorkspaceNameHandler(ws_name).get_name(scaling_factor=scale_factor, scaled=True), + InputWorkspace=ws.raw_ws, Factor=scale_factor) propagate_properties(ws, result) diff --git a/src/mslice/presenters/data_loader_presenter.py b/src/mslice/presenters/data_loader_presenter.py index d1e1a15f..80ecbda3 100644 --- a/src/mslice/presenters/data_loader_presenter.py +++ b/src/mslice/presenters/data_loader_presenter.py @@ -8,6 +8,7 @@ from mslice.presenters.interfaces.data_loader_presenter import DataLoaderPresenterInterface from mslice.presenters.presenter_utility import PresenterUtility from mslice.models.workspacemanager.file_io import load_from_ascii +from mslice.workspace.helperfunctions import WorkspaceNameHandler def apply_fixed_final_energy_to_a_valid_workspace(workspace_name, fixed_final_energy: float): @@ -39,7 +40,7 @@ def load_workspace(self, file_paths, merge=False, force_overwrite=False): if not self.file_types_match(file_paths): self._view.error_merge_different_file_formats() return - ws_names = [ws_names[0] + '_merged'] + ws_names = [WorkspaceNameHandler(ws_names[0]).get_name(merged=True)] file_paths = ['+'.join(file_paths)] self._load_ws(file_paths, ws_names, force_overwrite) diff --git a/src/mslice/presenters/slice_plotter_presenter.py b/src/mslice/presenters/slice_plotter_presenter.py index f1c51a77..d7c4d8f5 100644 --- a/src/mslice/presenters/slice_plotter_presenter.py +++ b/src/mslice/presenters/slice_plotter_presenter.py @@ -10,6 +10,7 @@ from mslice.models.workspacemanager.workspace_provider import get_workspace_handle from mslice.plotting.plot_window.overplot_interface import plot_overplot_line, remove_line from mslice.presenters.presenter_utility import PresenterUtility +from mslice.workspace.helperfunctions import WorkspaceNameHandler class SlicePlotterPresenter(PresenterUtility): @@ -31,19 +32,19 @@ def create_slice(self, selected_ws, x_axis, y_axis, intensity_start, intensity_e return slice def plot_from_cache(self, workspace): - ws_name = workspace.name.lstrip('__') + ws_name = WorkspaceNameHandler(workspace.name).get_name(make_ws_visible_in_ADS=True) create_slice_figure(ws_name, self) self.show_scattering_function(ws_name) def change_intensity(self, workspace_name, intensity_start, intensity_end): - workspace_name = workspace_name.lstrip('__') + workspace_name = WorkspaceNameHandler(workspace_name).get_name(make_ws_visible_in_ADS=True) intensity_start, intensity_end = self.validate_intensity(intensity_start, intensity_end) norm = Normalize(vmin=intensity_start, vmax=intensity_end) self._slice_cache[workspace_name].norm = norm def change_colourmap(self, workspace_name, colourmap): if colourmap in ALLOWED_CMAPS: - workspace_name = workspace_name.lstrip('__') + workspace_name = WorkspaceNameHandler(workspace_name).get_name(make_ws_visible_in_ADS=True) self._slice_cache[workspace_name].colourmap = colourmap else: raise ValueError('colourmap not recognised') diff --git a/src/mslice/presenters/workspace_manager_presenter.py b/src/mslice/presenters/workspace_manager_presenter.py index daa06f00..21f97097 100644 --- a/src/mslice/presenters/workspace_manager_presenter.py +++ b/src/mslice/presenters/workspace_manager_presenter.py @@ -2,6 +2,7 @@ from six import string_types from .busy import show_busy +from mslice.workspace.helperfunctions import WorkspaceNameHandler from mslice.widgets.workspacemanager.command import Command from mslice.widgets.workspacemanager import TAB_2D, TAB_NONPSD from mslice.models.workspacemanager.file_io import get_save_directory @@ -144,7 +145,7 @@ def _combine_workspace(self): return elif len(selected_workspaces) == 1: selected_workspaces.append(str(self._workspace_manager_view.add_workspace_dialog())) - new_workspace = selected_workspaces[0] + '_combined' + new_workspace = WorkspaceNameHandler(selected_workspaces[0]).get_name(combined=True) if all([is_pixel_workspace(workspace) for workspace in selected_workspaces]): combine_workspace(selected_workspaces, new_workspace) else: diff --git a/src/mslice/scripting/__init__.py b/src/mslice/scripting/__init__.py index c1611c2e..b078a59c 100644 --- a/src/mslice/scripting/__init__.py +++ b/src/mslice/scripting/__init__.py @@ -2,6 +2,7 @@ from mslice.models.workspacemanager.workspace_provider import get_workspace_handle from mslice.scripting.helperfunctions import add_plot_statements, replace_ws_special_chars from mslice.app.presenters import get_cut_plotter_presenter +from mslice.workspace.helperfunctions import WorkspaceNameHandler from six import string_types @@ -76,12 +77,14 @@ def _parse_prop(prop): pname = prop.name() hidden = False output_ws = None + if isinstance(pval, string_types): - pval = pval.replace("__MSL", "").replace("_HIDDEN", "") + pval = WorkspaceNameHandler(pval).get_name(make_ws_visible_in_ADS=True, make_ws_visible_in_mslice=True) + if prop.name() == "OutputWorkspace": output_ws = replace_ws_special_chars(pval) - if "_HIDDEN" in prop.value(): - hidden = True + hidden = WorkspaceNameHandler(prop.value()).assert_name(is_hidden_from_mslice=True) + return pname, pval, output_ws, hidden diff --git a/src/mslice/util/mantid/_workspace_ops.py b/src/mslice/util/mantid/_workspace_ops.py index 3a2b0917..537e4dd5 100644 --- a/src/mslice/util/mantid/_workspace_ops.py +++ b/src/mslice/util/mantid/_workspace_ops.py @@ -4,6 +4,7 @@ from mantid.api._workspaceops import _do_binary_operation from mantid.kernel.funcinspect import lhs_info from mslice.workspace.workspace import WorkspaceOperatorMixin +from mslice.workspace.helperfunctions import WorkspaceNameHandler _binary_operator_map = { "Plus": operator.add, @@ -65,7 +66,10 @@ def op_wrapper(self, other): result_info = lhs_info() # Replace output workspace name with a unique temporary name hidden in ADS if result_info[0] > 0: - result_info = (result_info[0], ('__MSLTMP' + str(uuid4())[:8],) + result_info[1][1:]) + temp_name = WorkspaceNameHandler(str(uuid4())[:8]).get_name( + hide_from_ADS=True, mslice_signature=True, temporary_signature=True + ) + result_info = (result_info[0], (temp_name,) + result_info[1][1:]) return _binary_op(self, other, algorithm, result_info, inplace, reverse) op_wrapper.__name__ = attr diff --git a/src/mslice/util/mantid/algorithm_wrapper.py b/src/mslice/util/mantid/algorithm_wrapper.py index b32e234a..acbf13d7 100644 --- a/src/mslice/util/mantid/algorithm_wrapper.py +++ b/src/mslice/util/mantid/algorithm_wrapper.py @@ -10,6 +10,8 @@ from mslice.workspace.base import WorkspaceBase as MsliceWorkspace from mslice.workspace.workspace import Workspace as MsliceWorkspace2D +from mslice.workspace.helperfunctions import WorkspaceNameHandler + def _parse_ws_names(args, kwargs): input_workspace = kwargs.get('InputWorkspace', None) @@ -20,9 +22,7 @@ def _parse_ws_names(args, kwargs): input_workspace = get_workspace_handle(args[0]) args = (_name_or_wrapper_to_workspace(args[0]),) + args[1:] - output_name = '' - if 'OutputWorkspace' in kwargs: - output_name = kwargs.pop('OutputWorkspace') + output_name = kwargs.pop('OutputWorkspace', '') for key in kwargs.keys(): if input_workspace is None and 'LHS' in key: @@ -49,14 +49,22 @@ def alg_wrapper(*args, **kwargs): kwargs['InputWorkspaces'] = [_name_or_wrapper_to_workspace(arg) for arg in kwargs['InputWorkspaces']] for ky in [k for k in kwargs.keys() if 'Workspace' in k]: - if isinstance(kwargs[ky], string_types) and '__MSL' not in kwargs[ky]: - kwargs[ky] = _name_or_wrapper_to_workspace(kwargs[ky]) + if isinstance(kwargs[ky], string_types): + if not WorkspaceNameHandler(kwargs[ky]).assert_name(is_hidden_from_ADS=True, has_mslice_signature=True): + kwargs[ky] = _name_or_wrapper_to_workspace(kwargs[ky]) if _alg_has_outputws(algorithm): - ads_name = '__MSL' + output_name if output_name else '__MSLTMP' + str(uuid4())[:8] + if output_name: + ads_name = WorkspaceNameHandler(output_name).get_name(hide_from_ADS=True, mslice_signature=True) + else: + print("Missing output workspace!") + ads_name = WorkspaceNameHandler(str(uuid4())[:8]).get_name( + hide_from_ADS=True, mslice_signature=True, temporary_signature=True + ) + store = kwargs.pop('store', True) if not store: - ads_name += '_HIDDEN' + ads_name = WorkspaceNameHandler(ads_name).get_name(hide_from_mslice=True) result = algorithm(*args, OutputWorkspace=ads_name, **kwargs) else: result = algorithm(*args, **kwargs) @@ -93,7 +101,8 @@ def add_to_ads(workspaces): except TypeError: workspaces = [workspaces] for workspace in workspaces: - startid = (5 if workspace.name.startswith('__mat') else 2) if workspace.name.startswith('__') else 0 + is_hidden_ws = WorkspaceNameHandler(workspace.name).assert_name(is_hidden_from_ADS=True) + startid = (5 if workspace.name.startswith('__mat') else 2) if is_hidden_ws else 0 AnalysisDataService.Instance().addOrReplace(workspace.name[startid:], workspace.raw_ws) @@ -101,6 +110,6 @@ def remove_from_ads(workspacename): if AnalysisDataService.Instance().doesExist(workspacename): AnalysisDataService.Instance().remove(workspacename) # Remove hidden workspaces from ADS - workspacename = '__MSL' + workspacename + workspacename = WorkspaceNameHandler(workspacename).get_name(mslice_signature=True, hide_from_ADS=True) if AnalysisDataService.Instance().doesExist(workspacename): AnalysisDataService.Instance().remove(workspacename) diff --git a/src/mslice/workspace/helperfunctions.py b/src/mslice/workspace/helperfunctions.py index 9bfbd056..fb95823f 100644 --- a/src/mslice/workspace/helperfunctions.py +++ b/src/mslice/workspace/helperfunctions.py @@ -1,6 +1,5 @@ import pickle import codecs - from mantid.simpleapi import DeleteWorkspace, RenameWorkspace @@ -85,7 +84,7 @@ def attribute_to_log(attrdict, raw_ws, append=False): def delete_workspace(workspace, ws): try: - if hasattr(workspace, str(ws)) and ws is not None and ws.name().endswith('_HIDDEN'): + if hasattr(workspace, str(ws)) and ws is not None and WorkspaceNameHandler(ws.name()).assert_name(is_hidden_from_mslice=True): DeleteWorkspace(ws) ws = None except RuntimeError: @@ -116,3 +115,93 @@ def __exit__(self, exc_type, exc_val, exc_tb): if self.workspace: self.workspace.remove_saved_attributes() return True + + +class WorkspaceNameHandler: + + def __init__(self, ws_name: str): + self.ws_name = ws_name + + def _add_prefix(self, prefix) -> str: + self.ws_name = prefix + self.ws_name + + def _add_sufix(self, sufix) -> str: + self.ws_name = self.ws_name + sufix + + def get_name( + self, + scaling_factor=None, + scaled=False, + subtracted=False, + summed=False, + rebosed=False, + combined=False, + merged=False, + hide_from_mslice=False, + hide_from_ADS=False, + mslice_signature=False, + temporary_signature=False, + make_ws_visible_in_ADS=False, + make_ws_visible_in_mslice=False): + + singular_arguments = [scaled, subtracted, summed, rebosed, combined, merged] + assert sum(singular_arguments) <= 1, "Two or more incompatible arguments were set to True." + + if scaled: + assert scaling_factor is not None, "Scaling factor should be provided to build name of workspace" + self._add_sufix("_ssf_" + f"{scaling_factor:.2f}".replace('.', '_')) + + if subtracted: + assert scaling_factor is not None, "Scaling factor should be provided to build name of workspace" + self._add_sufix("_minus_ssf_" + f"{scaling_factor:.2f}".replace('.', '_')) + + if summed: + self._add_sufix("_sum") + + if rebosed: + self._add_sufix("_bosed") + + if combined: + self._add_sufix("_combined") + + if merged: + self._add_sufix("_merged") + + if hide_from_mslice: + self._add_sufix("_HIDDEN") + + if temporary_signature: + self._add_prefix("TMP") + + if mslice_signature: + self._add_prefix("MSL") + + if hide_from_ADS: + self._add_prefix("__") + + if make_ws_visible_in_ADS: + self.ws_name = self.ws_name.replace('__MSL', '').replace('__', '') + + if make_ws_visible_in_mslice: + self.ws_name = self.ws_name.replace('_HIDDEN', '') + + return self.ws_name + + def assert_name( + self, + is_hidden_from_mslice=False, + is_hidden_from_ADS=False, + has_mslice_signature=False): + + result_flag = True + + if is_hidden_from_mslice: + result_flag = result_flag and (self.ws_name.endswith("_HIDDEN")) + + if is_hidden_from_ADS: + result_flag = result_flag and (self.ws_name.startswith("__")) + + if has_mslice_signature: + result_flag = result_flag and (self.ws_name.startswith("__MSL") or self.ws_name.startswith("MSL")) + + return result_flag diff --git a/tests/workspace_provider_test.py b/tests/workspace_provider_test.py index 98e41cea..c14aab65 100644 --- a/tests/workspace_provider_test.py +++ b/tests/workspace_provider_test.py @@ -13,6 +13,7 @@ from mslice.widgets.workspacemanager.command import Command from mantid.simpleapi import AddSampleLog from mslice.views.interfaces.workspace_view import WorkspaceView +from mslice.workspace.helperfunctions import WorkspaceNameHandler class MantidWorkspaceProviderTest(unittest.TestCase): @@ -44,16 +45,16 @@ def test_delete_workspace(self): def test_subtract_workspace(self): subtract(['test_ws_2d'], 'test_ws_2d', 0.95) - result = get_workspace_handle('test_ws_2d_subtracted') + result = get_workspace_handle(WorkspaceNameHandler('test_ws_2d').get_name(subtracted=True, scaling_factor=0.95)) np.testing.assert_array_almost_equal(result.raw_ws.dataY(0), [0.05] * 20) np.testing.assert_array_almost_equal(self.test_ws_2d.raw_ws.dataY(0), [1] * 20) - self.assertFalse('test_ws_2d_scaled' in get_visible_workspace_names()) + self.assertFalse(WorkspaceNameHandler('test_ws_2d').get_name(scaled=True, scaling_factor=0.95) in get_visible_workspace_names()) self.assertRaises(ValueError, subtract, ['test_ws_2d'], 'test_ws_md', 1.0) def test_add_workspace(self): original_data = self.test_ws_2d.raw_ws.dataY(0) add_workspace_runs(['test_ws_2d', 'test_ws_2d']) - result = get_workspace_handle('test_ws_2d_sum') + result = get_workspace_handle(WorkspaceNameHandler('test_ws_2d').get_name(summed=True)) np.testing.assert_array_almost_equal(result.raw_ws.dataY(0), [2.0] * 20) np.testing.assert_array_almost_equal(original_data, [1] * 20)