コード例 #1
0
 def testAbsoluteUnits(self):
     _add_natural_angle_step_parameter(self._TEST_WS_NAME)
     geometry = {
         'Shape': 'HollowCylinder',
         'Height': 4.0,
         'InnerRadius': 1.9,
         'OuterRadius': 2.0,
         'Center': [0.0, 0.0, 0.0]}
     material = {
         'ChemicalFormula': 'Cd S',
         'SampleNumberDensity': 0.01}
     SetSample(self._TEST_WS_NAME, geometry, material)
     vgeometry = {
         'Shape': 'HollowCylinder',
         'Height': 4.0,
         'InnerRadius': 1.9,
         'OuterRadius': 2.0,
         'Center': [0.0, 0.0, 0.0]}
     vmaterial = {
         'ChemicalFormula': 'V',
         'SampleNumberDensity': 0.1}
     SetSample(self._VANADIUM_WS_NAME, vgeometry, vmaterial)
     outWSName = 'outWS'
     algProperties = {
         'InputWorkspace': self._TEST_WS_NAME,
         'OutputWorkspace': outWSName,
         'SubalgorithmLogging': 'Logging ON',
         'AbsoluteUnitsNormalisation': 'Absolute Units ON',
         'IntegratedVanadiumWorkspace': self._VANADIUM_WS_NAME,
         'rethrow': True
     }
     run_algorithm('DirectILLReduction', **algProperties)
     self.assertTrue(mtd.doesExist(outWSName))
コード例 #2
0
 def setUp(self):
     Load(Filename='irs26176_graphite002_red.nxs', OutputWorkspace='sample')
     SetSample(InputWorkspace='sample',
               Geometry={
                   'Shape': 'FlatPlate',
                   'Height': 2.0,
                   'Width': 2.0,
                   'Thick': 0.1,
                   'Center': [0., 0., 0.]
               },
               Material={
                   'ChemicalFormula': 'H2-O',
                   'MassDensity': 1.0
               },
               ContainerGeometry={
                   'Shape': 'FlatPlateHolder',
                   'Height': 2.0,
                   'Width': 2.0,
                   'Thick': 0.1,
                   'FrontThick': 0.02,
                   'BackThick': 0.02,
                   'Center': [0., 0., 0.]
               },
               ContainerMaterial={
                   'ChemicalFormula': 'V',
                   'MassDensity': 6.0
               })
コード例 #3
0
    def PyExec(self):
        wksp = self.getProperty("InputWorkspace").value
        # these items are not grabbed from the logs
        geometryContainer = self.getProperty("ContainerGeometry").value
        materialContainer = self.getProperty("ContainerMaterial").value

        # get a convenient handle to the logs
        runObject = wksp.run()

        # this is used for determining some of the log names
        instrEnum = ConfigService.getInstrument(
            wksp.getInstrument().getFullName())

        # get information from the logs
        material = self._createMaterial(runObject)
        geometry = self._createGeometry(runObject, instrEnum)
        environment = self._createEnvironment(runObject, instrEnum)

        # let SetSample generate errors if anything is wrong
        SetSample(InputWorkspace=wksp,
                  Material=material,
                  Geometry=geometry,
                  Environment=environment,
                  ContainerGeometry=geometryContainer,
                  ContainerMaterial=materialContainer)

        # validate that sample shape was set to something with volume!=0
        if (wksp.sample().getShape().volume() == 0):
            raise RuntimeError("Resulting sample shape has volume of 0")
コード例 #4
0
 def runTest(self):
     config['default.facility'] = 'ILL'
     config['default.instrument'] = 'IN4'
     DirectILLCollectData(Run='ILL/IN4/085801-085802.nxs',
                          OutputWorkspace='vanadium',
                          OutputEPPWorkspace='vanadium-epps',
                          OutputRawWorkspace='vanadium-raw',
                          MonitorPeakWidthInSigmas=3.0)
     DirectILLIntegrateVanadium(InputWorkspace='vanadium',
                                OutputWorkspace='integrated',
                                EPPWorkspace='vanadium-epps')
     DirectILLDiagnostics(
         InputWorkspace='vanadium-raw',
         OutputWorkspace='diagnostics',
         SubalgorithmLogging='Logging ON',
         EPPWorkspace='vanadium-epps',
     )
     # Samples
     DirectILLCollectData(Run='ILL/IN4/087294+087295.nxs',
                          OutputWorkspace='sample',
                          OutputIncidentEnergyWorkspace='Ei',
                          OutputElasticChannelWorkspace='Elp',
                          MonitorPeakWidthInSigmas=3.0)
     # Containers
     DirectILLCollectData(Run='ILL/IN4/087306-087309.nxs',
                          OutputWorkspace='container',
                          IncidentEnergyWorkspace='Ei',
                          ElasticChannelWorkspace='Elp',
                          MonitorPeakWidthInSigmas=3.0)
     geometry = {
         'Shape': 'HollowCylinder',
         'Height': 4.0,
         'InnerRadius': 1.9,
         'OuterRadius': 2.0,
         'Center': [0.0, 0.0, 0.0]
     }
     material = {'ChemicalFormula': 'Cd S', 'SampleNumberDensity': 0.01}
     SetSample('sample', geometry, material)
     DirectILLSelfShielding(InputWorkspace='sample',
                            OutputWorkspace='corrections',
                            EventsPerPoint=20000)
     DirectILLApplySelfShielding(
         InputWorkspace='sample',
         OutputWorkspace='corrected',
         SelfShieldingCorrectionWorkspace='corrections',
         EmptyContainerWorkspace='container')
     DirectILLReduction(InputWorkspace='corrected',
                        OutputWorkspace='SofQW',
                        IntegratedVanadiumWorkspace='integrated',
                        DiagnosticsWorkspace='diagnostics')
     CropWorkspace(InputWorkspace='SofQW',
                   OutputWorkspace='cropped',
                   XMin=1.,
                   XMax=2.75,
                   StartWorkspaceIndex=83,
                   EndWorkspaceIndex=222)
     # The 'run_title' property has been deliberately erased from the test numor.
     # We need to add it manually because Save/LoadNexus will do the same for
     # the reference file.
     mtd['cropped'].mutableRun().addProperty('run_title', '', True)
コード例 #5
0
    def test_generate_geometry_cylinder_with_container(self):
        workspace = CreateSampleWorkspace()
        # float
        radius_float = 1.0
        height_float = 2.0
        center_float = [1.0, 2.0, 3.0]
        sample_details_float = sample_details.SampleDetails(
            radius=radius_float,
            shape="cylinder",
            height=height_float,
            center=center_float)
        sample_details_float.set_material(chemical_formula='Si')
        sample_details_float.set_container(radius=2.0, chemical_formula='V')
        # int
        radius_int = 1
        height_int = 3
        center_int = [1, 2, 3]
        sample_details_int = sample_details.SampleDetails(radius=radius_int,
                                                          shape="cylinder",
                                                          height=height_int,
                                                          center=center_int)
        sample_details_int.set_material(chemical_formula='Si')
        sample_details_int.set_container(radius=2, chemical_formula='V')
        # string
        radius_string = "1"
        height_string = "2"
        center_string = ["1", "2", "3"]
        sample_details_string = sample_details.SampleDetails(
            radius=radius_string,
            shape="cylinder",
            height=height_string,
            center=center_string)
        sample_details_string.set_material(chemical_formula='Si')
        sample_details_string.set_container(radius="2", chemical_formula='V')
        # mix
        radius_mix = 1.23
        height_mix = 2
        center_mix = ["1", 2, 3.45]
        sample_details_mix = sample_details.SampleDetails(radius=radius_mix,
                                                          shape="cylinder",
                                                          height=height_mix,
                                                          center=center_mix)
        sample_details_mix.set_material(chemical_formula='Si')
        sample_details_mix.set_container(radius="2", chemical_formula='V')

        sample_details_objects = [
            sample_details_float, sample_details_int, sample_details_string,
            sample_details_mix
        ]
        for sample_details_object in sample_details_objects:
            SetSample(
                workspace,
                Geometry=sample_details_object.generate_sample_geometry(),
                Material=sample_details_object.generate_sample_material(),
                ContainerGeometry=sample_details_object.
                generate_container_geometry(),
                ContainerMaterial=sample_details_object.
                generate_container_material())
コード例 #6
0
def setup_sample(donor_ws, material, geometry, environment):
    """
    Calls SetSample with the associated sample and container material and geometry for use
    in creating an input workspace for an Absorption Correction algorithm
    :param donor_ws:
    :param material:
    :param geometry:
    :param environment:
    """

    # Set the material, geometry, and container info
    SetSample(InputWorkspace=donor_ws,
              Material=material,
              Geometry=geometry,
              Environment=environment)
