{"action":"created","comment":{"url":"https://api.github.com/repos/mantidproject/mantid/pulls/comments/241753237","pull_request_review_id":185097078,"id":241753237,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDI0MTc1MzIzNw==","diff_hunk":"@@ -0,0 +1,603 @@\n+# Mantid Repository : https://github.com/mantidproject/mantid\n+#\n+# Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,\n+#     NScD Oak Ridge National Laboratory, European Spallation Source\n+#     & Institut Laue - Langevin\n+# SPDX - License - Identifier: GPL - 3.0 +\n+# flake8: noqa\n+\n+import numpy as np\n+from mantid.api import MatrixWorkspaceProperty, PropertyMode, WorkspaceUnitValidator\n+from mantid.api import DataProcessorAlgorithm, AlgorithmFactory\n+from mantid.api import AnalysisDataService, AlgorithmManager\n+from mantid.kernel import Direction, FloatArrayProperty, FloatBoundedValidator, FloatArrayMandatoryValidator, Logger\n+from mantid.api import IMaskWorkspace\n+\n+\n+class BilbySANSDataProcessor(DataProcessorAlgorithm):\n+    def __init__(self):\n+        DataProcessorAlgorithm.__init__(self)\n+\n+        self.sanslog = Logger(\"ANSTO SANS Data reduction\")\n+\n+    def category(self):\n+        return \"Workflow\\\\SANS\"\n+\n+    def seeAlso(self):\n+        return [\"Q1D\", \"TOFSANSResolutionByPixel\", \"SANSWideAngleCorrection\"]\n+\n+    def name(self):\n+        return \"BilbySANSDataProcessor\"\n+\n+    def summary(self):\n+        return \"BILBY SANS data reduction. Converts a workspace in wavelength into a 1D or 2D workspace of\" \\\n+               \" momentum transfer, assuming elastic scattering.\"\n+\n+    def PyInit(self):\n+        # input\n+        self.declareProperty(MatrixWorkspaceProperty('InputWorkspace', '',\n+                                                     direction=Direction.Input,\n+                                                     optional=PropertyMode.Mandatory),\n+                             doc='Particle counts as a function of wavelength')\n+\n+        self.declareProperty(MatrixWorkspaceProperty('InputMaskingWorkspace', '',\n+                                                     direction=Direction.Input,\n+                                                     optional=PropertyMode.Optional),\n+                             doc='Mask for the scattering data')\n+\n+        # blocked beam, beam shape and detector corrections\n+        self.declareProperty(MatrixWorkspaceProperty('BlockedBeamWorkspace', '',\n+                                                     direction=Direction.Input,\n+                                                     optional=PropertyMode.Optional),\n+                             doc='Blocked beam scattering')\n+\n+        self.declareProperty(MatrixWorkspaceProperty('EmptyBeamSpectrumShapeWorkspace', '',\n+                                                     direction=Direction.Input,\n+                                                     optional=PropertyMode.Mandatory,\n+                                                     validator=WorkspaceUnitValidator(\"Wavelength\")),\n+                             doc='Empty beam transmission, where only a given wavelength slice is considered')\n+\n+        self.declareProperty(MatrixWorkspaceProperty('SensitivityCorrectionMatrix', '',\n+                                                     direction=Direction.Input,\n+                                                     optional=PropertyMode.Optional),\n+                             doc='Detector sensitivity calibration data set')\n+\n+        self.declareProperty(MatrixWorkspaceProperty('TransmissionWorkspace', '',\n+                                                     direction=Direction.Input,\n+                                                     optional=PropertyMode.Mandatory),\n+                             doc='Sample transmission workspace')\n+\n+        self.declareProperty(MatrixWorkspaceProperty('TransmissionEmptyBeamWorkspace', '',\n+                                                     direction=Direction.Input,\n+                                                     optional=PropertyMode.Mandatory),\n+                             doc='Empty beam transmission workspace')\n+\n+        self.declareProperty(MatrixWorkspaceProperty('TransmissionMaskingWorkspace', '',\n+                                                     direction=Direction.Input,\n+                                                     optional=PropertyMode.Mandatory),\n+                             doc='Mask for the transmission data')\n+\n+        self.declareProperty(name='FitMethod',\n+                             defaultValue='log', doc='Function to use to fit transmission; can be Linear,'\n+                                                     ' Log, Polynomial (first letter shall be capital)')\n+\n+        self.declareProperty(name='PolynomialOrder',\n+                             defaultValue='3',\n+                             doc='Used only for Polynomial function, but needed as an input parameter anyway')\n+\n+        self.declareProperty(name='ScalingFactor',\n+                             defaultValue=1.0,\n+                             validator=FloatBoundedValidator(lower=0.0),\n+                             doc='Attenuating factor')\n+\n+        self.declareProperty(name='SampleThickness',\n+                             defaultValue=1.0,\n+                             validator=FloatBoundedValidator(lower=0.0),\n+                             doc='Thickness of sample')\n+\n+        self.declareProperty(FloatArrayProperty('BinningWavelength',\n+                                                direction=Direction.Input,\n+                                                validator=FloatArrayMandatoryValidator()),\n+                             doc='Wavelength boundaries for reduction: a comma separated list of first bin boundary,'\n+                                 ' width, last bin boundary')\n+\n+        self.declareProperty(FloatArrayProperty('BinningWavelengthTransm',\n+                                                direction=Direction.Input,\n+                                                validator=FloatArrayMandatoryValidator()),\n+                             doc='Wavelengths boundaries for transmission binning: a comma separated list of first bin'\n+                                 ' boundary, width, last bin')\n+\n+        self.declareProperty(FloatArrayProperty('BinningQ',\n+                                                direction=Direction.Input,\n+                                                validator=FloatArrayMandatoryValidator()),\n+                             doc='Output Q-boundaries: a comma separated list of first bin boundary,'\n+                                 ' width, last bin boundary')\n+\n+        self.declareProperty(name='Timemode',\n+                             defaultValue=True,\n+                             doc='If data collected in ToF or monochromatic mode')\n+\n+        self.declareProperty(name='AccountForGravity',\n+                             defaultValue=True,\n+                             doc='Whether to correct for the effects of gravity')\n+\n+        self.declareProperty(name='SolidAngleWeighting',\n+                             defaultValue=True,\n+                             doc='If True, pixels will be weighted by their solid angle')\n+\n+        self.declareProperty(name='RadiusCut',\n+                             defaultValue=1.0,\n+                             validator=FloatBoundedValidator(lower=0.0),\n+                             doc='To increase resolution some wavelengths are excluded within this distance from the'\n+                                 ' beam center (mm). Note that RadiusCut and WaveCut both need to be larger than 0 to'\n+                                 ' affect the effective cutoff. See the algorithm description for a detailed'\n+                                 ' explanation of the cutoff.')\n+\n+        self.declareProperty(name='WaveCut',\n+                             defaultValue=1.0,\n+                             validator=FloatBoundedValidator(lower=0.0),\n+                             doc='To increase resolution by starting to remove some wavelengths below this threshold'\n+                                 ' (angstrom). Note that WaveCut and RadiusCut both need to be larger than 0 to affect'\n+                                 ' on the effective cutoff. See the algorithm description for a detailed explanation'\n+                                 ' of the cutoff.')\n+\n+        self.declareProperty(name='WideAngleCorrection',\n+                             defaultValue=True,\n+                             doc='If true, the wide angle correction for transmissions will be applied')\n+\n+        self.declareProperty(name='Reduce2D',\n+                             defaultValue=False,\n+                             doc='If true, 2D data reduction will be performed')\n+\n+        self.declareProperty(MatrixWorkspaceProperty('OutputWorkspace', '', direction=Direction.Output),\n+                             doc='Name of the workspace that contains the result of the calculation. '\n+                                 'Created automatically.')\n+\n+        self.declareProperty(MatrixWorkspaceProperty('OutputWorkspaceTransmissionFit', '', direction=Direction.Output),\n+                             # This works only when transmission is True. Problems starts when it is not...\n+                             doc='Counts vs wavelength, fit for the sample transmission')\n+\n+    def validateInputs(self):\n+        inputs = dict()\n+\n+        ws_sam = self.getProperty(\"InputWorkspace\").value\n+        ws_samMsk = self.getProperty(\"InputMaskingWorkspace\").value\n+\n+        ws_blk = self.getProperty(\"BlockedBeamWorkspace\").value\n+        ws_emp = self.getProperty(\"EmptyBeamSpectrumShapeWorkspace\").value\n+        ws_sen = self.getProperty(\"SensitivityCorrectionMatrix\").value\n+\n+        ws_tranSam = self.getProperty(\"TransmissionWorkspace\").value\n+        ws_tranEmp = self.getProperty(\"TransmissionEmptyBeamWorkspace\").value\n+        ws_tranMsk = self.getProperty(\"TransmissionMaskingWorkspace\").value\n+\n+        scale = self.getProperty(\"ScalingFactor\").value\n+        thickness = self.getProperty(\"SampleThickness\").value\n+\n+        radiuscut = self.getProperty(\"RadiusCut\").value\n+        wavecut = self.getProperty(\"WaveCut\").value\n+\n+        # -- Validation --\n+        sam_histograms = ws_sam.getNumberHistograms()\n+        if sam_histograms <= 0:\n+            inputs[\"InputWorkspace\"] = \"hast to contain at least one spectrum\"\n+        elif not ws_sam.isHistogramData():\n+            inputs[\"InputWorkspace\"] = \"has to be a histogram\"\n+\n+        if ws_samMsk:\n+            isinstance(ws_samMsk, IMaskWorkspace)\n+\n+        if ws_blk:\n+            if not ws_blk.isHistogramData():\n+                inputs[\"BlockedBeamWorkspace\"] = \"has to be a histogram\"\n+            elif ws_blk.blocksize() != 1:\n+                inputs[\"BlockedBeamWorkspace\"] = \"each spectrum must contain only one y value\"\n+\n+        if ws_emp.getNumberHistograms() != 1:\n+            inputs[\"EmptyBeamSpectrumShapeWorkspace\"] = \"hast to contain only one spectrum\"\n+        elif not ws_emp.isHistogramData():\n+            inputs[\"EmptyBeamSpectrumShapeWorkspace\"] = \"has to be a histogram\"\n+\n+        if ws_sen:\n+            if ws_sen.getNumberHistograms() != sam_histograms:\n+                inputs[\"SensitivityCorrectionMatrix\"] = \"must have same number of spectra as the InputWorkspace\"\n+            elif not ws_sen.isHistogramData():\n+                inputs[\"SensitivityCorrectionMatrix\"] = \"has to be a histogram\"\n+            elif ws_sen.getAxis(0).getUnit().symbol():\n+                inputs[\"SensitivityCorrectionMatrix\"] = \"has to be unitless\"\n+\n+        tran_histograms = ws_tranSam.getNumberHistograms()\n+        if tran_histograms <= 0:\n+            inputs[\"TransmissionWorkspace\"] = \"hast to contain at least one spectrum\"\n+        elif not ws_tranSam.isHistogramData():\n+            inputs[\"TransmissionWorkspace\"] = \"has to be a histogram\"\n+\n+        if ws_tranEmp.getNumberHistograms() != tran_histograms:\n+            inputs[\"TransmissionEmptyBeamWorkspace\"] = \"must have same number of spectra as the TransmissionWorkspace\"\n+        elif not ws_tranEmp.isHistogramData():\n+            inputs[\"TransmissionEmptyBeamWorkspace\"] = \"has to be a histogram\"\n+\n+        if ws_tranMsk:\n+            isinstance(ws_tranMsk, IMaskWorkspace)\n+\n+        if scale <= 0.0:\n+            inputs[\"ScalingFactor\"] = \"has to be greater than zero\"\n+\n+        if thickness <= 0.0:\n+            inputs[\"SampleThickness\"] = \"has to be greater than zero\"\n+\n+        if radiuscut < 0.0:\n+            inputs[\"radiuscut\"] = \"has to be equal or greater than zero\"\n+\n+        if wavecut < 0.0:\n+            inputs[\"wavecut\"] = \"has to be equal or greater than zero\"\n+\n+        return inputs\n+\n+    def PyExec(self):\n+        self.sanslog.warning(\n+            \"SANSDataProcessing is in the beta phase of development. Properties may change without notice.\")\n+        self.sanslog.warning(\"Log on the changes is recorded in the body of SANSDataProcessor.py file\")\n+\n+        # -- Get Arguments --\n+        ws_sam = self.getProperty(\"InputWorkspace\").value\n+        ws_samMsk = self.getProperty(\"InputMaskingWorkspace\").value\n+\n+        ws_blk = self.getProperty(\"BlockedBeamWorkspace\").value\n+        ws_emp = self.getProperty(\"EmptyBeamSpectrumShapeWorkspace\").value\n+        ws_sen = self.getProperty(\"SensitivityCorrectionMatrix\").value\n+\n+        ws_tranSam = self.getProperty(\"TransmissionWorkspace\").value\n+        ws_tranEmp = self.getProperty(\"TransmissionEmptyBeamWorkspace\").value\n+        ws_tranMsk = self.getProperty(\"TransmissionMaskingWorkspace\").value\n+\n+        scale = self.getProperty(\"ScalingFactor\").value\n+        thickness = self.getProperty(\"SampleThickness\").value\n+\n+        binning_wavelength = self.getProperty(\"BinningWavelength\").value\n+        binning_q = self.getProperty(\"BinningQ\").value\n+\n+        wavecut = self.getProperty(\"WaveCut\").value\n+        radiuscut = self.getProperty(\"RadiusCut\").value\n+\n+        binning_wavelength_transm = self.getProperty(\"BinningWavelengthTransm\").value\n+        fitmethod = self.getProperty(\"FitMethod\").value\n+        polynomialorder = self.getProperty(\"PolynomialOrder\").value\n+\n+        time_mode = self.getProperty(\n+            \"TimeMode\").value\n+        # True if External time frame (i.e. choppers), False if Internal time frames (Neutron Velocity Selector)\n+        account_for_gravity = self.getProperty(\"AccountForGravity\").value\n+        solid_angle_weighting = self.getProperty(\"SolidAngleWeighting\").value\n+        wide_angle_correction = self.getProperty(\"WideAngleCorrection\").value\n+        reduce_2d = self.getProperty(\"Reduce2D\").value\n+\n+        # -- Masking --\n+        if ws_samMsk:\n+            self._apply_mask(ws_sam, ws_samMsk)\n+\n+        if ws_tranMsk:\n+            self._apply_mask(ws_tranSam, ws_tranMsk)\n+            self._apply_mask(ws_tranEmp, ws_tranMsk)\n+\n+        # -- Convert to Wavelength --  Only for the External time mode - choppers\n+        if time_mode:\n+            ws_sam = self._convert_units(ws_sam, \"Wavelength\")\n+            ws_tranSam = self._convert_units(ws_tranSam, \"Wavelength\")\n+            ws_tranEmp = self._convert_units(ws_tranEmp, \"Wavelength\")\n+\n+        # -- Transmission --\n+        # Intuitively one would think rebin for NVS data is not needed, but it does;\n+        # not perfect match in binning leads to error like \"not matching intervals for calculate_transmission\"\n+\n+        ws_sam = self._rebin(ws_sam, binning_wavelength, preserveevents=False)\n+        ws_tranSam = self._rebin(ws_tranSam, binning_wavelength_transm, preserveevents=False)\n+\n+        ws_tranEmp = self._rebin(ws_tranEmp, binning_wavelength_transm, preserveevents=False)\n+\n+        ws_tranroi = self._mask_to_roi(ws_tranMsk)\n+\n+        self.sanslog.information(\"FitMethod \" + fitmethod)\n+        self.sanslog.information(\"PolynomialOrder \" + polynomialorder)\n+\n+        ws_tran = self._calculate_transmission(ws_tranSam, ws_tranEmp, ws_tranroi, fitmethod, polynomialorder,\n+                                               binning_wavelength_transm)\n+\n+        ws_tranemp_scale = self._get_frame_count(ws_tranEmp)\n+        ws_transam_scale = self._get_frame_count(ws_tranSam)\n+\n+        f = self._single_valued_ws(ws_tranemp_scale / ws_transam_scale)\n+        ws_tran = self._multiply(ws_tran, f)\n+\n+        transmission_fit = ws_tran\n+        self.setProperty(\"OutputWorkspaceTransmissionFit\", transmission_fit)\n+\n+        # -- Blocked Beam Subtraction -- only if blk workspace has been provided (obviously)\n+        if ws_blk:\n+            ws_sam_time = self._get_frame_count(ws_sam)\n+            ws_blk_time = self._get_frame_count(ws_blk)\n+\n+            ws_blk_scaling = self._single_valued_ws(ws_sam_time / ws_blk_time)\n+\n+            # remove estimated blk counts from sample workspace\n+            self._apply_mask(ws_blk, ws_samMsk)  # masking blocked beam the same way as sample data\n+            if time_mode:\n+                ws_blk = self._convert_units(ws_blk, \"Wavelength\")\n+            ws_blk = self._rebin(ws_blk, binning_wavelength, preserveevents=False)\n+            # estimated blk counts for given measurement time and bin width\n+            ws_blk_est = self._multiply(ws_blk, ws_blk_scaling)\n+            ws_sam = self._subtract(ws_sam, ws_blk_est)\n+\n+        # sensitivity\n+        pixeladj = ws_sen\n+\n+        ws_tran = self._emp_shape_adjustment(ws_tran,\n+                                             ws_emp)  # swap arrays; ws_emp is always be shorter or equal to ws_tran\n+        wavelengthadj = self._multiply(ws_emp, ws_tran)\n+\n+        # calculate the wide angle correction for sample transmission\n+        if wide_angle_correction:\n+            wavepixeladj = self._wide_angle_correction(ws_sam, ws_tran)\n+        else:\n+            wavepixeladj = None\n+\n+        # distance to maximum of parabolic motion of neutrons\n+        real_l1 = self._get_l1(ws_sam)  # distance from the end of the last guide to the sample\n+        extralength = 0.5 * real_l1  # neutrons following parabolic trajectory with maximum at the middle of the L1\n+\n+        # normalize vector to counting time of sample & long empty beam run\n+        ws_emp_time = self._get_frame_count(ws_emp)\n+        ws_sam_time = self._get_frame_count(ws_sam)\n+        scale_full = scale * (ws_emp_time / ws_sam_time)\n+        # extra multiplier is needed because measured transmission is ~5% lower;\n+        # we need to divide result by lower number, hence need to lowering the final result, i.e. divide by 1.05\n+        f = self._single_valued_ws(scale_full / (thickness * 1.05))\n+\n+        if reduce_2d:\n+            q_max = binning_q[2]\n+            q_delta = binning_q[1]\n+            qxy = self._qxy(ws_sam, q_max, q_delta, pixeladj, wavelengthadj, account_for_gravity, solid_angle_weighting,\n+                            extralength)\n+            qxy = self._multiply(qxy, f)\n+            self.setProperty(\"OutputWorkspace\", qxy)\n+        else:\n+            deltar = 5.0  # Virtual ring width on the detector (mm). Hardcoded. Not sure it is a good way to go.\n+\n+            if (ws_sam.run().getProperty(\"source_aperture\").value):\n+                sourceapertureradius = float(ws_sam.run().getProperty(\"source_aperture\").value) / 2.0\n+                if sourceapertureradius > 40.0:\n+                    sourceapertureradius = 20.0\n+                    print(\"sourceapertureradius value cannot be retrieved; generic value of 20mm taken\")\n+            else:\n+                sourceapertureradius = 20.0  # radius in mm\n+                print(\"sourceapertureradius value cannot be retrieved; generic value of 20mm taken\")\n+\n+            if (ws_sam.run().getProperty(\"sample_aperture\").value):\n+                sampleapertureradius = float(ws_sam.run().getProperty(\"source_aperture\").value) / 2.0\n+                if sampleapertureradius > 40.0:\n+                    sampleapertureradius = 6.25\n+                    print(\"sampleapertureradius value cannot be retrieved; generic value of 6.25mm taken\")\n+            else:\n+                sampleapertureradius = 6.25  # radius in mm\n+                print(\"sampleapertureradius value cannot be retrieved; generic value of 6.25mm taken\")\n+\n+                # creating empty array for SigmaModerator\n+            # SigmaModerator is a mandatory parameter for ISIS, but not needed for the reactor facility\n+            number_of_bins = 10\n+            number_of_spectra = 1\n+            delta_wavelength = 0.1\n+\n+            data_x = np.zeros(number_of_bins + 1)\n+            data_y = np.zeros(number_of_bins)\n+            x_value = 0.5\n+            y_value = 0.0\n+            for index in range(number_of_bins):\n+                data_x[index] = x_value\n+                data_y[index] = y_value\n+                x_value += delta_wavelength\n+            data_x[number_of_bins] = x_value\n+            units = \"Wavelength\"\n+\n+            sigmamoderator = self._create_empty_ws(data_x, data_y, number_of_spectra, units)\n+\n+            # Call TOFSANSResolutionByPixel\n+            ws_sam = self._multiply(ws_sam, f)\n+            qresolution = self._tofsansresolutionbypixel(ws_sam, deltar, sampleapertureradius, sourceapertureradius,\n+                                                         sigmamoderator, real_l1, account_for_gravity, extralength)\n+\n+            # Call Q1D, now with resolution\n+            q1d = self._q1d(ws_sam, binning_q, pixeladj, wavelengthadj, wavepixeladj, account_for_gravity,\n+                            solid_angle_weighting, radiuscut, wavecut, extralength, qresolution)\n+\n+            self.setProperty(\"OutputWorkspace\", q1d)  # set output, file 1D pattern\n+\n+    def _get_time_span(self, ws):\n+        run = ws.getRun()\n+        duration = run.endTime() - run.starme()\n+        return float(duration.total_microseconds())\n+\n+    def _get_bm_counts(self, ws):\n+        return float(ws.run().getProperty(\"bm_counts\").value)\n+\n+    def _get_frame_count(self, ws):\n+        return float(ws.run().getProperty(\"frame_count\").value)\n+\n+    def _get_period(self, ws):\n+        return float(ws.run().getProperty(\"period\").value)\n+\n+    def _get_l1(self, ws):\n+        return float(ws.run().getProperty(\"L1\").value)\n+\n+    def _apply_mask(self, ws, mask):\n+        alg = self.createChildAlgorithm(\"MaskDetectors\")\n+        alg.setProperty(\"Workspace\", ws)\n+        alg.setProperty(\"MaskedWorkspace\", mask)\n+        alg.execute()\n+\n+    def _convert_units(self, ws, unit):\n+        alg = self.createChildAlgorithm(\"ConvertUnits\")\n+        alg.setProperty(\"InputWorkspace\", ws)\n+        alg.setProperty(\"Target\", unit)\n+        alg.execute()\n+\n+        return alg.getProperty(\"OutputWorkspace\").value\n+\n+    def _rebin(self, ws, binning, preserveevents):\n+        alg = self.createChildAlgorithm(\"Rebin\")\n+        alg.setProperty(\"InputWorkspace\", ws)\n+        alg.setProperty(\"Params\", binning)\n+        alg.setProperty(\"PreserveEvents\", preserveevents)\n+        alg.execute()\n+\n+        return alg.getProperty(\"OutputWorkspace\").value\n+\n+    def _multiply(self, a, b):\n+        alg = self.createChildAlgorithm(\"Multiply\")\n+        alg.setProperty(\"LHSWorkspace\", a)\n+        alg.setProperty(\"RHSWorkspace\", b)\n+        alg.execute()\n+\n+        return alg.getProperty(\"OutputWorkspace\").value\n+\n+    def _scale_mult(self, ws_input, factor, operation):\n+        alg = self.createChildAlgorithm(\"Scale\")\n+        alg.setProperty(\"InputWorkspace\", ws_input)\n+        alg.setProperty(\"Factor\", factor)\n+        alg.setProperty(\"Operation\", operation)\n+        alg.execute()\n+        return alg.getProperty(\"OutputWorkspace\").value\n+\n+    def _subtract(self, a, b):\n+        alg = self.createChildAlgorithm(\"Minus\")\n+        alg.setProperty(\"LHSWorkspace\", a)\n+        alg.setProperty(\"RHSWorkspace\", b)\n+        alg.execute()\n+        return alg.getProperty(\"OutputWorkspace\").value\n+\n+    def _single_valued_ws(self, value):\n+        alg = self.createChildAlgorithm(\"CreateSingleValuedWorkspace\")\n+        alg.setProperty(\"DataValue\", value)\n+        alg.execute()\n+        return alg.getProperty(\"OutputWorkspace\").value\n+\n+    def _mask_to_roi(self, ws_mask):\n+        # invert mask and then extract \"masked\" detectors in order to get ROI\n+        # BUG in Mantid forces us to use AnalysisDataService\n+        alg = AlgorithmManager.create(\"InvertMask\")","path":"Framework/PythonInterface/plugins/algorithms/BilbySANSDataProcessor.py","position":486,"original_position":486,"commit_id":"171da06c334b11ef40b7d46606b7e5e5f5c2bf23","original_commit_id":"171da06c334b11ef40b7d46606b7e5e5f5c2bf23","user":{"login":"Pasarus","id":24723609,"node_id":"MDQ6VXNlcjI0NzIzNjA5","avatar_url":"https://avatars2.githubusercontent.com/u/24723609?v=4","gravatar_id":"","url":"https://api.github.com/users/Pasarus","html_url":"https://github.com/Pasarus","followers_url":"https://api.github.com/users/Pasarus/followers","following_url":"https://api.github.com/users/Pasarus/following{/other_user}","gists_url":"https://api.github.com/users/Pasarus/gists{/gist_id}","starred_url":"https://api.github.com/users/Pasarus/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Pasarus/subscriptions","organizations_url":"https://api.github.com/users/Pasarus/orgs","repos_url":"https://api.github.com/users/Pasarus/repos","events_url":"https://api.github.com/users/Pasarus/events{/privacy}","received_events_url":"https://api.github.com/users/Pasarus/received_events","type":"User","site_admin":false},"body":"Could I ask why this call isn't being made just on one line (e.g. InvertMask(InputWorkspaces=ws_mask, OutputWorkspace=\"_ws\") instead of using the AlgorithmManager? (Mostly for my own blind curiosity)","created_at":"2018-12-14T13:25:41Z","updated_at":"2018-12-14T13:47:36Z","html_url":"https://github.com/mantidproject/mantid/pull/23109#discussion_r241753237","pull_request_url":"https://api.github.com/repos/mantidproject/mantid/pulls/23109","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/mantidproject/mantid/pulls/comments/241753237"},"html":{"href":"https://github.com/mantidproject/mantid/pull/23109#discussion_r241753237"},"pull_request":{"href":"https://api.github.com/repos/mantidproject/mantid/pulls/23109"}}},"pull_request":{"url":"https://api.github.com/repos/mantidproject/mantid/pulls/23109","id":204096312,"node_id":"MDExOlB1bGxSZXF1ZXN0MjA0MDk2MzEy","html_url":"https://github.com/mantidproject/mantid/pull/23109","diff_url":"https://github.com/mantidproject/mantid/pull/23109.diff","patch_url":"https://github.com/mantidproject/mantid/pull/23109.patch","issue_url":"https://api.github.com/repos/mantidproject/mantid/issues/23109","number":23109,"state":"open","locked":false,"title":"Added algorithm and system tests framework ","user":{"login":"Mantid-Matthew","id":32058966,"node_id":"MDQ6VXNlcjMyMDU4OTY2","avatar_url":"https://avatars1.githubusercontent.com/u/32058966?v=4","gravatar_id":"","url":"https://api.github.com/users/Mantid-Matthew","html_url":"https://github.com/Mantid-Matthew","followers_url":"https://api.github.com/users/Mantid-Matthew/followers","following_url":"https://api.github.com/users/Mantid-Matthew/following{/other_user}","gists_url":"https://api.github.com/users/Mantid-Matthew/gists{/gist_id}","starred_url":"https://api.github.com/users/Mantid-Matthew/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Mantid-Matthew/subscriptions","organizations_url":"https://api.github.com/users/Mantid-Matthew/orgs","repos_url":"https://api.github.com/users/Mantid-Matthew/repos","events_url":"https://api.github.com/users/Mantid-Matthew/events{/privacy}","received_events_url":"https://api.github.com/users/Mantid-Matthew/received_events","type":"User","site_admin":false},"body":"**Description of work.**\r\n\r\nThis adds the algorithm BilbySANSDataProcessor.py  as well as associated scripts to the mantid codebase. It also adds a system test for this algorithm.\r\n\r\n**Report to:** Anna. <!--If the original issue was raised by a user they should be named here.-->\r\n\r\n**To test:**\r\n\r\nAlready validated by instrument scientist. Code and documentation review and checking tests pass still required.\r\n\r\n<!-- Instructions for testing. -->\r\n\r\nFixes #23108. <!-- and fix #xxxx or close #xxxx xor resolves #xxxx -->\r\n\r\nDoes this update require release notes?\r\n- [ ] Yes\r\n- [ ] No\r\n<!--\r\nIf yes, edit the file docs/source/release/... \r\n-->\r\n\r\n---\r\n\r\n#### Reviewer ####\r\n\r\nPlease comment on the following ([full description](http://www.mantidproject.org/Individual_Ticket_Testing)):\r\n\r\n##### Code Review #####\r\n\r\n- [ ] Is the code of an acceptable quality?\r\n- [ ] Does the code conform to the [coding standards](http://www.mantidproject.org/Coding_Standards)?\r\n- [ ] Are the unit tests small and test the class in isolation?\r\n- [ ] If there are changes in the release notes then do they describe the changes appropriately?\r\n\r\n##### Functional Tests #####\r\n\r\n- [ ] Do changes function as described? Add comments below that describe the tests performed?\r\n- [ ] Do the changes handle unexpected situations, e.g. bad input?\r\n- [ ] Has the relevant (user and developer) documentation been added/updated?\r\n\r\nDoes everything look good? Mark the review as **Approve**. A member of `@mantidproject/gatekeepers` will take care of it.\r\n","created_at":"2018-07-26T10:25:08Z","updated_at":"2018-12-14T13:47:35Z","closed_at":null,"merged_at":null,"merge_commit_sha":"e18b9e6fe4c4fd267fb5328d1c8e09fcf7b8a552","assignee":{"login":"Pasarus","id":24723609,"node_id":"MDQ6VXNlcjI0NzIzNjA5","avatar_url":"https://avatars2.githubusercontent.com/u/24723609?v=4","gravatar_id":"","url":"https://api.github.com/users/Pasarus","html_url":"https://github.com/Pasarus","followers_url":"https://api.github.com/users/Pasarus/followers","following_url":"https://api.github.com/users/Pasarus/following{/other_user}","gists_url":"https://api.github.com/users/Pasarus/gists{/gist_id}","starred_url":"https://api.github.com/users/Pasarus/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Pasarus/subscriptions","organizations_url":"https://api.github.com/users/Pasarus/orgs","repos_url":"https://api.github.com/users/Pasarus/repos","events_url":"https://api.github.com/users/Pasarus/events{/privacy}","received_events_url":"https://api.github.com/users/Pasarus/received_events","type":"User","site_admin":false},"assignees":[{"login":"Pasarus","id":24723609,"node_id":"MDQ6VXNlcjI0NzIzNjA5","avatar_url":"https://avatars2.githubusercontent.com/u/24723609?v=4","gravatar_id":"","url":"https://api.github.com/users/Pasarus","html_url":"https://github.com/Pasarus","followers_url":"https://api.github.com/users/Pasarus/followers","following_url":"https://api.github.com/users/Pasarus/following{/other_user}","gists_url":"https://api.github.com/users/Pasarus/gists{/gist_id}","starred_url":"https://api.github.com/users/Pasarus/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Pasarus/subscriptions","organizations_url":"https://api.github.com/users/Pasarus/orgs","repos_url":"https://api.github.com/users/Pasarus/repos","events_url":"https://api.github.com/users/Pasarus/events{/privacy}","received_events_url":"https://api.github.com/users/Pasarus/received_events","type":"User","site_admin":false}],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":40342875,"node_id":"MDU6TGFiZWw0MDM0Mjg3NQ==","url":"https://api.github.com/repos/mantidproject/mantid/labels/Component:%20SANS","name":"Component: SANS","color":"009800","default":false}],"milestone":{"url":"https://api.github.com/repos/mantidproject/mantid/milestones/68","html_url":"https://github.com/mantidproject/mantid/milestone/68","labels_url":"https://api.github.com/repos/mantidproject/mantid/milestones/68/labels","id":3113735,"node_id":"MDk6TWlsZXN0b25lMzExMzczNQ==","number":68,"title":"Release 3.14 (4.0?)","description":"Code freeze: 1st Mar\r\nBeta test: 6th - 19th Mar","creator":{"login":"NickDraper","id":1017173,"node_id":"MDQ6VXNlcjEwMTcxNzM=","avatar_url":"https://avatars1.githubusercontent.com/u/1017173?v=4","gravatar_id":"","url":"https://api.github.com/users/NickDraper","html_url":"https://github.com/NickDraper","followers_url":"https://api.github.com/users/NickDraper/followers","following_url":"https://api.github.com/users/NickDraper/following{/other_user}","gists_url":"https://api.github.com/users/NickDraper/gists{/gist_id}","starred_url":"https://api.github.com/users/NickDraper/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/NickDraper/subscriptions","organizations_url":"https://api.github.com/users/NickDraper/orgs","repos_url":"https://api.github.com/users/NickDraper/repos","events_url":"https://api.github.com/users/NickDraper/events{/privacy}","received_events_url":"https://api.github.com/users/NickDraper/received_events","type":"User","site_admin":false},"open_issues":284,"closed_issues":893,"state":"open","created_at":"2018-02-13T15:42:17Z","updated_at":"2018-12-14T13:30:59Z","due_on":"2019-03-25T07:00:00Z","closed_at":null},"commits_url":"https://api.github.com/repos/mantidproject/mantid/pulls/23109/commits","review_comments_url":"https://api.github.com/repos/mantidproject/mantid/pulls/23109/comments","review_comment_url":"https://api.github.com/repos/mantidproject/mantid/pulls/comments{/number}","comments_url":"https://api.github.com/repos/mantidproject/mantid/issues/23109/comments","statuses_url":"https://api.github.com/repos/mantidproject/mantid/statuses/171da06c334b11ef40b7d46606b7e5e5f5c2bf23","head":{"label":"mantidproject:23108_adding_bilby_algorithm_to_code_base","ref":"23108_adding_bilby_algorithm_to_code_base","sha":"171da06c334b11ef40b7d46606b7e5e5f5c2bf23","user":{"login":"mantidproject","id":671496,"node_id":"MDEyOk9yZ2FuaXphdGlvbjY3MTQ5Ng==","avatar_url":"https://avatars0.githubusercontent.com/u/671496?v=4","gravatar_id":"","url":"https://api.github.com/users/mantidproject","html_url":"https://github.com/mantidproject","followers_url":"https://api.github.com/users/mantidproject/followers","following_url":"https://api.github.com/users/mantidproject/following{/other_user}","gists_url":"https://api.github.com/users/mantidproject/gists{/gist_id}","starred_url":"https://api.github.com/users/mantidproject/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mantidproject/subscriptions","organizations_url":"https://api.github.com/users/mantidproject/orgs","repos_url":"https://api.github.com/users/mantidproject/repos","events_url":"https://api.github.com/users/mantidproject/events{/privacy}","received_events_url":"https://api.github.com/users/mantidproject/received_events","type":"Organization","site_admin":false},"repo":{"id":2594116,"node_id":"MDEwOlJlcG9zaXRvcnkyNTk0MTE2","name":"mantid","full_name":"mantidproject/mantid","private":false,"owner":{"login":"mantidproject","id":671496,"node_id":"MDEyOk9yZ2FuaXphdGlvbjY3MTQ5Ng==","avatar_url":"https://avatars0.githubusercontent.com/u/671496?v=4","gravatar_id":"","url":"https://api.github.com/users/mantidproject","html_url":"https://github.com/mantidproject","followers_url":"https://api.github.com/users/mantidproject/followers","following_url":"https://api.github.com/users/mantidproject/following{/other_user}","gists_url":"https://api.github.com/users/mantidproject/gists{/gist_id}","starred_url":"https://api.github.com/users/mantidproject/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mantidproject/subscriptions","organizations_url":"https://api.github.com/users/mantidproject/orgs","repos_url":"https://api.github.com/users/mantidproject/repos","events_url":"https://api.github.com/users/mantidproject/events{/privacy}","received_events_url":"https://api.github.com/users/mantidproject/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/mantidproject/mantid","description":"Main repository for Mantid code","fork":false,"url":"https://api.github.com/repos/mantidproject/mantid","forks_url":"https://api.github.com/repos/mantidproject/mantid/forks","keys_url":"https://api.github.com/repos/mantidproject/mantid/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mantidproject/mantid/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mantidproject/mantid/teams","hooks_url":"https://api.github.com/repos/mantidproject/mantid/hooks","issue_events_url":"https://api.github.com/repos/mantidproject/mantid/issues/events{/number}","events_url":"https://api.github.com/repos/mantidproject/mantid/events","assignees_url":"https://api.github.com/repos/mantidproject/mantid/assignees{/user}","branches_url":"https://api.github.com/repos/mantidproject/mantid/branches{/branch}","tags_url":"https://api.github.com/repos/mantidproject/mantid/tags","blobs_url":"https://api.github.com/repos/mantidproject/mantid/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mantidproject/mantid/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mantidproject/mantid/git/refs{/sha}","trees_url":"https://api.github.com/repos/mantidproject/mantid/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mantidproject/mantid/statuses/{sha}","languages_url":"https://api.github.com/repos/mantidproject/mantid/languages","stargazers_url":"https://api.github.com/repos/mantidproject/mantid/stargazers","contributors_url":"https://api.github.com/repos/mantidproject/mantid/contributors","subscribers_url":"https://api.github.com/repos/mantidproject/mantid/subscribers","subscription_url":"https://api.github.com/repos/mantidproject/mantid/subscription","commits_url":"https://api.github.com/repos/mantidproject/mantid/commits{/sha}","git_commits_url":"https://api.github.com/repos/mantidproject/mantid/git/commits{/sha}","comments_url":"https://api.github.com/repos/mantidproject/mantid/comments{/number}","issue_comment_url":"https://api.github.com/repos/mantidproject/mantid/issues/comments{/number}","contents_url":"https://api.github.com/repos/mantidproject/mantid/contents/{+path}","compare_url":"https://api.github.com/repos/mantidproject/mantid/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mantidproject/mantid/merges","archive_url":"https://api.github.com/repos/mantidproject/mantid/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mantidproject/mantid/downloads","issues_url":"https://api.github.com/repos/mantidproject/mantid/issues{/number}","pulls_url":"https://api.github.com/repos/mantidproject/mantid/pulls{/number}","milestones_url":"https://api.github.com/repos/mantidproject/mantid/milestones{/number}","notifications_url":"https://api.github.com/repos/mantidproject/mantid/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mantidproject/mantid/labels{/name}","releases_url":"https://api.github.com/repos/mantidproject/mantid/releases{/id}","deployments_url":"https://api.github.com/repos/mantidproject/mantid/deployments","created_at":"2011-10-17T19:07:38Z","updated_at":"2018-12-14T10:27:53Z","pushed_at":"2018-12-14T13:09:49Z","git_url":"git://github.com/mantidproject/mantid.git","ssh_url":"git@github.com:mantidproject/mantid.git","clone_url":"https://github.com/mantidproject/mantid.git","svn_url":"https://github.com/mantidproject/mantid","homepage":"www.mantidproject.org","size":525129,"stargazers_count":97,"watchers_count":97,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":60,"mirror_url":null,"archived":false,"open_issues_count":1916,"license":{"key":"gpl-3.0","name":"GNU General Public License v3.0","spdx_id":"GPL-3.0","url":"https://api.github.com/licenses/gpl-3.0","node_id":"MDc6TGljZW5zZTk="},"forks":60,"open_issues":1916,"watchers":97,"default_branch":"master"}},"base":{"label":"mantidproject:master","ref":"master","sha":"fe067c5ee3ab67590f8bd304265f9c35a6fc76aa","user":{"login":"mantidproject","id":671496,"node_id":"MDEyOk9yZ2FuaXphdGlvbjY3MTQ5Ng==","avatar_url":"https://avatars0.githubusercontent.com/u/671496?v=4","gravatar_id":"","url":"https://api.github.com/users/mantidproject","html_url":"https://github.com/mantidproject","followers_url":"https://api.github.com/users/mantidproject/followers","following_url":"https://api.github.com/users/mantidproject/following{/other_user}","gists_url":"https://api.github.com/users/mantidproject/gists{/gist_id}","starred_url":"https://api.github.com/users/mantidproject/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mantidproject/subscriptions","organizations_url":"https://api.github.com/users/mantidproject/orgs","repos_url":"https://api.github.com/users/mantidproject/repos","events_url":"https://api.github.com/users/mantidproject/events{/privacy}","received_events_url":"https://api.github.com/users/mantidproject/received_events","type":"Organization","site_admin":false},"repo":{"id":2594116,"node_id":"MDEwOlJlcG9zaXRvcnkyNTk0MTE2","name":"mantid","full_name":"mantidproject/mantid","private":false,"owner":{"login":"mantidproject","id":671496,"node_id":"MDEyOk9yZ2FuaXphdGlvbjY3MTQ5Ng==","avatar_url":"https://avatars0.githubusercontent.com/u/671496?v=4","gravatar_id":"","url":"https://api.github.com/users/mantidproject","html_url":"https://github.com/mantidproject","followers_url":"https://api.github.com/users/mantidproject/followers","following_url":"https://api.github.com/users/mantidproject/following{/other_user}","gists_url":"https://api.github.com/users/mantidproject/gists{/gist_id}","starred_url":"https://api.github.com/users/mantidproject/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mantidproject/subscriptions","organizations_url":"https://api.github.com/users/mantidproject/orgs","repos_url":"https://api.github.com/users/mantidproject/repos","events_url":"https://api.github.com/users/mantidproject/events{/privacy}","received_events_url":"https://api.github.com/users/mantidproject/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/mantidproject/mantid","description":"Main repository for Mantid code","fork":false,"url":"https://api.github.com/repos/mantidproject/mantid","forks_url":"https://api.github.com/repos/mantidproject/mantid/forks","keys_url":"https://api.github.com/repos/mantidproject/mantid/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mantidproject/mantid/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mantidproject/mantid/teams","hooks_url":"https://api.github.com/repos/mantidproject/mantid/hooks","issue_events_url":"https://api.github.com/repos/mantidproject/mantid/issues/events{/number}","events_url":"https://api.github.com/repos/mantidproject/mantid/events","assignees_url":"https://api.github.com/repos/mantidproject/mantid/assignees{/user}","branches_url":"https://api.github.com/repos/mantidproject/mantid/branches{/branch}","tags_url":"https://api.github.com/repos/mantidproject/mantid/tags","blobs_url":"https://api.github.com/repos/mantidproject/mantid/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mantidproject/mantid/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mantidproject/mantid/git/refs{/sha}","trees_url":"https://api.github.com/repos/mantidproject/mantid/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mantidproject/mantid/statuses/{sha}","languages_url":"https://api.github.com/repos/mantidproject/mantid/languages","stargazers_url":"https://api.github.com/repos/mantidproject/mantid/stargazers","contributors_url":"https://api.github.com/repos/mantidproject/mantid/contributors","subscribers_url":"https://api.github.com/repos/mantidproject/mantid/subscribers","subscription_url":"https://api.github.com/repos/mantidproject/mantid/subscription","commits_url":"https://api.github.com/repos/mantidproject/mantid/commits{/sha}","git_commits_url":"https://api.github.com/repos/mantidproject/mantid/git/commits{/sha}","comments_url":"https://api.github.com/repos/mantidproject/mantid/comments{/number}","issue_comment_url":"https://api.github.com/repos/mantidproject/mantid/issues/comments{/number}","contents_url":"https://api.github.com/repos/mantidproject/mantid/contents/{+path}","compare_url":"https://api.github.com/repos/mantidproject/mantid/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mantidproject/mantid/merges","archive_url":"https://api.github.com/repos/mantidproject/mantid/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mantidproject/mantid/downloads","issues_url":"https://api.github.com/repos/mantidproject/mantid/issues{/number}","pulls_url":"https://api.github.com/repos/mantidproject/mantid/pulls{/number}","milestones_url":"https://api.github.com/repos/mantidproject/mantid/milestones{/number}","notifications_url":"https://api.github.com/repos/mantidproject/mantid/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mantidproject/mantid/labels{/name}","releases_url":"https://api.github.com/repos/mantidproject/mantid/releases{/id}","deployments_url":"https://api.github.com/repos/mantidproject/mantid/deployments","created_at":"2011-10-17T19:07:38Z","updated_at":"2018-12-14T10:27:53Z","pushed_at":"2018-12-14T13:09:49Z","git_url":"git://github.com/mantidproject/mantid.git","ssh_url":"git@github.com:mantidproject/mantid.git","clone_url":"https://github.com/mantidproject/mantid.git","svn_url":"https://github.com/mantidproject/mantid","homepage":"www.mantidproject.org","size":525129,"stargazers_count":97,"watchers_count":97,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":60,"mirror_url":null,"archived":false,"open_issues_count":1916,"license":{"key":"gpl-3.0","name":"GNU General Public License v3.0","spdx_id":"GPL-3.0","url":"https://api.github.com/licenses/gpl-3.0","node_id":"MDc6TGljZW5zZTk="},"forks":60,"open_issues":1916,"watchers":97,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/mantidproject/mantid/pulls/23109"},"html":{"href":"https://github.com/mantidproject/mantid/pull/23109"},"issue":{"href":"https://api.github.com/repos/mantidproject/mantid/issues/23109"},"comments":{"href":"https://api.github.com/repos/mantidproject/mantid/issues/23109/comments"},"review_comments":{"href":"https://api.github.com/repos/mantidproject/mantid/pulls/23109/comments"},"review_comment":{"href":"https://api.github.com/repos/mantidproject/mantid/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/mantidproject/mantid/pulls/23109/commits"},"statuses":{"href":"https://api.github.com/repos/mantidproject/mantid/statuses/171da06c334b11ef40b7d46606b7e5e5f5c2bf23"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"Pasarus"}}