def _update_function_from_params(self, function_str, params):
        params_dict = TableWorkspaceDictionaryFacade(params)

        functions = function_str.split(';')
        new_functions = [functions[0]]

        idx = 0;
        for func in functions[1:]:
            new_params = []

            for param in func.split(','):
                if param.split('=')[0] == 'name':
                    new_params.append(param)

            param_prefix = 'f{0}.'.format(idx)
            for name, value in params_dict.items():
                if param_prefix in name:
                    new_params.append('{0}={1}'.format(name, value))

            new_functions.append(','.join(new_params))
            idx += 1

        new_function_str = ';'.join(new_functions)

        return new_function_str
    def _get_correction_scale_factor(self, correction_name, corrections,
                                     params_ws):
        index = self._get_correction_workspace(correction_name, corrections)[0]
        if index is None:
            raise RuntimeError('No workspace for given correction')

        params_dict = TableWorkspaceDictionaryFacade(params_ws)
        scale_param_name = 'f%d.Scaling' % index

        return params_dict[scale_param_name]
Exemple #3
0
    def _run_fit_impl(self,
                      data_ws,
                      workspace_index,
                      fit_options,
                      simulation=False):
        """
            Run the Fit algorithm with the given options on the input data
            @param data_ws :: The workspace containing the data to fit too
            @param workspace_index :: The spectra to fit against
            @param fit_options :: An object of type FittingOptions containing
                                  the parameters
            @param simulation :: If true then only a single iteration is run
        """
        if simulation:
            raise RuntimeError("Simulation not implemented yet")
        else:
            # Run fitting first time using constraints matrix to reduce active parameter set
            function_str = fit_options.create_function_str()
            constraints = fit_options.create_constraints_str()
            ties = fit_options.create_ties_str()
            user_ties = self.getProperty('Ties').value
            if user_ties != "":
                ties = ties + ',' + user_ties

            _, params, fitted_data = self._do_fit(
                function_str,
                data_ws,
                workspace_index,
                constraints,
                ties,
                max_iter=self.getProperty("MaxIterations").value)

            # Run second time using standard CompositeFunction & no constraints matrix to
            # calculate correct reduced chisq
            param_values = TableWorkspaceDictionaryFacade(params)

        function_str = fit_options.create_function_str(param_values)
        max_iter = 0 if simulation else 1
        reduced_chi_square, _, _ = self._do_fit(function_str,
                                                data_ws,
                                                workspace_index,
                                                constraints,
                                                ties,
                                                max_iter=max_iter)

        return reduced_chi_square, params, fitted_data
    def _gamma_correction(self):
        correction_background_ws = str(
            self._correction_wsg) + "_GammaBackground"

        fit_opts = parse_fit_options(
            mass_values=self._masses,
            profile_strs=self.getProperty("MassProfiles").value,
            constraints_str=self.getProperty("IntensityConstraints").value)
        params_dict = TableWorkspaceDictionaryFacade(
            self.getProperty("FitParameters").value)
        func_str = fit_opts.create_function_str(params_dict)

        ms.VesuvioCalculateGammaBackground(
            InputWorkspace=self._output_ws,
            ComptonFunction=func_str,
            BackgroundWorkspace=correction_background_ws,
            CorrectedWorkspace='__corrected_dummy')
        ms.DeleteWorkspace('__corrected_dummy')

        return correction_background_ws
    def _ms_correction(self):
        """
        Calculates the contributions from multiple scattering
        on the input data from the set of given options
        """
        params_dict = TableWorkspaceDictionaryFacade(
            self.getProperty("FitParameters").value)

        atom_props = list()
        intensities = list()

        contains_hydrogen = False

        i = 0

        for idx, mass in enumerate(self._masses):

            if str(idx) in self._index_to_symbol_map:
                symbol = self._index_to_symbol_map[str(idx)].value
            else:
                symbol = None

            if symbol == 'H' and self._back_scattering:
                contains_hydrogen = True
                continue

            intensity_prop = 'f%d.Intensity' % i
            c0_prop = 'f%d.C_0' % i

            if intensity_prop in params_dict:
                intensity = params_dict[intensity_prop]
            elif c0_prop in params_dict:
                intensity = params_dict[c0_prop]
            else:
                i = i + 1
                continue

            # The program DINSMS_BATCH uses those sample parameters together with the sigma divided
            # by the sum absolute of scattering intensities for each detector (detector bank),
            # sigma/int_sum
            # Thus:
            # intensity = intensity/intensity_sum

            # In the thin sample limit, 1-exp(-n*dens*sigma) ~ n*dens*sigma, effectively the same
            # scattering power (ratio of double to single scatt.)  is obtained either by using
            # relative intensities ( sigma/int_sum ) or density divided by the total intensity
            # However, in the realistic case of thick sample, the SampleDensity, dens,  must be
            # obtained by iterative numerical solution of the Eq:
            # 1-exp(-n*dens*sigma) = measured scattering power of the sample.
            # For this, a program like THICK must be used.
            # The program THICK also uses sigma/int_sum to be consistent with the prgram
            # DINSMS_BATCH

            width_prop = 'f%d.Width' % i
            sigma_x_prop = 'f%d.SigmaX' % i
            sigma_y_prop = 'f%d.SigmaY' % i
            sigma_z_prop = 'f%d.SigmaZ' % i

            if width_prop in params_dict:
                width = params_dict['f%d.Width' % i]
            elif sigma_x_prop in params_dict:
                sigma_x = float(params_dict[sigma_x_prop])
                sigma_y = float(params_dict[sigma_y_prop])
                sigma_z = float(params_dict[sigma_z_prop])
                width = math.sqrt((sigma_x**2 + sigma_y**2 + sigma_z**2) / 3.0)
            else:
                i = i + 1
                continue

            atom_props.append(mass)
            atom_props.append(intensity)
            atom_props.append(width)
            intensities.append(intensity)

            # Check for NoneType is necessary as hydrogen constraints are
            # stored in a C++ PropertyManager object, not a dict; call to
            # __contains__ must match the C++ signature.
            if self._back_scattering and symbol is not None and symbol in self._hydrogen_constraints:
                self._hydrogen_constraints[symbol].value[
                    'intensity'] = intensity

            i = i + 1

        if self._back_scattering and contains_hydrogen:
            material_builder = MaterialBuilder()
            hydrogen = material_builder.setFormula('H').build()
            hydrogen_intensity = \
                self._calculate_hydrogen_intensity(hydrogen, self._hydrogen_constraints)
            hydrogen_width = 5
            atom_props.append(hydrogen.relativeMolecularMass())
            atom_props.append(hydrogen_intensity)
            atom_props.append(hydrogen_width)
            intensities.append(hydrogen_intensity)

        intensity_sum = sum(intensities)

        # Create the sample shape
        # Input dimensions are expected in CM
        ms.CreateSampleShape(InputWorkspace=self._output_ws,
                             ShapeXML=create_cuboid_xml(
                                 self.getProperty("SampleHeight").value / 100.,
                                 self.getProperty("SampleWidth").value / 100.,
                                 self.getProperty("SampleDepth").value / 100.))

        # Massage options into how algorithm expects them
        total_scatter_correction = str(
            self._correction_wsg) + "_TotalScattering"
        multi_scatter_correction = str(
            self._correction_wsg) + "_MultipleScattering"

        # Calculation
        # In the thin sample limit, 1-exp(-n*dens*sigma) ~ n*dens*sigma, effectively the same
        # scattering power(ratio of double to single scatt.)  is obtained either by using relative
        # intensities ( sigma/int_sum )or density divided by the total intensity.
        # However, in the realistic case of thick sample, the SampleDensity, dens,  must be
        # obtained by iterative numerical solution of the Eq:
        # 1-exp(-n*dens*sigma) = measured scattering power of the sample.
        # For this, a program like THICK must be used.
        # The program THICK also uses sigma/int_sum to be consistent with the prgram DINSMS_BATCH
        # The algorithm VesuvioCalculateMs called by the algorithm VesuvioCorrections takes the
        # parameter AtomicProperties with the absolute intensities, contraty to DINSMS_BATCH which
        # takes in relative intensities.
        # To compensate for this, the thickness parameter, dens (SampleDensity),  is divided in by
        # the sum of absolute intensities in VesuvioCorrections before being passed to
        # VesuvioCalculateMs.
        # Then, for the modified VesuvioCorrection algorithm one can use the thickenss parameter is
        # as is from the THICK command, i.e. 43.20552
        # This works, however, only in the thin sample limit, contrary to the THICK program. Thus,
        # for some detectors (detector banks) the SampleDensiy parameter may be over(under)
        # estimated.

        ms.VesuvioCalculateMS(
            InputWorkspace=self._output_ws,
            NoOfMasses=int(len(atom_props) / 3),
            SampleDensity=self.getProperty("SampleDensity").value /
            intensity_sum,
            AtomicProperties=atom_props,
            BeamRadius=self.getProperty("BeamRadius").value,
            NumEventsPerRun=self.getProperty("NumEvents").value,
            TotalScatteringWS=total_scatter_correction,
            MultipleScatteringWS=multi_scatter_correction)

        # Smooth the output
        smooth_neighbours = self.getProperty("SmoothNeighbours").value
        ms.SmoothData(InputWorkspace=total_scatter_correction,
                      OutputWorkspace=total_scatter_correction,
                      NPoints=smooth_neighbours)
        ms.SmoothData(InputWorkspace=multi_scatter_correction,
                      OutputWorkspace=multi_scatter_correction,
                      NPoints=smooth_neighbours)

        return total_scatter_correction, multi_scatter_correction