コード例 #7
0
def set_sample(ws_name,
               geometry=None,
               chemical_formula=None,
               mass_density=None):
    if 'Center' not in geometry:
        geometry.update({'Center': [
            0.,
            0.,
            0.,
        ]})
    if "Shape" not in geometry:
        geometry.update({'Shape': 'Cylinder'})
    SetSample(InputWorkspace=ws_name,
              Geometry=geometry,
              Material={
                  'ChemicalFormula': chemical_formula,
                  'SampleMassDensity': mass_density
              })
コード例 #8
0
 def testAbsoluteUnitsNoVanadiumMaterial(self):
     _add_natural_angle_step_parameter(self._TEST_WS_NAME)
     geometry = {
         'Shape': 'HollowCylinder',
         'Height': 4.0,
         'InnerRadius': 1.9,
         'OuterRadius': 2.0,
         'Center': [0.0, 0.0, 0.0]}
     material = {
         'ChemicalFormula': 'Cd S',
         'SampleNumberDensity': 0.01}
     SetSample(self._TEST_WS_NAME, geometry, material)
     algProperties = {
         'InputWorkspace': self._TEST_WS_NAME,
         'OutputWorkspace': 'outWS',
         'SubalgorithmLogging': 'Logging ON',
         'AbsoluteUnitsNormalisation': 'Absolute Units ON',
         'IntegratedVanadiumWorkspace': self._VANADIUM_WS_NAME
     }
     self.assertRaises(RuntimeError,DirectILLReduction,**algProperties)
コード例 #9
0
 def setUpClass(cls):
     Load('irs26176_graphite002_red.nxs', OutputWorkspace='red_ws')
     Load('osi104367_elf.nxs', OutputWorkspace='indirect_elastic_ws')
     Load('ILL_IN16B_FWS_Reduced.nxs', OutputWorkspace='indirect_fws_ws')
     Load('HRP38692a.nxs', OutputWorkspace='elastic_ws')
     Load('MAR21335_Ei60meV.nxs', OutputWorkspace='direct_ws')
     Load('irs26176_graphite002_red.nxs', OutputWorkspace='geoms_ws')
     # set this workspace to have defined sample and can geometries to test the preset option
     SetSample('geoms_ws',
               Geometry={
                   'Shape': 'Cylinder',
                   'Height': 4.0,
                   'Radius': 2.0,
                   'Center': [0., 0., 0.]
               },
               Material={'ChemicalFormula': 'Ni'},
               ContainerGeometry={
                   'Shape': 'HollowCylinder',
                   'Height': 4.0,
                   'InnerRadius': 2.0,
                   'OuterRadius': 3.5
               })
コード例 #10
0
    def PyExec(self):
        raw_ws = self.getProperty('InputWorkspace').value
        sample_geometry = self.getPropertyValue('SampleGeometry')
        sample_material = self.getPropertyValue('SampleMaterial')
        cal_file_name = self.getPropertyValue('CalFileName')
        SetSample(InputWorkspace=raw_ws,
                  Geometry=sample_geometry,
                  Material=sample_material)
        # find the closest monitor to the sample for incident spectrum
        raw_spec_info = raw_ws.spectrumInfo()
        incident_index = None
        for i in range(raw_spec_info.size()):
            if raw_spec_info.isMonitor(i):
                l2 = raw_spec_info.position(i)[2]
                if not incident_index:
                    incident_index = i
                else:
                    if raw_spec_info.position(incident_index)[2] < l2 < 0:
                        incident_index = i
        monitor = ExtractSpectra(InputWorkspace=raw_ws,
                                 WorkspaceIndexList=[incident_index])
        monitor = ConvertUnits(InputWorkspace=monitor, Target="Wavelength")
        x_data = monitor.dataX(0)
        min_x = np.min(x_data)
        max_x = np.max(x_data)
        width_x = (max_x - min_x) / x_data.size
        fit_spectra = FitIncidentSpectrum(
            InputWorkspace=monitor,
            BinningForCalc=[min_x, 1 * width_x, max_x],
            BinningForFit=[min_x, 10 * width_x, max_x],
            FitSpectrumWith="CubicSpline")
        self_scattering_correction = CalculatePlaczekSelfScattering(
            InputWorkspace=raw_ws, IncidentSpecta=fit_spectra)
        cal_workspace = LoadCalFile(InputWorkspace=self_scattering_correction,
                                    CalFileName=cal_file_name,
                                    Workspacename='cal_workspace',
                                    MakeOffsetsWorkspace=False,
                                    MakeMaskWorkspace=False)
        self_scattering_correction = DiffractionFocussing(
            InputWorkspace=self_scattering_correction,
            GroupingFilename=cal_file_name)

        n_pixel = np.zeros(self_scattering_correction.getNumberHistograms())

        for i in range(cal_workspace.getNumberHistograms()):
            grouping = cal_workspace.dataY(i)
            if grouping[0] > 0:
                n_pixel[int(grouping[0] - 1)] += 1
        correction_ws = CreateWorkspace(
            DataY=n_pixel,
            DataX=[0, 1],
            NSpec=self_scattering_correction.getNumberHistograms())
        self_scattering_correction = Divide(
            LHSWorkspace=self_scattering_correction,
            RHSWorkspace=correction_ws)
        ConvertToDistribution(Workspace=self_scattering_correction)
        self_scattering_correction = ConvertUnits(
            InputWorkspace=self_scattering_correction,
            Target="MomentumTransfer",
            EMode='Elastic')
        DeleteWorkspace('cal_workspace_group')
        DeleteWorkspace(correction_ws)
        DeleteWorkspace(fit_spectra)
        DeleteWorkspace(monitor)
        DeleteWorkspace(raw_ws)
        self.setProperty('OutputWorkspace', self_scattering_correction)
