diff --git a/Code/Mantid/Framework/CurveFitting/src/PlotPeakByLogValue.cpp b/Code/Mantid/Framework/CurveFitting/src/PlotPeakByLogValue.cpp index 28cc8d5afa6c61d7ff0f47701ff07e8730e33405..72c78e9a0640d00b9b37ae04f22646331f814ce6 100644 --- a/Code/Mantid/Framework/CurveFitting/src/PlotPeakByLogValue.cpp +++ b/Code/Mantid/Framework/CurveFitting/src/PlotPeakByLogValue.cpp @@ -26,6 +26,7 @@ #include "MantidAPI/CompositeFunction.h" #include "MantidAPI/TableRow.h" #include "MantidAPI/ITableWorkspace.h" +#include "MantidAPI/BinEdgeAxis.h" #include "MantidKernel/ListValidator.h" #include "MantidKernel/MandatoryValidator.h" @@ -157,9 +158,11 @@ void PlotPeakByLogValue::exec() { result->addColumn("str", "Source name"); isDataName = true; } else if (logName.empty()) { - result->addColumn("double", "axis-1"); + auto col = result->addColumn("double", "axis-1"); + col->setPlotType(1); // X-values inplots } else { - result->addColumn("double", logName); + auto col = result->addColumn("double", logName); + col->setPlotType(1); // X-values inplots } // Create an instance of the fitting function to obtain the names of fitting // parameters @@ -227,7 +230,13 @@ void PlotPeakByLogValue::exec() { double logValue = 0; if (logName.empty()) { API::Axis *axis = data.ws->getAxis(1); - logValue = (*axis)(j); + if(dynamic_cast<BinEdgeAxis *>(axis)) { + double lowerEdge((*axis)(j)); + double upperEdge((*axis)(j+1)); + logValue = lowerEdge + (upperEdge - lowerEdge) / 2; + } + else + logValue = (*axis)(j); } else if (logName != "SourceName") { Kernel::Property *prop = data.ws->run().getLogData(logName); if (!prop) { diff --git a/Code/Mantid/Framework/CurveFitting/test/PlotPeakByLogValueTest.h b/Code/Mantid/Framework/CurveFitting/test/PlotPeakByLogValueTest.h index c94af2789dac1b146785a132707b9fb8acba2294..cc9be62a8b6aec56c8c2d4c3603c9be2f5208be9 100644 --- a/Code/Mantid/Framework/CurveFitting/test/PlotPeakByLogValueTest.h +++ b/Code/Mantid/Framework/CurveFitting/test/PlotPeakByLogValueTest.h @@ -14,6 +14,7 @@ #include "MantidAPI/ParamFunction.h" #include "MantidAPI/FunctionFactory.h" #include "MantidAPI/WorkspaceGroup.h" +#include "MantidAPI/BinEdgeAxis.h" #include "MantidKernel/TimeSeriesProperty.h" #include "MantidKernel/UnitFactory.h" @@ -222,7 +223,6 @@ public: WorkspaceCreationHelper::removeWS("PlotPeakResult"); } - void testWorkspaceList_plotting_against_ws_names() { createData(); @@ -249,7 +249,32 @@ public: deleteData(); WorkspaceCreationHelper::removeWS("PlotPeakResult"); + } + + void testSpectraList_plotting_against_bin_edge_axis() + { + auto ws = createTestWorkspace(); + AnalysisDataService::Instance().add( "PLOTPEAKBYLOGVALUETEST_WS", ws ); + + PlotPeakByLogValue alg; + alg.initialize(); + alg.setPropertyValue("Input","PLOTPEAKBYLOGVALUETEST_WS,i0;PLOTPEAKBYLOGVALUETEST_WS,i1"); + alg.setPropertyValue("OutputWorkspace","PlotPeakResult"); + alg.setPropertyValue("Function","name=LinearBackground,A0=1,A1=0.3;name=Gaussian,PeakCentre=5,Height=2,Sigma=0.1"); + alg.execute(); + + TWS_type result = WorkspaceCreationHelper::getWS<TableWorkspace>("PlotPeakResult"); + TS_ASSERT_EQUALS(result->columnCount(),12); + std::vector<std::string> tnames = result->getColumnNames(); + TS_ASSERT_EQUALS(tnames.size(),12); + TS_ASSERT_EQUALS(tnames[0],"axis-1"); + + TS_ASSERT_EQUALS(result->Double(0,0),0.5); + TS_ASSERT_EQUALS(result->Double(1,0),3.0); + + WorkspaceCreationHelper::removeWS("PlotPeakResult"); + WorkspaceCreationHelper::removeWS("PLOTPEAKBYLOGVALUETEST_WS"); } void test_passWorkspaceIndexToFunction() @@ -549,6 +574,14 @@ private: } testWS->setX(0, xdata); testWS->setX(1, xdata); + + std::vector<double> edges; + edges.push_back(0.0); + edges.push_back(1.0); + edges.push_back(5.0); + BinEdgeAxis *axis = new BinEdgeAxis(edges); + testWS->replaceAxis(1, axis); + return testWS; } diff --git a/Code/Mantid/Framework/Kernel/inc/MantidKernel/Memory.h b/Code/Mantid/Framework/Kernel/inc/MantidKernel/Memory.h index ad94db51ce2ccfa56e5339f2923922faceef4d01..4bb7be30c529e99f0366b7b8e84ad4d1d095ad02 100644 --- a/Code/Mantid/Framework/Kernel/inc/MantidKernel/Memory.h +++ b/Code/Mantid/Framework/Kernel/inc/MantidKernel/Memory.h @@ -57,6 +57,8 @@ public: std::size_t residentMem() const; std::size_t virtualMem() const; std::size_t reservedMem() const; + std::size_t getCurrentRSS() const; + std::size_t getPeakRSS() const; double getFreeRatio() const; private: diff --git a/Code/Mantid/Framework/Kernel/src/Memory.cpp b/Code/Mantid/Framework/Kernel/src/Memory.cpp index ad360465db7b7217055e2c18b2b1854d3e5061f1..a1f11272d0ac8ca2f642115b8bd1e441366ca495 100644 --- a/Code/Mantid/Framework/Kernel/src/Memory.cpp +++ b/Code/Mantid/Framework/Kernel/src/Memory.cpp @@ -9,10 +9,13 @@ #include <unistd.h> #include <fstream> #include <malloc.h> +#include <stdio.h> +#include <sys/resource.h> #endif #ifdef __APPLE__ #include <malloc/malloc.h> #include <sys/sysctl.h> +#include <mach/mach.h> #include <mach/mach_host.h> #include <mach/task.h> #endif @@ -130,13 +133,13 @@ void process_mem_usage(size_t &vm_usage, size_t &resident_set) { */ bool read_mem_info(size_t &sys_avail, size_t &sys_total) { std::ifstream file("/proc/meminfo"); - std::string line; + string line; int values_found(0); // Need to set this to zero sys_avail = 0; while (getline(file, line)) { std::istringstream is(line); - std::string tag; + string tag; long value(0); is >> tag >> value; if (!is) @@ -411,7 +414,7 @@ size_t MemoryStats::availMem() const { return this->avail_memory; } * Returns the memory usage of the current process in kiB * @returns An unsigned containing the memory used by the current process in kiB */ -std::size_t MemoryStats::residentMem() const { return this->res_usage; } +size_t MemoryStats::residentMem() const { return this->res_usage; } /** * Returns the virtual memory usage of the current process in kiB @@ -419,7 +422,7 @@ std::size_t MemoryStats::residentMem() const { return this->res_usage; } * process in kiB */ -std::size_t MemoryStats::virtualMem() const { return this->vm_usage; } +size_t MemoryStats::virtualMem() const { return this->vm_usage; } /** * Returns the reserved memory that has not been factored into the available @@ -432,7 +435,7 @@ std::size_t MemoryStats::virtualMem() const { return this->vm_usage; } * memory calculation * @returns An extra area of memory that can still be allocated. */ -std::size_t MemoryStats::reservedMem() const { +size_t MemoryStats::reservedMem() const { #ifdef _WIN32 MEMORY_BASIC_INFORMATION info; // Windows structure char *addr = NULL; @@ -486,6 +489,96 @@ std::ostream &operator<<(std::ostream &out, const MemoryStats &stats) { return out; } +/** + * @returns the peak (maximum so far) resident set size (physical + * memory use) measured in bytes, or zero if the value cannot be + * determined on this OS. + * + * This was adopted from + *http://nadeausoftware.com/articles/2012/07/c_c_tip_how_get_process_resident_set_size_physical_memory_use + */ +size_t MemoryStats::getPeakRSS() const { +#if defined(_WIN32) + /* Windows -------------------------------------------------- */ + PROCESS_MEMORY_COUNTERS info; + GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)); + return (size_t)info.PeakWorkingSetSize; + +#elif(defined(_AIX) || defined(__TOS__AIX__)) || \ + (defined(__sun__) || defined(__sun) || \ + defined(sun) && (defined(__SVR4) || defined(__svr4__))) + /* AIX and Solaris ------------------------------------------ */ + struct psinfo psinfo; + int fd = -1; + if ((fd = open("/proc/self/psinfo", O_RDONLY)) == -1) + return (size_t)0L; /* Can't open? */ + if (read(fd, &psinfo, sizeof(psinfo)) != sizeof(psinfo)) { + close(fd); + return (size_t)0L; /* Can't read? */ + } + close(fd); + return (size_t)(psinfo.pr_rssize * 1024L); + +#elif defined(__unix__) || defined(__unix) || defined(unix) || \ + (defined(__APPLE__) && defined(__MACH__)) + /* BSD, Linux, and OSX -------------------------------------- */ + struct rusage rusage; + getrusage(RUSAGE_SELF, &rusage); +#if defined(__APPLE__) && defined(__MACH__) + return (size_t)rusage.ru_maxrss; +#else + return (size_t)(rusage.ru_maxrss * 1024L); +#endif + +#else + /* Unknown OS ----------------------------------------------- */ + return (size_t)0L; /* Unsupported. */ +#endif +} + +/** + * @returns the current resident set size (physical memory use) measured + * in bytes, or zero if the value cannot be determined on this OS. + * + * This was adopted from + *http://nadeausoftware.com/articles/2012/07/c_c_tip_how_get_process_resident_set_size_physical_memory_use + */ +size_t MemoryStats::getCurrentRSS() const { +#if defined(_WIN32) + /* Windows -------------------------------------------------- */ + PROCESS_MEMORY_COUNTERS info; + GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)); + return (size_t)info.WorkingSetSize; + +#elif defined(__APPLE__) && defined(__MACH__) + /* OSX ------------------------------------------------------ */ + struct mach_task_basic_info info; + mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT; + if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, + &infoCount) != KERN_SUCCESS) + return (size_t)0L; /* Can't access? */ + return (size_t)info.resident_size; + +#elif defined(__linux__) || defined(__linux) || defined(linux) || \ + defined(__gnu_linux__) + /* Linux ---------------------------------------------------- */ + long rss = 0L; + FILE *fp = NULL; + if ((fp = fopen("/proc/self/statm", "r")) == NULL) + return (size_t)0L; /* Can't open? */ + if (fscanf(fp, "%*s%20ld", &rss) != 1) { + fclose(fp); + return (size_t)0L; /* Can't read? */ + } + fclose(fp); + return (size_t)rss * (size_t)sysconf(_SC_PAGESIZE); + +#else + /* AIX, BSD, Solaris, and Unknown OS ------------------------ */ + return (size_t)0L; /* Unsupported. */ +#endif +} + // -------------------------- concrete instantiations template DLLExport string memToString<uint32_t>(const uint32_t); template DLLExport string memToString<uint64_t>(const uint64_t); diff --git a/Code/Mantid/Framework/PythonInterface/mantid/kernel/src/Exports/Memory.cpp b/Code/Mantid/Framework/PythonInterface/mantid/kernel/src/Exports/Memory.cpp index 764c9b9cc4210788fa05eeaace23335fe3f2b8b9..46aad239e32e0b3cebd83ae3ca11ca510013c9b5 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/kernel/src/Exports/Memory.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/kernel/src/Exports/Memory.cpp @@ -7,11 +7,13 @@ using namespace boost::python; void export_MemoryStats() { class_<MemoryStats>("MemoryStats", init<>("Construct MemoryStats object.")) - .def("update", &MemoryStats::update) - .def("totalMem", &MemoryStats::totalMem) - .def("availMem", &MemoryStats::availMem) - .def("residentMem", &MemoryStats::residentMem) - .def("virtualMem", &MemoryStats::virtualMem) - .def("reservedMem", &MemoryStats::reservedMem) - .def("getFreeRatio", &MemoryStats::getFreeRatio); + .def("update", &MemoryStats::update, args("self")) + .def("totalMem", &MemoryStats::totalMem, args("self")) + .def("availMem", &MemoryStats::availMem, args("self")) + .def("residentMem", &MemoryStats::residentMem, args("self")) + .def("virtualMem", &MemoryStats::virtualMem, args("self")) + .def("reservedMem", &MemoryStats::reservedMem, args("self")) + .def("getFreeRatio", &MemoryStats::getFreeRatio, args("self")) + .def("getCurrentRSS", &MemoryStats::getCurrentRSS, args("self")) + .def("getPeakRSS", &MemoryStats::getPeakRSS, args("self")); } diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/MSDFit.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/MSDFit.py index 7285abe4f676d36f3d0c687c4fe9d785843d07b1..de147bde8f794a7a787b822a0e9c8c5def0b3e0c 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/MSDFit.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/MSDFit.py @@ -99,13 +99,18 @@ class MSDFit(DataProcessorAlgorithm): input_params = [self._input_ws + ',i%d' % i for i in xrange(self._spec_range[0], self._spec_range[1] + 1)] input_params = ';'.join(input_params) - PlotPeakByLogValue(Input=input_params, OutputWorkspace=self._output_msd_ws, - Function=function, StartX=self._x_range[0], EndX=self._x_range[1], - FitType='Sequential', CreateOutput=True) + PlotPeakByLogValue(Input=input_params, + OutputWorkspace=self._output_msd_ws, + Function=function, + StartX=self._x_range[0], + EndX=self._x_range[1], + FitType='Sequential', + CreateOutput=True) DeleteWorkspace(self._output_msd_ws + '_NormalisedCovarianceMatrices') DeleteWorkspace(self._output_msd_ws + '_Parameters') - RenameWorkspace(self._output_msd_ws, OutputWorkspace=self._output_param_ws) + RenameWorkspace(self._output_msd_ws, + OutputWorkspace=self._output_param_ws) params_table = mtd[self._output_param_ws] diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ResNorm.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/ResNorm.py similarity index 100% rename from Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ResNorm.py rename to Code/Mantid/Framework/PythonInterface/plugins/algorithms/ResNorm.py diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py index 918abd99d95b19c7b6bd7e82b3ba080c29cad760..8e046158a12cc9ac8c222cf45149bc8ab9b344be 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py @@ -209,10 +209,11 @@ class ElasticWindowMultiple(DataProcessorAlgorithm): logger.notice('Vertical axis is in run number') unit = ('Run No', 'last 3 digits') - q_ws_axis = mtd[self._q_workspace].getAxis(1) + # Create a new vertical axis for the Q and Q**2 workspaces + q_ws_axis = NumericAxis.create(len(input_workspace_names)) q_ws_axis.setUnit("Label").setLabel(unit[0], unit[1]) - q2_ws_axis = mtd[self._q2_workspace].getAxis(1) + q2_ws_axis = NumericAxis.create(len(input_workspace_names)) q2_ws_axis.setUnit("Label").setLabel(unit[0], unit[1]) # Set the vertical axis values @@ -224,6 +225,10 @@ class ElasticWindowMultiple(DataProcessorAlgorithm): q_ws_axis.setValue(idx, float(run_numbers[idx][-3:])) q2_ws_axis.setValue(idx, float(run_numbers[idx][-3:])) + # Add the new vertical axis to each workspace + mtd[self._q_workspace].replaceAxis(1, q_ws_axis) + mtd[self._q2_workspace].replaceAxis(1, q2_ws_axis) + # Process the ELF workspace if self._elf_workspace != '': logger.information('Creating ELF workspace') diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/PoldiDataAnalysis.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/PoldiDataAnalysis.py index 765d12c751604f0d974faf8e6c0f617bbce3e159..1a5d147fa66d0bb7b0992a29b675f904a34795d4 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/PoldiDataAnalysis.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/PoldiDataAnalysis.py @@ -81,6 +81,10 @@ class PoldiDataAnalysis(PythonAlgorithm): doc=('If this is activated, plot the sum of residuals and calculated spectrum together ' 'with the theoretical spectrum and the residuals.')) + self.declareProperty("OutputIntegratedIntensities", False, direction=Direction.Input, + doc=("If this option is checked the peak intensities of the 2D-fit will be integrated, " + "otherwise they will be the maximum intensity.")) + self.declareProperty('OutputRawFitParameters', False, direction=Direction.Input, doc=('Activating this option produces an output workspace which contains the raw ' 'fit parameters.')) @@ -97,6 +101,7 @@ class PoldiDataAnalysis(PythonAlgorithm): self.profileFunction = self.getProperty("ProfileFunction").value self.useGlobalParameters = self.getProperty("TieProfileParameters").value self.maximumRelativeFwhm = self.getProperty("MaximumRelativeFwhm").value + self.outputIntegratedIntensities = self.getProperty("OutputIntegratedIntensities").value self.globalParameters = '' if self.useGlobalParameters: @@ -247,6 +252,7 @@ class PoldiDataAnalysis(PythonAlgorithm): OutputWorkspace=spectrum2DName, Calculated1DSpectrum=spectrum1DName, RefinedPoldiPeakWorkspace=refinedPeaksName, + OutputIntegratedIntensities=self.outputIntegratedIntensities, RefinedCellParameters=refinedCellName, RawFitParameters=rawFitParametersWorkspaceName) diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ResNorm2.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ResNorm2.py new file mode 100644 index 0000000000000000000000000000000000000000..0a22122c248f00cd4e96de38ea44822620e45d66 --- /dev/null +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ResNorm2.py @@ -0,0 +1,202 @@ +#pylint: disable=no-init +from mantid.api import (PythonAlgorithm, AlgorithmFactory, MatrixWorkspaceProperty, + WorkspaceGroup, WorkspaceGroupProperty) +from mantid.kernel import Direction +from mantid.simpleapi import * + + +class ResNorm(PythonAlgorithm): + + _res_ws = None + _van_ws = None + _e_min = None + _e_max = None + _create_output = None + _out_ws = None + + + def category(self): + return "Workflow\\MIDAS;PythonAlgorithms" + + + def summary(self): + return """Creates a group normalisation file by taking a resolution file + and fitting it to all the groups in the resolution (vanadium) + reduction.""" + + def version(self): + return 2 + + + def PyInit(self): + self.declareProperty(MatrixWorkspaceProperty('ResolutionWorkspace', '', + direction=Direction.Input), + doc='Workspace containing resolution') + + self.declareProperty(MatrixWorkspaceProperty('VanadiumWorkspace', '', + direction=Direction.Input), + doc='Workspace containing reduction of vanadium run') + + self.declareProperty(name='EnergyMin', + defaultValue=-0.2, + doc='Minimum energy for fit. Default=-0.2') + + self.declareProperty(name='EnergyMax', + defaultValue=0.2, + doc='Maximum energy for fit. Default=0.2') + + self.declareProperty(name='CreateOutput', + defaultValue=False, + doc='Create additional fitting output') + + self.declareProperty(WorkspaceGroupProperty('OutputWorkspace', '', + direction=Direction.Output), + doc='Fitted parameter output') + + + def validateInputs(self): + self._get_properties() + issues = dict() + + # Validate fitting range in energy + if self._e_min > self._e_max: + issues['EnergyMax'] = 'Must be less than EnergyMin' + + res_ws = mtd[self._res_ws] + # Can't use a WorkspaceGroup for resolution + if isinstance(res_ws, WorkspaceGroup): + issues['ResolutionWorkspace'] = 'Must be a MatrixWorkspace' + + # Resolution should only have one histogram + elif mtd[self._res_ws].getNumberHistograms() != 1: + issues['ResolutionWorkspace'] = 'Must have exactly one histogram' + + return issues + + + def _get_properties(self): + self._res_ws = self.getPropertyValue('ResolutionWorkspace') + self._van_ws = self.getPropertyValue('VanadiumWorkspace') + self._e_min = self.getProperty('EnergyMin').value + self._e_max = self.getProperty('EnergyMax').value + self._create_output = self.getProperty('CreateOutput').value + self._out_ws = self.getPropertyValue('OutputWorkspace') + + + def PyExec(self): + from IndirectCommon import getWSprefix + + # Process vanadium workspace + van_ws = ConvertSpectrumAxis(InputWorkspace=self._van_ws, + OutputWorkspace='__ResNorm_vanadium', + Target='ElasticQ', + EMode='Indirect') + + num_hist = van_ws.getNumberHistograms() + + v_values = van_ws.getAxis(1).extractValues() + v_unit = van_ws.getAxis(1).getUnit().unitID() + + # Process resolution workspace + padded_res_ws = self._process_res_ws(num_hist) + + input_str = '' + for idx in range(num_hist): + input_str += '%s,i%d;' % (padded_res_ws, idx) + + out_name = getWSprefix(self._res_ws) + 'ResNorm_Fit' + function = 'name=TabulatedFunction,Workspace=%s,Scaling=1,Shift=0,XScaling=1,ties=(Shift=0)' % self._van_ws + + fit_params = PlotPeakByLogValue(Input=input_str, + OutputWorkspace=out_name, + Function=function, + FitType='Individual', + PassWSIndexToFunction=True, + CreateOutput=self._create_output, + StartX=self._e_min, + EndX=self._e_max) + + params = {'XScaling':'Stretch', 'Scaling':'Intensity'} + result_workspaces = [] + for param_name, output_name in params.items(): + result_workspaces.append(self._process_fit_params(fit_params, param_name, v_values, v_unit, output_name)) + + GroupWorkspaces(InputWorkspaces=result_workspaces, + OutputWorkspace=self._out_ws) + self.setProperty('OutputWorkspace', self._out_ws) + + DeleteWorkspace(van_ws) + DeleteWorkspace(padded_res_ws) + if not self._create_output: + DeleteWorkspace(fit_params) + + + def _process_res_ws(self, num_hist): + """ + Generate a resolution workspaes with the same number of histograms + as the vanadium run, with area normalised to 1. + + @param num_hist Number of histograms required + @return Padded workspace + """ + + norm_res_ws = '__ResNorm_unityres' + NormaliseToUnity(InputWorkspace=self._res_ws, + OutputWorkspace=norm_res_ws) + + ws_name = '__ResNorm_res_%s_%dspec' % (self._res_ws, num_hist) + + for idx in range(num_hist): + input_ws_1 = ws_name + if idx == 0: + input_ws_1 = norm_res_ws + + AppendSpectra(InputWorkspace1=input_ws_1, + InputWorkspace2=norm_res_ws, + OutputWorkspace=ws_name) + + DeleteWorkspace(norm_res_ws) + + return mtd[ws_name] + + + #pylint: disable=too-many-arguments + def _process_fit_params(self, fit_params, parameter_name, x_axis, x_unit, workspace_suffix=None): + """ + Generate the output workspace containing fit parameters using the + fit parameter table from PlotPeakByLogValue. + + @param fit_params Fit parameters as table workspace + @param parameter_name Parameter name to extract + @param x_axis Values for X axis of output workspace + @param x_unit Unit for X axis of output workspace + @param workspace_suffix Suffix of result workspace name + """ + + if workspace_suffix is None: + workspace_suffix = parameter_name + + col_names = fit_params.getColumnNames() + + y_values = [] + e_values = [] + + y_values = fit_params.column(col_names.index(parameter_name)) + e_values = fit_params.column(col_names.index(parameter_name + '_Err')) + + ws_name = self._out_ws + '_' + workspace_suffix + + CreateWorkspace(OutputWorkspace=ws_name, + DataX=x_axis, + DataY=y_values, + DataE=e_values, + NSpec=1, + UnitX=x_unit, + VerticalAxisUnit='Text', + VerticalAxisValues=[parameter_name]) + + return ws_name + + +# Register algorithm with Mantid +AlgorithmFactory.subscribe(ResNorm) diff --git a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt index 9e32c9b72529524f47858b2d3e16e2ebf39ddc2f..9d46caf2c6746cbbb9a5b084ae3ecd6375639161 100644 --- a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt +++ b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt @@ -47,6 +47,7 @@ set ( TEST_PY_FILES MolDynTest.py MSDFitTest.py PDDetermineCharacterizationsTest.py + ResNorm2Test.py RetrieveRunInfoTest.py SANSWideAngleCorrectionTest.py SavePlot1DTest.py diff --git a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/ResNorm2Test.py b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/ResNorm2Test.py new file mode 100644 index 0000000000000000000000000000000000000000..4d974788fee7016b3b8d01ff0c19498bf22b0913 --- /dev/null +++ b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/ResNorm2Test.py @@ -0,0 +1,75 @@ +import unittest +from mantid.simpleapi import * +from mantid.api import MatrixWorkspace, WorkspaceGroup + + +class ResNorm2Test(unittest.TestCase): + + _res_ws = None + _van_ws = None + + + def setUp(self): + self._res_ws = Load(Filename='irs26173_graphite002_res.nxs', + OutputWorkspace='__ResNormTest_Resolution') + self._van_ws = Load(Filename='irs26173_graphite002_red.nxs', + OutputWorkspace='__ResNormTest_Vanadium') + + + def _validate_result(self, result): + """ + Validates that the result workspace is of the correct type, units and shape. + + @param result Result workspace form ResNorm + """ + + self.assertTrue(isinstance(result, WorkspaceGroup)) + self.assertEquals(result.getNumberOfEntries(), 2) + + expected_names = [result.name() + '_' + n for n in ['Intensity', 'Stretch']] + for name in expected_names: + self.assertTrue(name in result.getNames()) + + for idx in range(result.getNumberOfEntries()): + sub_ws = result.getItem(idx) + self.assertTrue(isinstance(sub_ws, MatrixWorkspace)) + self.assertEqual(sub_ws.blocksize(), self._van_ws.getNumberHistograms()) + self.assertEquals(sub_ws.getAxis(0).getUnit().unitID(), 'MomentumTransfer') + + + def test_basic(self): + """ + Tests a basic run of ResNorm. + """ + result = ResNorm(ResolutionWorkspace=self._res_ws, + VanadiumWorkspace=self._van_ws, + Version=2) + self._validate_result(result) + + + def test_with_limits(self): + """ + Tests a basic run of ResNorm with energy limits. + """ + result = ResNorm(ResolutionWorkspace=self._res_ws, + VanadiumWorkspace=self._van_ws, + EnergyMin=-0.1, + EnergyMax=0.1, + Version=2) + self._validate_result(result) + + + def test_with_bad_limits(self): + """ + Tests validation for energy range. + """ + self.assertRaises(RuntimeError, ResNorm, + ResolutionWorkspace=self._res_ws, + VanadiumWorkspace=self._van_ws, + EnergyMin=0.1, + EnergyMax=-0.1, + Version=2) + + +if __name__=="__main__": + unittest.main() diff --git a/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp b/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp index 6f7a0af47eec43203941c19348339fa12a68245e..df7b16d2aebb20a9fadc16a13f9a582e533d8499 100644 --- a/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp +++ b/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp @@ -398,19 +398,28 @@ PoldiFitPeaks2D::getPeakFromPeakFunction(IPeakFunction_sptr profileFunction, errorAlg->execute(); double centre = profileFunction->centre(); - double height = profileFunction->height(); double fwhmValue = profileFunction->fwhm(); ITableWorkspace_sptr errorTable = errorAlg->getProperty("OutputWorkspace"); - double centreError = errorTable->cell<double>(0, 2); - double heightError = errorTable->cell<double>(1, 2); double fwhmError = errorTable->cell<double>(2, 2); UncertainValue d(centre, centreError); - UncertainValue intensity(height, heightError); UncertainValue fwhm(fwhmValue, fwhmError); + UncertainValue intensity; + + bool useIntegratedIntensities = getProperty("OutputIntegratedIntensities"); + if (useIntegratedIntensities) { + double integratedIntensity = profileFunction->intensity(); + double integratedIntensityError = errorTable->cell<double>(3, 2); + intensity = UncertainValue(integratedIntensity, integratedIntensityError); + } else { + double height = profileFunction->height(); + double heightError = errorTable->cell<double>(1, 2); + intensity = UncertainValue(height, heightError); + } + // Create peak with extracted parameters and supplied hkl PoldiPeak_sptr peak = PoldiPeak::create(MillerIndices(hkl), d, intensity, UncertainValue(1.0)); @@ -1215,6 +1224,11 @@ void PoldiFitPeaks2D::init() { "", Direction::Output), "Table workspace with fitted peaks."); + declareProperty("OutputIntegratedIntensities", false, + "If this option is checked, the peaks in the algorithm's " + "output will have integrated intensities instead of the " + "maximum."); + declareProperty(new WorkspaceProperty<Workspace>( "RefinedCellParameters", "", Direction::Output, PropertyMode::Optional)); diff --git a/Code/Mantid/MantidPlot/make_package.rb.in b/Code/Mantid/MantidPlot/make_package.rb.in index afab0d3b60844b00e4b7bade807835eea796d039..1d52b0a5615bd1f87251fc793d272b563a853cc4 100755 --- a/Code/Mantid/MantidPlot/make_package.rb.in +++ b/Code/Mantid/MantidPlot/make_package.rb.in @@ -204,12 +204,12 @@ end #Copy over python libraries not included with OSX. #currently missing epics path = "/Library/Python/2.7/site-packages" -directories = ["sphinx","sphinx_bootstrap_theme","IPython","zmq","pygments","backports","certifi","tornado","markupsafe","jinja2","psutil"] +directories = ["sphinx","sphinx_bootstrap_theme","IPython","zmq","pygments","backports","certifi","tornado","markupsafe","jinja2","psutil","jsonschema","functools32","ptyprocess"] directories.each do |directory| addPythonLibrary("#{path}/#{directory}") end -files = ["gnureadline.so","readline.py","pyparsing.py"] +files = ["gnureadline.so","readline.py","pyparsing.py","mistune.py","mistune.so"] files.each do |file| copyFile("#{path}/#{file}") end diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/MultiDatasetFit/MultiDatasetFit.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/MultiDatasetFit/MultiDatasetFit.h index dc99c26083257f54aff33cd7fbb63838793d855c..c89adb98b1243722541ae8ed799ce3fd6172c165 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/MultiDatasetFit/MultiDatasetFit.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/MultiDatasetFit/MultiDatasetFit.h @@ -88,6 +88,8 @@ private slots: void enableZoom(); void enablePan(); void enableRange(); + void checkFittingType(); + void setLogNames(); protected: virtual void initLayout(); @@ -104,6 +106,8 @@ private: void removeSpectra(QList<int> rows); void loadSettings(); void saveSettings() const; + void fitSequential(); + void fitSimultaneous(); /// The form generated by Qt Designer Ui::MultiDatasetFit m_uiForm; diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/MultiDatasetFit/MDFPlotController.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/MultiDatasetFit/MDFPlotController.cpp index 07d64ae00c11981ab67a1891b4bbbe31e5938ee4..79717f8541fe074679783154b91765cc2ce2c622 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/MultiDatasetFit/MDFPlotController.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/MultiDatasetFit/MDFPlotController.cpp @@ -5,6 +5,8 @@ #include "MantidQtCustomInterfaces/MultiDatasetFit/MDFDatasetPlotData.h" #include "MantidQtMantidWidgets/RangeSelector.h" +#include "MantidAPI/AnalysisDataService.h" +#include "MantidAPI/WorkspaceGroup.h" #include <boost/make_shared.hpp> @@ -115,12 +117,15 @@ boost::shared_ptr<DatasetPlotData> PlotController::getData(int index) QString wsName = m_table->item( index, wsColumn )->text(); int wsIndex = m_table->item( index, wsIndexColumn )->text().toInt(); QString outputWorkspaceName = owner()->getOutputWorkspaceName(); - if ( !outputWorkspaceName.isEmpty() ) - { - outputWorkspaceName += QString("_%1").arg(index); + std::string outName = outputWorkspaceName.toStdString(); + if (!outputWorkspaceName.isEmpty() && + Mantid::API::AnalysisDataService::Instance().doesExist(outName)) { + auto ws = Mantid::API::AnalysisDataService::Instance().retrieve(outName); + if (auto group = boost::dynamic_pointer_cast<Mantid::API::WorkspaceGroup>(ws)) { + outputWorkspaceName = QString::fromStdString(group->getItem(index)->name()); + } } - try - { + try { data = boost::make_shared<DatasetPlotData>( wsName, wsIndex, outputWorkspaceName ); m_plotData.insert(index, data ); } diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/MultiDatasetFit/MultiDatasetFit.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/MultiDatasetFit/MultiDatasetFit.cpp index 03065dd8bff32ada7e34d99dc2e724cec80e7c28..a8d5f4f86c76c36ba01a247d352fab6555c62b72 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/MultiDatasetFit/MultiDatasetFit.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/MultiDatasetFit/MultiDatasetFit.cpp @@ -4,6 +4,9 @@ #include "MantidQtCustomInterfaces/MultiDatasetFit/MDFEditLocalParameterDialog.h" #include "MantidAPI/AlgorithmManager.h" +#include "MantidAPI/FunctionFactory.h" +#include "MantidAPI/ITableWorkspace.h" +#include "MantidKernel/TimeSeriesProperty.h" #include "MantidQtAPI/AlgorithmRunner.h" #include "MantidQtMantidWidgets/FitOptionsBrowser.h" @@ -72,6 +75,7 @@ void MultiDatasetFit::initLayout() m_uiForm.btnNext); connect(m_dataController,SIGNAL(dataTableUpdated()),m_plotController,SLOT(tableUpdated())); connect(m_dataController,SIGNAL(dataSetUpdated(int)),m_plotController,SLOT(updateRange(int))); + connect(m_dataController,SIGNAL(dataTableUpdated()),this,SLOT(setLogNames())); connect(m_plotController,SIGNAL(fittingRangeChanged(int, double, double)),m_dataController,SLOT(setFittingRange(int, double, double))); connect(m_uiForm.cbShowDataErrors,SIGNAL(toggled(bool)),m_plotController,SLOT(showDataErrors(bool))); connect(m_uiForm.btnToVisibleRange,SIGNAL(clicked()),m_plotController,SLOT(resetRange())); @@ -84,12 +88,15 @@ void MultiDatasetFit::initLayout() splitter->addWidget( m_functionBrowser ); connect(m_functionBrowser,SIGNAL(localParameterButtonClicked(const QString&)),this,SLOT(editLocalParameterValues(const QString&))); connect(m_functionBrowser,SIGNAL(functionStructureChanged()),this,SLOT(reset())); + connect(m_functionBrowser,SIGNAL(globalsChanged()),this,SLOT(checkFittingType())); connect(m_plotController,SIGNAL(currentIndexChanged(int)),m_functionBrowser,SLOT(setCurrentDataset(int))); connect(m_dataController,SIGNAL(spectraRemoved(QList<int>)),m_functionBrowser,SLOT(removeDatasets(QList<int>))); connect(m_dataController,SIGNAL(spectraAdded(int)),m_functionBrowser,SLOT(addDatasets(int))); - m_fitOptionsBrowser = new MantidQt::MantidWidgets::FitOptionsBrowser(NULL); - splitter->addWidget( m_fitOptionsBrowser ); + m_fitOptionsBrowser = new MantidQt::MantidWidgets::FitOptionsBrowser( + NULL, MantidQt::MantidWidgets::FitOptionsBrowser::SimultaneousAndSequential); + connect(m_fitOptionsBrowser,SIGNAL(changedToSequentialFitting()),this,SLOT(setLogNames())); + splitter->addWidget(m_fitOptionsBrowser); m_uiForm.browserLayout->addWidget( splitter ); @@ -149,15 +156,54 @@ boost::shared_ptr<Mantid::API::IFunction> MultiDatasetFit::createFunction() cons return m_functionBrowser->getGlobalFunction(); } -/// Run the fitting algorithm. -void MultiDatasetFit::fit() +/// Fit the data sets sequentially if there are no global parameters. +void MultiDatasetFit::fitSequential() { - if ( !m_functionBrowser->hasFunction() ) + try { - QMessageBox::warning( this, "MantidPlot - Warning","Function wasn't set." ); - return; + std::ostringstream input; + + int n = getNumberOfSpectra(); + for(int ispec = 0; ispec < n; ++ispec) + { + input << getWorkspaceName(ispec) << ",i" << getWorkspaceIndex(ispec) << ";"; + } + + auto fun = m_functionBrowser->getFunction(); + auto fit = Mantid::API::AlgorithmManager::Instance().create("PlotPeakByLogValue"); + fit->initialize(); + fit->setPropertyValue("Function", fun->asString() ); + fit->setPropertyValue("Input", input.str()); + auto range = getFittingRange(0); + fit->setProperty( "StartX", range.first ); + fit->setProperty( "EndX", range.second ); + + m_fitOptionsBrowser->copyPropertiesToAlgorithm(*fit); + + m_outputWorkspaceName = m_fitOptionsBrowser->getProperty("OutputWorkspace").toStdString() + "_Workspaces"; + + m_fitRunner.reset( new API::AlgorithmRunner() ); + connect( m_fitRunner.get(),SIGNAL(algorithmComplete(bool)), this, SLOT(finishFit(bool)), Qt::QueuedConnection ); + + m_fitRunner->startAlgorithm(fit); + + } + catch(std::exception& e) + { + QString mess(e.what()); + const int maxSize = 500; + if ( mess.size() > maxSize ) + { + mess = mess.mid(0,maxSize); + mess += "..."; + } + QMessageBox::critical( this, "MantidPlot - Error", QString("PlotPeakByLogValue failed:\n\n %1").arg(mess) ); } +} +/// Fit the data simultaneously. +void MultiDatasetFit::fitSimultaneous() +{ try { auto fun = createFunction(); @@ -190,7 +236,7 @@ void MultiDatasetFit::fit() fit->setPropertyValue("Output",m_outputWorkspaceName); m_fitOptionsBrowser->setProperty("Output","out"); } - m_outputWorkspaceName += "_Workspace"; + m_outputWorkspaceName += "_Workspaces"; m_fitRunner.reset( new API::AlgorithmRunner() ); connect( m_fitRunner.get(),SIGNAL(algorithmComplete(bool)), this, SLOT(finishFit(bool)), Qt::QueuedConnection ); @@ -211,6 +257,31 @@ void MultiDatasetFit::fit() } } +/// Run the fitting algorithm. +void MultiDatasetFit::fit() +{ + if ( !m_functionBrowser->hasFunction() ) + { + QMessageBox::warning( this, "MantidPlot - Warning","Function wasn't set." ); + return; + } + + auto fittingType = m_fitOptionsBrowser->getCurrentFittingType(); + + if (fittingType == MantidWidgets::FitOptionsBrowser::Simultaneous) + { + fitSimultaneous(); + } + else if (fittingType == MantidWidgets::FitOptionsBrowser::Sequential) + { + fitSequential(); + } + else + { + throw std::logic_error("Unrecognised fitting type. Only Normal and Sequential are accepted."); + } +} + /// Get the workspace name of the i-th spectrum. /// @param i :: Index of a spectrum in the data table. std::string MultiDatasetFit::getWorkspaceName(int i) const @@ -264,8 +335,37 @@ void MultiDatasetFit::finishFit(bool error) { m_plotController->clear(); m_plotController->update(); - Mantid::API::IFunction_sptr fun = m_fitRunner->getAlgorithm()->getProperty("Function"); - updateParameters( *fun ); + Mantid::API::IFunction_sptr fun; + if (m_fitOptionsBrowser->getCurrentFittingType() == MantidWidgets::FitOptionsBrowser::Simultaneous) + { + fun = m_fitRunner->getAlgorithm()->getProperty("Function"); + updateParameters( *fun ); + } + else + { + auto paramsWSName = m_fitOptionsBrowser->getProperty("OutputWorkspace").toStdString(); + if (!Mantid::API::AnalysisDataService::Instance().doesExist(paramsWSName)) return; + size_t nSpectra = getNumberOfSpectra(); + if (nSpectra == 0) return; + fun = m_functionBrowser->getGlobalFunction(); + auto nParams = fun->nParams() / nSpectra; + auto params = Mantid::API::AnalysisDataService::Instance().retrieveWS<Mantid::API::ITableWorkspace>(paramsWSName); + if (nParams * 2 + 2 != params->columnCount()) + { + throw std::logic_error("Output table workspace has unexpected number of columns."); + } + for(size_t index = 0; index < nSpectra; ++index) + { + std::string prefix = "f" + boost::lexical_cast<std::string>(index) + "."; + for(size_t ip = 0; ip < nParams; ++ip) + { + auto colIndex = ip * 2 + 1; + auto column = params->getColumn(colIndex); + fun->setParameter(prefix + column->name(), column->toDouble(index)); + } + } + updateParameters( *fun ); + } } } @@ -455,5 +555,49 @@ void MultiDatasetFit::saveSettings() const settings.setValue("ApplyRangeToAll",m_uiForm.cbApplyRangeToAll->isChecked()); } +/// Make sure that simultaneous fitting is on +/// when the function has at least one global parameter. +void MultiDatasetFit::checkFittingType() +{ + auto globals = m_functionBrowser->getGlobalParameters(); + if (globals.isEmpty()) + { + m_fitOptionsBrowser->unlockCurrentFittingType(); + } + else + { + m_fitOptionsBrowser->lockCurrentFittingType(MantidWidgets::FitOptionsBrowser::Simultaneous); + } +} + +/** + * Collect names of the logs in the data workspaces and pass them on to m_fitOptionsBrowser. + */ +void MultiDatasetFit::setLogNames() +{ + if (getNumberOfSpectra() > 0) + { + try + { + auto ws = Mantid::API::AnalysisDataService::Instance().retrieveWS<Mantid::API::MatrixWorkspace>(getWorkspaceName(0)); + const std::vector<Mantid::Kernel::Property*> logs = ws->run().getLogData(); + QStringList logNames; + for(int i=0;i<static_cast<int>(logs.size());++i) + { + if (dynamic_cast<Mantid::Kernel::TimeSeriesProperty<double>*>(logs[i])) + { + logNames << QString::fromStdString(logs[i]->name()); + } + } + if (!logNames.isEmpty()) + { + m_fitOptionsBrowser->setLogNames(logNames); + } + } + catch (...) + {/*Maybe the data table hasn't updated yet*/} + } +} + } // CustomInterfaces } // MantidQt diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/Muon/ALCBaselineModellingModel.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/Muon/ALCBaselineModellingModel.cpp index dd2f753aade53571bc7c06d640db57707b02b9bf..ab69c56ceb3c1de9d1a8c74cafa9b3619fccfa7d 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/Muon/ALCBaselineModellingModel.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/Muon/ALCBaselineModellingModel.cpp @@ -172,26 +172,34 @@ namespace CustomInterfaces MatrixWorkspace_const_sptr ALCBaselineModellingModel::data() const { - IAlgorithm_sptr extract = AlgorithmManager::Instance().create("ExtractSingleSpectrum"); - extract->setChild(true); - extract->setProperty("InputWorkspace", boost::const_pointer_cast<MatrixWorkspace>(m_data)); - extract->setProperty("WorkspaceIndex", 0); - extract->setProperty("OutputWorkspace", "__NotUsed__"); - extract->execute(); - MatrixWorkspace_const_sptr result = extract->getProperty("OutputWorkspace"); - return result; + if (m_data) { + IAlgorithm_sptr extract = AlgorithmManager::Instance().create("ExtractSingleSpectrum"); + extract->setChild(true); + extract->setProperty("InputWorkspace", boost::const_pointer_cast<MatrixWorkspace>(m_data)); + extract->setProperty("WorkspaceIndex", 0); + extract->setProperty("OutputWorkspace", "__NotUsed__"); + extract->execute(); + MatrixWorkspace_const_sptr result = extract->getProperty("OutputWorkspace"); + return result; + } else { + return MatrixWorkspace_const_sptr(); + } } MatrixWorkspace_const_sptr ALCBaselineModellingModel::correctedData() const { - IAlgorithm_sptr extract = AlgorithmManager::Instance().create("ExtractSingleSpectrum"); - extract->setChild(true); - extract->setProperty("InputWorkspace", boost::const_pointer_cast<MatrixWorkspace>(m_data)); - extract->setProperty("WorkspaceIndex", 2); - extract->setProperty("OutputWorkspace", "__NotUsed__"); - extract->execute(); - MatrixWorkspace_const_sptr result = extract->getProperty("OutputWorkspace"); - return result; + if (m_data && (m_data->getNumberHistograms()==3) ) { + IAlgorithm_sptr extract = AlgorithmManager::Instance().create("ExtractSingleSpectrum"); + extract->setChild(true); + extract->setProperty("InputWorkspace", boost::const_pointer_cast<MatrixWorkspace>(m_data)); + extract->setProperty("WorkspaceIndex", 2); + extract->setProperty("OutputWorkspace", "__NotUsed__"); + extract->execute(); + MatrixWorkspace_const_sptr result = extract->getProperty("OutputWorkspace"); + return result; + } else { + return MatrixWorkspace_const_sptr(); + } } } // namespace CustomInterfaces diff --git a/Code/Mantid/MantidQt/CustomInterfaces/test/ALCBaselineModellingModelTest.h b/Code/Mantid/MantidQt/CustomInterfaces/test/ALCBaselineModellingModelTest.h index d9cb119841ca2ce481a305e963d4057206240b4c..724760d3469d7614736e3176ff31c8961bad4d75 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/test/ALCBaselineModellingModelTest.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/test/ALCBaselineModellingModelTest.h @@ -145,6 +145,16 @@ public: TS_ASSERT_THROWS_NOTHING(m_model->exportModel()); } + void test_noData() + { + // Set a null shared pointer + MatrixWorkspace_const_sptr data = MatrixWorkspace_const_sptr(); + m_model->setData(data); + + TS_ASSERT_THROWS_NOTHING(m_model->data()); + TS_ASSERT_THROWS_NOTHING(m_model->correctedData()); + } + }; diff --git a/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FitOptionsBrowser.h b/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FitOptionsBrowser.h index a8f1429c57de969b5e52759a0c78aedbc4f23cc7..cd156c85a0dec4456553d01b46ed22118cfb6fd7 100644 --- a/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FitOptionsBrowser.h +++ b/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FitOptionsBrowser.h @@ -43,13 +43,28 @@ class EXPORT_OPT_MANTIDQT_MANTIDWIDGETS FitOptionsBrowser: public QWidget { Q_OBJECT public: + /// Support for fitting algorithms: + /// Simultaneous: Fit + /// Sequential: PlotPeakByLogValue + /// SimultaneousAndSequential: both Fit and PlotPeakByLogValue, toggled with + /// "Fitting" property. + enum FittingType {Simultaneous = 0, Sequential, SimultaneousAndSequential}; + /// Constructor - FitOptionsBrowser(QWidget *parent = NULL); + FitOptionsBrowser(QWidget *parent = NULL, FittingType fitType = Simultaneous); QString getProperty(const QString& name) const; void setProperty(const QString& name, const QString& value); void copyPropertiesToAlgorithm(Mantid::API::IAlgorithm& fit) const; void saveSettings(QSettings& settings) const; void loadSettings(const QSettings& settings); + FittingType getCurrentFittingType() const; + void setCurrentFittingType(FittingType fitType); + void lockCurrentFittingType(FittingType fitType); + void unlockCurrentFittingType(); + void setLogNames(const QStringList& logNames); + +signals: + void changedToSequentialFitting(); private slots: @@ -59,25 +74,33 @@ private: void createBrowser(); void createProperties(); + void createCommonProperties(); + void createSimultaneousFitProperties(); + void createSequentialFitProperties(); void updateMinimizer(); + void switchFitType(); + void displayNormalFitProperties(); + void displaySequentialFitProperties(); + QtProperty* createPropertyProperty(Mantid::Kernel::Property* prop); QtProperty* addDoubleProperty(const QString& name); + void addProperty(const QString& name, QtProperty* prop, + QString (FitOptionsBrowser::*getter)(QtProperty*)const, + void (FitOptionsBrowser::*setter)(QtProperty*,const QString&)); + // Setters and getters - QString getMinimizer() const; - void setMinimizer(const QString&); - QString getCostFunction() const; - void setCostFunction(const QString&); - QString getMaxIterations() const; - void setMaxIterations(const QString&); - QString getOutput() const; - void setOutput(const QString&); - QString getIgnoreInvalidData() const; - void setIgnoreInvalidData(const QString&); - - void addProperty(const QString& name, - QString (FitOptionsBrowser::*getter)()const, - void (FitOptionsBrowser::*setter)(const QString&)); + QString getMinimizer(QtProperty*) const; + void setMinimizer(QtProperty*, const QString&); + + QString getIntProperty(QtProperty*) const; + void setIntProperty(QtProperty*, const QString&); + QString getBoolProperty(QtProperty*) const; + void setBoolProperty(QtProperty*, const QString&); + QString getStringEnumProperty(QtProperty*) const; + void setStringEnumProperty(QtProperty*, const QString&); + QString getStringProperty(QtProperty*) const; + void setStringProperty(QtProperty*, const QString&); /// Qt property browser which displays properties QtTreePropertyBrowser* m_browser; @@ -95,6 +118,8 @@ private: /// Manager for groups of properties QtGroupPropertyManager* m_groupManager; + /// FitType property + QtProperty* m_fittingTypeProp; /// Minimizer group property QtProperty* m_minimizerGroup; /// Minimizer property @@ -103,18 +128,39 @@ private: QtProperty* m_costFunction; /// MaxIterations property QtProperty* m_maxIterations; + + // Fit properties /// Output property QtProperty* m_output; /// IgnoreInvalidData property QtProperty* m_ignoreInvalidData; + // PlotPeakByLogValue properties + /// FitType property + QtProperty* m_fitType; + /// OutputWorkspace property + QtProperty* m_outputWorkspace; + /// LogValue property + QtProperty* m_logValue; + /// Precision of doubles in m_doubleManager int m_decimals; + typedef void (FitOptionsBrowser::*SetterType)(QtProperty*, const QString&); + typedef QString (FitOptionsBrowser::*GetterType)(QtProperty*)const; + /// Maps algorithm property name to the QtProperty + QMap<QString,QtProperty*> m_propertyNameMap; /// Store for the properties setter methods - QMap<QString,void (FitOptionsBrowser::*)(const QString&)> m_setters; + QMap<QtProperty*,SetterType> m_setters; /// Store for the properties getter methods - QMap<QString,QString (FitOptionsBrowser::*)()const> m_getters; + QMap<QtProperty*,GetterType> m_getters; + + /// The Fitting Type + FittingType m_fittingType; + /// Store special properties of the normal Fit + QList<QtProperty*> m_simultaneousProperties; + /// Store special properties of the sequential Fit + QList<QtProperty*> m_sequentialProperties; }; } // MantidWidgets diff --git a/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FunctionBrowser.h b/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FunctionBrowser.h index 115b9ffbd2e785809d692ca1aa54c258ff2d4c1f..5302d5dab2eefdb29cf267585df262be3c1a64c5 100644 --- a/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FunctionBrowser.h +++ b/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FunctionBrowser.h @@ -153,6 +153,7 @@ signals: void localParameterButtonClicked(const QString& parName); void functionStructureChanged(); + void globalsChanged(); public slots: @@ -289,6 +290,7 @@ protected slots: /// Called when a function parameter property is changed void parameterChanged(QtProperty*); void parameterButtonClicked(QtProperty*); + void globalChanged(QtProperty*, const QString&, bool); protected: /// Manager for function group properties diff --git a/Code/Mantid/MantidQt/MantidWidgets/src/FitOptionsBrowser.cpp b/Code/Mantid/MantidQt/MantidWidgets/src/FitOptionsBrowser.cpp index a7a39d3337707c84ce53e13f2b7c3e1bb9ca3c57..5ff51742f09233d7d57d1a7c55d3d0cbeb8c8a34 100644 --- a/Code/Mantid/MantidQt/MantidWidgets/src/FitOptionsBrowser.cpp +++ b/Code/Mantid/MantidQt/MantidWidgets/src/FitOptionsBrowser.cpp @@ -43,10 +43,11 @@ namespace MantidWidgets /** * Constructor * @param parent :: The parent widget. + * @param fitType :: The type of the underlying fitting algorithm. */ -FitOptionsBrowser::FitOptionsBrowser(QWidget *parent) +FitOptionsBrowser::FitOptionsBrowser(QWidget *parent, FittingType fitType) :QWidget(parent), - m_decimals(6) + m_decimals(6), m_fittingType(fitType) { // create m_browser createBrowser(); @@ -99,6 +100,28 @@ void FitOptionsBrowser::createBrowser() */ void FitOptionsBrowser::createProperties() { + createCommonProperties(); + if (m_fittingType == Simultaneous || m_fittingType == SimultaneousAndSequential) + { + createSimultaneousFitProperties(); + } + if (m_fittingType == Sequential || m_fittingType == SimultaneousAndSequential) + { + createSequentialFitProperties(); + } +} + +void FitOptionsBrowser::createCommonProperties() +{ + if (m_fittingType == SimultaneousAndSequential) + { + m_fittingTypeProp = m_enumManager->addProperty("Fitting"); + QStringList types; + types << "Simultaneous" << "Sequential"; + m_enumManager->setEnumNames(m_fittingTypeProp, types); + m_browser->addProperty(m_fittingTypeProp); + } + // Create MaxIterations property m_maxIterations = m_intManager->addProperty("Max Iterations"); { @@ -106,7 +129,7 @@ void FitOptionsBrowser::createProperties() m_intManager->setMinimum(m_maxIterations,0); m_browser->addProperty(m_maxIterations); - addProperty("MaxIterations", &FitOptionsBrowser::getMaxIterations, &FitOptionsBrowser::setMaxIterations); + addProperty("MaxIterations", m_maxIterations, &FitOptionsBrowser::getIntProperty, &FitOptionsBrowser::setIntProperty); } // Set up the minimizer property. @@ -135,10 +158,8 @@ void FitOptionsBrowser::createProperties() { m_enumManager->setValue(m_minimizer,i); } - m_browser->addProperty(m_minimizerGroup); - - addProperty("Minimizer", &FitOptionsBrowser::getMinimizer, &FitOptionsBrowser::setMinimizer); + addProperty("Minimizer", m_minimizer, &FitOptionsBrowser::getMinimizer, &FitOptionsBrowser::setMinimizer); } // Create cost function property @@ -148,40 +169,101 @@ void FitOptionsBrowser::createProperties() std::vector<std::string> costOptions = Mantid::API::CostFunctionFactory::Instance().getKeys(); QStringList costFunctions; - // Store them in the m_minimizer enum property for(auto it = costOptions.begin(); it != costOptions.end(); ++it) { costFunctions << QString::fromStdString(*it); } m_enumManager->setEnumNames(m_costFunction,costFunctions); - m_browser->addProperty(m_costFunction); - - addProperty("CostFunction", &FitOptionsBrowser::getCostFunction, &FitOptionsBrowser::setCostFunction); + addProperty("CostFunction", m_costFunction, &FitOptionsBrowser::getStringEnumProperty, &FitOptionsBrowser::setStringEnumProperty); } +} + +void FitOptionsBrowser::createSimultaneousFitProperties() +{ // Create Output property m_output = m_stringManager->addProperty("Output"); { m_browser->addProperty(m_output); - addProperty("Output", &FitOptionsBrowser::getOutput, &FitOptionsBrowser::setOutput); + addProperty("Output", m_output, &FitOptionsBrowser::getStringProperty, &FitOptionsBrowser::setStringProperty); + m_simultaneousProperties << m_output; } // Create Ignore property m_ignoreInvalidData = m_boolManager->addProperty("Ignore Invalid Data"); { m_browser->addProperty(m_ignoreInvalidData); - addProperty("IgnoreInvalidData", &FitOptionsBrowser::getIgnoreInvalidData, &FitOptionsBrowser::setIgnoreInvalidData); + addProperty("IgnoreInvalidData", m_ignoreInvalidData, &FitOptionsBrowser::getBoolProperty, &FitOptionsBrowser::setBoolProperty); + m_simultaneousProperties << m_ignoreInvalidData; } } -void FitOptionsBrowser::addProperty(const QString& name, - QString (FitOptionsBrowser::*getter)()const, - void (FitOptionsBrowser::*setter)(const QString&)) +void FitOptionsBrowser::createSequentialFitProperties() { - m_getters[name] = getter; - m_setters[name] = setter; + // Create FitType property + m_fitType = m_enumManager->addProperty("Fit Type"); + { + QStringList types; + types << "Sequential" << "Individual"; + m_enumManager->setEnumNames(m_fitType,types); + m_enumManager->setValue(m_fitType,0); + addProperty("FitType", m_fitType, &FitOptionsBrowser::getStringEnumProperty, &FitOptionsBrowser::setStringEnumProperty); + m_sequentialProperties << m_fitType; + } + + // Create OutputWorkspace property + m_outputWorkspace = m_stringManager->addProperty("OutputWorkspace"); + { + addProperty("OutputWorkspace", m_outputWorkspace, &FitOptionsBrowser::getStringProperty, &FitOptionsBrowser::setStringProperty); + m_sequentialProperties << m_outputWorkspace; + } + + // Create CreateOutput property + auto prop = m_boolManager->addProperty("Create Output"); + { + addProperty("CreateOutput", prop, &FitOptionsBrowser::getBoolProperty, &FitOptionsBrowser::setBoolProperty); + m_sequentialProperties << prop; + } + + // Create OutputCompositeMembers property + prop = m_boolManager->addProperty("Output Composite Members"); + { + addProperty("OutputCompositeMembers", prop, &FitOptionsBrowser::getBoolProperty, &FitOptionsBrowser::setBoolProperty); + m_sequentialProperties << prop; + } + + // Create ConvolveMembers property + prop = m_boolManager->addProperty("Convolve Members"); + { + addProperty("ConvolveMembers", prop, &FitOptionsBrowser::getBoolProperty, &FitOptionsBrowser::setBoolProperty); + m_sequentialProperties << prop; + } + + // Create PassWSIndexToFunction property + prop = m_boolManager->addProperty("Pass WS Index To Function"); + { + addProperty("PassWSIndexToFunction", prop, &FitOptionsBrowser::getBoolProperty, &FitOptionsBrowser::setBoolProperty); + m_sequentialProperties << prop; + } + + // Create LogValue property + m_logValue = m_enumManager->addProperty("Log Value"); + { + //m_enumManager->setValue(m_logValue,0); + addProperty("LogValue", m_logValue, &FitOptionsBrowser::getStringEnumProperty, &FitOptionsBrowser::setStringEnumProperty); + m_sequentialProperties << m_logValue; + } +} + +void FitOptionsBrowser::addProperty(const QString& name, QtProperty* prop, + QString (FitOptionsBrowser::*getter)(QtProperty*)const, + void (FitOptionsBrowser::*setter)(QtProperty*,const QString&)) +{ + m_propertyNameMap[name] = prop; + m_getters[prop] = getter; + m_setters[prop] = setter; } @@ -207,6 +289,10 @@ void FitOptionsBrowser::enumChanged(QtProperty* prop) { updateMinimizer(); } + else if (prop == m_fittingTypeProp) + { + switchFitType(); + } } /** @@ -242,6 +328,53 @@ void FitOptionsBrowser::updateMinimizer() } } +/** + * Switch the current fit type according to the value in the FitType property. + */ +void FitOptionsBrowser::switchFitType() +{ + auto fitType = m_enumManager->value(m_fittingTypeProp); + if (fitType == 0) + { + displayNormalFitProperties(); + } + else + { + displaySequentialFitProperties(); + } +} + +/** + * Show normal Fit properties and hide the others. + */ +void FitOptionsBrowser::displayNormalFitProperties() +{ + foreach(QtProperty* prop, m_simultaneousProperties) + { + m_browser->addProperty(prop); + } + foreach(QtProperty* prop, m_sequentialProperties) + { + m_browser->removeProperty(prop); + } +} + +/** + * Show sequential fit (PlotPeakByLogValue) properties and hide the others. + */ +void FitOptionsBrowser::displaySequentialFitProperties() +{ + foreach(QtProperty* prop, m_sequentialProperties) + { + m_browser->addProperty(prop); + } + foreach(QtProperty* prop, m_simultaneousProperties) + { + m_browser->removeProperty(prop); + } + emit changedToSequentialFitting(); +} + /** * Create a QtProperty for an Algorithm Property * and attach it to the correct manager. @@ -314,11 +447,16 @@ QtProperty* FitOptionsBrowser::createPropertyProperty(Mantid::Kernel::Property* */ void FitOptionsBrowser::copyPropertiesToAlgorithm(Mantid::API::IAlgorithm& fit) const { - for(auto p = m_getters.constBegin(); p != m_getters.constEnd(); ++p) + for(auto p = m_propertyNameMap.constBegin(); p != m_propertyNameMap.constEnd(); ++p) + { + auto propertyName = p.key().toStdString(); + if (fit.existsProperty(propertyName)) { - auto f = p.value(); - fit.setPropertyValue( p.key().toStdString(), (this->*f)().toStdString() ); + auto prop = p.value(); + auto f = m_getters[prop]; + fit.setPropertyValue(propertyName, (this->*f)(prop).toStdString() ); } + } } /** @@ -327,12 +465,13 @@ void FitOptionsBrowser::copyPropertiesToAlgorithm(Mantid::API::IAlgorithm& fit) */ QString FitOptionsBrowser::getProperty(const QString& name) const { - if ( !m_getters.contains(name) ) + if ( !m_propertyNameMap.contains(name) ) { throw std::runtime_error("Property " + name.toStdString() + " isn't supported by the browser."); } - auto f = m_getters[name]; - return (this->*f)(); + auto prop = m_propertyNameMap[name]; + auto f = m_getters[prop]; + return (this->*f)(prop); } /** @@ -342,18 +481,19 @@ QString FitOptionsBrowser::getProperty(const QString& name) const */ void FitOptionsBrowser::setProperty(const QString& name, const QString& value) { - if ( !m_getters.contains(name) ) + if ( !m_propertyNameMap.contains(name) ) { throw std::runtime_error("Property " + name.toStdString() + " isn't supported by the browser."); } - auto f = m_setters[name]; - (this->*f)(value); + auto prop = m_propertyNameMap[name]; + auto f = m_setters[prop]; + (this->*f)(prop,value); } /** * Get the value of the Minimizer property. */ -QString FitOptionsBrowser::getMinimizer() const +QString FitOptionsBrowser::getMinimizer(QtProperty*) const { int i = m_enumManager->value(m_minimizer); QString minimStr = m_enumManager->enumNames(m_minimizer)[i]; @@ -401,94 +541,109 @@ QString FitOptionsBrowser::getMinimizer() const * Set new value to the Minimizer property. * @param value :: The new value. */ -void FitOptionsBrowser::setMinimizer(const QString& value) +void FitOptionsBrowser::setMinimizer(QtProperty*, const QString& value) { QStringList terms = value.split(','); int i = m_enumManager->enumNames(m_minimizer).indexOf(terms[0]); m_enumManager->setValue(m_minimizer,i); } +// ------------------------- Generic setters and getters ------------------------------// + /** - * Get the value of the CostFunction property. + * Get the value of an integer algorithm property. + * @param prop :: The corresponding QtProperty. */ -QString FitOptionsBrowser::getCostFunction() const +QString FitOptionsBrowser::getIntProperty(QtProperty* prop) const { - int i = m_enumManager->value(m_costFunction); - return m_enumManager->enumNames(m_costFunction)[i]; + return QString::number(m_intManager->value(prop)); } /** - * Set new value to the CostFunction property. + * Set a new value of an integer algorithm property. + * @param prop :: The corresponding QtProperty. * @param value :: The new value. */ -void FitOptionsBrowser::setCostFunction(const QString& value) +void FitOptionsBrowser::setIntProperty(QtProperty* prop, const QString& value) { - int i = m_enumManager->enumNames(m_costFunction).indexOf(value); - m_enumManager->setValue(m_costFunction,i); + m_intManager->setValue(prop,value.toInt()); } /** - * Get the value of the MaxIterations property. + * Get the value of a bool algorithm property. + * @param prop :: The corresponding QtProperty. */ -QString FitOptionsBrowser::getMaxIterations() const +QString FitOptionsBrowser::getBoolProperty(QtProperty* prop) const { - return QString::number(m_intManager->value(m_maxIterations)); + return QString::number(m_boolManager->value(prop)); } /** - * Set new value to the MaxIterations property. + * Set a new value of a bool algorithm property. + * @param prop :: The corresponding QtProperty. * @param value :: The new value. */ -void FitOptionsBrowser::setMaxIterations(const QString& value) +void FitOptionsBrowser::setBoolProperty(QtProperty* prop, const QString& value) { - m_intManager->setValue(m_maxIterations,value.toInt()); + bool boolValue = (value == "1") || (value.lower() == "true"); + m_boolManager->setValue( prop, boolValue ); } /** - * Get the value of the Output property. + * Get the value of a string algorithm property with predefined set of values. + * @param prop :: The corresponding QtProperty. */ -QString FitOptionsBrowser::getOutput() const +QString FitOptionsBrowser::getStringEnumProperty(QtProperty* prop) const { - return m_stringManager->value(m_output); + int i = m_enumManager->value(prop); + if (i < 0) return ""; + return m_enumManager->enumNames(prop)[i]; } /** - * Set new value to the Output property. + * Set a new value of a string algorithm property with predefined set of values. + * @param prop :: The corresponding QtProperty. * @param value :: The new value. */ -void FitOptionsBrowser::setOutput(const QString& value) +void FitOptionsBrowser::setStringEnumProperty(QtProperty* prop, const QString& value) { - m_stringManager->setValue(m_output,value); + int i = m_enumManager->enumNames(prop).indexOf(value); + if (i >= 0) + m_enumManager->setValue(prop,i); } /** - * Get the value of the IgnoreInvalidData property. + * Get the value of a string algorithm property. + * @param prop :: The corresponding QtProperty. */ -QString FitOptionsBrowser::getIgnoreInvalidData() const +QString FitOptionsBrowser::getStringProperty(QtProperty* prop) const { - return QString::number(m_boolManager->value(m_ignoreInvalidData)); + return m_stringManager->value(prop); } /** - * Set new value to the IgnoreInvalidData property. + * Set a new value of a string algorithm property. + * @param prop :: The corresponding QtProperty. * @param value :: The new value. */ -void FitOptionsBrowser::setIgnoreInvalidData(const QString& value) +void FitOptionsBrowser::setStringProperty(QtProperty* prop, const QString& value) { - bool boolValue = (value == "1") || (value == "true"); - m_boolManager->setValue( m_ignoreInvalidData, boolValue ); + m_stringManager->setValue(prop, value); } +// ------------------------------------------------------------------------------------// + /** * Save the last property values in settings. * @param settings :: A QSettings instance provided by the user of this class. */ void FitOptionsBrowser::saveSettings(QSettings& settings) const { - for(auto p = m_getters.constBegin(); p != m_getters.constEnd(); ++p) + for(auto p = m_propertyNameMap.constBegin(); p != m_propertyNameMap.constEnd(); ++p) { - auto f = p.value(); - settings.setValue( p.key(), (this->*f)() ); + auto prop = p.value(); + auto f = m_getters[prop]; + settings.setValue( p.key(), (this->*f)(prop) ); } } @@ -498,17 +653,81 @@ void FitOptionsBrowser::saveSettings(QSettings& settings) const */ void FitOptionsBrowser::loadSettings(const QSettings& settings) { - for(auto p = m_setters.constBegin(); p != m_setters.constEnd(); ++p) + for(auto p = m_propertyNameMap.constBegin(); p != m_propertyNameMap.constEnd(); ++p) { QString value = settings.value( p.key() ).toString(); if ( !value.isEmpty() ) { - auto f = p.value(); - (this->*f)( value ); + auto prop = p.value(); + auto f = m_setters[prop]; + (this->*f)(prop, value); } } } +/** + * Get the current fitting type, ie which algorithm to use: + * Simultaneous for Fit and Sequential for PlotPeakByLogValue. + */ +FitOptionsBrowser::FittingType FitOptionsBrowser::getCurrentFittingType() const +{ + auto value = m_enumManager->value(m_fittingTypeProp); + return static_cast<FitOptionsBrowser::FittingType>(value); +} + +/** + * Set the current fitting type, ie which algorithm to use: + * Simultaneous for Fit and Sequential for PlotPeakByLogValue. + */ +void FitOptionsBrowser::setCurrentFittingType(FitOptionsBrowser::FittingType fitType) +{ + m_enumManager->setValue(m_fittingTypeProp, fitType); +} + +/** + * Lock the browser in a particular fitting type state. Disable the switch option. + * @param fitType :: Fitting type to lock the browser in. + */ +void FitOptionsBrowser::lockCurrentFittingType(FitOptionsBrowser::FittingType fitType) +{ + m_enumManager->setValue(m_fittingTypeProp, fitType); + m_fittingTypeProp->setEnabled(false); +} + +/** + * Make the fitting type changeable again. + */ +void FitOptionsBrowser::unlockCurrentFittingType() +{ + m_fittingTypeProp->setEnabled(true); +} + +/** + * Define log names to use with the LogValue property. + * @param logNames :: The log names + */ +void FitOptionsBrowser::setLogNames(const QStringList& logNames) +{ + auto i = m_enumManager->value(m_logValue); + if (!logNames.isEmpty() && logNames.front().isEmpty()) + { + m_enumManager->setEnumNames(m_logValue, logNames); + } + else + { + QStringList names = logNames; + names.insert(0,""); + m_enumManager->setEnumNames(m_logValue, names); + } + if (i < logNames.size()) + { + m_enumManager->setValue(m_logValue, i); + } + else + { + m_enumManager->setValue(m_logValue, 0); + } +} } // MantidWidgets } // MantidQt diff --git a/Code/Mantid/MantidQt/MantidWidgets/src/FunctionBrowser.cpp b/Code/Mantid/MantidQt/MantidWidgets/src/FunctionBrowser.cpp index 6a1fec1998500607aeb2285e94c3e85923cbb12e..a5091090e1853d2504aafb2b319a9723dbd797a3 100644 --- a/Code/Mantid/MantidQt/MantidWidgets/src/FunctionBrowser.cpp +++ b/Code/Mantid/MantidQt/MantidWidgets/src/FunctionBrowser.cpp @@ -165,6 +165,7 @@ void FunctionBrowser::createBrowser() m_browser->setContextMenuPolicy(Qt::CustomContextMenu); connect(m_browser, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(popupMenu(const QPoint &))); + connect(m_browser, SIGNAL(optionChanged(QtProperty*, const QString&, bool)), this, SLOT(globalChanged(QtProperty*, const QString&, bool))); connect(m_attributeStringManager,SIGNAL(propertyChanged(QtProperty*)),this,SLOT(attributeChanged(QtProperty*))); connect(m_attributeDoubleManager,SIGNAL(propertyChanged(QtProperty*)),this,SLOT(attributeChanged(QtProperty*))); @@ -2189,6 +2190,13 @@ void FunctionBrowser::setColumnSizes(int s0, int s1, int s2) m_browser->setColumnSizes(s0, s1, s2); } +/** + * Emit a signal when any of the Global options change. + */ +void FunctionBrowser::globalChanged(QtProperty*, const QString&, bool) +{ + emit globalsChanged(); +} } // MantidWidgets } // MantidQt diff --git a/Code/Mantid/QtPropertyBrowser/src/qttreepropertybrowser.cpp b/Code/Mantid/QtPropertyBrowser/src/qttreepropertybrowser.cpp index 58bee7f04ccc37853953ad4fc870e594fd514959..53f493d7bee8d791a84e17494c4fdab5350c34ff 100644 --- a/Code/Mantid/QtPropertyBrowser/src/qttreepropertybrowser.cpp +++ b/Code/Mantid/QtPropertyBrowser/src/qttreepropertybrowser.cpp @@ -134,9 +134,12 @@ public: setChecked( ! isChecked() ); m_property->setOption( m_optionName, isChecked() ); update(); + emit optionChanged(m_property, m_optionName, isChecked()); } void setChecked(bool on){m_checked = on;} bool isChecked() const {return m_checked;} +signals: + void optionChanged(QtProperty*, const QString&, bool); private: QtProperty *m_property; QString m_optionName; @@ -351,6 +354,9 @@ public: QTreeWidgetItem *editedItem() const { return m_editedItem; } +signals: + void optionChanged(QtProperty*, const QString&, bool); + private slots: void slotEditorDestroyed(QObject *object); @@ -435,6 +441,7 @@ QWidget *QtPropertyEditorDelegate::createEditor(QWidget *parent, if ( property->hasOption(optionName) ) { QWidget *editor = new PropertyOptionCheckBox(parent,property,optionName); + connect(editor,SIGNAL(optionChanged(QtProperty*, const QString&, bool)),this,SIGNAL(optionChanged(QtProperty*, const QString&, bool))); return editor; } } @@ -591,6 +598,7 @@ void QtTreePropertyBrowserPrivate::init(QWidget *parent, const QStringList &opti m_treeWidget->setEditTriggers(QAbstractItemView::EditKeyPressed); m_delegate = new QtPropertyEditorDelegate(parent); m_delegate->setEditorPrivate(this); + QObject::connect(m_delegate,SIGNAL(optionChanged(QtProperty*, const QString&, bool)),parent,SIGNAL(optionChanged(QtProperty*, const QString&, bool))); m_treeWidget->setItemDelegate(m_delegate); m_treeWidget->header()->setMovable(false); m_treeWidget->header()->setResizeMode(QHeaderView::Stretch); diff --git a/Code/Mantid/QtPropertyBrowser/src/qttreepropertybrowser.h b/Code/Mantid/QtPropertyBrowser/src/qttreepropertybrowser.h index 51d367dc7bf8b0bb0c489b8d1ac4bce1e5138704..80072884d6001d464d2d1e6292ace6bc98413c96 100644 --- a/Code/Mantid/QtPropertyBrowser/src/qttreepropertybrowser.h +++ b/Code/Mantid/QtPropertyBrowser/src/qttreepropertybrowser.h @@ -159,6 +159,7 @@ Q_SIGNALS: void collapsed(QtBrowserItem *item); void expanded(QtBrowserItem *item); + void optionChanged(QtProperty*, const QString&, bool); protected: virtual void itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem); diff --git a/Code/Mantid/Testing/Data/UnitTest/irs26173_graphite002_red.nxs.md5 b/Code/Mantid/Testing/Data/UnitTest/irs26173_graphite002_red.nxs.md5 new file mode 100644 index 0000000000000000000000000000000000000000..dd49338b31255373fb60d986554ea8a6ce46902c --- /dev/null +++ b/Code/Mantid/Testing/Data/UnitTest/irs26173_graphite002_red.nxs.md5 @@ -0,0 +1 @@ +f52ac64ec23fb50b6d4649592aee4fdb \ No newline at end of file diff --git a/Code/Mantid/Testing/SystemTests/tests/analysis/POLDIFitPeaks2DTest.py b/Code/Mantid/Testing/SystemTests/tests/analysis/POLDIFitPeaks2DTest.py index 81007b721a560d782e1fa7f3cd4b18da8e4d91c0..cebeabf3e16062e9e85b38687d2352a6c861c8f5 100644 --- a/Code/Mantid/Testing/SystemTests/tests/analysis/POLDIFitPeaks2DTest.py +++ b/Code/Mantid/Testing/SystemTests/tests/analysis/POLDIFitPeaks2DTest.py @@ -1,8 +1,9 @@ -#pylint: disable=no-init,invalid-name,too-many-locals +# pylint: disable=no-init,invalid-name,too-many-locals,too-few-public-methods import stresstesting from mantid.simpleapi import * import numpy as np + class POLDIFitPeaks2DTest(stresstesting.MantidStressTest): """The system test currently checks that the calculation of 2D spectra works correctly.""" @@ -18,7 +19,7 @@ class POLDIFitPeaks2DTest(stresstesting.MantidStressTest): def loadAndPrepareData(self, filenames): for dataFile in filenames: - LoadSINQFile(Instrument='POLDI',Filename=dataFile + ".hdf",OutputWorkspace=dataFile) + LoadSINQFile(Instrument='POLDI', Filename=dataFile + ".hdf", OutputWorkspace=dataFile) LoadInstrument(Workspace=dataFile, InstrumentName="POLDI", RewriteSpectraMap=True) PoldiTruncateData(InputWorkspace=dataFile, OutputWorkspace=dataFile) @@ -28,19 +29,21 @@ class POLDIFitPeaks2DTest(stresstesting.MantidStressTest): def loadReferenceSpectrum(self, filenames): for dataFile in filenames: - Load(Filename="%s_2d_reference_Spectrum.nxs" % (dataFile), OutputWorkspace="%s_2d_reference_Spectrum" % (dataFile)) + Load(Filename="%s_2d_reference_Spectrum.nxs" % (dataFile), + OutputWorkspace="%s_2d_reference_Spectrum" % (dataFile)) LoadInstrument(Workspace="%s_2d_reference_Spectrum" % (dataFile), InstrumentName="POLDI") - Load(Filename="%s_1d_reference_Spectrum.nxs" % (dataFile), OutputWorkspace="%s_1d_reference_Spectrum" % (dataFile)) + Load(Filename="%s_1d_reference_Spectrum.nxs" % (dataFile), + OutputWorkspace="%s_1d_reference_Spectrum" % (dataFile)) def runCalculateSpectrum2D(self, filenames): for dataFile in filenames: PoldiFitPeaks2D(InputWorkspace="%s_2d_reference_Spectrum" % (dataFile), - PoldiPeakWorkspace="%s_reference_Peaks" % (dataFile), - FitConstantBackground=False, FitLinearBackground=False, - RefinedPoldiPeakWorkspace="%s_refined_Peaks" % (dataFile), - OutputWorkspace="%s_2d_calculated_Spectrum" % (dataFile), - Calculated1DSpectrum="%s_1d_calculated_Spectrum" % (dataFile), - MaximumIterations=100) + PoldiPeakWorkspace="%s_reference_Peaks" % (dataFile), + FitConstantBackground=False, FitLinearBackground=False, + RefinedPoldiPeakWorkspace="%s_refined_Peaks" % (dataFile), + OutputWorkspace="%s_2d_calculated_Spectrum" % (dataFile), + Calculated1DSpectrum="%s_1d_calculated_Spectrum" % (dataFile), + MaximumIterations=100) def analyseResults(self, filenames): for dataFile in filenames: @@ -66,7 +69,6 @@ class POLDIFitPeaks2DTest(stresstesting.MantidStressTest): self.assertLessThan(np.fabs(value - reference), error) - spectra1D = ["%s_1d_%s_Spectrum"] for wsName in spectra1D: @@ -85,8 +87,8 @@ class POLDIFitPeaks2DTest(stresstesting.MantidStressTest): self.assertTrue(np.all(xDataCalc == xDataRef)) self.assertLessThan(maxDifference, 0.07) -class POLDIFitPeaks2DPawleyTest(stresstesting.MantidStressTest): +class POLDIFitPeaks2DPawleyTest(stresstesting.MantidStressTest): def runTest(self): si = PoldiLoadRuns(2013, 6903, 6904, 2) corr = PoldiAutoCorrelation('si_data_6904') @@ -110,3 +112,48 @@ class POLDIFitPeaks2DPawleyTest(stresstesting.MantidStressTest): self.assertLessThan(np.abs(cell_a_err), 5.0e-5) self.assertLessThan(np.abs(cell_a - 5.4311946) / cell_a_err, 1.5) + DeleteWorkspace(si_refs) + DeleteWorkspace(indexed) + DeleteWorkspace(peaks) + DeleteWorkspace(si) + DeleteWorkspace(fit2d) + DeleteWorkspace(fit1d) + DeleteWorkspace(fit_plots) + DeleteWorkspace(peaks_ref_2d) + + +class POLDIFitPeaks2DIntegratedIntensities(stresstesting.MantidStressTest): + def runTest(self): + si = PoldiLoadRuns(2013, 6903, 6904, 2) + corr = PoldiAutoCorrelation('si_data_6904') + peaks = PoldiPeakSearch(corr, MaximumPeakNumber=8) + peaks_ref, fit_plots = PoldiFitPeaks1D(corr, PoldiPeakTable='peaks') + + # Run the same analysis twice, once with integrated and once with maximum intensities + # Since a Gaussian is used, the integration can be checked numerically. + fit2d, fit1d, peaks_ref_2d = PoldiFitPeaks2D('si_data_6904', peaks_ref, + OutputIntegratedIntensities=False, + MaximumIterations=100) + + fit2d, fit1d, peaks_ref_2d_integrated = PoldiFitPeaks2D('si_data_6904', peaks_ref, + OutputIntegratedIntensities=True, + MaximumIterations=100) + + self.assertEquals(peaks_ref_2d.rowCount(), peaks_ref_2d_integrated.rowCount()) + + for i in range(peaks_ref_2d.rowCount()): + rowHeight = peaks_ref_2d.row(i) + + sigmaGaussian = (rowHeight['FWHM (rel.)'] * rowHeight['d']) / (2.0 * np.sqrt(2.0 * np.log(2.0))) + integratedGaussian = rowHeight['Intensity'] * np.sqrt(np.pi * 2.0) * sigmaGaussian + + rowIntegrated = peaks_ref_2d_integrated.row(i) + + # The numerical peak integration is done with a precision of 1e-10 + self.assertDelta(integratedGaussian, rowIntegrated['Intensity'], 1e-10) + + DeleteWorkspace(fit2d) + DeleteWorkspace(fit1d) + DeleteWorkspace(si) + DeleteWorkspace(peaks) + DeleteWorkspace(fit_plots) diff --git a/Code/Mantid/docs/source/algorithms/PoldiFitPeaks2D-v1.rst b/Code/Mantid/docs/source/algorithms/PoldiFitPeaks2D-v1.rst index cb85043511ca6b1d9669830e69b02879bd2e0089..d20d3751daa2734c61909f6b2a9a80259af15c0e 100644 --- a/Code/Mantid/docs/source/algorithms/PoldiFitPeaks2D-v1.rst +++ b/Code/Mantid/docs/source/algorithms/PoldiFitPeaks2D-v1.rst @@ -21,7 +21,7 @@ Alternatively, if the peaks have been indexed using a different method, the log PoldiFitPeaks2D can also be used to calculate a theoretical 2D pattern from a set of peaks by limiting the iterations to 0. -In addition to performing the 2D-fit, a theoretical 1D-diffractogram of the fit-function is calculated as well, which can be used in conjunction with :ref:`algm-PoldiAnalyseResiduals` to assess the quality of a fit. +In addition to performing the 2D-fit, a theoretical 1D-diffractogram of the fit-function is calculated as well, which can be used in conjunction with :ref:`algm-PoldiAnalyseResiduals` to assess the quality of a fit. Depending on the value of the `OutputIntegratedIntensity`-option, the output peaks intensities are either integrated or describe the maximum. Usage ----- diff --git a/Code/Mantid/docs/source/algorithms/ResNorm-v1.rst b/Code/Mantid/docs/source/algorithms/ResNorm-v1.rst index e43e7b7820d6f2a0ab8cf706c8136f9a53fafbcd..33f9724048a398f2af826bceed73a1ba89099d94 100644 --- a/Code/Mantid/docs/source/algorithms/ResNorm-v1.rst +++ b/Code/Mantid/docs/source/algorithms/ResNorm-v1.rst @@ -31,7 +31,7 @@ Usage ws = CropWorkspace(ws, StartWorkspaceIndex=0, EndWorkspaceIndex=9) ws = ScaleX(ws, -5, "Add") ws = ScaleX(ws, 0.1, "Multiply") - + #load instrument and instrument parameters LoadInstrument(ws, InstrumentName='IRIS') path = os.path.join(config['instrumentDefinition.directory'], 'IRIS_graphite_002_Parameters.xml') @@ -43,7 +43,14 @@ Usage ws = createSampleWorkspace("irs26173_graphite002_red", random=True) res = createSampleWorkspace("irs26173_graphite002_res") - ResNorm(VanNumber='26176', ResNumber='26173', InputType='Workspace', ResInputType='Workspace', Instrument='irs', Analyser='graphite002', Plot='None') + ResNorm(VanNumber='26176', + ResNumber='26173', + InputType='Workspace', + ResInputType='Workspace', + Instrument='irs', + Analyser='graphite002', + Plot='None', + Version=1) .. categories:: diff --git a/Code/Mantid/docs/source/algorithms/ResNorm-v2.rst b/Code/Mantid/docs/source/algorithms/ResNorm-v2.rst new file mode 100644 index 0000000000000000000000000000000000000000..ca9e6f496e2edb0523968e51e8142b61c11bda1d --- /dev/null +++ b/Code/Mantid/docs/source/algorithms/ResNorm-v2.rst @@ -0,0 +1,68 @@ +.. algorithm:: + +.. summary:: + +.. alias:: + +.. properties:: + +Description +----------- + +This algorithm fits the variation of the width of the resolution file to give a +stretch factor and fits the peak intensities by normalising the peak area to +unity and performing a linear fit with the vanadium. + +The outpout workspace is a WorkspaceGroup containing two MatrixWorkspaces named +*_Intensity* and *_Stretch* with the fitted parameters. + +Usage +----- + +**Example - a basic example using ResNorm.** + +.. testcode:: ExIRISResNorm + + def createSampleWorkspace(name, num_spec=10, random=False): + """ + Creates a sample workspace with a single lorentzian that looks like IRIS data + """ + import os + + # Create sample data + function = "name=Lorentzian,Amplitude=8,PeakCentre=5,FWHM=0.7" + ws = CreateSampleWorkspace("Histogram", + Function="User Defined", + UserDefinedFunction=function, + XUnit="DeltaE", + Random=random, + XMin=0, + XMax=10, + BinWidth=0.01) + + # Reduce number of spectra + ws = CropWorkspace(ws, + StartWorkspaceIndex=0, + EndWorkspaceIndex=num_spec-1) + + ws = ScaleX(ws, -5, "Add") + ws = ScaleX(ws, 0.1, "Multiply") + + # Load instrument and instrument parameters + LoadInstrument(ws, InstrumentName='IRIS') + path = os.path.join(config['instrumentDefinition.directory'], 'IRIS_graphite_002_Parameters.xml') + LoadParameterFile(ws, Filename=path) + ws = RenameWorkspace(ws, OutputWorkspace=name) + + return ws + + + van = createSampleWorkspace("irs26173_graphite002_red", random=True) + res = createSampleWorkspace("irs26173_graphite002_res", num_spec=1) + + res_norm = ResNorm(ResolutionWorkspace=res, + VanadiumWorkspace=van, + Version=2) + + +.. categories::