diff --git a/Code/Mantid/Framework/PythonInterface/mantid/simpleapi.py b/Code/Mantid/Framework/PythonInterface/mantid/simpleapi.py index a8504f916262da4b9f247d1dd228e5a850b044ca..1ded6b0bf0352e05f97a0fe0054a9010ac70383b 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/simpleapi.py +++ b/Code/Mantid/Framework/PythonInterface/mantid/simpleapi.py @@ -20,6 +20,7 @@ """ from __future__ import absolute_import +import os, string import mantid.api as _api import mantid.kernel as _kernel @@ -31,7 +32,7 @@ from mantid.api._aliases import * #------------------------ Specialized function calls -------------------------- # List of specialized algorithms -__SPECIALIZED_FUNCTIONS__ = ["Load", "Fit"] +__SPECIALIZED_FUNCTIONS__ = ["Load", "Fit", "CutMD"] # List of specialized algorithms __MDCOORD_FUNCTIONS__ = ["PeakIntensityVsRadius", "CentroidPeaksMD","IntegratePeaksMD"] # The "magic" keyword to enable/disable logging @@ -257,22 +258,124 @@ def FitDialog(*args, **kwargs): #--------------------------------------------------- -------------------------- -#This dictionary maps algorithm names to functions that preprocess their inputs -#in the simpleapi. The functions take args and kwargs as regular arguments and -#modify them as required. +def CutMD(*args, **kwargs): + """ + Slices multidimensional workspaces using input projection information and binning limits. + """ + (in_wss,) = _get_mandatory_args('CutMD', ["InputWorkspace"], *args, **kwargs) + + # If the input isn't a list, wrap it in one so we can iterate easily + if isinstance(in_wss, list): + in_list = in_wss + handling_multiple_workspaces = True + else: + in_list = [in_wss] + handling_multiple_workspaces = False + + # Remove from keywords so it is not set twice + if "InputWorkspace" in kwargs: + del kwargs['InputWorkspace'] + + #Make sure we were given some output workspace names + lhs = _kernel.funcreturns.lhs_info() + if lhs[0] == 0 and 'OutputWorkspace' not in kwargs: + raise RuntimeError("Unable to set output workspace name. Please either assign the output of " + "CutMD to a variable or use the OutputWorkspace keyword.") + + #Take what we were given + if "OutputWorkspace" in kwargs: + out_names = kwargs["OutputWorkspace"] + else: + out_names = list(lhs[1]) + + #Ensure the output names we were given are valid + if handling_multiple_workspaces: + if not isinstance(out_names, list): + raise RuntimeError("Multiple OutputWorkspaces must be given as a list when processing multiple InputWorkspaces.") + else: + #We wrap in a list for our convenience. The user musn't pass us one though. + if not isinstance(out_names, list): + out_names = [out_names] + elif len(out_names) != 1: + raise RuntimeError("Only one OutputWorkspace required") + + if len(out_names) != len(in_list): + raise RuntimeError("Different number of input and output workspaces given.") + + # Split PBins up into P1Bin, P2Bin, etc. + if "PBins" in kwargs: + bins = kwargs["PBins"] + del kwargs["PBins"] + if isinstance(bins, tuple) or isinstance(bins, list): + for bin in range(len(bins)): + kwargs["P{0}Bin".format(bin+1)] = bins[bin] + + # Create and execute + algm = _create_algorithm_object('CutMD') + _set_logging_option(algm, kwargs) -_algorithm_preprocessors = dict() + # Now check that all the kwargs we've got are correct + for key in kwargs.keys(): + if key not in algm: + raise RuntimeError("Unknown property: {0}".format(key)) + + # We're now going to build to_process, which is the list of workspaces we want to process. + to_process = list() + for i in range(len(in_list)): + ws = in_list[i] + + if isinstance(ws, _api.Workspace): + #It's a workspace, do nothing to it + to_process.append(ws) + elif isinstance(ws, str): + if ws in mtd: + #It's a name of something in the ads, just take it from the ads + to_process.append(_api.AnalysisDataService[ws]) + else: + #Let's try treating it as a filename + load_alg = AlgorithmManager.create("Load") + load_alg.setLogging(True) + load_alg.setAlwaysStoreInADS(False) + load_alg.setProperty("Filename", ws) + load_alg.setProperty("OutputWorkspace", "__loaded_by_cutmd_{0}".format(i+1)) + load_alg.execute() + if not load_alg.isExecuted(): + raise TypeError("Failed to load " + ws) + wsn = load_alg.getProperty("OutputWorkspace").valueAsStr + to_process.append(_api.AnalysisDataService[wsn]) + else: + raise TypeError("Unexpected type: " + type(ws)) + + #Run the algorithm across the inputs and outputs + for i in range(len(to_process)): + _set_properties(algm, **kwargs) + algm.setProperty('InputWorkspace', to_process[i]) + algm.setProperty('OutputWorkspace', out_names[i]) + algm.execute() -def _pp_cutmd(args, kwargs): - if "PBins" in kwargs: - bins = kwargs["PBins"] - del kwargs["PBins"] - if isinstance(bins, tuple) or isinstance(bins, list): - #PBin has been provided, we need to split it out into P1Bin, P2Bin, etc. - for bin in range(len(bins)): - kwargs["P{0}Bin".format(bin+1)] = bins[bin] + #Get the workspace objects so we can return them + for i in range(len(out_names)): + out_names[i] = _api.AnalysisDataService[out_names[i]] -_algorithm_preprocessors["CutMD"] = _pp_cutmd + #We should only return a list if we're handling multiple workspaces + if handling_multiple_workspaces: + return out_names + else: + return out_names[0] + +# Have a better load signature for autocomplete +_signature = "\bInputWorkspace" +# Getting the code object for Load +_f = CutMD.func_code +# Creating a new code object nearly identical, but with the two variable names replaced +# by the property list. +_c = _f.__new__(_f.__class__, _f.co_argcount, _f.co_nlocals, _f.co_stacksize, _f.co_flags, _f.co_code, _f.co_consts, _f.co_names,\ + (_signature, "kwargs"), _f.co_filename, _f.co_name, _f.co_firstlineno, _f.co_lnotab, _f.co_freevars) + +# Replace the code object of the wrapper function +CutMD.func_code = _c + +#--------------------------------------------------- -------------------------- def _get_function_spec(func): """Get the python function signature for the given function object @@ -568,10 +671,6 @@ def _create_algorithm_function(algorithm, version, _algm_object): the proper version of the algorithm without failing. """ - # If needed, preprocess this algorithm's input - if algorithm in _algorithm_preprocessors: - _algorithm_preprocessors[algorithm](args, kwargs) - _version = version if "Version" in kwargs: _version = kwargs["Version"] diff --git a/Code/Mantid/docs/source/algorithms/CutMD-v1.rst b/Code/Mantid/docs/source/algorithms/CutMD-v1.rst index 98b00565f70354061e153679fb13593d870b82d5..da2f0f251e15456314cd10bdb50cc2a8e139241e 100644 --- a/Code/Mantid/docs/source/algorithms/CutMD-v1.rst +++ b/Code/Mantid/docs/source/algorithms/CutMD-v1.rst @@ -9,11 +9,20 @@ Description ----------- -This algorithm performs slicing of multiDimensional data according to a chosen projection, and binning choice. The algorithm uses :ref:`algm-BinMD` or -:ref:`algm-SliceMD` to achieve the binning of the data. The choice of child algorithm used for the slicing is controlled by the NoPix option. +This algorithm performs slicing of multiDimensional data according to a chosen +projection, and binning choice. The algorithm uses :ref:`algm-BinMD` or +:ref:`algm-SliceMD` to achieve the binning of the data. The choice of child +algorithm used for the slicing is controlled by the NoPix option. The synax is similar to that used by `Horace <http://horace.isis.rl.ac.uk/Manipulating_and_extracting_data_from_SQW_files_and_objects#cut_sqw>`__. +Unlike most Mantid algorithms, CutMD can accept a list of workspaces as the +input workspace, given as the name of a workspace in the analysis data service +or the path to a workspace, or simply a workspace object in python. These will +all then be processed sequentially with the same options. The only requirement +is that the same number of output workspaces are also given so that CutMD knows +what to call each output workspace created. + Usage ----- @@ -39,6 +48,10 @@ Usage # Apply the cut (PBins property sets the P1Bin, P2Bin, etc. properties for you) out_md = CutMD(to_cut, Projection=proj_ws, PBins=([0.1], [0.1], [0.1], [-5,5]), NoPix=True) + + #Another way we can call CutMD: + #[out1, out2, out3] = CutMD([to_cut, "some_other_file.nxs", "some_workspace_name"], ...) + print 'number of dimensions', out_md.getNumDims() print 'number of dimensions not integrated', len(out_md.getNonIntegratedDimensions()) dim_dE = out_md.getDimension(3)