def TotalScatteringReduction(config=None):
    facility = config['Facility']
    title = config['Title']
    instr = config['Instrument']

    # Get an instance to Mantid's logger
    log = Logger("TotalScatteringReduction")

    # Get sample info
    sample = get_sample(config)
    sam_mass_density = sample.get('MassDensity', None)
    sam_packing_fraction = sample.get('PackingFraction', None)
    sam_geometry = sample.get('Geometry', None)
    sam_material = sample.get('Material', None)

    sam_geo_dict = {
        'Shape': 'Cylinder',
        'Radius': config['Sample']['Geometry']['Radius'],
        'Height': config['Sample']['Geometry']['Height']
    }
    sam_mat_dict = {
        'ChemicalFormula': sam_material,
        'SampleMassDensity': sam_mass_density
    }
    if 'Environment' in config:
        sam_env_dict = {
            'Name': config['Environment']['Name'],
            'Container': config['Environment']['Container']
        }
    else:
        sam_env_dict = {'Name': 'InAir', 'Container': 'PAC06'}
    # Get normalization info
    van = get_normalization(config)
    van_mass_density = van.get('MassDensity', None)
    van_packing_fraction = van.get('PackingFraction', 1.0)
    van_geometry = van.get('Geometry', None)
    van_material = van.get('Material', 'V')

    van_geo_dict = {
        'Shape': 'Cylinder',
        'Radius': config['Normalization']['Geometry']['Radius'],
        'Height': config['Normalization']['Geometry']['Height']
    }
    van_mat_dict = {
        'ChemicalFormula': van_material,
        'SampleMassDensity': van_mass_density
    }

    # Get calibration, characterization, and other settings
    merging = config['Merging']
    binning = merging['QBinning']
    characterizations = merging.get('Characterizations', None)

    # Grouping
    grouping = merging.get('Grouping', None)
    cache_dir = config.get("CacheDir", os.path.abspath('.'))
    OutputDir = config.get("OutputDir", os.path.abspath('.'))

    # Create Nexus file basenames
    sample['Runs'] = expand_ints(sample['Runs'])
    sample['Background']['Runs'] = expand_ints(sample['Background'].get(
        'Runs', None))
    '''
    Currently not implemented:
    # wkspIndices = merging.get('SumBanks', None)
    # high_q_linear_fit_range = config['HighQLinearFitRange']

    POWGEN options not used
    #alignAndFocusArgs['RemovePromptPulseWidth'] = 50
    # alignAndFocusArgs['CompressTolerance'] use defaults
    # alignAndFocusArgs['UnwrapRef'] POWGEN option
    # alignAndFocusArgs['LowResRef'] POWGEN option
    # alignAndFocusArgs['LowResSpectrumOffset'] POWGEN option

    How much of each bank gets merged has info here in the form of
    # {"ID", "Qmin", "QMax"}
    # alignAndFocusArgs['CropWavelengthMin'] from characterizations file
    # alignAndFocusArgs['CropWavelengthMax'] from characterizations file
    '''

    if facility == 'SNS':
        facility_file_format = '%s_%d'
    else:
        facility_file_format = '%s%d'

    sam_scans = ','.join(
        [facility_file_format % (instr, num) for num in sample['Runs']])
    container_scans = ','.join([
        facility_file_format % (instr, num)
        for num in sample['Background']["Runs"]
    ])
    container_bg = None
    if "Background" in sample['Background']:
        sample['Background']['Background']['Runs'] = expand_ints(
            sample['Background']['Background']['Runs'])
        container_bg = ','.join([
            facility_file_format % (instr, num)
            for num in sample['Background']['Background']['Runs']
        ])
        if len(container_bg) == 0:
            container_bg = None

    van['Runs'] = expand_ints(van['Runs'])
    van_scans = ','.join(
        [facility_file_format % (instr, num) for num in van['Runs']])

    van_bg_scans = None
    if 'Background' in van:
        van_bg_scans = van['Background']['Runs']
        van_bg_scans = expand_ints(van_bg_scans)
        van_bg_scans = ','.join(
            [facility_file_format % (instr, num) for num in van_bg_scans])

    # Override Nexus file basename with Filenames if present
    if "Filenames" in sample:
        sam_scans = ','.join(sample["Filenames"])
    if "Filenames" in sample['Background']:
        container_scans = ','.join(sample['Background']["Filenames"])
    if "Background" in sample['Background']:
        if "Filenames" in sample['Background']['Background']:
            container_bg = ','.join(
                sample['Background']['Background']['Filenames'])
    if "Filenames" in van:
        van_scans = ','.join(van["Filenames"])
    if "Background" in van:
        if "Filenames" in van['Background']:
            van_bg_scans = ','.join(van['Background']["Filenames"])

    # Output nexus filename
    nexus_filename = title + '.nxs'
    try:
        os.remove(nexus_filename)
    except OSError:
        pass

    # Get sample corrections
    sam_abs_corr = sample.get("AbsorptionCorrection", None)
    sam_ms_corr = sample.get("MultipleScatteringCorrection", None)
    sam_inelastic_corr = SetInelasticCorrection(
        sample.get('InelasticCorrection', None))

    # Warn about having absorption correction and multiple scat correction set
    if sam_abs_corr and sam_ms_corr:
        log.warning(MS_AND_ABS_CORR_WARNING)

    # Compute the absorption correction on the sample if it was provided
    sam_abs_ws = ''
    con_abs_ws = ''
    if sam_abs_corr:
        msg = "Applying '{}' absorption correction to sample"
        log.notice(msg.format(sam_abs_corr["Type"]))
        sam_abs_ws, con_abs_ws = create_absorption_wksp(
            sam_scans, sam_abs_corr["Type"], sam_geo_dict, sam_mat_dict,
            sam_env_dict, **config)

    # Get vanadium corrections
    van_mass_density = van.get('MassDensity', van_mass_density)
    van_packing_fraction = van.get('PackingFraction', van_packing_fraction)
    van_abs_corr = van.get("AbsorptionCorrection", {"Type": None})
    van_ms_corr = van.get("MultipleScatteringCorrection", {"Type": None})
    van_inelastic_corr = SetInelasticCorrection(
        van.get('InelasticCorrection', None))

    # Warn about having absorption correction and multiple scat correction set
    if van_abs_corr["Type"] and van_ms_corr["Type"]:
        log.warning(MS_AND_ABS_CORR_WARNING)

    # Compute the absorption correction for the vanadium if provided
    van_abs_corr_ws = ''
    if van_abs_corr:
        msg = "Applying '{}' absorption correction to vanadium"
        log.notice(msg.format(van_abs_corr["Type"]))
        van_abs_corr_ws, van_con_ws = create_absorption_wksp(
            van_scans, van_abs_corr["Type"], van_geo_dict, van_mat_dict,
            **config)

    alignAndFocusArgs = dict()
    alignAndFocusArgs['CalFilename'] = config['Calibration']['Filename']
    # alignAndFocusArgs['GroupFilename'] don't use
    # alignAndFocusArgs['Params'] = "0.,0.02,40."
    alignAndFocusArgs['ResampleX'] = -6000
    alignAndFocusArgs['Dspacing'] = False
    alignAndFocusArgs['PreserveEvents'] = False
    alignAndFocusArgs['MaxChunkSize'] = 8
    alignAndFocusArgs['CacheDir'] = os.path.abspath(cache_dir)

    # Get any additional AlignAndFocusArgs from JSON input
    if "AlignAndFocusArgs" in config:
        otherArgs = config["AlignAndFocusArgs"]
        alignAndFocusArgs.update(otherArgs)

    # Setup grouping
    output_grouping = False
    grp_wksp = "wksp_output_group"

    if grouping:
        if 'Initial' in grouping:
            if grouping['Initial'] and not grouping['Initial'] == u'':
                alignAndFocusArgs['GroupFilename'] = grouping['Initial']
        if 'Output' in grouping:
            if grouping['Output'] and not grouping['Output'] == u'':
                output_grouping = True
                LoadDetectorsGroupingFile(InputFile=grouping['Output'],
                                          OutputWorkspace=grp_wksp)
    # If no output grouping specified, create it with Calibration Grouping
    if not output_grouping:
        LoadDiffCal(alignAndFocusArgs['CalFilename'],
                    InstrumentName=instr,
                    WorkspaceName=grp_wksp.replace('_group', ''),
                    MakeGroupingWorkspace=True,
                    MakeCalWorkspace=False,
                    MakeMaskWorkspace=False)

    # Setup the 6 bank method if no grouping specified
    if not grouping:
        CreateGroupingWorkspace(InstrumentName=instr,
                                GroupDetectorsBy='Group',
                                OutputWorkspace=grp_wksp)
        alignAndFocusArgs['GroupingWorkspace'] = grp_wksp

    # TODO take out the RecalculatePCharge in the future once tested
    # Load Sample
    print("#-----------------------------------#")
    print("# Sample")
    print("#-----------------------------------#")
    sam_wksp = load('sample', sam_scans, sam_geometry, sam_material,
                    sam_mass_density, sam_abs_ws, **alignAndFocusArgs)
    sample_title = "sample_and_container"
    save_banks(InputWorkspace=sam_wksp,
               Filename=nexus_filename,
               Title=sample_title,
               OutputDir=OutputDir,
               GroupingWorkspace=grp_wksp,
               Binning=binning)

    sam_molecular_mass = mtd[sam_wksp].sample().getMaterial(
    ).relativeMolecularMass()
    natoms = getNumberAtoms(sam_packing_fraction,
                            sam_mass_density,
                            sam_molecular_mass,
                            Geometry=sam_geometry)

    # Load Sample Container
    print("#-----------------------------------#")
    print("# Sample Container")
    print("#-----------------------------------#")
    container = load('container',
                     container_scans,
                     absorption_wksp=con_abs_ws,
                     **alignAndFocusArgs)
    save_banks(InputWorkspace=container,
               Filename=nexus_filename,
               Title=container,
               OutputDir=OutputDir,
               GroupingWorkspace=grp_wksp,
               Binning=binning)

    # Load Sample Container Background

    if container_bg is not None:
        print("#-----------------------------------#")
        print("# Sample Container's Background")
        print("#-----------------------------------#")
        container_bg = load('container_background', container_bg,
                            **alignAndFocusArgs)
        save_banks(InputWorkspace=container_bg,
                   Filename=nexus_filename,
                   Title=container_bg,
                   OutputDir=OutputDir,
                   GroupingWorkspace=grp_wksp,
                   Binning=binning)

    # Load Vanadium

    print("#-----------------------------------#")
    print("# Vanadium")
    print("#-----------------------------------#")
    van_wksp = load('vanadium', van_scans, van_geometry, van_material,
                    van_mass_density, van_abs_corr_ws, **alignAndFocusArgs)
    vanadium_title = "vanadium_and_background"

    save_banks(InputWorkspace=van_wksp,
               Filename=nexus_filename,
               Title=vanadium_title,
               OutputDir=OutputDir,
               GroupingWorkspace=grp_wksp,
               Binning=binning)

    van_material = mtd[van_wksp].sample().getMaterial()
    van_molecular_mass = van_material.relativeMolecularMass()
    nvan_atoms = getNumberAtoms(1.0,
                                van_mass_density,
                                van_molecular_mass,
                                Geometry=van_geometry)

    print("Sample natoms:", natoms)
    print("Vanadium natoms:", nvan_atoms)
    print("Vanadium natoms / Sample natoms:", nvan_atoms / natoms)

    # Load Vanadium Background
    van_bg = None
    if van_bg_scans is not None:
        print("#-----------------------------------#")
        print("# Vanadium Background")
        print("#-----------------------------------#")
        van_bg = load('vanadium_background', van_bg_scans, **alignAndFocusArgs)
        vanadium_bg_title = "vanadium_background"
        save_banks(InputWorkspace=van_bg,
                   Filename=nexus_filename,
                   Title=vanadium_bg_title,
                   OutputDir=OutputDir,
                   GroupingWorkspace=grp_wksp,
                   Binning=binning)

    # Load Instrument Characterizations
    if characterizations:
        PDDetermineCharacterizations(
            InputWorkspace=sam_wksp,
            Characterizations='characterizations',
            ReductionProperties='__snspowderreduction')
        propMan = PropertyManagerDataService.retrieve('__snspowderreduction')
        qmax = 2. * np.pi / propMan['d_min'].value
        qmin = 2. * np.pi / propMan['d_max'].value
        for a, b in zip(qmin, qmax):
            print('Qrange:', a, b)
        # TODO: Add when we apply Qmin, Qmax cropping
        # mask_info = generate_cropping_table(qmin, qmax)

    # STEP 1: Subtract Backgrounds

    sam_raw = 'sam_raw'
    CloneWorkspace(InputWorkspace=sam_wksp,
                   OutputWorkspace=sam_raw)  # for later

    container_raw = 'container_raw'
    CloneWorkspace(InputWorkspace=container,
                   OutputWorkspace=container_raw)  # for later

    if van_bg is not None:
        RebinToWorkspace(WorkspaceToRebin=van_bg,
                         WorkspaceToMatch=van_wksp,
                         OutputWorkspace=van_bg)
        Minus(LHSWorkspace=van_wksp,
              RHSWorkspace=van_bg,
              OutputWorkspace=van_wksp)

    RebinToWorkspace(WorkspaceToRebin=container,
                     WorkspaceToMatch=sam_wksp,
                     OutputWorkspace=container)
    Minus(LHSWorkspace=sam_wksp,
          RHSWorkspace=container,
          OutputWorkspace=sam_wksp)

    if container_bg is not None:
        RebinToWorkspace(WorkspaceToRebin=container_bg,
                         WorkspaceToMatch=container,
                         OutputWorkspace=container_bg)
        Minus(LHSWorkspace=container,
              RHSWorkspace=container_bg,
              OutputWorkspace=container)

    for wksp in [container, van_wksp, sam_wksp]:
        ConvertUnits(InputWorkspace=wksp,
                     OutputWorkspace=wksp,
                     Target="MomentumTransfer",
                     EMode="Elastic")
    container_title = "container_minus_back"
    vanadium_title = "vanadium_minus_back"
    sample_title = "sample_minus_back"
    save_banks(InputWorkspace=container,
               Filename=nexus_filename,
               Title=container_title,
               OutputDir=OutputDir,
               GroupingWorkspace=grp_wksp,
               Binning=binning)
    save_banks(InputWorkspace=van_wksp,
               Filename=nexus_filename,
               Title=vanadium_title,
               OutputDir=OutputDir,
               GroupingWorkspace=grp_wksp,
               Binning=binning)
    save_banks(InputWorkspace=sam_wksp,
               Filename=nexus_filename,
               Title=sample_title,
               OutputDir=OutputDir,
               GroupingWorkspace=grp_wksp,
               Binning=binning)

    # STEP 2.0: Prepare vanadium as normalization calibrant

    # Multiple-Scattering and Absorption (Steps 2-4) for Vanadium

    van_corrected = 'van_corrected'
    ConvertUnits(InputWorkspace=van_wksp,
                 OutputWorkspace=van_corrected,
                 Target="Wavelength",
                 EMode="Elastic")

    if "Type" in van_abs_corr:
        if van_abs_corr['Type'] == 'Carpenter' \
                or van_ms_corr['Type'] == 'Carpenter':
            CarpenterSampleCorrection(
                InputWorkspace=van_corrected,
                OutputWorkspace=van_corrected,
                CylinderSampleRadius=van['Geometry']['Radius'])
        elif van_abs_corr['Type'] == 'Mayers' \
                or van_ms_corr['Type'] == 'Mayers':
            if van_ms_corr['Type'] == 'Mayers':
                MayersSampleCorrection(InputWorkspace=van_corrected,
                                       OutputWorkspace=van_corrected,
                                       MultipleScattering=True)
            else:
                MayersSampleCorrection(InputWorkspace=van_corrected,
                                       OutputWorkspace=van_corrected,
                                       MultipleScattering=False)
        else:
            print("NO VANADIUM absorption or multiple scattering!")
    else:
        CloneWorkspace(InputWorkspace=van_corrected,
                       OutputWorkspace=van_corrected)

    ConvertUnits(InputWorkspace=van_corrected,
                 OutputWorkspace=van_corrected,
                 Target='MomentumTransfer',
                 EMode='Elastic')
    vanadium_title += "_ms_abs_corrected"
    save_banks(InputWorkspace=van_corrected,
               Filename=nexus_filename,
               Title=vanadium_title,
               OutputDir=OutputDir,
               GroupingWorkspace=grp_wksp,
               Binning=binning)
    save_banks(InputWorkspace=van_corrected,
               Filename=nexus_filename,
               Title=vanadium_title + "_with_peaks",
               OutputDir=OutputDir,
               GroupingWorkspace=grp_wksp,
               Binning=binning)

    # TODO subtract self-scattering of vanadium (According to Eq. 7 of Howe,
    # McGreevey, and Howells, JPCM, 1989)

    # Smooth Vanadium (strip peaks plus smooth)

    ConvertUnits(InputWorkspace=van_corrected,
                 OutputWorkspace=van_corrected,
                 Target='dSpacing',
                 EMode='Elastic')

    # After StripVanadiumPeaks, the workspace goes from EventWorkspace ->
    # Workspace2D
    StripVanadiumPeaks(InputWorkspace=van_corrected,
                       OutputWorkspace=van_corrected,
                       BackgroundType='Quadratic')
    ConvertUnits(InputWorkspace=van_corrected,
                 OutputWorkspace=van_corrected,
                 Target='MomentumTransfer',
                 EMode='Elastic')
    vanadium_title += '_peaks_stripped'
    save_banks(InputWorkspace=van_corrected,
               Filename=nexus_filename,
               Title=vanadium_title,
               OutputDir=OutputDir,
               GroupingWorkspace=grp_wksp,
               Binning=binning)

    ConvertUnits(InputWorkspace=van_corrected,
                 OutputWorkspace=van_corrected,
                 Target='TOF',
                 EMode='Elastic')

    FFTSmooth(InputWorkspace=van_corrected,
              OutputWorkspace=van_corrected,
              Filter="Butterworth",
              Params='20,2',
              IgnoreXBins=True,
              AllSpectra=True)

    ConvertUnits(InputWorkspace=van_corrected,
                 OutputWorkspace=van_corrected,
                 Target='MomentumTransfer',
                 EMode='Elastic')

    vanadium_title += '_smoothed'
    save_banks(InputWorkspace=van_corrected,
               Filename=nexus_filename,
               Title=vanadium_title,
               OutputDir=OutputDir,
               GroupingWorkspace=grp_wksp,
               Binning=binning)

    # Inelastic correction
    if van_inelastic_corr['Type'] == "Placzek":
        van_scan = van['Runs'][0]
        van_incident_wksp = 'van_incident_wksp'
        van_inelastic_opts = van['InelasticCorrection']
        lambda_binning_fit = van_inelastic_opts['LambdaBinningForFit']
        lambda_binning_calc = van_inelastic_opts['LambdaBinningForCalc']
        print('van_scan:', van_scan)
        GetIncidentSpectrumFromMonitor(Filename=facility_file_format %
                                       (instr, van_scan),
                                       OutputWorkspace=van_incident_wksp)

        fit_type = van['InelasticCorrection']['FitSpectrumWith']
        FitIncidentSpectrum(InputWorkspace=van_incident_wksp,
                            OutputWorkspace=van_incident_wksp,
                            FitSpectrumWith=fit_type,
                            BinningForFit=lambda_binning_fit,
                            BinningForCalc=lambda_binning_calc,
                            PlotDiagnostics=False)

        van_placzek = 'van_placzek'

        SetSample(InputWorkspace=van_incident_wksp,
                  Material={
                      'ChemicalFormula': str(van_material),
                      'SampleMassDensity': str(van_mass_density)
                  })

        CalculatePlaczekSelfScattering(IncidentWorkspace=van_incident_wksp,
                                       ParentWorkspace=van_corrected,
                                       OutputWorkspace=van_placzek,
                                       L1=19.5,
                                       L2=alignAndFocusArgs['L2'],
                                       Polar=alignAndFocusArgs['Polar'])

        ConvertToHistogram(InputWorkspace=van_placzek,
                           OutputWorkspace=van_placzek)

        # Save before rebin in Q
        for wksp in [van_placzek, van_corrected]:
            ConvertUnits(InputWorkspace=wksp,
                         OutputWorkspace=wksp,
                         Target='MomentumTransfer',
                         EMode='Elastic')

            Rebin(InputWorkspace=wksp,
                  OutputWorkspace=wksp,
                  Params=binning,
                  PreserveEvents=True)

        save_banks(InputWorkspace=van_placzek,
                   Filename=nexus_filename,
                   Title="vanadium_placzek",
                   OutputDir=OutputDir,
                   GroupingWorkspace=grp_wksp,
                   Binning=binning)

        # Rebin in Wavelength
        for wksp in [van_placzek, van_corrected]:
            ConvertUnits(InputWorkspace=wksp,
                         OutputWorkspace=wksp,
                         Target='Wavelength',
                         EMode='Elastic')
            Rebin(InputWorkspace=wksp,
                  OutputWorkspace=wksp,
                  Params=lambda_binning_calc,
                  PreserveEvents=True)

        # Save after rebin in Q
        for wksp in [van_placzek, van_corrected]:
            ConvertUnits(InputWorkspace=wksp,
                         OutputWorkspace=wksp,
                         Target='MomentumTransfer',
                         EMode='Elastic')

        # Subtract correction in Wavelength
        for wksp in [van_placzek, van_corrected]:
            ConvertUnits(InputWorkspace=wksp,
                         OutputWorkspace=wksp,
                         Target='Wavelength',
                         EMode='Elastic')
            if not mtd[wksp].isDistribution():
                ConvertToDistribution(wksp)

        Minus(LHSWorkspace=van_corrected,
              RHSWorkspace=van_placzek,
              OutputWorkspace=van_corrected)

        # Save after subtraction
        for wksp in [van_placzek, van_corrected]:
            ConvertUnits(InputWorkspace=wksp,
                         OutputWorkspace=wksp,
                         Target='MomentumTransfer',
                         EMode='Elastic')

        vanadium_title += '_placzek_corrected'
        save_banks(InputWorkspace=van_corrected,
                   Filename=nexus_filename,
                   Title=vanadium_title,
                   OutputDir=OutputDir,
                   GroupingWorkspace=grp_wksp,
                   Binning=binning)

    ConvertUnits(InputWorkspace=van_corrected,
                 OutputWorkspace=van_corrected,
                 Target='MomentumTransfer',
                 EMode='Elastic')

    SetUncertainties(InputWorkspace=van_corrected,
                     OutputWorkspace=van_corrected,
                     SetError='zero')

    # STEP 2.1: Normalize by Vanadium

    wksp_list = [sam_wksp, sam_raw, van_corrected]
    for name in wksp_list:
        ConvertUnits(InputWorkspace=name,
                     OutputWorkspace=name,
                     Target='MomentumTransfer',
                     EMode='Elastic',
                     ConvertFromPointData=False)

        Rebin(InputWorkspace=name,
              OutputWorkspace=name,
              Params=binning,
              PreserveEvents=True)

    # Save the sample - back / normalized
    Divide(LHSWorkspace=sam_wksp,
           RHSWorkspace=van_corrected,
           OutputWorkspace=sam_wksp)

    sample_title += "_normalized"
    save_banks(InputWorkspace=sam_wksp,
               Filename=nexus_filename,
               Title=sample_title,
               OutputDir=OutputDir,
               GroupingWorkspace=grp_wksp,
               Binning=binning)

    # Save the sample / normalized (ie no background subtraction)
    Divide(LHSWorkspace=sam_raw,
           RHSWorkspace=van_corrected,
           OutputWorkspace=sam_raw)

    save_banks(InputWorkspace=sam_raw,
               Filename=nexus_filename,
               Title="sample_normalized",
               OutputDir=OutputDir,
               GroupingWorkspace=grp_wksp,
               Binning=binning)

    # Output an initial I(Q) for sample
    iq_filename = title + '_initial_iofq_banks.nxs'
    save_banks(InputWorkspace=sam_wksp,
               Filename=iq_filename,
               Title="IQ_banks",
               OutputDir=OutputDir,
               GroupingWorkspace=grp_wksp,
               Binning=binning)

    wksp_list = [container, container_raw, van_corrected]
    if container_bg is not None:
        wksp_list.append(container_bg)
    if van_bg is not None:
        wksp_list.append(van_bg)

    for name in wksp_list:
        ConvertUnits(InputWorkspace=name,
                     OutputWorkspace=name,
                     Target='MomentumTransfer',
                     EMode='Elastic',
                     ConvertFromPointData=False)

        Rebin(InputWorkspace=name,
              OutputWorkspace=name,
              Params=binning,
              PreserveEvents=True)

    # Save the container - container_background / normalized
    Divide(LHSWorkspace=container,
           RHSWorkspace=van_corrected,
           OutputWorkspace=container)

    container_title += '_normalized'
    save_banks(InputWorkspace=container,
               Filename=nexus_filename,
               Title=container_title,
               OutputDir=OutputDir,
               GroupingWorkspace=grp_wksp,
               Binning=binning)

    # Save the container / normalized (ie no background subtraction)
    Divide(LHSWorkspace=container_raw,
           RHSWorkspace=van_corrected,
           OutputWorkspace=container_raw)

    save_banks(InputWorkspace=container_raw,
               Filename=nexus_filename,
               Title="container_normalized",
               OutputDir=OutputDir,
               GroupingWorkspace=grp_wksp,
               Binning=binning)

    # Save the container_background / normalized
    if container_bg is not None:
        Divide(LHSWorkspace=container_bg,
               RHSWorkspace=van_corrected,
               OutputWorkspace=container_bg)

        container_bg_title = "container_back_normalized"
        save_banks(InputWorkspace=container_bg,
                   Filename=nexus_filename,
                   Title=container_bg_title,
                   OutputDir=OutputDir,
                   GroupingWorkspace=grp_wksp,
                   Binning=binning)

    # Save the vanadium_background / normalized
    if van_bg is not None:
        Divide(LHSWorkspace=van_bg,
               RHSWorkspace=van_corrected,
               OutputWorkspace=van_bg)

        vanadium_bg_title += "_normalized"
        save_banks(InputWorkspace=van_bg,
                   Filename=nexus_filename,
                   Title=vanadium_bg_title,
                   OutputDir=OutputDir,
                   GroupingWorkspace=grp_wksp,
                   Binning=binning)

    # STEP 3 & 4: Subtract multiple scattering and apply absorption correction

    ConvertUnits(InputWorkspace=sam_wksp,
                 OutputWorkspace=sam_wksp,
                 Target="Wavelength",
                 EMode="Elastic")

    sam_corrected = 'sam_corrected'
    if sam_abs_corr and sam_ms_corr:
        if sam_abs_corr['Type'] == 'Carpenter' \
                or sam_ms_corr['Type'] == 'Carpenter':
            CarpenterSampleCorrection(
                InputWorkspace=sam_wksp,
                OutputWorkspace=sam_corrected,
                CylinderSampleRadius=sample['Geometry']['Radius'])
        elif sam_abs_corr['Type'] == 'Mayers' \
                or sam_ms_corr['Type'] == 'Mayers':
            if sam_ms_corr['Type'] == 'Mayers':
                MayersSampleCorrection(InputWorkspace=sam_wksp,
                                       OutputWorkspace=sam_corrected,
                                       MultipleScattering=True)
            else:
                MayersSampleCorrection(InputWorkspace=sam_wksp,
                                       OutputWorkspace=sam_corrected,
                                       MultipleScattering=False)
        else:
            print("NO SAMPLE absorption or multiple scattering!")
            CloneWorkspace(InputWorkspace=sam_wksp,
                           OutputWorkspace=sam_corrected)

        ConvertUnits(InputWorkspace=sam_corrected,
                     OutputWorkspace=sam_corrected,
                     Target='MomentumTransfer',
                     EMode='Elastic')

        sample_title += "_ms_abs_corrected"
        save_banks(InputWorkspace=sam_corrected,
                   Filename=nexus_filename,
                   Title=sample_title,
                   OutputDir=OutputDir,
                   GroupingWorkspace=grp_wksp,
                   Binning=binning)
    else:
        CloneWorkspace(InputWorkspace=sam_wksp, OutputWorkspace=sam_corrected)

    # STEP 5: Divide by number of atoms in sample

    mtd[sam_corrected] = (nvan_atoms / natoms) * mtd[sam_corrected]
    ConvertUnits(InputWorkspace=sam_corrected,
                 OutputWorkspace=sam_corrected,
                 Target='MomentumTransfer',
                 EMode='Elastic')

    sample_title += "_norm_by_atoms"
    save_banks(InputWorkspace=sam_corrected,
               Filename=nexus_filename,
               Title=sample_title,
               OutputDir=OutputDir,
               GroupingWorkspace=grp_wksp,
               Binning=binning)

    # STEP 6: Divide by total scattering length squared = total scattering
    # cross-section over 4 * pi
    van_material = mtd[van_corrected].sample().getMaterial()
    sigma_v = van_material.totalScatterXSection()
    prefactor = (sigma_v / (4. * np.pi))
    msg = "Total scattering cross-section of Vanadium:{} sigma_v / 4*pi: {}"
    print(msg.format(sigma_v, prefactor))

    mtd[sam_corrected] = prefactor * mtd[sam_corrected]
    sample_title += '_multiply_by_vanSelfScat'
    save_banks(InputWorkspace=sam_corrected,
               Filename=nexus_filename,
               Title=sample_title,
               OutputDir=OutputDir,
               GroupingWorkspace=grp_wksp,
               Binning=binning)

    # STEP 7: Inelastic correction
    ConvertUnits(InputWorkspace=sam_corrected,
                 OutputWorkspace=sam_corrected,
                 Target='Wavelength',
                 EMode='Elastic')

    if sam_inelastic_corr['Type'] == "Placzek":
        if sam_material is None:
            error = "For Placzek correction, must specifiy a sample material."
            raise Exception(error)
        for sam_scan in sample['Runs']:
            sam_incident_wksp = 'sam_incident_wksp'
            sam_inelastic_opts = sample['InelasticCorrection']
            lambda_binning_fit = sam_inelastic_opts['LambdaBinningForFit']
            lambda_binning_calc = sam_inelastic_opts['LambdaBinningForCalc']
            GetIncidentSpectrumFromMonitor(Filename=facility_file_format %
                                           (instr, sam_scan),
                                           OutputWorkspace=sam_incident_wksp)

            fit_type = sample['InelasticCorrection']['FitSpectrumWith']
            FitIncidentSpectrum(InputWorkspace=sam_incident_wksp,
                                OutputWorkspace=sam_incident_wksp,
                                FitSpectrumWith=fit_type,
                                BinningForFit=lambda_binning_fit,
                                BinningForCalc=lambda_binning_calc)

            sam_placzek = 'sam_placzek'
            SetSample(InputWorkspace=sam_incident_wksp,
                      Material={
                          'ChemicalFormula': str(sam_material),
                          'SampleMassDensity': str(sam_mass_density)
                      })
            CalculatePlaczekSelfScattering(IncidentWorkspace=sam_incident_wksp,
                                           ParentWorkspace=sam_corrected,
                                           OutputWorkspace=sam_placzek,
                                           L1=19.5,
                                           L2=alignAndFocusArgs['L2'],
                                           Polar=alignAndFocusArgs['Polar'])

            ConvertToHistogram(InputWorkspace=sam_placzek,
                               OutputWorkspace=sam_placzek)

        # Save before rebin in Q
        for wksp in [sam_placzek, sam_corrected]:
            ConvertUnits(InputWorkspace=wksp,
                         OutputWorkspace=wksp,
                         Target='MomentumTransfer',
                         EMode='Elastic')

            Rebin(InputWorkspace=wksp,
                  OutputWorkspace=wksp,
                  Params=binning,
                  PreserveEvents=True)

        save_banks(InputWorkspace=sam_placzek,
                   Filename=nexus_filename,
                   Title="sample_placzek",
                   OutputDir=OutputDir,
                   GroupingWorkspace=grp_wksp,
                   Binning=binning)

        # Save after rebin in Q
        for wksp in [sam_placzek, sam_corrected]:
            ConvertUnits(InputWorkspace=wksp,
                         OutputWorkspace=wksp,
                         Target='MomentumTransfer',
                         EMode='Elastic')

        Minus(LHSWorkspace=sam_corrected,
              RHSWorkspace=sam_placzek,
              OutputWorkspace=sam_corrected)

        # Save after subtraction
        for wksp in [sam_placzek, sam_corrected]:
            ConvertUnits(InputWorkspace=wksp,
                         OutputWorkspace=wksp,
                         Target='MomentumTransfer',
                         EMode='Elastic')

        sample_title += '_placzek_corrected'
        save_banks(InputWorkspace=sam_corrected,
                   Filename=nexus_filename,
                   Title=sample_title,
                   OutputDir=OutputDir,
                   GroupingWorkspace=grp_wksp,
                   Binning=binning)

    # STEP 7: Output spectrum

    # TODO Since we already went from Event -> 2D workspace, can't use this
    # anymore
    print('sam:', mtd[sam_corrected].id())
    print('van:', mtd[van_corrected].id())
    if alignAndFocusArgs['PreserveEvents']:
        CompressEvents(InputWorkspace=sam_corrected,
                       OutputWorkspace=sam_corrected)

    # F(Q) bank-by-bank Section
    fq_banks_wksp = "FQ_banks_wksp"
    CloneWorkspace(InputWorkspace=sam_corrected, OutputWorkspace=fq_banks_wksp)
    # TODO: Add the following when implemented - FQ_banks = 'FQ_banks'

    # S(Q) bank-by-bank Section
    material = mtd[sam_corrected].sample().getMaterial()
    if material.name() is None or len(material.name().strip()) == 0:
        raise RuntimeError('Sample material was not set')
    bcoh_avg_sqrd = material.cohScatterLength() * material.cohScatterLength()
    btot_sqrd_avg = material.totalScatterLengthSqrd()
    laue_monotonic_diffuse_scat = btot_sqrd_avg / bcoh_avg_sqrd
    sq_banks_wksp = 'SQ_banks_wksp'
    CloneWorkspace(InputWorkspace=sam_corrected, OutputWorkspace=sq_banks_wksp)

    # TODO: Add the following when implemented
    '''
    SQ_banks = (1. / bcoh_avg_sqrd) * \
        mtd[sq_banks_wksp] - laue_monotonic_diffuse_scat + 1.
    '''

    # Save S(Q) and F(Q) to diagnostics NeXus file
    save_banks(InputWorkspace=fq_banks_wksp,
               Filename=nexus_filename,
               Title="FQ_banks",
               OutputDir=OutputDir,
               GroupingWorkspace=grp_wksp,
               Binning=binning)

    save_banks(InputWorkspace=sq_banks_wksp,
               Filename=nexus_filename,
               Title="SQ_banks",
               OutputDir=OutputDir,
               GroupingWorkspace=grp_wksp,
               Binning=binning)

    # Output a main S(Q) and F(Q) file
    fq_filename = title + '_fofq_banks_corrected.nxs'
    save_banks(InputWorkspace=fq_banks_wksp,
               Filename=fq_filename,
               Title="FQ_banks",
               OutputDir=OutputDir,
               GroupingWorkspace=grp_wksp,
               Binning=binning)

    sq_filename = title + '_sofq_banks_corrected.nxs'
    save_banks(InputWorkspace=sq_banks_wksp,
               Filename=sq_filename,
               Title="SQ_banks",
               OutputDir=OutputDir,
               GroupingWorkspace=grp_wksp,
               Binning=binning)

    # Print log information
    print("<b>^2:", bcoh_avg_sqrd)
    print("<b^2>:", btot_sqrd_avg)
    print("Laue term:", laue_monotonic_diffuse_scat)
    print("sample total xsection:",
          mtd[sam_corrected].sample().getMaterial().totalScatterXSection())
    print("vanadium total xsection:",
          mtd[van_corrected].sample().getMaterial().totalScatterXSection())

    # Output Bragg Diffraction
    ConvertUnits(InputWorkspace=sam_corrected,
                 OutputWorkspace=sam_corrected,
                 Target="TOF",
                 EMode="Elastic")

    ConvertToHistogram(InputWorkspace=sam_corrected,
                       OutputWorkspace=sam_corrected)

    xmin, xmax = get_each_spectra_xmin_xmax(mtd[sam_corrected])

    CropWorkspaceRagged(InputWorkspace=sam_corrected,
                        OutputWorkspace=sam_corrected,
                        Xmin=xmin,
                        Xmax=xmax)

    xmin_rebin = min(xmin)
    xmax_rebin = max(xmax)
    tof_binning = "{xmin},-0.01,{xmax}".format(xmin=xmin_rebin,
                                               xmax=xmax_rebin)

    Rebin(InputWorkspace=sam_corrected,
          OutputWorkspace=sam_corrected,
          Params=tof_binning)

    SaveGSS(InputWorkspace=sam_corrected,
            Filename=os.path.join(os.path.abspath(OutputDir), title + ".gsa"),
            SplitFiles=False,
            Append=False,
            MultiplyByBinWidth=True,
            Format="SLOG",
            ExtendedHeader=True)

    return mtd[sam_corrected]