Exemple #6
0
    def _ms_correction(self):
        """
        Calculates the contributions from multiple scattering
        on the input data from the set of given options
        """

        masses = self.getProperty("Masses").value
        params_ws_name = self.getPropertyValue("FitParameters")
        params_dict = TableWorkspaceDictionaryFacade(mtd[params_ws_name])

        atom_props = list()
        intensities = list()

        for i, mass in enumerate(masses):
            intentisty_prop = 'f%d.Intensity' % i
            c0_prop = 'f%d.C_0' % i

            if intentisty_prop in params_dict:
                intentisy = params_dict[intentisty_prop]
            elif c0_prop in params_dict:
                intentisy = params_dict[c0_prop]
            else:
                continue

            # The program DINSMS_BATCH uses those sample parameters together with the sigma divided
            # by the sum absolute of scattering intensities for each detector (detector bank),
            # sigma/int_sum
            # Thus:
            # intensity = intensity/intensity_sum

            # In the thin sample limit, 1-exp(-n*dens*sigma) ~ n*dens*sigma, effectively the same
            # scattering power (ratio of double to single scatt.)  is obtained either by using
            # relative intensities ( sigma/int_sum ) or density divided by the total intensity
            # However, in the realistic case of thick sample, the SampleDensity, dens,  must be
            # obtained by iterative numerical solution of the Eq:
            # 1-exp(-n*dens*sigma) = measured scattering power of the sample.
            # For this, a program like THICK must be used.
            # The program THICK also uses sigma/int_sum to be consistent with the prgram
            # DINSMS_BATCH

            width_prop = 'f%d.Width' % i
            sigma_x_prop = 'f%d.SigmaX' % i
            sigma_y_prop = 'f%d.SigmaY' % i
            sigma_z_prop = 'f%d.SigmaZ' % i

            if width_prop in params_dict:
                width = params_dict['f%d.Width' % i]
            elif sigma_x_prop in params_dict:
                sigma_x = float(params_dict[sigma_x_prop])
                sigma_y = float(params_dict[sigma_y_prop])
                sigma_z = float(params_dict[sigma_z_prop])
                width = math.sqrt((sigma_x**2 + sigma_y**2 + sigma_z**2) / 3.0)
            else:
                continue

            atom_props.append(mass)
            atom_props.append(intentisy)
            atom_props.append(width)
            intensities.append(intentisy)

        intensity_sum = sum(intensities)

        # Create the sample shape
        # Input dimensions are expected in CM
        ms.CreateSampleShape(InputWorkspace=self._output_ws,
                             ShapeXML=create_cuboid_xml(
                                 self.getProperty("SampleHeight").value / 100.,
                                 self.getProperty("SampleWidth").value / 100.,
                                 self.getProperty("SampleDepth").value / 100.))

        # Massage options into how algorithm expects them
        total_scatter_correction = str(
            self._correction_wsg) + "_TotalScattering"
        multi_scatter_correction = str(
            self._correction_wsg) + "_MultipleScattering"

        # Calculation
        # In the thin sample limit, 1-exp(-n*dens*sigma) ~ n*dens*sigma, effectively the same
        # scattering power(ratio of double to single scatt.)  is obtained either by using relative
        # intensities ( sigma/int_sum )or density divided by the total intensity.
        # However, in the realistic case of thick sample, the SampleDensity, dens,  must be
        # obtained by iterative numerical solution of the Eq:
        # 1-exp(-n*dens*sigma) = measured scattering power of the sample.
        # For this, a program like THICK must be used.
        # The program THICK also uses sigma/int_sum to be consistent with the prgram DINSMS_BATCH
        # The algorithm VesuvioCalculateMs called by the algorithm VesuvioCorrections takes the
        # parameter AtomicProperties with the absolute intensities, contraty to DINSMS_BATCH which
        # takes in relative intensities.
        # To compensate for this, the thickness parameter, dens (SampleDensity),  is divided in by
        # the sum of absolute intensities in VesuvioCorrections before being passed to
        # VesuvioCalculateMs.
        # Then, for the modified VesuvioCorrection algorithm one can use the thickenss parameter is
        # as is from the THICK command, i.e. 43.20552
        # This works, however, only in the thin sample limit, contrary to the THICK program. Thus,
        # for some detectors (detector banks) the SampleDensiy parameter may be over(under)
        # estimated.

        ms.VesuvioCalculateMS(
            InputWorkspace=self._output_ws,
            NoOfMasses=len(atom_props) / 3,
            SampleDensity=self.getProperty("SampleDensity").value /
            intensity_sum,
            AtomicProperties=atom_props,
            BeamRadius=self.getProperty("BeamRadius").value,
            NumEventsPerRun=self.getProperty("NumEvents").value,
            TotalScatteringWS=total_scatter_correction,
            MultipleScatteringWS=multi_scatter_correction)

        # Smooth the output
        smooth_neighbours = self.getProperty("SmoothNeighbours").value
        ms.SmoothData(InputWorkspace=total_scatter_correction,
                      OutputWorkspace=total_scatter_correction,
                      NPoints=smooth_neighbours)
        ms.SmoothData(InputWorkspace=multi_scatter_correction,
                      OutputWorkspace=multi_scatter_correction,
                      NPoints=smooth_neighbours)

        return total_scatter_correction, multi_scatter_correction