コード例 #12
0
    def PyExec(self):

        # Set up progress reporting
        n_prog_reports = 2
        if self._can_ws_name is not None:
            n_prog_reports += 1
        prog = Progress(self, 0.0, 1.0, n_prog_reports)

        sample_wave_ws = '__sam_wave'
        convert_unit_alg = self.createChildAlgorithm("ConvertUnits",
                                                     enableLogging=False)
        convert_unit_alg.setProperty("InputWorkspace", self._sample_ws_name)
        convert_unit_alg.setProperty("OutputWorkspace", sample_wave_ws)
        convert_unit_alg.setProperty("Target", 'Wavelength')
        convert_unit_alg.setProperty("EMode", self._emode)
        convert_unit_alg.setProperty("EFixed", self._efixed)
        convert_unit_alg.execute()
        mtd.addOrReplace(sample_wave_ws,
                         convert_unit_alg.getProperty("OutputWorkspace").value)

        prog.report('Calculating sample corrections')
        SetBeam(sample_wave_ws,
                Geometry={
                    'Shape': 'Slit',
                    'Width': self._beam_width,
                    'Height': self._beam_height
                })

        if self._sample_density_type == 'Mass Density':
            sample_mat_list = {
                'ChemicalFormula': self._sample_chemical_formula,
                'SampleMassDensity': self._sample_density
            }
        if self._sample_density_type == 'Number Density':
            sample_mat_list = {
                'ChemicalFormula': self._sample_chemical_formula,
                'SampleNumberDensity': self._sample_density
            }

        SetSample(sample_wave_ws,
                  Geometry={
                      'Shape': 'Cylinder',
                      'Height': self._sample_height,
                      'Radius': self._sample_radius,
                      'Center': [0., 0., 0.]
                  },
                  Material=sample_mat_list)

        prog.report('Calculating sample corrections')
        MonteCarloAbsorption(InputWorkspace=sample_wave_ws,
                             OutputWorkspace=self._ass_ws,
                             EventsPerPoint=self._events,
                             NumberOfWavelengthPoints=self._number_wavelengths,
                             Interpolation='CSpline')

        group = self._ass_ws

        delete_alg = self.createChildAlgorithm("DeleteWorkspace",
                                               enableLogging=False)
        divide_alg = self.createChildAlgorithm("Divide", enableLogging=False)
        minus_alg = self.createChildAlgorithm("Minus", enableLogging=False)

        if self._can_ws_name is not None:
            can_wave_ws = '__can_wave'
            convert_unit_alg.setProperty("InputWorkspace", self._can_ws_name)
            convert_unit_alg.setProperty("OutputWorkspace", can_wave_ws)
            convert_unit_alg.setProperty("Target", 'Wavelength')
            convert_unit_alg.setProperty("EMode", self._emode)
            convert_unit_alg.setProperty("EFixed", self._efixed)
            convert_unit_alg.execute()
            mtd.addOrReplace(
                can_wave_ws,
                convert_unit_alg.getProperty("OutputWorkspace").value)

            if self._can_scale != 1.0:
                logger.information('Scaling can by: %s' % self._can_scale)
                scale_alg = self.createChildAlgorithm("Scale",
                                                      enableLogging=False)
                scale_alg.setProperty("InputWorkspace", can_wave_ws)
                scale_alg.setProperty("OutputWorkspace", can_wave_ws)
                scale_alg.setProperty("Factor", self._can_scale)
                scale_alg.setProperty("Operation", 'Multiply')
                scale_alg.execute()

            can_thickness = self._can_radius - self._sample_radius
            logger.information('Container thickness: ' + str(can_thickness))

            if self._use_can_corrections:
                # Doing can corrections
                prog.report('Calculating container corrections')
                divide_alg.setProperty("LHSWorkspace", sample_wave_ws)
                divide_alg.setProperty("RHSWorkspace", self._ass_ws)
                divide_alg.setProperty("OutputWorkspace", sample_wave_ws)
                divide_alg.execute()

                if self._sample_density_type == 'Mass Density':
                    container_mat_list = {
                        'ChemicalFormula': self._can_chemical_formula,
                        'SampleMassDensity': self._can_density
                    }
                if self._sample_density_type == 'Number Density':
                    container_mat_list = {
                        'ChemicalFormula': self._can_chemical_formula,
                        'SampleNumberDensity': self._can_density
                    }

                SetSample(can_wave_ws,
                          Geometry={
                              'Shape': 'HollowCylinder',
                              'Height': self._sample_height,
                              'InnerRadius': self._sample_radius,
                              'OuterRadius': self._can_radius,
                              'Center': [0., 0., 0.]
                          },
                          Material=container_mat_list)

                MonteCarloAbsorption(
                    InputWorkspace=can_wave_ws,
                    OutputWorkspace=self._acc_ws,
                    EventsPerPoint=self._events,
                    NumberOfWavelengthPoints=self._number_wavelengths,
                    Interpolation='CSpline')

                divide_alg.setProperty("LHSWorkspace", can_wave_ws)
                divide_alg.setProperty("RHSWorkspace", self._acc_ws)
                divide_alg.setProperty("OutputWorkspace", can_wave_ws)
                divide_alg.execute()
                minus_alg.setProperty("LHSWorkspace", sample_wave_ws)
                minus_alg.setProperty("RHSWorkspace", can_wave_ws)
                minus_alg.setProperty("OutputWorkspace", sample_wave_ws)
                minus_alg.execute()
                group += ',' + self._acc_ws

            else:
                # Doing simple can subtraction
                prog.report('Calculating container scaling')
                minus_alg.setProperty("LHSWorkspace", sample_wave_ws)
                minus_alg.setProperty("RHSWorkspace", can_wave_ws)
                minus_alg.setProperty("OutputWorkspace", sample_wave_ws)
                minus_alg.execute()
                divide_alg.setProperty("LHSWorkspace", sample_wave_ws)
                divide_alg.setProperty("RHSWorkspace", self._ass_ws)
                divide_alg.setProperty("OutputWorkspace", sample_wave_ws)
                divide_alg.execute()

            delete_alg.setProperty("Workspace", can_wave_ws)
            delete_alg.execute()

        else:
            divide_alg.setProperty("LHSWorkspace", sample_wave_ws)
            divide_alg.setProperty("RHSWorkspace", self._ass_ws)
            divide_alg.setProperty("OutputWorkspace", sample_wave_ws)
            divide_alg.execute()

        convert_unit_alg.setProperty("InputWorkspace", sample_wave_ws)
        convert_unit_alg.setProperty("OutputWorkspace", self._output_ws)
        convert_unit_alg.setProperty("Target", 'DeltaE')
        convert_unit_alg.setProperty("EMode", self._emode)
        convert_unit_alg.setProperty("EFixed", self._efixed)
        convert_unit_alg.execute()
        mtd.addOrReplace(self._output_ws,
                         convert_unit_alg.getProperty("OutputWorkspace").value)
        delete_alg.setProperty("Workspace", sample_wave_ws)
        delete_alg.execute()

        # Record sample logs
        prog.report('Recording sample logs')
        sample_log_workspaces = [self._output_ws, self._ass_ws]
        sample_logs = [('sample_shape', 'cylinder'),
                       ('sample_filename', self._sample_ws_name),
                       ('sample_radius', self._sample_radius)]

        if self._can_ws_name is not None:
            sample_logs.append(('container_filename', self._can_ws_name))
            sample_logs.append(('container_scale', self._can_scale))
            if self._use_can_corrections:
                sample_log_workspaces.append(self._acc_ws)
                sample_logs.append(('container_thickness', can_thickness))

        log_names = [item[0] for item in sample_logs]
        log_values = [item[1] for item in sample_logs]

        add_sample_log_alg = self.createChildAlgorithm("AddSampleLogMultiple",
                                                       enableLogging=False)
        for ws_name in sample_log_workspaces:
            add_sample_log_alg.setProperty("Workspace", ws_name)
            add_sample_log_alg.setProperty("LogNames", log_names)
            add_sample_log_alg.setProperty("LogValues", log_values)
            add_sample_log_alg.execute()

        self.setProperty('OutputWorkspace', self._output_ws)

        # Output the Abs group workspace if it is wanted, delete if not
        if self._abs_ws == '':
            delete_alg.setProperty("Workspace", self._ass_ws)
            delete_alg.execute()
            if self._can_ws_name is not None and self._use_can_corrections:
                delete_alg.setProperty("Workspace", self._acc_ws)
                delete_alg.execute()

        else:
            GroupWorkspaces(InputWorkspaces=group,
                            OutputWorkspace=self._abs_ws,
                            EnableLogging=False)
            self.setProperty('CorrectionsWorkspace', self._abs_ws)
コード例 #13
0
 def PyExec(self):
     raw_ws = self.getProperty('InputWorkspace').value
     sample_geometry = self.getPropertyValue('SampleGeometry')
     sample_material = self.getPropertyValue('SampleMaterial')
     cal_file_name = self.getPropertyValue('CalFileName')
     SetSample(InputWorkspace=raw_ws,
               Geometry=sample_geometry,
               Material=sample_material)
     # find the closest monitor to the sample for incident spectrum
     raw_spec_info = raw_ws.spectrumInfo()
     incident_index = None
     for i in range(raw_spec_info.size()):
         if raw_spec_info.isMonitor(i):
             l2 = raw_spec_info.position(i)[2]
             if not incident_index:
                 incident_index = i
             else:
                 if raw_spec_info.position(incident_index)[2] < l2 < 0:
                     incident_index = i
     monitor = ExtractSpectra(InputWorkspace=raw_ws, WorkspaceIndexList=[incident_index])
     monitor = ConvertUnits(InputWorkspace=monitor, Target="Wavelength")
     x_data = monitor.dataX(0)
     min_x = np.min(x_data)
     max_x = np.max(x_data)
     width_x = (max_x - min_x) / x_data.size
     fit_spectra = FitIncidentSpectrum(InputWorkspace=monitor,
                                       BinningForCalc=[min_x, 1 * width_x, max_x],
                                       BinningForFit=[min_x, 10 * width_x, max_x],
                                       FitSpectrumWith="CubicSpline")
     self_scattering_correction = CalculatePlaczekSelfScattering(InputWorkspace=raw_ws,
                                                                 IncidentSpectra=fit_spectra,
                                                                 ScaleByPackingFraction=False,
                                                                 Version=1)
     # Convert to Q
     self_scattering_correction = ConvertUnits(InputWorkspace=self_scattering_correction,
                                               Target="MomentumTransfer", EMode='Elastic')
     cal_workspace = LoadCalFile(InputWorkspace=self_scattering_correction,
                                 CalFileName=cal_file_name,
                                 Workspacename='cal_workspace',
                                 MakeOffsetsWorkspace=False,
                                 MakeMaskWorkspace=False,
                                 MakeGroupingWorkspace=True)
     ssc_min_x, ssc_max_x = float('inf'), float('-inf')
     for index in range(self_scattering_correction.getNumberHistograms()):
         spec_info = self_scattering_correction.spectrumInfo()
         if not spec_info.isMasked(index) and not spec_info.isMonitor(index):
             ssc_x_data = np.ma.masked_invalid(self_scattering_correction.dataX(index))
             if np.min(ssc_x_data) < ssc_min_x:
                 ssc_min_x = np.min(ssc_x_data)
             if np.max(ssc_x_data) > ssc_max_x:
                 ssc_max_x = np.max(ssc_x_data)
     ssc_width_x = (ssc_max_x - ssc_min_x) / ssc_x_data.size
     # TO DO: calculate rebin parameters per group
     # and run GroupDetectors on each separately
     self_scattering_correction = Rebin(InputWorkspace=self_scattering_correction,
                                        Params=[ssc_min_x, ssc_width_x, ssc_max_x],
                                        IgnoreBinErrors=True)
     self_scattering_correction = GroupDetectors(InputWorkspace=self_scattering_correction,
                                                 CopyGroupingFromWorkspace='cal_workspace_group')
     n_pixel = np.zeros(self_scattering_correction.getNumberHistograms())
     for i in range(cal_workspace.getNumberHistograms()):
         grouping = cal_workspace.dataY(i)
         if grouping[0] > 0:
             n_pixel[int(grouping[0] - 1)] += 1
     correction_ws = CreateWorkspace(DataY=n_pixel, DataX=[0, 1],
                                     NSpec=self_scattering_correction.getNumberHistograms())
     self_scattering_correction = Divide(LHSWorkspace=self_scattering_correction, RHSWorkspace=correction_ws)
     DeleteWorkspace('cal_workspace_group')
     DeleteWorkspace(correction_ws)
     DeleteWorkspace(fit_spectra)
     DeleteWorkspace(monitor)
     DeleteWorkspace(raw_ws)
     self.setProperty('OutputWorkspace', self_scattering_correction)
コード例 #14
0
    def PyExec(self):
        # setup progress reporting
        prog = Progress(self, 0.0, 1.0, 3)

        prog.report('Setting up sample environment')

        # set the beam shape
        SetBeam(self._input_ws_name,
                Geometry={
                    'Shape': 'Slit',
                    'Width': self._beam_width,
                    'Height': self._beam_height
                })

        # set the sample geometry
        sample_geometry = dict()
        sample_geometry['Height'] = self._height

        if self._shape == 'FlatPlate':
            sample_geometry['Shape'] = 'FlatPlate'
            sample_geometry['Width'] = self._width
            sample_geometry['Thick'] = self._thickness
            sample_geometry['Center'] = [0.0, 0.0, self._center]
            sample_geometry['Angle'] = self._angle

        if self._shape == 'Cylinder':
            sample_geometry['Shape'] = 'Cylinder'
            sample_geometry['Radius'] = self._radius
            sample_geometry['Center'] = [0.0, 0.0, 0.0]

        if self._shape == 'Annulus':
            sample_geometry['Shape'] = 'HollowCylinder'
            sample_geometry['InnerRadius'] = self._inner_radius
            sample_geometry['OuterRadius'] = self._outer_radius
            sample_geometry['Center'] = [0.0, 0.0, 0.0]
            sample_geometry['Axis'] = 1

        # set sample
        if self._material_defined:
            # set sample without sample material
            SetSample(InputWorkspace=self._input_ws_name,
                      Geometry=sample_geometry)

        else:
            # set the sample material
            sample_material = dict()
            sample_material['ChemicalFormula'] = self._chemical_formula

            if self._density_type == 'Mass Density':
                sample_material['SampleMassDensity'] = self._density
            if self._density_type == 'Number Density':
                sample_material['SampleNumberDensity'] = self._density

            SetSample(InputWorkspace=self._input_ws_name,
                      Geometry=sample_geometry,
                      Material=sample_material)

        prog.report('Calculating sample corrections')

        MonteCarloAbsorption(InputWorkspace=self._input_ws_name,
                             OutputWorkspace=self._output_ws,
                             EventsPerPoint=self._events,
                             NumberOfWavelengthPoints=self._number_wavelengths,
                             Interpolation=self._interpolation)

        prog.report('Recording Sample Logs')

        log_names = ['beam_height', 'beam_width']
        log_values = [self._beam_height, self._beam_width]

        # add sample geometry to sample logs
        for key, value in sample_geometry.items():
            log_names.append('sample_' + key.lower())
            log_values.append(value)

        add_sample_log_alg = self.createChildAlgorithm('AddSampleLogMultiple',
                                                       enableLogging=False)
        add_sample_log_alg.setProperty('Workspace', self._output_ws)
        add_sample_log_alg.setProperty('LogNames', log_names)
        add_sample_log_alg.setProperty('LogValues', log_values)
        add_sample_log_alg.execute()

        self.setProperty('OutputWorkspace', self._output_ws)
コード例 #15
0
    def test_generate_geometry_slab_with_container(self):
        workspace = CreateSampleWorkspace()

        thickness_float = 2.2
        width_float = 1.0
        height_float = 2.0
        center_float = [1.0, 2.0, 3.0]
        angle_float = 3.0
        sample_details_float = sample_details.SampleDetails(
            thickness=thickness_float,
            shape="slab",
            height=height_float,
            width=width_float,
            center=center_float,
            angle=angle_float)
        sample_details_float.set_material(chemical_formula='Si')
        sample_details_float.set_container(front_thick=2.0,
                                           back_thick=2.2,
                                           chemical_formula='V')

        thickness_int = 1
        width_int = 2
        height_int = 3
        center_int = [1, 2, 3]
        angle_int = 4
        sample_details_int = sample_details.SampleDetails(
            thickness=thickness_int,
            shape="slab",
            height=height_int,
            width=width_int,
            center=center_int,
            angle=angle_int)
        sample_details_int.set_material(chemical_formula='Si')
        sample_details_int.set_container(front_thick=2,
                                         back_thick=1,
                                         chemical_formula='V')

        thickness_string = "5"
        width_string = "1"
        height_string = "2"
        center_string = ["1", "2", "3"]
        angle_string = "3"
        sample_details_string = sample_details.SampleDetails(
            thickness=thickness_string,
            shape="slab",
            height=height_string,
            width=width_string,
            center=center_string,
            angle=angle_string)
        sample_details_string.set_material(chemical_formula='Si')
        sample_details_string.set_container(front_thick="2",
                                            back_thick="2.2",
                                            chemical_formula='V')

        thickness_mix = "5"
        width_mix = 3.5
        height_mix = "2"
        center_mix = ["1", 2, 3.45]
        angle_mix = 3
        sample_details_mix = sample_details.SampleDetails(
            thickness=thickness_mix,
            shape="slab",
            height=height_mix,
            width=width_mix,
            center=center_mix,
            angle=angle_mix)
        sample_details_mix.set_material(chemical_formula='Si')
        sample_details_mix.set_container(front_thick="2.0",
                                         back_thick=2,
                                         chemical_formula='V')

        sample_details_objects = [
            sample_details_float, sample_details_int, sample_details_string,
            sample_details_mix
        ]
        for sample_details_object in sample_details_objects:
            SetSample(
                workspace,
                Geometry=sample_details_object.generate_sample_geometry(),
                Material=sample_details_object.generate_sample_material(),
                ContainerGeometry=sample_details_object.
                generate_container_geometry(),
                ContainerMaterial=sample_details_object.
                generate_container_material())