From 5376137d6a932f3329966b4de27a4dd49be10eeb Mon Sep 17 00:00:00 2001 From: Raquel Alvarez Banos <raquel.alvarez.banos@gmail.com> Date: Tue, 19 Jul 2016 13:10:15 +0100 Subject: [PATCH] Re #16869 Merging master and solving conflicts --- .gitignore | 2 + CMakeLists.txt | 23 +- .../API/inc/MantidAPI/AlgorithmFactory.h | 18 +- .../API/inc/MantidAPI/AlgorithmManager.h | 14 +- .../API/inc/MantidAPI/AnalysisDataService.h | 17 +- .../API/inc/MantidAPI/ArchiveSearchFactory.h | 17 +- Framework/API/inc/MantidAPI/CatalogFactory.h | 17 +- Framework/API/inc/MantidAPI/CatalogManager.h | 13 +- Framework/API/inc/MantidAPI/ColumnFactory.h | 17 +- .../API/inc/MantidAPI/ConstraintFactory.h | 16 +- .../API/inc/MantidAPI/CostFunctionFactory.h | 16 +- Framework/API/inc/MantidAPI/DllConfig.h | 2 + .../API/inc/MantidAPI/DomainCreatorFactory.h | 17 +- Framework/API/inc/MantidAPI/FileFinder.h | 17 +- .../API/inc/MantidAPI/FileLoaderRegistry.h | 18 +- .../API/inc/MantidAPI/FrameworkManager.h | 17 +- .../API/inc/MantidAPI/FuncMinimizerFactory.h | 16 +- Framework/API/inc/MantidAPI/FunctionFactory.h | 17 +- .../inc/MantidAPI/ImplicitFunctionFactory.h | 20 +- .../ImplicitFunctionParameterParserFactory.h | 22 +- .../MantidAPI/ImplicitFunctionParserFactory.h | 20 +- .../API/inc/MantidAPI/InstrumentDataService.h | 20 +- .../API/inc/MantidAPI/LiveListenerFactory.h | 15 +- .../inc/MantidAPI/RemoteJobManagerFactory.h | 19 +- .../inc/MantidAPI/ScriptRepositoryFactory.h | 18 +- .../API/inc/MantidAPI/TransformScaleFactory.h | 19 +- .../API/inc/MantidAPI/WorkspaceFactory.h | 19 +- Framework/API/src/ArchiveSearchFactory.cpp | 1 - Framework/API/src/Expression.cpp | 4 +- Framework/API/src/TransformScaleFactory.cpp | 1 + Framework/API/src/WorkspaceProperty.cpp | 24 +- Framework/Algorithms/CMakeLists.txt | 9 +- .../inc/MantidAlgorithms/CropToComponent.h | 50 + Framework/Algorithms/src/CropToComponent.cpp | 133 ++ .../Algorithms/src/EQSANSTofStructure.cpp | 2 +- Framework/Algorithms/src/FilterByLogValue.cpp | 2 +- .../Algorithms/src/FindPeakBackground.cpp | 4 +- Framework/Algorithms/src/GetAllEi.cpp | 2 +- Framework/Algorithms/src/SmoothNeighbours.cpp | 6 +- .../Algorithms/test/CropToComponentTest.h | 157 +++ Framework/CMakeLists.txt | 2 +- .../src/ConnectedComponentLabeling.cpp | 2 +- .../Crystal/src/IntegratePeakTimeSlices.cpp | 16 +- .../Crystal/src/OptimizeCrystalPlacement.cpp | 3 +- .../inc/MantidCurveFitting/DllConfig.h | 2 + .../DataHandling/src/CheckMantidVersion.cpp | 6 +- .../DataHandling/src/DownloadInstrument.cpp | 6 +- Framework/DataHandling/src/LoadEventNexus.cpp | 1 + .../DataHandling/src/LoadEventPreNexus.cpp | 5 +- Framework/DataHandling/src/LoadILLSANS.cpp | 2 +- Framework/DataHandling/src/LoadRKH.cpp | 38 +- Framework/DataHandling/src/LoadSassena.cpp | 2 +- Framework/DataHandling/src/LoadTBL.cpp | 14 +- Framework/DataHandling/src/SaveNXcanSAS.cpp | 41 +- Framework/DataHandling/src/SetSample.cpp | 4 +- Framework/DataHandling/test/LoadRKHTest.h | 75 +- .../inc/MantidDataObjects/DllConfig.h | 2 + .../DataObjects/inc/MantidDataObjects/MDBox.h | 7 +- .../inc/MantidDataObjects/MDBoxBase.tcc | 3 +- .../inc/MantidDataObjects/MDEvent.h | 7 +- .../inc/MantidDataObjects/MDEventFactory.h | 385 +++--- .../inc/MantidDataObjects/MDLeanEvent.h | 4 +- .../inc/MantidDataObjects/TableColumn.h | 2 +- Framework/DataObjects/src/EventList.cpp | 43 +- Framework/DataObjects/src/EventWorkspace.cpp | 4 +- Framework/DataObjects/src/MDEventFactory.cpp | 257 ++-- Framework/DataObjects/src/Workspace2D.cpp | 4 +- .../DataObjects/src/WorkspaceSingleValue.cpp | 4 +- .../src/generate_mdevent_declarations.py | 25 +- .../Crystal/BraggScattererFactory.h | 13 +- .../MantidGeometry/Crystal/CenteringGroup.h | 12 +- .../Crystal/PointGroupFactory.h | 13 +- .../Crystal/SpaceGroupFactory.h | 13 +- .../Crystal/SymmetryElementFactory.h | 12 +- .../Crystal/SymmetryOperationFactory.h | 13 +- .../Geometry/inc/MantidGeometry/DllConfig.h | 2 + .../inc/MantidGeometry/Instrument/Parameter.h | 12 +- .../Instrument/ParameterFactory.h | 12 +- .../MDGeometry/MDGeometryXMLBuilder.h | 4 +- .../Instrument/SampleEnvironmentFactory.cpp | 2 +- .../src/Instrument/SampleEnvironmentSpec.cpp | 2 +- .../SampleEnvironmentSpecParser.cpp | 2 +- Framework/Geometry/src/Objects/Object.cpp | 16 +- Framework/ICat/inc/MantidICat/DllConfig.h | 2 + Framework/Kernel/CMakeLists.txt | 25 +- Framework/Kernel/inc/MantidKernel/ANN/ANN.h | 9 +- .../Kernel/inc/MantidKernel/ConfigService.h | 12 +- Framework/Kernel/inc/MantidKernel/DllConfig.h | 2 + .../inc/MantidKernel/GitHubApiHelper.h.in | 60 + .../Kernel/inc/MantidKernel/InternetHelper.h | 9 +- .../Kernel/inc/MantidKernel/LibraryManager.h | 12 +- .../MantidKernel/PropertyManagerDataService.h | 12 +- Framework/Kernel/inc/MantidKernel/System.h | 6 + .../Kernel/inc/MantidKernel/ThreadPool.h | 2 +- Framework/Kernel/inc/MantidKernel/Timer.h | 2 +- .../Kernel/inc/MantidKernel/UnitFactory.h | 9 +- .../Kernel/inc/MantidKernel/UsageService.h | 16 +- .../inc/MantidKernel/WarningSuppressions.h | 6 + Framework/Kernel/inc/MantidKernel/cow_ptr.h | 27 +- Framework/Kernel/src/ArrayProperty.cpp | 12 +- Framework/Kernel/src/ConfigService.cpp | 1 + .../Kernel/src/FilteredTimeSeriesProperty.cpp | 2 +- Framework/Kernel/src/GitHubApiHelper.cpp | 115 ++ Framework/Kernel/src/InternetHelper.cpp | 8 +- Framework/Kernel/src/MaskedProperty.cpp | 2 +- Framework/Kernel/src/Matrix.cpp | 8 +- Framework/Kernel/src/PropertyWithValue.cpp | 43 +- Framework/Kernel/src/TimeSeriesProperty.cpp | 19 +- Framework/Kernel/src/TimeSplitter.cpp | 10 +- Framework/Kernel/src/UsageService.cpp | 2 +- Framework/Kernel/src/VMD.cpp | 36 +- Framework/MDAlgorithms/CMakeLists.txt | 3 + .../MantidMDAlgorithms/CreateMDWorkspace.h | 4 + .../inc/MantidMDAlgorithms/DllConfig.h | 2 + .../MantidMDAlgorithms/IntegratePeaksMDHKL.h | 59 + .../inc/MantidMDAlgorithms/MDTransfFactory.h | 14 +- .../Quantification/ForegroundModelFactory.h | 18 +- .../MDResolutionConvolutionFactory.h | 18 +- .../MDAlgorithms/src/CreateMDWorkspace.cpp | 38 +- .../MDAlgorithms/src/IntegratePeaksMDHKL.cpp | 314 +++++ Framework/MDAlgorithms/src/ReplicateMD.cpp | 18 +- .../test/IntegratePeaksMDHKLTest.h | 192 +++ .../kernel/src/Converters/NDArrayToVector.cpp | 2 +- .../src/Converters/NDArrayTypeIndex.cpp | 2 +- .../src/Registry/SequenceTypeHandler.cpp | 2 +- .../CylinderPaalmanPingsCorrection2.py | 8 +- .../plugins/algorithms/ExportSpectraMask.py | 208 +++ .../plugins/algorithms/LoadPreNexusLive.py | 118 ++ .../FlatPlatePaalmanPingsCorrection.py | 6 +- .../python/plugins/algorithms/CMakeLists.txt | 1 + .../CylinderPaalmanPingsCorrection2Test.py | 22 +- .../algorithms/ExportSpectraMaskTest.py | 92 ++ .../FlatPlatePaalmanPingsCorrectionTest.py | 21 +- Framework/SINQ/inc/MantidSINQ/DllConfig.h | 2 + Framework/ScriptRepository/CMakeLists.txt | 1 + .../inc/MantidScriptRepository/DllConfig.h | 22 + .../ScriptRepositoryImpl.h | 11 +- .../TestHelpers/src/MDEventsTestHelper.cpp | 7 +- MantidPlot/src/FloatingWindow.cpp | 8 + .../inc/MantidQtAPI/AlgorithmInputHistory.h | 17 +- MantidQt/API/inc/MantidQtAPI/DllOption.h | 2 + .../API/inc/MantidQtAPI/InterfaceFactory.h | 27 +- .../SelectionNotificationService.h | 18 +- MantidQt/API/src/SignalBlocker.cpp | 8 +- .../ConvertTableToMatrixWorkspaceDialog.cpp | 6 +- MantidQt/CustomInterfaces/CMakeLists.txt | 10 + .../inc/MantidQtCustomInterfaces/DllConfig.h | 2 + .../EnggDiffFittingPresWorker.h | 69 + .../EnggDiffFittingPresenter.h | 167 +++ .../EnggDiffFittingViewQtWidget.h | 239 ++++ .../EnggDiffractionPresWorker.h | 14 - .../EnggDiffractionPresenter.h | 86 +- .../EnggDiffractionViewQtGUI.h | 118 +- .../IEnggDiffFittingPresenter.h | 64 + .../EnggDiffraction/IEnggDiffFittingView.h | 222 ++++ .../IEnggDiffractionCalibration.h | 64 + .../IEnggDiffractionPresenter.h | 5 +- .../IEnggDiffractionPythonRunner.h | 56 + .../IEnggDiffractionSettings.h | 60 + .../EnggDiffraction/IEnggDiffractionUserMsg.h | 92 ++ .../EnggDiffraction/IEnggDiffractionView.h | 248 +--- .../MantidQtCustomInterfaces/Indirect/Elwin.h | 3 +- .../EnggDiffFittingPresenter.cpp | 1126 +++++++++++++++++ .../EnggDiffFittingViewQtWidget.cpp | 666 ++++++++++ .../EnggDiffractionPresenter.cpp | 1084 +--------------- .../EnggDiffractionViewQtGUI.cpp | 633 +-------- .../CustomInterfaces/src/Indirect/Elwin.cpp | 69 +- .../src/Reflectometry/TransferResults.cpp | 7 +- .../test/EnggDiffFittingPresenterTest.h | 419 ++++++ .../test/EnggDiffFittingViewMock.h | 122 ++ .../test/EnggDiffractionPresenterTest.h | 303 +---- .../test/EnggDiffractionViewMock.h | 77 +- .../DataProcessorAppendGroupCommand.h | 4 +- .../DataProcessorAppendRowCommand.h | 4 +- .../DataProcessorClearSelectedCommand.h | 4 +- .../DataProcessorUI/DataProcessorCommand.h | 7 +- .../DataProcessorCopySelectedCommand.h | 4 +- .../DataProcessorCutSelectedCommand.h | 4 +- .../DataProcessorDeleteGroupCommand.h | 4 +- .../DataProcessorDeleteRowCommand.h | 4 +- .../DataProcessorExpandCommand.h | 4 +- .../DataProcessorExportTableCommand.h | 4 +- .../DataProcessorGroupRowsCommand.h | 4 +- .../DataProcessorImportTableCommand.h | 4 +- .../DataProcessorNewTableCommand.h | 4 +- .../DataProcessorOpenTableCommand.h | 4 +- .../DataProcessorOptionsCommand.h | 4 +- .../DataProcessorPasteSelectedCommand.h | 4 +- .../DataProcessorPlotGroupCommand.h | 4 +- .../DataProcessorPlotRowCommand.h | 4 +- .../DataProcessorProcessCommand.h | 4 +- .../DataProcessorSaveTableAsCommand.h | 4 +- .../DataProcessorSaveTableCommand.h | 4 +- .../DataProcessorSeparatorCommand.h | 4 +- .../DataProcessorWorkspaceCommand.h | 4 +- .../DataProcessorGenerateNotebook.cpp | 34 +- .../GenericDataProcessorPresenter.cpp | 71 +- .../DataProcessorGenerateNotebookTest.h | 35 +- MantidQt/Python/sip_mantidqt.cpp.in | 9 + .../inc/MantidQtSliceViewer/PeakPalette.h | 4 +- QtPropertyBrowser/CMakeLists.txt | 8 +- QtPropertyBrowser/src/qtpropertybrowser.h | 14 +- .../osiris97944_graphite002_red.nxs.md5 | 1 + .../tests/analysis/ISISIndirectInelastic.py | 22 +- .../analysis/reference/II.OSIRISIqt.nxs.md5 | 1 + .../reference/II.OSIRISIqtFitMulti.nxs.md5 | 1 + Testing/Tools/CMakeLists.txt | 2 +- Testing/Tools/gmock-1.7.0/CMakeLists.txt | 2 +- .../Tools/gmock-1.7.0/gtest/CMakeLists.txt | 2 +- Vates/VatesAPI/CMakeLists.txt | 2 +- .../inc/MantidVatesAPI/vtkMDHWSignalArray.h | 22 +- Vates/VatesAPI/src/ADSWorkspaceProvider.cpp | 8 +- Vates/VatesAPI/src/vtkPeakMarkerFactory.cpp | 4 +- Vates/VatesAPI/test/MockObjects.h | 40 +- .../vtkDataSetToNonOrthogonalDataSetTest.h | 26 +- Vates/VatesAPI/test/vtkMDHWSignalArrayTest.h | 12 +- .../StandAloneExec/CMakeLists.txt | 2 +- .../src/SaveScreenshotReaction.cpp | 19 +- buildconfig/CMake/Bootstrap.cmake | 2 +- buildconfig/CMake/CommonSetup.cmake | 9 +- buildconfig/CMake/Coveralls.cmake | 2 +- buildconfig/CMake/GNUSetup.cmake | 19 +- buildconfig/CMake/LinuxPackageScripts.cmake | 2 +- buildconfig/CMake/ParaViewSetup.cmake | 2 +- buildconfig/CMake/SquishTestScript.cmake | 2 +- buildconfig/Jenkins/buildscript | 4 +- buildconfig/Jenkins/buildscript.bat | 4 +- buildconfig/Jenkins/doctests | 15 +- buildconfig/Jenkins/pylint-buildscript | 9 +- .../algorithms/BASISReduction311-v1.rst | 68 + docs/source/algorithms/CropToComponent-v1.rst | 50 + .../algorithms/ExportSpectraMask-v1.rst | 65 + .../algorithms/IntegratePeaksMDHKL-v1.rst | 103 ++ .../source/algorithms/LoadPreNexusLive-v1.rst | 32 + docs/source/algorithms/ReplicateMD-v1.rst | 8 +- docs/source/concepts/HistogramData.rst | 14 +- docs/source/images/IntegratePeaksMDHKLbkg.png | Bin 0 -> 18380 bytes docs/source/images/IntegratePeaksMDHKLbox.png | Bin 0 -> 22669 bytes .../source/images/IntegratePeaksMDHKLpeak.png | Bin 0 -> 20949 bytes docs/source/images/peak3d.png | Bin 0 -> 63391 bytes docs/source/release/v3.8.0/diffraction.rst | 14 + .../release/v3.8.0/direct_inelastic.rst | 6 + docs/source/release/v3.8.0/framework.rst | 11 + .../release/v3.8.0/indirect_inelastic.rst | 4 + docs/source/release/v3.8.0/sans.rst | 8 +- docs/source/release/v3.8.0/ui.rst | 7 + instrument/TOPAZ_Definition_2016-04-06.xml | 5 +- instrument/TOPAZ_Definition_2016-07-14.xml | 259 ++++ scripts/HFIR_4Circle_Reduction/MainWindow.ui | 120 +- .../HFIR_4Circle_Reduction/View3DWidget.ui | 332 ++--- scripts/HFIR_4Circle_Reduction/__init__.py | 3 +- .../HFIR_4Circle_Reduction/detector2dview.py | 5 - .../fourcircle_utility.py | 1 - scripts/HFIR_4Circle_Reduction/fputility.py | 1 + scripts/HFIR_4Circle_Reduction/guiutility.py | 4 +- scripts/HFIR_4Circle_Reduction/hfctables.py | 27 +- .../multi_threads_helpers.py | 252 ++++ .../peakprocesshelper.py | 29 +- .../reduce4circleControl.py | 37 +- .../reduce4circleGUI.py | 386 +++--- 260 files changed, 7900 insertions(+), 4177 deletions(-) create mode 100644 Framework/Algorithms/inc/MantidAlgorithms/CropToComponent.h create mode 100644 Framework/Algorithms/src/CropToComponent.cpp create mode 100644 Framework/Algorithms/test/CropToComponentTest.h create mode 100644 Framework/Kernel/inc/MantidKernel/GitHubApiHelper.h.in create mode 100644 Framework/Kernel/src/GitHubApiHelper.cpp create mode 100644 Framework/MDAlgorithms/inc/MantidMDAlgorithms/IntegratePeaksMDHKL.h create mode 100644 Framework/MDAlgorithms/src/IntegratePeaksMDHKL.cpp create mode 100644 Framework/MDAlgorithms/test/IntegratePeaksMDHKLTest.h create mode 100644 Framework/PythonInterface/plugins/algorithms/ExportSpectraMask.py create mode 100644 Framework/PythonInterface/plugins/algorithms/LoadPreNexusLive.py create mode 100644 Framework/PythonInterface/test/python/plugins/algorithms/ExportSpectraMaskTest.py create mode 100644 Framework/ScriptRepository/inc/MantidScriptRepository/DllConfig.h create mode 100644 MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingPresWorker.h create mode 100644 MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingPresenter.h create mode 100644 MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingViewQtWidget.h create mode 100644 MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffFittingPresenter.h create mode 100644 MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffFittingView.h create mode 100644 MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionCalibration.h create mode 100644 MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionPythonRunner.h create mode 100644 MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionSettings.h create mode 100644 MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionUserMsg.h create mode 100644 MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffFittingPresenter.cpp create mode 100644 MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffFittingViewQtWidget.cpp create mode 100644 MantidQt/CustomInterfaces/test/EnggDiffFittingPresenterTest.h create mode 100644 MantidQt/CustomInterfaces/test/EnggDiffFittingViewMock.h create mode 100644 Testing/Data/SystemTest/osiris97944_graphite002_red.nxs.md5 create mode 100644 Testing/SystemTests/tests/analysis/reference/II.OSIRISIqt.nxs.md5 create mode 100644 Testing/SystemTests/tests/analysis/reference/II.OSIRISIqtFitMulti.nxs.md5 create mode 100644 docs/source/algorithms/BASISReduction311-v1.rst create mode 100644 docs/source/algorithms/CropToComponent-v1.rst create mode 100644 docs/source/algorithms/ExportSpectraMask-v1.rst create mode 100644 docs/source/algorithms/IntegratePeaksMDHKL-v1.rst create mode 100644 docs/source/algorithms/LoadPreNexusLive-v1.rst create mode 100644 docs/source/images/IntegratePeaksMDHKLbkg.png create mode 100644 docs/source/images/IntegratePeaksMDHKLbox.png create mode 100644 docs/source/images/IntegratePeaksMDHKLpeak.png create mode 100644 docs/source/images/peak3d.png create mode 100644 instrument/TOPAZ_Definition_2016-07-14.xml create mode 100644 scripts/HFIR_4Circle_Reduction/multi_threads_helpers.py diff --git a/.gitignore b/.gitignore index 1e78a1f3c6a..0c7d91a11b3 100644 --- a/.gitignore +++ b/.gitignore @@ -167,6 +167,8 @@ Desktop.ini .tags .tags_sorted_by_file +#Dynamically created files +Framework/Kernel/inc/MantidKernel/GitHubApiHelper.h Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/LibHelper.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a55c27ade9..a09673e2de7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,21 +1,8 @@ ########################################################################### # CMake version check. -# Require >= 3.3 for Windows as previous versions contained a bug that -# prevented external data from working correctly. Other systems require -# 2.8.12 to avoid recompiling system packages +# Require CMake 3.5, required by ParaView 5.1.0 ########################################################################### -if (CMAKE_HOST_WIN32) - cmake_minimum_required ( VERSION 3.3.0 ) -else() - cmake_minimum_required ( VERSION 2.8.12 ) -endif() - -if(POLICY CMP0053) - #Simplify variable reference and escape sequence evaluation. - #Claims to dramatically improve CMake configure and generate time - #requires CMake 3.1 or later - cmake_policy(SET CMP0053 NEW) -endif() +cmake_minimum_required ( VERSION 3.5 ) # Define the project name. project ( Mantid ) @@ -306,9 +293,9 @@ if ( ENABLE_CPACK ) "libpocofoundation11,libpocoutil11,libpoconet11,libpoconetssl11,libpococrypto11,libpocoxml11," "python-pycifrw (>= 4.2.1)" ) set ( PERFTOOLS_DEB_PACKAGE "libgoogle-perftools4 (>= 1.7)" ) - if( "${UNIX_CODENAME}" STREQUAL "wily" OR "${UNIX_CODENAME}" STREQUAL "xenial") - list ( APPEND DEPENDS_LIST ", libnexus0v5 (>= 4.3),libjsoncpp0v5 (>= 0.7.0),libqscintilla2-12v5, libmuparser2v5,libqwtplot3d-qt4-0v5") - list (REMOVE_ITEM DEPENDS_LIST "libjsoncpp0 (>=0.7.0)," "libqscintilla2-11," "libmuparser2," "libnexus0 (>= 4.3)," "libqwtplot3d-qt4-0,") + if( "${UNIX_CODENAME}" STREQUAL "xenial") + list ( APPEND DEPENDS_LIST ", libnexus0v5 (>= 4.3),libjsoncpp1,libqscintilla2-12v5, libmuparser2v5,libqwtplot3d-qt4-0v5,libgsl2,liboce-foundation10,liboce-modeling10") + list (REMOVE_ITEM DEPENDS_LIST "libjsoncpp0 (>=0.7.0)," "libqscintilla2-11," "libmuparser2," "libnexus0 (>= 4.3)," "libqwtplot3d-qt4-0," "libgsl0ldbl," "liboce-foundation8,liboce-modeling8,") endif() # parse list to string required for deb package string ( REPLACE ";" "" CPACK_DEBIAN_PACKAGE_DEPENDS ${DEPENDS_LIST} ) diff --git a/Framework/API/inc/MantidAPI/AlgorithmFactory.h b/Framework/API/inc/MantidAPI/AlgorithmFactory.h index a9d7bb805be..c0e1afdd9d1 100644 --- a/Framework/API/inc/MantidAPI/AlgorithmFactory.h +++ b/Framework/API/inc/MantidAPI/AlgorithmFactory.h @@ -168,16 +168,7 @@ private: VersionMap m_vmap; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// AlgorithmFactoryImpl (needed for dllexport/dllimport) and a typedef for it. -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class MANTID_API_DLL - Mantid::Kernel::SingletonHolder<AlgorithmFactoryImpl>; -#endif /* _WIN32 */ - -typedef MANTID_API_DLL Mantid::Kernel::SingletonHolder<AlgorithmFactoryImpl> - AlgorithmFactory; +typedef Mantid::Kernel::SingletonHolder<AlgorithmFactoryImpl> AlgorithmFactory; /// Convenient typedef for an UpdateNotification typedef Mantid::Kernel::DynamicFactory<Algorithm>::UpdateNotification @@ -188,4 +179,11 @@ typedef const Poco::AutoPtr<Mantid::Kernel::DynamicFactory< } // namespace API } // namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL + Mantid::Kernel::SingletonHolder<Mantid::API::AlgorithmFactoryImpl>; +} +} + #endif /*MANTID_API_ALGORITHMFACTORY_H_*/ diff --git a/Framework/API/inc/MantidAPI/AlgorithmManager.h b/Framework/API/inc/MantidAPI/AlgorithmManager.h index abb76dfe13c..cc777057963 100644 --- a/Framework/API/inc/MantidAPI/AlgorithmManager.h +++ b/Framework/API/inc/MantidAPI/AlgorithmManager.h @@ -102,16 +102,16 @@ private: mutable std::mutex m_managedMutex; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// AlgorithmManagerImpl (needed for dllexport/dllimport) and a typedef for it. -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class MANTID_API_DLL - Mantid::Kernel::SingletonHolder<AlgorithmManagerImpl>; -#endif /* _WIN32 */ typedef Mantid::Kernel::SingletonHolder<AlgorithmManagerImpl> AlgorithmManager; } // namespace API } // Namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL + Mantid::Kernel::SingletonHolder<Mantid::API::AlgorithmManagerImpl>; +} +} + #endif /* MANTID_API_ALGORITHMMANAGER_H_ */ diff --git a/Framework/API/inc/MantidAPI/AnalysisDataService.h b/Framework/API/inc/MantidAPI/AnalysisDataService.h index b99dfb0f5dd..d46cd86ba7f 100644 --- a/Framework/API/inc/MantidAPI/AnalysisDataService.h +++ b/Framework/API/inc/MantidAPI/AnalysisDataService.h @@ -178,15 +178,7 @@ private: std::string m_illegalChars; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// AnalysisDataServiceImpl (needed for dllexport/dllimport) and a typedef for -/// it. -#ifdef _WIN32 -// this breaks new namespace declaration rules; need to find a better fix -template class MANTID_API_DLL - Mantid::Kernel::SingletonHolder<AnalysisDataServiceImpl>; -#endif /* _WIN32 */ -typedef MANTID_API_DLL Mantid::Kernel::SingletonHolder<AnalysisDataServiceImpl> +typedef Mantid::Kernel::SingletonHolder<AnalysisDataServiceImpl> AnalysisDataService; typedef Mantid::Kernel::DataService<Mantid::API::Workspace>::AddNotification @@ -249,4 +241,11 @@ typedef const Poco::AutoPtr<AnalysisDataServiceImpl::GroupUpdatedNotification> & } // Namespace API } // Namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL + Mantid::Kernel::SingletonHolder<Mantid::API::AnalysisDataServiceImpl>; +} +} + #endif /*MANTID_KERNEL_ANALYSISDATASERVICE_H_*/ diff --git a/Framework/API/inc/MantidAPI/ArchiveSearchFactory.h b/Framework/API/inc/MantidAPI/ArchiveSearchFactory.h index 78a4d211d36..a08b918d1fd 100644 --- a/Framework/API/inc/MantidAPI/ArchiveSearchFactory.h +++ b/Framework/API/inc/MantidAPI/ArchiveSearchFactory.h @@ -56,17 +56,16 @@ private: ~ArchiveSearchFactoryImpl() override = default; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// AlgorithmFactoryImpl (needed for dllexport/dllimport) and a typedef for it. -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class MANTID_API_DLL - Mantid::Kernel::SingletonHolder<ArchiveSearchFactoryImpl>; -#endif /* _WIN32 */ - -typedef MANTID_API_DLL Mantid::Kernel::SingletonHolder<ArchiveSearchFactoryImpl> +typedef Mantid::Kernel::SingletonHolder<ArchiveSearchFactoryImpl> ArchiveSearchFactory; } } +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL + Mantid::Kernel::SingletonHolder<Mantid::API::ArchiveSearchFactoryImpl>; +} +} + #endif // MANTID_API_ARCHIVESEARCHFACTORY_H_ diff --git a/Framework/API/inc/MantidAPI/CatalogFactory.h b/Framework/API/inc/MantidAPI/CatalogFactory.h index 391bcf6753f..b6133d3315d 100644 --- a/Framework/API/inc/MantidAPI/CatalogFactory.h +++ b/Framework/API/inc/MantidAPI/CatalogFactory.h @@ -76,19 +76,18 @@ private: mutable std::map<std::string, boost::shared_ptr<ICatalog>> m_createdCatalogs; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// CatalogFactoryImpl (needed for dllexport/dllimport) . -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class MANTID_API_DLL - Mantid::Kernel::SingletonHolder<CatalogFactoryImpl>; -#endif /* _WIN32 */ /// The specialisation of the SingletonHolder class that holds the /// CatalogFactory -typedef MANTID_API_DLL Mantid::Kernel::SingletonHolder<CatalogFactoryImpl> - CatalogFactory; +typedef Mantid::Kernel::SingletonHolder<CatalogFactoryImpl> CatalogFactory; } // namespace API } // namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL + Mantid::Kernel::SingletonHolder<Mantid::API::CatalogFactoryImpl>; +} +} + #endif /*MANTID_API_CATALOGFACTORYIMPL_H_*/ diff --git a/Framework/API/inc/MantidAPI/CatalogManager.h b/Framework/API/inc/MantidAPI/CatalogManager.h index 7b8cf565a7b..d7bc46ddcff 100644 --- a/Framework/API/inc/MantidAPI/CatalogManager.h +++ b/Framework/API/inc/MantidAPI/CatalogManager.h @@ -67,11 +67,14 @@ private: std::map<CatalogSession_sptr, ICatalog_sptr> m_activeCatalogs; }; -#ifdef _WIN32 -template class MANTID_API_DLL Kernel::SingletonHolder<CatalogManagerImpl>; -#endif -typedef MANTID_API_DLL Kernel::SingletonHolder<CatalogManagerImpl> - CatalogManager; +typedef Kernel::SingletonHolder<CatalogManagerImpl> CatalogManager; +} +} + +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL + Kernel::SingletonHolder<Mantid::API::CatalogManagerImpl>; } } #endif /* MANTID_ICAT_CATALOGMANAGERIMPL_H_ */ diff --git a/Framework/API/inc/MantidAPI/ColumnFactory.h b/Framework/API/inc/MantidAPI/ColumnFactory.h index 2d85aa07592..df6a3d92e98 100644 --- a/Framework/API/inc/MantidAPI/ColumnFactory.h +++ b/Framework/API/inc/MantidAPI/ColumnFactory.h @@ -63,17 +63,16 @@ private: ~ColumnFactoryImpl() override = default; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// AlgorithmFactoryImpl (needed for dllexport/dllimport) and a typedef for it. -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class MANTID_API_DLL - Mantid::Kernel::SingletonHolder<ColumnFactoryImpl>; -#endif /* _WIN32 */ -typedef MANTID_API_DLL Mantid::Kernel::SingletonHolder<ColumnFactoryImpl> - ColumnFactory; +typedef Mantid::Kernel::SingletonHolder<ColumnFactoryImpl> ColumnFactory; } // namespace API } // namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL + Mantid::Kernel::SingletonHolder<Mantid::API::ColumnFactoryImpl>; +} +} + #endif /*MANTID_API_COLUMNFACTORY_H_*/ diff --git a/Framework/API/inc/MantidAPI/ConstraintFactory.h b/Framework/API/inc/MantidAPI/ConstraintFactory.h index aa39886f793..560770e3bc4 100644 --- a/Framework/API/inc/MantidAPI/ConstraintFactory.h +++ b/Framework/API/inc/MantidAPI/ConstraintFactory.h @@ -72,19 +72,19 @@ private: ~ConstraintFactoryImpl() override = default; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// AlgorithmFactoryImpl (needed for dllexport/dllimport) and a typedef for it. -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class MANTID_API_DLL - Mantid::Kernel::SingletonHolder<ConstraintFactoryImpl>; -#endif /* _WIN32 */ -typedef MANTID_API_DLL Mantid::Kernel::SingletonHolder<ConstraintFactoryImpl> +typedef Mantid::Kernel::SingletonHolder<ConstraintFactoryImpl> ConstraintFactory; } // namespace API } // namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL + Mantid::Kernel::SingletonHolder<Mantid::API::ConstraintFactoryImpl>; +} +} + /** * Macro for declaring a new type of function to be used with the * FunctionFactory diff --git a/Framework/API/inc/MantidAPI/CostFunctionFactory.h b/Framework/API/inc/MantidAPI/CostFunctionFactory.h index c6675f363ff..26d5b33867b 100644 --- a/Framework/API/inc/MantidAPI/CostFunctionFactory.h +++ b/Framework/API/inc/MantidAPI/CostFunctionFactory.h @@ -63,17 +63,17 @@ private: CostFunctionFactoryImpl(); }; -/// Forward declaration of a specialisation of SingletonHolder for -/// AlgorithmFactoryImpl (needed for dllexport/dllimport) and a typedef for it. -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class MANTID_API_DLL - Mantid::Kernel::SingletonHolder<CostFunctionFactoryImpl>; -#endif /* _WIN32 */ -typedef MANTID_API_DLL Mantid::Kernel::SingletonHolder<CostFunctionFactoryImpl> +typedef Mantid::Kernel::SingletonHolder<CostFunctionFactoryImpl> CostFunctionFactory; } // namespace API } // namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL + Mantid::Kernel::SingletonHolder<Mantid::API::CostFunctionFactoryImpl>; +} +} + #endif /*MANTID_API_COSTFUNCTIONFACTORY_H_*/ diff --git a/Framework/API/inc/MantidAPI/DllConfig.h b/Framework/API/inc/MantidAPI/DllConfig.h index ff00439cca8..28be254b9c8 100644 --- a/Framework/API/inc/MantidAPI/DllConfig.h +++ b/Framework/API/inc/MantidAPI/DllConfig.h @@ -32,8 +32,10 @@ #ifdef IN_MANTID_API #define MANTID_API_DLL DLLExport +#define EXTERN_MANTID_API #else #define MANTID_API_DLL DLLImport +#define EXTERN_MANTID_API EXTERN_IMPORT #endif /* IN_MANTID_API*/ #endif // MANTID_API_DLLCONFIG_H_ diff --git a/Framework/API/inc/MantidAPI/DomainCreatorFactory.h b/Framework/API/inc/MantidAPI/DomainCreatorFactory.h index d88d4212241..9aace3d1ea1 100644 --- a/Framework/API/inc/MantidAPI/DomainCreatorFactory.h +++ b/Framework/API/inc/MantidAPI/DomainCreatorFactory.h @@ -68,18 +68,17 @@ private: using Kernel::DynamicFactory<IDomainCreator>::createUnwrapped; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// DomainCreatorFactoryImpl (needed for dllexport/dllimport) and a typedef for -/// it. -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class MANTID_API_DLL - Mantid::Kernel::SingletonHolder<DomainCreatorFactoryImpl>; -#endif /* _WIN32 */ -typedef MANTID_API_DLL Mantid::Kernel::SingletonHolder<DomainCreatorFactoryImpl> +typedef Mantid::Kernel::SingletonHolder<DomainCreatorFactoryImpl> DomainCreatorFactory; } // namespace API } // namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL + Mantid::Kernel::SingletonHolder<Mantid::API::DomainCreatorFactoryImpl>; +} +} + #endif /* MANTID_API_DOMAINCREATORFACTORY_H_ */ diff --git a/Framework/API/inc/MantidAPI/FileFinder.h b/Framework/API/inc/MantidAPI/FileFinder.h index 7c52f42ca2b..ffd119eda43 100644 --- a/Framework/API/inc/MantidAPI/FileFinder.h +++ b/Framework/API/inc/MantidAPI/FileFinder.h @@ -94,15 +94,14 @@ private: int m_globOption; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// AlgorithmFactoryImpl (needed for dllexport/dllimport) and a typedef for it. -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class MANTID_API_DLL Mantid::Kernel::SingletonHolder<FileFinderImpl>; -#endif /* _WIN32 */ - -typedef MANTID_API_DLL Mantid::Kernel::SingletonHolder<FileFinderImpl> - FileFinder; +typedef Mantid::Kernel::SingletonHolder<FileFinderImpl> FileFinder; +} +} + +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL + Mantid::Kernel::SingletonHolder<Mantid::API::FileFinderImpl>; } } diff --git a/Framework/API/inc/MantidAPI/FileLoaderRegistry.h b/Framework/API/inc/MantidAPI/FileLoaderRegistry.h index 02fd7a228b4..c53d1efb878 100644 --- a/Framework/API/inc/MantidAPI/FileLoaderRegistry.h +++ b/Framework/API/inc/MantidAPI/FileLoaderRegistry.h @@ -144,20 +144,18 @@ private: mutable Kernel::Logger m_log; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// FileLoaderRegistryImpl (needed for dllexport/dllimport) and a typedef for -/// it. -#ifdef _WIN32 -// this breaks new namespace declaration rules; need to find a better fix -template class MANTID_API_DLL - Mantid::Kernel::SingletonHolder<FileLoaderRegistryImpl>; -#endif /* _WIN32 */ - /// Type for the actual singleton instance -typedef MANTID_API_DLL Mantid::Kernel::SingletonHolder<FileLoaderRegistryImpl> +typedef Mantid::Kernel::SingletonHolder<FileLoaderRegistryImpl> FileLoaderRegistry; } // namespace API } // namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL + Mantid::Kernel::SingletonHolder<Mantid::API::FileLoaderRegistryImpl>; +} +} + #endif /* MANTID_API_FILELOADERREGISTRY_H_ */ diff --git a/Framework/API/inc/MantidAPI/FrameworkManager.h b/Framework/API/inc/MantidAPI/FrameworkManager.h index e62304b667e..583f5aec33a 100644 --- a/Framework/API/inc/MantidAPI/FrameworkManager.h +++ b/Framework/API/inc/MantidAPI/FrameworkManager.h @@ -137,17 +137,16 @@ private: #endif }; -/// Forward declaration of a specialisation of SingletonHolder for -/// AlgorithmFactoryImpl (needed for dllexport/dllimport) and a typedef for it. -#ifdef _WIN32 -// this breaks new namespace declaration rules; need to find a better fix -template class MANTID_API_DLL - Mantid::Kernel::SingletonHolder<FrameworkManagerImpl>; -#endif /* _WIN32 */ -typedef MANTID_API_DLL Mantid::Kernel::SingletonHolder<FrameworkManagerImpl> - FrameworkManager; +typedef Mantid::Kernel::SingletonHolder<FrameworkManagerImpl> FrameworkManager; } // namespace Kernel } // namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL + Mantid::Kernel::SingletonHolder<Mantid::API::FrameworkManagerImpl>; +} +} + #endif /*MANTID_API_FRAMEWORKMANAGER_H_*/ diff --git a/Framework/API/inc/MantidAPI/FuncMinimizerFactory.h b/Framework/API/inc/MantidAPI/FuncMinimizerFactory.h index e8864ac53d0..7944b5e2f91 100644 --- a/Framework/API/inc/MantidAPI/FuncMinimizerFactory.h +++ b/Framework/API/inc/MantidAPI/FuncMinimizerFactory.h @@ -61,19 +61,19 @@ private: FuncMinimizerFactoryImpl(); }; -/// Forward declaration of a specialisation of SingletonHolder for -/// AlgorithmFactoryImpl (needed for dllexport/dllimport) and a typedef for it. -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class MANTID_API_DLL - Mantid::Kernel::SingletonHolder<FuncMinimizerFactoryImpl>; -#endif /* _WIN32 */ -typedef MANTID_API_DLL Mantid::Kernel::SingletonHolder<FuncMinimizerFactoryImpl> +typedef Mantid::Kernel::SingletonHolder<FuncMinimizerFactoryImpl> FuncMinimizerFactory; } // namespace API } // namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL + Mantid::Kernel::SingletonHolder<Mantid::API::FuncMinimizerFactoryImpl>; +} +} + /** * Macro for declaring a new type of minimizers to be used with the * FuncMinimizerFactory diff --git a/Framework/API/inc/MantidAPI/FunctionFactory.h b/Framework/API/inc/MantidAPI/FunctionFactory.h index 76a21ecdf0c..36962ff2898 100644 --- a/Framework/API/inc/MantidAPI/FunctionFactory.h +++ b/Framework/API/inc/MantidAPI/FunctionFactory.h @@ -142,15 +142,7 @@ const std::vector<std::string> &FunctionFactoryImpl::getFunctionNames() const { return typeNames; } -/// Forward declaration of a specialisation of SingletonHolder for -/// AlgorithmFactoryImpl (needed for dllexport/dllimport) and a typedef for it. -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class MANTID_API_DLL - Mantid::Kernel::SingletonHolder<FunctionFactoryImpl>; -#endif /* _WIN32 */ -typedef MANTID_API_DLL Mantid::Kernel::SingletonHolder<FunctionFactoryImpl> - FunctionFactory; +typedef Mantid::Kernel::SingletonHolder<FunctionFactoryImpl> FunctionFactory; /// Convenient typedef for an UpdateNotification typedef FunctionFactoryImpl::UpdateNotification @@ -161,6 +153,13 @@ typedef const Poco::AutoPtr<FunctionFactoryUpdateNotification> & } // namespace API } // namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL + Mantid::Kernel::SingletonHolder<Mantid::API::FunctionFactoryImpl>; +} +} + /** * Macro for declaring a new type of function to be used with the * FunctionFactory diff --git a/Framework/API/inc/MantidAPI/ImplicitFunctionFactory.h b/Framework/API/inc/MantidAPI/ImplicitFunctionFactory.h index c0083dc3a61..10b8c9f04b4 100644 --- a/Framework/API/inc/MantidAPI/ImplicitFunctionFactory.h +++ b/Framework/API/inc/MantidAPI/ImplicitFunctionFactory.h @@ -64,17 +64,15 @@ private: ~ImplicitFunctionFactoryImpl() override = default; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// ImplicitFunctionFactoryImpl (needed for dllexport/dllimport) and a typedef -/// for it. -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class MANTID_API_DLL - Mantid::Kernel::SingletonHolder<ImplicitFunctionFactoryImpl>; -#endif /* _WIN32 */ - -typedef MANTID_API_DLL Mantid::Kernel::SingletonHolder< - ImplicitFunctionFactoryImpl> ImplicitFunctionFactory; +typedef Mantid::Kernel::SingletonHolder<ImplicitFunctionFactoryImpl> + ImplicitFunctionFactory; +} +} + +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL + Mantid::Kernel::SingletonHolder<Mantid::API::ImplicitFunctionFactoryImpl>; } } diff --git a/Framework/API/inc/MantidAPI/ImplicitFunctionParameterParserFactory.h b/Framework/API/inc/MantidAPI/ImplicitFunctionParameterParserFactory.h index f7722e5d9f2..98578f7383c 100644 --- a/Framework/API/inc/MantidAPI/ImplicitFunctionParameterParserFactory.h +++ b/Framework/API/inc/MantidAPI/ImplicitFunctionParameterParserFactory.h @@ -62,18 +62,16 @@ private: ~ImplicitFunctionParameterParserFactoryImpl() override = default; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// ImplicitFunctionFactoryImpl (needed for dllexport/dllimport) and a typedef -/// for it. -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class MANTID_API_DLL - Mantid::Kernel::SingletonHolder<ImplicitFunctionParameterParserFactoryImpl>; -#endif /* _WIN32 */ - -typedef MANTID_API_DLL - Mantid::Kernel::SingletonHolder<ImplicitFunctionParameterParserFactoryImpl> - ImplicitFunctionParameterParserFactory; +typedef Mantid::Kernel::SingletonHolder< + ImplicitFunctionParameterParserFactoryImpl> + ImplicitFunctionParameterParserFactory; +} +} + +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL Mantid::Kernel::SingletonHolder< + Mantid::API::ImplicitFunctionParameterParserFactoryImpl>; } } diff --git a/Framework/API/inc/MantidAPI/ImplicitFunctionParserFactory.h b/Framework/API/inc/MantidAPI/ImplicitFunctionParserFactory.h index 703dafa5b12..0c6b2e00f18 100644 --- a/Framework/API/inc/MantidAPI/ImplicitFunctionParserFactory.h +++ b/Framework/API/inc/MantidAPI/ImplicitFunctionParserFactory.h @@ -66,17 +66,15 @@ private: ~ImplicitFunctionParserFactoryImpl() override = default; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// ImplicitFunctionFactoryImpl (needed for dllexport/dllimport) and a typedef -/// for it. -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class MANTID_API_DLL - Mantid::Kernel::SingletonHolder<ImplicitFunctionParserFactoryImpl>; -#endif /* _WIN32 */ - -typedef MANTID_API_DLL Mantid::Kernel::SingletonHolder< - ImplicitFunctionParserFactoryImpl> ImplicitFunctionParserFactory; +typedef Mantid::Kernel::SingletonHolder<ImplicitFunctionParserFactoryImpl> + ImplicitFunctionParserFactory; +} +} + +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL Mantid::Kernel::SingletonHolder< + Mantid::API::ImplicitFunctionParserFactoryImpl>; } } diff --git a/Framework/API/inc/MantidAPI/InstrumentDataService.h b/Framework/API/inc/MantidAPI/InstrumentDataService.h index c4d5a2d4cf4..3ff486fb1ce 100644 --- a/Framework/API/inc/MantidAPI/InstrumentDataService.h +++ b/Framework/API/inc/MantidAPI/InstrumentDataService.h @@ -48,17 +48,17 @@ private: operator=(const InstrumentDataServiceImpl &) = delete; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// AnalysisDataServiceImpl (needed for dllexport/dllimport) and a typedef for -/// it. -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class MANTID_API_DLL - Mantid::Kernel::SingletonHolder<InstrumentDataServiceImpl>; -#endif /* _WIN32 */ -typedef MANTID_API_DLL Mantid::Kernel::SingletonHolder< - InstrumentDataServiceImpl> InstrumentDataService; +typedef Mantid::Kernel::SingletonHolder<InstrumentDataServiceImpl> + InstrumentDataService; } // Namespace API } // Namespace Mantid + +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL + Mantid::Kernel::SingletonHolder<Mantid::API::InstrumentDataServiceImpl>; +} +} + #endif /*INSTRUMENTDATASERVICE_*/ diff --git a/Framework/API/inc/MantidAPI/LiveListenerFactory.h b/Framework/API/inc/MantidAPI/LiveListenerFactory.h index d48e45071bf..585c40015e3 100644 --- a/Framework/API/inc/MantidAPI/LiveListenerFactory.h +++ b/Framework/API/inc/MantidAPI/LiveListenerFactory.h @@ -73,17 +73,16 @@ private: ILiveListener *createUnwrapped(const std::string &className) const override; }; -/// Forward declaration of a specialisation of SingletonHolder (needed for -/// dllexport/dllimport). -#ifdef _WIN32 -// this breaks new namespace declaration rules; need to find a better fix -template class MANTID_API_DLL Kernel::SingletonHolder<LiveListenerFactoryImpl>; -#endif /* _WIN32 */ -/// The specialisation of the SingletonHolder class that holds the -/// LiveListenerFactory typedef Kernel::SingletonHolder<LiveListenerFactoryImpl> LiveListenerFactory; } // namespace API } // namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL + Kernel::SingletonHolder<Mantid::API::LiveListenerFactoryImpl>; +} +} + #endif /* MANTID_API_LIVELISTENERFACTORYIMPL_H_ */ diff --git a/Framework/API/inc/MantidAPI/RemoteJobManagerFactory.h b/Framework/API/inc/MantidAPI/RemoteJobManagerFactory.h index 814981add05..8fb819cd541 100644 --- a/Framework/API/inc/MantidAPI/RemoteJobManagerFactory.h +++ b/Framework/API/inc/MantidAPI/RemoteJobManagerFactory.h @@ -86,21 +86,20 @@ private: using Kernel::DynamicFactory<IRemoteJobManager>::create; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// RemoteJobManagerFactoryImpl (needed for dllexport) and a typedef for it. -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class MANTID_API_DLL - Mantid::Kernel::SingletonHolder<RemoteJobManagerFactoryImpl>; -#endif /* _WIN32 */ - // The factory is just a specialisation of SingletonHolder -typedef MANTID_API_DLL Mantid::Kernel::SingletonHolder< - RemoteJobManagerFactoryImpl> RemoteJobManagerFactory; +typedef Mantid::Kernel::SingletonHolder<RemoteJobManagerFactoryImpl> + RemoteJobManagerFactory; } // namespace API } // namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL + Mantid::Kernel::SingletonHolder<Mantid::API::RemoteJobManagerFactoryImpl>; +} +} + /* Macro to register (remote job manager) classes into the factory. As * with the equivalent macros of the workspace factory or the * algorithm factory, this creates a global object in an anonymous diff --git a/Framework/API/inc/MantidAPI/ScriptRepositoryFactory.h b/Framework/API/inc/MantidAPI/ScriptRepositoryFactory.h index 61886bebd0d..f5bad9732e7 100644 --- a/Framework/API/inc/MantidAPI/ScriptRepositoryFactory.h +++ b/Framework/API/inc/MantidAPI/ScriptRepositoryFactory.h @@ -67,19 +67,19 @@ private: ~ScriptRepositoryFactoryImpl() override = default; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// AlgorithmFactoryImpl (needed for dllexport/dllimport) and a typedef for it. -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class MANTID_API_DLL - Mantid::Kernel::SingletonHolder<ScriptRepositoryFactoryImpl>; -#endif /* _WIN32 */ -typedef MANTID_API_DLL Mantid::Kernel::SingletonHolder< - ScriptRepositoryFactoryImpl> ScriptRepositoryFactory; +typedef Mantid::Kernel::SingletonHolder<ScriptRepositoryFactoryImpl> + ScriptRepositoryFactory; } // namespace API } // namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL + Mantid::Kernel::SingletonHolder<Mantid::API::ScriptRepositoryFactoryImpl>; +} +} + /** * Macro for declaring a new type of function to be used with the * FunctionFactory diff --git a/Framework/API/inc/MantidAPI/TransformScaleFactory.h b/Framework/API/inc/MantidAPI/TransformScaleFactory.h index e2101893d4c..8d58b083210 100644 --- a/Framework/API/inc/MantidAPI/TransformScaleFactory.h +++ b/Framework/API/inc/MantidAPI/TransformScaleFactory.h @@ -67,18 +67,17 @@ private: // Do not use default methods }; -/// Forward declaration of a specialisation of SingletonHolder for -/// TransformScaleFactoryImpl (needed for dllexport/dllimport) and a typedef for -/// it. -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class MANTID_API_DLL - Mantid::Kernel::SingletonHolder<TransformScaleFactoryImpl>; -#endif /* _WIN32 */ -typedef MANTID_API_DLL Mantid::Kernel::SingletonHolder< - TransformScaleFactoryImpl> TransformScaleFactory; +typedef Mantid::Kernel::SingletonHolder<TransformScaleFactoryImpl> + TransformScaleFactory; } // namespace API } // namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL + Mantid::Kernel::SingletonHolder<Mantid::API::TransformScaleFactoryImpl>; +} +} + #endif /* MANTID_API_TRANSFORMSCALEFACTORY_H_ */ diff --git a/Framework/API/inc/MantidAPI/WorkspaceFactory.h b/Framework/API/inc/MantidAPI/WorkspaceFactory.h index b6070b6f7c5..72c840e567f 100644 --- a/Framework/API/inc/MantidAPI/WorkspaceFactory.h +++ b/Framework/API/inc/MantidAPI/WorkspaceFactory.h @@ -99,15 +99,7 @@ private: using Kernel::DynamicFactory<Workspace>::create; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// AlgorithmFactoryImpl (needed for dllexport/dllimport) and a typedef for it. -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class MANTID_API_DLL - Mantid::Kernel::SingletonHolder<WorkspaceFactoryImpl>; -#endif /* _WIN32 */ -typedef MANTID_API_DLL Mantid::Kernel::SingletonHolder<WorkspaceFactoryImpl> - WorkspaceFactory; +typedef Mantid::Kernel::SingletonHolder<WorkspaceFactoryImpl> WorkspaceFactory; template <class T, class... InitArgs> boost::shared_ptr<T> createWorkspace(InitArgs... args) { @@ -116,7 +108,14 @@ boost::shared_ptr<T> createWorkspace(InitArgs... args) { return ws; } -} // namespace Kernel +} // namespace API } // namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_API template class MANTID_API_DLL + Mantid::Kernel::SingletonHolder<Mantid::API::WorkspaceFactoryImpl>; +} +} + #endif /*MANTID_KERNEL_WORKSPACEFACTORY_H_*/ diff --git a/Framework/API/src/ArchiveSearchFactory.cpp b/Framework/API/src/ArchiveSearchFactory.cpp index c05b3aa0aef..bdca4a699c1 100644 --- a/Framework/API/src/ArchiveSearchFactory.cpp +++ b/Framework/API/src/ArchiveSearchFactory.cpp @@ -8,6 +8,5 @@ namespace API { /// Default constructor ArchiveSearchFactoryImpl::ArchiveSearchFactoryImpl() {} - } // namespace API } // namespace Mantid diff --git a/Framework/API/src/Expression.cpp b/Framework/API/src/Expression.cpp index f918e836db5..7daa152eb27 100644 --- a/Framework/API/src/Expression.cpp +++ b/Framework/API/src/Expression.cpp @@ -311,7 +311,7 @@ void Expression::tokenize() { if (!tokens.empty()) { // remove operators of higher prec - m_tokens.push_back(Token(tokens[0])); + m_tokens.emplace_back(tokens[0]); for (size_t i = 0; i < tokens.size(); i++) { Token &tok = tokens[i]; std::string op = m_expr.substr(tok.ie + 1, tok.is1 - tok.ie - 1); //? @@ -320,7 +320,7 @@ void Expression::tokenize() { last_tok.ie = tok.ie; last_tok.is1 = tok.is1; if (i != tokens.size() - 1) - m_tokens.push_back(Token(tokens[i + 1])); + m_tokens.emplace_back(tokens[i + 1]); } } } diff --git a/Framework/API/src/TransformScaleFactory.cpp b/Framework/API/src/TransformScaleFactory.cpp index 6de6bb9fe86..d0cccf43747 100644 --- a/Framework/API/src/TransformScaleFactory.cpp +++ b/Framework/API/src/TransformScaleFactory.cpp @@ -43,5 +43,6 @@ TransformScaleFactoryImpl::createUnwrapped(const std::string &className) const { throw Kernel::Exception::NotImplementedError( "Don't use this method - use the safe one!!!"); } + } // namespace Mantid } // namespace API diff --git a/Framework/API/src/WorkspaceProperty.cpp b/Framework/API/src/WorkspaceProperty.cpp index 42a78b08551..7284be35e72 100644 --- a/Framework/API/src/WorkspaceProperty.cpp +++ b/Framework/API/src/WorkspaceProperty.cpp @@ -9,18 +9,18 @@ namespace Mantid { namespace API { ///@cond TEMPLATE -template MANTID_API_DLL class Mantid::API::WorkspaceProperty< - Mantid::API::Workspace>; -template MANTID_API_DLL class Mantid::API::WorkspaceProperty< - Mantid::API::IEventWorkspace>; -template MANTID_API_DLL class Mantid::API::WorkspaceProperty< - Mantid::API::IMDEventWorkspace>; -template MANTID_API_DLL class Mantid::API::WorkspaceProperty< - Mantid::API::IMDWorkspace>; -template MANTID_API_DLL class Mantid::API::WorkspaceProperty< - Mantid::API::MatrixWorkspace>; -template MANTID_API_DLL class Mantid::API::WorkspaceProperty< - Mantid::API::ITableWorkspace>; +template class MANTID_API_DLL + Mantid::API::WorkspaceProperty<Mantid::API::Workspace>; +template class MANTID_API_DLL + Mantid::API::WorkspaceProperty<Mantid::API::IEventWorkspace>; +template class MANTID_API_DLL + Mantid::API::WorkspaceProperty<Mantid::API::IMDEventWorkspace>; +template class MANTID_API_DLL + Mantid::API::WorkspaceProperty<Mantid::API::IMDWorkspace>; +template class MANTID_API_DLL + Mantid::API::WorkspaceProperty<Mantid::API::MatrixWorkspace>; +template class MANTID_API_DLL + Mantid::API::WorkspaceProperty<Mantid::API::ITableWorkspace>; ///@endcond TEMPLATE } // namespace API } // namespace Mantid diff --git a/Framework/Algorithms/CMakeLists.txt b/Framework/Algorithms/CMakeLists.txt index 7942576c62f..e5b7fe79b1f 100644 --- a/Framework/Algorithms/CMakeLists.txt +++ b/Framework/Algorithms/CMakeLists.txt @@ -77,6 +77,7 @@ set ( SRC_FILES src/CreateTransmissionWorkspace.cpp src/CreateTransmissionWorkspaceAuto.cpp src/CreateWorkspace.cpp + src/CropToComponent.cpp src/CropWorkspace.cpp src/CrossCorrelate.cpp src/CuboidGaugeVolumeAbsorption.cpp @@ -314,7 +315,7 @@ set ( INC_FILES inc/MantidAlgorithms/AverageLogData.h inc/MantidAlgorithms/BinaryOperateMasks.h inc/MantidAlgorithms/BinaryOperation.h - inc/MantidAlgorithms/BoostOptionalToAlgorithmProperty.h + inc/MantidAlgorithms/BoostOptionalToAlgorithmProperty.h inc/MantidAlgorithms/CalMuonDeadTime.h inc/MantidAlgorithms/CalMuonDetectorPhases.h inc/MantidAlgorithms/CalculateDIFC.h @@ -374,6 +375,7 @@ set ( INC_FILES inc/MantidAlgorithms/CreateTransmissionWorkspace.h inc/MantidAlgorithms/CreateTransmissionWorkspaceAuto.h inc/MantidAlgorithms/CreateWorkspace.h + inc/MantidAlgorithms/CropToComponent.h inc/MantidAlgorithms/CropWorkspace.h inc/MantidAlgorithms/CrossCorrelate.h inc/MantidAlgorithms/CuboidGaugeVolumeAbsorption.h @@ -685,6 +687,7 @@ set ( TEST_FILES CreateTransmissionWorkspaceAutoTest.h CreateTransmissionWorkspaceTest.h CreateWorkspaceTest.h + CropToComponentTest.h CropWorkspaceTest.h CuboidGaugeVolumeAbsorptionTest.h CylinderAbsorptionTest.h @@ -736,7 +739,7 @@ set ( TEST_FILES GetDetOffsetsMultiPeaksTest.h GetDetectorOffsetsTest.h GetEiTest.h - GetEiV1Test.h + GetEiV1Test.h GetTimeSeriesLogInformationTest.h GroupWorkspacesTest.h HRPDSlabCanAbsorptionTest.h @@ -759,8 +762,8 @@ set ( TEST_FILES MaxEnt/MaxentEntropyPositiveValuesTest.h MaxEnt/MaxentSpaceComplexTest.h MaxEnt/MaxentSpaceRealTest.h - MaxEntTest.h MaxEnt/MaxentTransformFourierTest.h + MaxEntTest.h MaxMinTest.h MayersSampleCorrectionStrategyTest.h MayersSampleCorrectionTest.h diff --git a/Framework/Algorithms/inc/MantidAlgorithms/CropToComponent.h b/Framework/Algorithms/inc/MantidAlgorithms/CropToComponent.h new file mode 100644 index 00000000000..f679c542f35 --- /dev/null +++ b/Framework/Algorithms/inc/MantidAlgorithms/CropToComponent.h @@ -0,0 +1,50 @@ +#ifndef MANTID_ALGORITHMS_CROPTOCOMPONENT_H_ +#define MANTID_ALGORITHMS_CROPTOCOMPONENT_H_ + +#include "MantidAPI/Algorithm.h" +#include "MantidAlgorithms/DllConfig.h" +namespace Mantid { +namespace Algorithms { + +/** CropToComponent : Crops a workspace to a set of components. + + Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge + National Laboratory & European Spallation Source + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + File change history is stored at: <https://github.com/mantidproject/mantid> + Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ +class MANTID_ALGORITHMS_DLL CropToComponent final : public API::Algorithm { +public: + const std::string name() const override final; + int version() const override final; + const std::string category() const override final; + const std::string summary() const override final; + +protected: + std::map<std::string, std::string> validateInputs() override; + +private: + void init() override final; + void exec() override final; +}; + +} // namespace Algorithms +} // namespace Mantid + +#endif /* MANTID_ALGORITHMS_CROPTOCOMPONENT_H_ */ diff --git a/Framework/Algorithms/src/CropToComponent.cpp b/Framework/Algorithms/src/CropToComponent.cpp new file mode 100644 index 00000000000..87d41f8fa02 --- /dev/null +++ b/Framework/Algorithms/src/CropToComponent.cpp @@ -0,0 +1,133 @@ +#include "MantidAPI/AlgorithmManager.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidAlgorithms/CropToComponent.h" +#include "MantidGeometry/IDetector.h" +#include "MantidGeometry/Instrument.h" +#include "MantidKernel/ArrayProperty.h" + +namespace { + +void getDetectors( + Mantid::API::MatrixWorkspace_sptr workspace, + const std::vector<std::string> &componentNames, + std::vector<Mantid::Geometry::IDetector_const_sptr> &detectors) { + auto instrument = workspace->getInstrument(); + for (const auto &componentName : componentNames) { + instrument->getDetectorsInBank(detectors, componentName); + } +} + +void getDetectorIDs( + std::vector<Mantid::Geometry::IDetector_const_sptr> &detectors, + std::vector<Mantid::detid_t> &detectorIDs) { + auto numberOfDetectors = static_cast<int>(detectors.size()); + PARALLEL_FOR_NO_WSP_CHECK() + for (int index = 0; index < numberOfDetectors; ++index) { + auto det = detectors[index]; + detectorIDs[index] = det->getID(); + } +} +} + +namespace Mantid { +namespace Algorithms { + +using Mantid::Kernel::Direction; +using Mantid::API::WorkspaceProperty; + +// Register the algorithm into the AlgorithmFactory +DECLARE_ALGORITHM(CropToComponent) + +//---------------------------------------------------------------------------------------------- + +/// Algorithms name for identification. @see Algorithm::name +const std::string CropToComponent::name() const { return "CropToComponent"; } + +/// Algorithm's version for identification. @see Algorithm::version +int CropToComponent::version() const { return 1; } + +/// Algorithm's category for identification. @see Algorithm::category +const std::string CropToComponent::category() const { + return "Transforms\\Splitting"; +} + +/// Algorithm's summary for use in the GUI and help. @see Algorithm::summary +const std::string CropToComponent::summary() const { + return "Crops a workspace to a set of components."; +} + +//---------------------------------------------------------------------------------------------- +/** Initialize the algorithm's properties. + */ +void CropToComponent::init() { + declareProperty( + Kernel::make_unique<WorkspaceProperty<Mantid::API::MatrixWorkspace>>( + "InputWorkspace", "", Direction::Input), + "An input workspace."); + declareProperty( + Kernel::make_unique<WorkspaceProperty<Mantid::API::MatrixWorkspace>>( + "OutputWorkspace", "", Direction::Output), + "An output workspace."); + declareProperty( + Kernel::make_unique<Mantid::Kernel::ArrayProperty<std::string>>( + "ComponentNames"), + "List of component names which are used to crop the workspace." + "to."); +} + +//---------------------------------------------------------------------------------------------- +/** Execute the algorithm. + */ +void CropToComponent::exec() { + // Get the names of the components + std::vector<std::string> componentNames = getProperty("ComponentNames"); + Mantid::API::MatrixWorkspace_sptr inputWorkspace = + getProperty("InputWorkspace"); + + // Get all detectors + std::vector<Mantid::Geometry::IDetector_const_sptr> detectors; + getDetectors(inputWorkspace, componentNames, detectors); + + // Get the detector IDs from the Detectors + std::vector<detid_t> detectorIDs(detectors.size()); + getDetectorIDs(detectors, detectorIDs); + + // Run ExtractSpectra in order to obtain the cropped workspace + auto extract_alg = Mantid::API::AlgorithmManager::Instance().createUnmanaged( + "ExtractSpectra"); + extract_alg->setChild(true); + extract_alg->initialize(); + extract_alg->setProperty("InputWorkspace", inputWorkspace); + extract_alg->setProperty("OutputWorkspace", "dummy"); + extract_alg->setProperty("DetectorList", detectorIDs); + extract_alg->execute(); + Mantid::API::MatrixWorkspace_sptr outputWorkspace = + extract_alg->getProperty("OutputWorkspace"); + + // Set the output + setProperty("OutputWorkspace", outputWorkspace); +} + +std::map<std::string, std::string> CropToComponent::validateInputs() { + std::map<std::string, std::string> result; + Mantid::API::MatrixWorkspace_sptr inputWorkspace = + getProperty("InputWorkspace"); + std::vector<std::string> componentNames = getProperty("ComponentNames"); + + // Make sure that the component exists on the input workspace + auto instrument = inputWorkspace->getInstrument(); + for (auto &componentName : componentNames) { + auto detector = instrument->getComponentByName(componentName); + if (!detector) { + std::string message = + "The component name " + componentName + + " does not exist on the workspace. Specify a valid component."; + result["ComponentNames"] = message; + break; + } + } + return result; +} + +} // namespace Algorithms +} // namespace Mantid diff --git a/Framework/Algorithms/src/EQSANSTofStructure.cpp b/Framework/Algorithms/src/EQSANSTofStructure.cpp index 71844e0682a..83bb0bf2f21 100644 --- a/Framework/Algorithms/src/EQSANSTofStructure.cpp +++ b/Framework/Algorithms/src/EQSANSTofStructure.cpp @@ -182,7 +182,7 @@ void EQSANSTofStructure::execEvent( // At this point the events in the second frame are still off by a frame if (frame_skipping && rel_tof > tof_frame_width) newtof += tof_frame_width; - clean_events.push_back(TofEvent(newtof, it->pulseTime())); + clean_events.emplace_back(newtof, it->pulseTime()); } events.clear(); events.reserve(clean_events.size()); diff --git a/Framework/Algorithms/src/FilterByLogValue.cpp b/Framework/Algorithms/src/FilterByLogValue.cpp index ba5bc4ccb20..8d0c0766ee4 100644 --- a/Framework/Algorithms/src/FilterByLogValue.cpp +++ b/Framework/Algorithms/src/FilterByLogValue.cpp @@ -153,7 +153,7 @@ void FilterByLogValue::exec() { splitter.push_back(interval); } // And the last one - splitter.push_back(SplittingInterval(lastTime, run_stop, 0)); + splitter.emplace_back(lastTime, run_stop, 0); } else { // ----- Filter by value ------ diff --git a/Framework/Algorithms/src/FindPeakBackground.cpp b/Framework/Algorithms/src/FindPeakBackground.cpp index 9afbfb85263..e73aef39c23 100644 --- a/Framework/Algorithms/src/FindPeakBackground.cpp +++ b/Framework/Algorithms/src/FindPeakBackground.cpp @@ -176,12 +176,12 @@ void FindPeakBackground::exec() { // for loop can start > 1 for multiple peaks vector<cont_peak> peaks; if (mask[0] == 1) { - peaks.push_back(cont_peak()); + peaks.emplace_back(); peaks.back().start = l0; } for (size_t l = 1; l < n - l0; ++l) { if (mask[l] != mask[l - 1] && mask[l] == 1) { - peaks.push_back(cont_peak()); + peaks.emplace_back(); peaks.back().start = l + l0; } else if (!peaks.empty()) { size_t ipeak = peaks.size() - 1; diff --git a/Framework/Algorithms/src/GetAllEi.cpp b/Framework/Algorithms/src/GetAllEi.cpp index 1eb440656c4..894da3e4857 100644 --- a/Framework/Algorithms/src/GetAllEi.cpp +++ b/Framework/Algorithms/src/GetAllEi.cpp @@ -340,7 +340,7 @@ void GetAllEi::exec() { bool found = findMonitorPeak(monitorWS, guess_ei[i], monsRangeMin, monsRangeMax, energy, height, twoSigma); if (found) { - peaks.push_back(peakKeeper(energy, height, 0.5 * twoSigma)); + peaks.emplace_back(energy, height, 0.5 * twoSigma); if (peaks.back().energy > maxPeakEnergy) maxPeakEnergy = peaks.back().energy; } diff --git a/Framework/Algorithms/src/SmoothNeighbours.cpp b/Framework/Algorithms/src/SmoothNeighbours.cpp index d4ff294cd7f..8425a3f741b 100644 --- a/Framework/Algorithms/src/SmoothNeighbours.cpp +++ b/Framework/Algorithms/src/SmoothNeighbours.cpp @@ -249,7 +249,7 @@ void SmoothNeighbours::findNeighboursRectangular() { // Build a map to sort by the detectorID std::vector<std::pair<int, int>> v1; for (int i = 0; i < static_cast<int>(detList.size()); i++) - v1.push_back(std::pair<int, int>(detList[i]->getAtXY(0, 0)->getID(), i)); + v1.emplace_back(detList[i]->getAtXY(0, 0)->getID(), i); // To sort in descending order if (sum) @@ -286,7 +286,7 @@ void SmoothNeighbours::findNeighboursRectangular() { auto mapEntry = pixel_to_wi.find(pixelID); if (mapEntry != pixel_to_wi.end()) { size_t wi = mapEntry->second; - neighbours.push_back(weightedNeighbour(wi, smweight)); + neighbours.emplace_back(wi, smweight); // Count the total weight totalWeight += smweight; } @@ -420,7 +420,7 @@ void SmoothNeighbours::findNeighboursUbiqutious() { noNeigh++; used[neighWI] = true; } - neighbours.push_back(weightedNeighbour(neighWI, weight)); + neighbours.emplace_back(neighWI, weight); totalWeight += weight; } } diff --git a/Framework/Algorithms/test/CropToComponentTest.h b/Framework/Algorithms/test/CropToComponentTest.h new file mode 100644 index 00000000000..7353994ea18 --- /dev/null +++ b/Framework/Algorithms/test/CropToComponentTest.h @@ -0,0 +1,157 @@ +#ifndef MANTID_ALGORITHMS_CROPTOCOMPONENTTEST_H_ +#define MANTID_ALGORITHMS_CROPTOCOMPONENTTEST_H_ + +#include <cxxtest/TestSuite.h> + +#include "MantidAPI/AlgorithmManager.h" +#include "MantidAlgorithms/CropToComponent.h" +#include "MantidGeometry/Instrument.h" +#include "MantidTestHelpers/WorkspaceCreationHelper.h" +#include <numeric> + +class CropToComponentTest : public CxxTest::TestSuite { +public: + // This pair of boilerplate methods prevent the suite being created statically + // This means the constructor isn't called when running other tests + static CropToComponentTest *createSuite() { + return new CropToComponentTest(); + } + static void destroySuite(CropToComponentTest *suite) { delete suite; } + + void test_Init() { + Mantid::Algorithms::CropToComponent alg; + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT(alg.isInitialized()) + } + + void test_exec() { + // Arrange + int numberOfBanks = 4; + int numberOfPixelsPerBank = 3; + + auto inputWorkspace = + getSampleWorkspace(numberOfBanks, numberOfPixelsPerBank); + std::vector<std::string> componentNames = {"bank2", "bank3"}; + + // Act + Mantid::Algorithms::CropToComponent crop; + crop.setChild(true); + crop.initialize(); + crop.setProperty("InputWorkspace", inputWorkspace); + crop.setProperty("OutputWorkspace", "dummy"); + crop.setProperty("ComponentNames", componentNames); + crop.execute(); + TS_ASSERT(crop.isExecuted()) + Mantid::API::MatrixWorkspace_sptr outputWorkspace = + crop.getProperty("OutputWorkspace"); + + // Assert + size_t expectedNumberOfHistograms = 18; + std::vector<Mantid::detid_t> expectedIDs(expectedNumberOfHistograms); + std::iota(expectedIDs.begin(), expectedIDs.end(), 18); + doAsssert(outputWorkspace, expectedIDs, expectedNumberOfHistograms); + } + + void test_that_no_specified_bank_returns_everything() { + // Arrange + int numberOfBanks = 4; + int numberOfPixelsPerBank = 3; + + auto inputWorkspace = + getSampleWorkspace(numberOfBanks, numberOfPixelsPerBank); + std::vector<std::string> componentNames = {}; + + // Act + Mantid::Algorithms::CropToComponent crop; + crop.setChild(true); + crop.initialize(); + crop.setProperty("InputWorkspace", inputWorkspace); + crop.setProperty("OutputWorkspace", "dummy"); + crop.setProperty("ComponentNames", componentNames); + crop.execute(); + TS_ASSERT(crop.isExecuted()) + Mantid::API::MatrixWorkspace_sptr outputWorkspace = + crop.getProperty("OutputWorkspace"); + + // Assert + size_t expectedNumberOfHistograms = 36; + std::vector<Mantid::detid_t> expectedIDs(expectedNumberOfHistograms); + std::iota(expectedIDs.begin(), expectedIDs.end(), 9); + doAsssert(outputWorkspace, expectedIDs, expectedNumberOfHistograms); + } + + void test_that_single_bank_can_be_extracted() { + // Arrange + int numberOfBanks = 4; + int numberOfPixelsPerBank = 3; + + auto inputWorkspace = + getSampleWorkspace(numberOfBanks, numberOfPixelsPerBank); + std::vector<std::string> componentNames = {"bank3"}; + + // Act + Mantid::Algorithms::CropToComponent crop; + crop.setChild(true); + crop.initialize(); + crop.setProperty("InputWorkspace", inputWorkspace); + crop.setProperty("OutputWorkspace", "dummy"); + crop.setProperty("ComponentNames", componentNames); + crop.execute(); + TS_ASSERT(crop.isExecuted()) + Mantid::API::MatrixWorkspace_sptr outputWorkspace = + crop.getProperty("OutputWorkspace"); + + // Assert + size_t expectedNumberOfHistograms = 9; + std::vector<Mantid::detid_t> expectedIDs(expectedNumberOfHistograms); + std::iota(expectedIDs.begin(), expectedIDs.end(), 27); + } + + void test_that_incorrect_component_name_is_not_accepeted() { + // Arrange + int numberOfBanks = 4; + int numberOfPixelsPerBank = 3; + + auto inputWorkspace = + getSampleWorkspace(numberOfBanks, numberOfPixelsPerBank); + std::vector<std::string> componentNames = {"wrong_detector_name"}; + + // Act + Mantid::Algorithms::CropToComponent crop; + crop.setChild(true); + crop.initialize(); + crop.setRethrows(true); + crop.setProperty("InputWorkspace", inputWorkspace); + crop.setProperty("OutputWorkspace", "dummy"); + crop.setProperty("ComponentNames", componentNames); + TSM_ASSERT_THROWS("Invalid detector names will throw.", crop.execute(), + std::runtime_error) + } + +private: + Mantid::API::MatrixWorkspace_sptr + getSampleWorkspace(int numberOfBanks, int numbersOfPixelPerBank) { + return WorkspaceCreationHelper::create2DWorkspaceWithRectangularInstrument( + numberOfBanks, numbersOfPixelPerBank, 2); + } + + void doAsssert(Mantid::API::MatrixWorkspace_sptr workspace, + std::vector<Mantid::detid_t> &expectedIDs, + size_t expectedNumberOfHistograms) { + // Assert + const auto numberOfHistograms = workspace->getNumberHistograms(); + TS_ASSERT_EQUALS(numberOfHistograms, expectedNumberOfHistograms); + + std::vector<size_t> indices(numberOfHistograms); + std::iota(indices.begin(), indices.end(), 0); + + for (const auto index : indices) { + auto det = workspace->getDetector(index); + Mantid::detid_t detectorID = det->getID(); + TSM_ASSERT_EQUALS("The detector IDs should match.", expectedIDs[index], + detectorID); + } + } +}; + +#endif /* MANTID_ALGORITHMS_CROPTOCOMPONENTTEST_H_ */ diff --git a/Framework/CMakeLists.txt b/Framework/CMakeLists.txt index 594e0bb4406..254833ef76f 100644 --- a/Framework/CMakeLists.txt +++ b/Framework/CMakeLists.txt @@ -1,5 +1,5 @@ # This is mainly here so you don't get a complaint when running cmake -cmake_minimum_required (VERSION 2.8.12) +cmake_minimum_required (VERSION 3.5) # Add the path to our custom 'find' modules set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../buildconfig/CMake") diff --git a/Framework/Crystal/src/ConnectedComponentLabeling.cpp b/Framework/Crystal/src/ConnectedComponentLabeling.cpp index 92394ec1385..920b852f6ff 100644 --- a/Framework/Crystal/src/ConnectedComponentLabeling.cpp +++ b/Framework/Crystal/src/ConnectedComponentLabeling.cpp @@ -143,7 +143,7 @@ size_t doConnectedComponentLabeling(IMDIterator *iterator, correcly provided for all neighbours until the end. We must store indexes instead. */ - edgeIndexVec.push_back(EdgeIndexPair(currentIndex, neighIndex)); + edgeIndexVec.emplace_back(currentIndex, neighIndex); continue; } diff --git a/Framework/Crystal/src/IntegratePeakTimeSlices.cpp b/Framework/Crystal/src/IntegratePeakTimeSlices.cpp index 7ceca56b992..b9f67285fa6 100644 --- a/Framework/Crystal/src/IntegratePeakTimeSlices.cpp +++ b/Framework/Crystal/src/IntegratePeakTimeSlices.cpp @@ -1944,11 +1944,11 @@ DataModeHandler::CalcConstraints(std::vector<std::pair<double, double>> &Bounds, double min = max<double>(0.0, back_calc - NSigs * (1 + relError) * sqrt(backVar)); double maxx = back + NSigs * (1.8 + relError) * sqrt(backVar); - Bounds.push_back(pair<double, double>(min, maxx)); - Bounds.push_back(pair<double, double>( + Bounds.emplace_back(min, maxx); + Bounds.emplace_back( max<double>(0.0, Intensity_calc - NSigs * (1 + relError) * sqrt(IntensVar)), - Intensity_calc + NSigs * (1 + relError) * sqrt(IntensVar))); + Intensity_calc + NSigs * (1 + relError) * sqrt(IntensVar)); double relErr1 = relError * .75; double val = col_calc; double minn = std::max<double>(MinCol - .5, (1 - relErr1) * val); @@ -1957,7 +1957,7 @@ DataModeHandler::CalcConstraints(std::vector<std::pair<double, double>> &Bounds, str << "," << minn << "<" << "Mcol" << "<" << maxx; - Bounds.push_back(pair<double, double>(minn, maxx)); + Bounds.emplace_back(minn, maxx); val = row_calc; @@ -1966,7 +1966,7 @@ DataModeHandler::CalcConstraints(std::vector<std::pair<double, double>> &Bounds, str << "," << minn << "<" << "Mrow" << "<" << maxx; - Bounds.push_back(pair<double, double>(minn, maxx)); + Bounds.emplace_back(minn, maxx); if (N >= 5) { val = Vx_calc; @@ -1981,8 +1981,7 @@ DataModeHandler::CalcConstraints(std::vector<std::pair<double, double>> &Bounds, str << "," << (1 - relErr1) * valmin << "<" << "SScol" << "<" << (1 + relErr1) * valmax; - Bounds.push_back( - pair<double, double>((1 - relErr1) * valmin, (1 + relErr1) * valmax)); + Bounds.emplace_back((1 - relErr1) * valmin, (1 + relErr1) * valmax); val = Vy_calc; valmin = val; @@ -1994,8 +1993,7 @@ DataModeHandler::CalcConstraints(std::vector<std::pair<double, double>> &Bounds, str << "," << (1 - relErr1) * valmin << "<" << "SSrow" << "<" << (1 + relErr1) * valmax; - Bounds.push_back( - pair<double, double>((1 - relErr1) * valmin, (1 + relErr1) * valmax)); + Bounds.emplace_back((1 - relErr1) * valmin, (1 + relErr1) * valmax); } return str.str(); diff --git a/Framework/Crystal/src/OptimizeCrystalPlacement.cpp b/Framework/Crystal/src/OptimizeCrystalPlacement.cpp index 9ab37743fad..4a69009583a 100644 --- a/Framework/Crystal/src/OptimizeCrystalPlacement.cpp +++ b/Framework/Crystal/src/OptimizeCrystalPlacement.cpp @@ -190,8 +190,7 @@ void OptimizeCrystalPlacement::exec() { Geometry::Goniometer Gon(peak.getGoniometerMatrix()); std::vector<double> phichiOmega = Gon.getEulerAngles("YZY"); - ChiPhiOmega.push_back( - V3D(phichiOmega[1], phichiOmega[2], phichiOmega[0])); + ChiPhiOmega.emplace_back(phichiOmega[1], phichiOmega[2], phichiOmega[0]); } if (use) // add to lists for workspace diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/DllConfig.h b/Framework/CurveFitting/inc/MantidCurveFitting/DllConfig.h index c6d841c31d5..37a8e248edd 100644 --- a/Framework/CurveFitting/inc/MantidCurveFitting/DllConfig.h +++ b/Framework/CurveFitting/inc/MantidCurveFitting/DllConfig.h @@ -32,8 +32,10 @@ #ifdef IN_MANTID_CURVEFITTING #define MANTID_CURVEFITTING_DLL DLLExport +#define EXTERN_MANTID_CURVEFITTING #else #define MANTID_CURVEFITTING_DLL DLLImport +#define EXTERN_MANTID_CURVEFITTING EXTERN_IMPORT #endif /* IN_MANTID_CURVEFITTING*/ #endif // MANTID_CURVEFITTING_DLLCONFIG_H_ diff --git a/Framework/DataHandling/src/CheckMantidVersion.cpp b/Framework/DataHandling/src/CheckMantidVersion.cpp index bdfb17058b3..4f9929c48c6 100644 --- a/Framework/DataHandling/src/CheckMantidVersion.cpp +++ b/Framework/DataHandling/src/CheckMantidVersion.cpp @@ -1,5 +1,5 @@ #include "MantidDataHandling/CheckMantidVersion.h" -#include "MantidKernel/InternetHelper.h" +#include "MantidKernel/GitHubApiHelper.h" #include "MantidKernel/MantidVersion.h" #include "MantidKernel/Strings.h" @@ -226,11 +226,11 @@ behaviour. */ std::string CheckMantidVersion::getVersionsFromGitHub(const std::string &url) { - Kernel::InternetHelper inetHelper; + Kernel::GitHubApiHelper inetHelper; std::ostringstream os; int tzd = 0; - inetHelper.headers().emplace( + inetHelper.addHeader( "if-modified-since", Poco::DateTimeFormatter::format( Poco::DateTimeParser::parse(MantidVersion::releaseDate(), tzd), diff --git a/Framework/DataHandling/src/DownloadInstrument.cpp b/Framework/DataHandling/src/DownloadInstrument.cpp index e446b377eb7..d47dd8fa33f 100644 --- a/Framework/DataHandling/src/DownloadInstrument.cpp +++ b/Framework/DataHandling/src/DownloadInstrument.cpp @@ -1,7 +1,7 @@ #include "MantidDataHandling/DownloadInstrument.h" #include "MantidKernel/ChecksumHelper.h" #include "MantidKernel/ConfigService.h" -#include "MantidKernel/InternetHelper.h" +#include "MantidKernel/GitHubApiHelper.h" // Poco #include <Poco/DateTimeFormat.h> @@ -362,8 +362,8 @@ int DownloadInstrument::doDownloadFile(const std::string &urlFile, } int retStatus = 0; - InternetHelper inetHelper; - inetHelper.headers() = headers; + GitHubApiHelper inetHelper; + inetHelper.headers().insert(headers.begin(), headers.end()); retStatus = inetHelper.downloadFile(urlFile, localFilePath); return retStatus; } diff --git a/Framework/DataHandling/src/LoadEventNexus.cpp b/Framework/DataHandling/src/LoadEventNexus.cpp index 1fe5cb378f9..71760e76dcd 100644 --- a/Framework/DataHandling/src/LoadEventNexus.cpp +++ b/Framework/DataHandling/src/LoadEventNexus.cpp @@ -1803,6 +1803,7 @@ void LoadEventNexus::loadEvents(API::Progress *const prog, m_ws->setAllX(axis); createWorkspaceIndexMaps(monitors, std::vector<std::string>()); + return; } // --------- Loading only one bank ? ---------------------------------- diff --git a/Framework/DataHandling/src/LoadEventPreNexus.cpp b/Framework/DataHandling/src/LoadEventPreNexus.cpp index 601c0c149c5..83c5f156bbe 100644 --- a/Framework/DataHandling/src/LoadEventPreNexus.cpp +++ b/Framework/DataHandling/src/LoadEventPreNexus.cpp @@ -933,9 +933,8 @@ void LoadEventPreNexus::readPulseidFile(const std::string &filename, if (num_pulses > 0) { this->pulsetimes.reserve(num_pulses); for (const auto &pulse : pulses) { - this->pulsetimes.push_back( - DateAndTime(static_cast<int64_t>(pulse.seconds), - static_cast<int64_t>(pulse.nanoseconds))); + this->pulsetimes.emplace_back(static_cast<int64_t>(pulse.seconds), + static_cast<int64_t>(pulse.nanoseconds)); this->event_indices.push_back(pulse.event_index); temp = pulse.pCurrent; diff --git a/Framework/DataHandling/src/LoadILLSANS.cpp b/Framework/DataHandling/src/LoadILLSANS.cpp index d3b64ee0809..d3f787b1718 100644 --- a/Framework/DataHandling/src/LoadILLSANS.cpp +++ b/Framework/DataHandling/src/LoadILLSANS.cpp @@ -25,7 +25,7 @@ DECLARE_NEXUS_FILELOADER_ALGORITHM(LoadILLSANS) /** Constructor */ LoadILLSANS::LoadILLSANS() - : m_supportedInstruments{"D33"}, m_defaultBinning{2} {} + : m_supportedInstruments{"D33"}, m_defaultBinning{0, 0} {} //---------------------------------------------------------------------------------------------- /// Algorithm's name for identification. @see Algorithm::name diff --git a/Framework/DataHandling/src/LoadRKH.cpp b/Framework/DataHandling/src/LoadRKH.cpp index 93c209d27b5..8ee788fae7c 100644 --- a/Framework/DataHandling/src/LoadRKH.cpp +++ b/Framework/DataHandling/src/LoadRKH.cpp @@ -20,6 +20,25 @@ #include <MantidKernel/StringTokenizer.h> #include <istream> +#include <numeric> +#include <boost/regex.hpp> + +namespace { +// Check if we are dealing with a unit line +bool isUnit(const Mantid::Kernel::StringTokenizer &codes) { + // The unit line needs to have the format of + // 1. Either 0 or 6 [06] + // 2. Then several characters [\w] + // 3. Open bracket + // 4. Several characters + // 5. Close bracket + std::string input = + std::accumulate(codes.begin(), codes.end(), std::string("")); + std::string reg("^[06][\\w]+\\([/ \\w\\^-]+\\)$"); + boost::regex baseRegex(reg); + return boost::regex_match(input, baseRegex); +} +} namespace Mantid { namespace DataHandling { @@ -192,15 +211,20 @@ void LoadRKH::exec() { // Set the output workspace setProperty("OutputWorkspace", result); } + /** Determines if the file is 1D or 2D based on the first after the workspace's * title * @param testLine :: the first line in the file after the title * @return true if the file must contain 1D data */ bool LoadRKH::is2D(const std::string &testLine) { - // check the line part of a valid for 2D data else assume the file is 1D - return readUnit(testLine) != "C++ no unit found"; + // split the line into words + const Mantid::Kernel::StringTokenizer codes( + testLine, " ", Mantid::Kernel::StringTokenizer::TOK_TRIM | + Mantid::Kernel::StringTokenizer::TOK_IGNORE_EMPTY); + return isUnit(codes); } + /** Read a data file that contains only one spectrum into a workspace * @return the new workspace */ @@ -466,6 +490,11 @@ const std::string LoadRKH::readUnit(const std::string &line) { const Mantid::Kernel::StringTokenizer codes( line, " ", Mantid::Kernel::StringTokenizer::TOK_TRIM | Mantid::Kernel::StringTokenizer::TOK_IGNORE_EMPTY); + + if (!isUnit(codes)) { + return "C++ no unit found"; + } + if (codes.count() < 1) { return "C++ no unit found"; } @@ -493,8 +522,9 @@ const std::string LoadRKH::readUnit(const std::string &line) { if (unit.find('(') != 0 || unit.find(')') != unit.size()) { std::string qCode = std::to_string(SaveRKH::Q_CODE); if (symbol == qCode && theQuantity == "q" && - unit == "(1/Angstrom)") { // 6 q (1/Angstrom) is the synatx for - // MomentumTransfer + (unit == "(1/Angstrom)" || + unit == "(Angstrom^-1)")) { // 6 q (1/Angstrom) is the synatx for + // MomentumTransfer return "MomentumTransfer"; } diff --git a/Framework/DataHandling/src/LoadSassena.cpp b/Framework/DataHandling/src/LoadSassena.cpp index 8bbb51bc042..785472d7a10 100644 --- a/Framework/DataHandling/src/LoadSassena.cpp +++ b/Framework/DataHandling/src/LoadSassena.cpp @@ -137,7 +137,7 @@ MantidVec LoadSassena::loadQvectors(const hid_t &h5file, if (getProperty("SortByQVectors")) { std::vector<mypair> qvmodpair; for (int iq = 0; iq < nq; iq++) - qvmodpair.push_back(mypair(qvmod[iq], iq)); + qvmodpair.emplace_back(qvmod[iq], iq); std::sort(qvmodpair.begin(), qvmodpair.end(), compare); for (int iq = 0; iq < nq; iq++) sorting_indexes.push_back(qvmodpair[iq].second); diff --git a/Framework/DataHandling/src/LoadTBL.cpp b/Framework/DataHandling/src/LoadTBL.cpp index 91292b3504d..ae4c4305445 100644 --- a/Framework/DataHandling/src/LoadTBL.cpp +++ b/Framework/DataHandling/src/LoadTBL.cpp @@ -330,15 +330,11 @@ void LoadTBL::exec() { auto colScale = ws->addColumn("str", "Scale"); auto colOptions = ws->addColumn("str", "Options"); - colStitch->setPlotType(0); - colRuns->setPlotType(0); - colTheta->setPlotType(0); - colTrans->setPlotType(0); - colQmin->setPlotType(0); - colQmax->setPlotType(0); - colDqq->setPlotType(0); - colScale->setPlotType(0); - colOptions->setPlotType(0); + for (size_t i = 0; i < ws->columnCount(); i++) { + auto col = ws->getColumn(i); + col->setPlotType(0); + } + // we are using the old ReflTBL format // where all of the entries are on one line // so we must reset the stream to reread the first line. diff --git a/Framework/DataHandling/src/SaveNXcanSAS.cpp b/Framework/DataHandling/src/SaveNXcanSAS.cpp index 88e6ec7c618..93e757a5bcc 100644 --- a/Framework/DataHandling/src/SaveNXcanSAS.cpp +++ b/Framework/DataHandling/src/SaveNXcanSAS.cpp @@ -385,9 +385,9 @@ void addData1D(H5::Group &data, Mantid::API::MatrixWorkspace_sptr workspace) { std::map<std::string, std::string> qAttributes; auto qUnit = getUnitFromMDDimension(workspace->getDimension(0)); qUnit = getMomentumTransferLabel(qUnit); - qAttributes.insert(std::make_pair(sasUnitAttr, qUnit)); + qAttributes.emplace(sasUnitAttr, qUnit); if (workspace->hasDx(0)) { - qAttributes.insert(std::make_pair(sasUncertaintyAttr, sasDataQdev)); + qAttributes.emplace(sasUncertaintyAttr, sasDataQdev); } if (workspace->isHistogramData()) { @@ -404,8 +404,8 @@ void addData1D(H5::Group &data, Mantid::API::MatrixWorkspace_sptr workspace) { std::map<std::string, std::string> iAttributes; auto iUnit = getIntensityUnit(workspace); iUnit = getIntensityUnitLabel(iUnit); - iAttributes.insert(std::make_pair(sasUnitAttr, iUnit)); - iAttributes.insert(std::make_pair(sasUncertaintyAttr, sasDataIdev)); + iAttributes.emplace(sasUnitAttr, iUnit); + iAttributes.emplace(sasUncertaintyAttr, sasDataIdev); writeArray1DWithStrAttributes(data, sasDataI, intensity, iAttributes); @@ -424,7 +424,7 @@ void addData1D(H5::Group &data, Mantid::API::MatrixWorkspace_sptr workspace) { if (workspace->hasDx(0)) { const auto qResolution = workspace->readDx(0); std::map<std::string, std::string> xUncertaintyAttributes; - xUncertaintyAttributes.insert(std::make_pair(sasUnitAttr, qUnit)); + xUncertaintyAttributes.emplace(sasUnitAttr, qUnit); if (workspace->isHistogramData()) { std::vector<double> qResolutionCentres; @@ -567,7 +567,7 @@ void addData2D(H5::Group &data, Mantid::API::MatrixWorkspace_sptr workspace) { std::map<std::string, std::string> qxAttributes; auto qxUnit = getUnitFromMDDimension(workspace->getXDimension()); qxUnit = getMomentumTransferLabel(qxUnit); - qxAttributes.insert(std::make_pair(sasUnitAttr, qxUnit)); + qxAttributes.emplace(sasUnitAttr, qxUnit); QxExtractor<double> qxExtractor; write2DWorkspace(data, workspace, sasDataQx, qxExtractor, qxAttributes); @@ -575,7 +575,7 @@ void addData2D(H5::Group &data, Mantid::API::MatrixWorkspace_sptr workspace) { std::map<std::string, std::string> qyAttributes; auto qyUnit = getUnitFromMDDimension(workspace->getDimension(1)); qyUnit = getMomentumTransferLabel(qyUnit); - qyAttributes.insert(std::make_pair(sasUnitAttr, qyUnit)); + qyAttributes.emplace(sasUnitAttr, qyUnit); SpectrumAxisValueProvider spectrumAxisValueProvider(workspace); write2DWorkspace(data, workspace, sasDataQy, spectrumAxisValueProvider, @@ -585,8 +585,8 @@ void addData2D(H5::Group &data, Mantid::API::MatrixWorkspace_sptr workspace) { std::map<std::string, std::string> iAttributes; auto iUnit = getIntensityUnit(workspace); iUnit = getIntensityUnitLabel(iUnit); - iAttributes.insert(std::make_pair(sasUnitAttr, iUnit)); - iAttributes.insert(std::make_pair(sasUncertaintyAttr, sasDataIdev)); + iAttributes.emplace(sasUnitAttr, iUnit); + iAttributes.emplace(sasUncertaintyAttr, sasDataIdev); auto iExtractor = [](Mantid::API::MatrixWorkspace_sptr ws, int index) { return ws->dataY(index).data(); @@ -658,9 +658,9 @@ void addTransmission(H5::Group &group, if (unit.empty()) { unit = sasNone; } - transmissionAttributes.insert(std::make_pair(sasUnitAttr, unit)); - transmissionAttributes.insert( - std::make_pair(sasUncertaintyAttr, sasTransmissionSpectrumTdev)); + transmissionAttributes.emplace(sasUnitAttr, unit); + transmissionAttributes.emplace(sasUncertaintyAttr, + sasTransmissionSpectrumTdev); writeArray1DWithStrAttributes(transmission, sasTransmissionSpectrumT, transmissionData, transmissionAttributes); @@ -669,7 +669,7 @@ void addTransmission(H5::Group &group, // Add Tdev with units const auto transmissionErrors = workspace->readE(0); std::map<std::string, std::string> transmissionErrorAttributes; - transmissionErrorAttributes.insert(std::make_pair(sasUnitAttr, unit)); + transmissionErrorAttributes.emplace(sasUnitAttr, unit); writeArray1DWithStrAttributes(transmission, sasTransmissionSpectrumTdev, transmissionErrors, @@ -683,7 +683,7 @@ void addTransmission(H5::Group &group, if (lambdaUnit.empty() || lambdaUnit == "Angstrom") { lambdaUnit = sasAngstrom; } - lambdaAttributes.insert(std::make_pair(sasUnitAttr, lambdaUnit)); + lambdaAttributes.emplace(sasUnitAttr, lambdaUnit); writeArray1DWithStrAttributes(transmission, sasTransmissionSpectrumLambda, lambda, lambdaAttributes); @@ -747,14 +747,14 @@ std::map<std::string, std::string> SaveNXcanSAS::validateInputs() { if (!workspace || !boost::dynamic_pointer_cast<const Mantid::DataObjects::Workspace2D>( workspace)) { - result.insert(std::make_pair("InputWorkspace", - "The InputWorkspace must be a Workspace2D.")); + result.emplace("InputWorkspace", + "The InputWorkspace must be a Workspace2D."); } // Don't allow ragged workspaces for now if (!API::WorkspaceHelpers::commonBoundaries(workspace)) { - result.insert(std::make_pair( - "InputWorkspace", "The InputWorkspace cannot be a ragged workspace.")); + result.emplace("InputWorkspace", + "The InputWorkspace cannot be a ragged workspace."); } // Transmission data should be 1D @@ -765,9 +765,8 @@ std::map<std::string, std::string> SaveNXcanSAS::validateInputs() { auto checkTransmission = [&result](Mantid::API::MatrixWorkspace_sptr trans, std::string propertyName) { if (trans->getNumberHistograms() != 1) { - result.insert(std::make_pair( - propertyName, - "The input workspaces for transmissions have to be 1D.")); + result.emplace(propertyName, + "The input workspaces for transmissions have to be 1D."); } }; diff --git a/Framework/DataHandling/src/SetSample.cpp b/Framework/DataHandling/src/SetSample.cpp index 0d68c11241d..da1ded25344 100644 --- a/Framework/DataHandling/src/SetSample.cpp +++ b/Framework/DataHandling/src/SetSample.cpp @@ -225,8 +225,8 @@ void SetSample::setSampleShape(API::MatrixWorkspace_sptr &workspace, for (const auto &prop : props) { // assume in cm const double val = args->getProperty(prop->name()); - shapeArgs.insert(std::make_pair( - boost::algorithm::to_lower_copy(prop->name()), val * 0.01)); + shapeArgs.emplace(boost::algorithm::to_lower_copy(prop->name()), + val * 0.01); } } auto shapeObject = can->createSampleShape(shapeArgs); diff --git a/Framework/DataHandling/test/LoadRKHTest.h b/Framework/DataHandling/test/LoadRKHTest.h index 19350604e02..eed7b29b0d9 100644 --- a/Framework/DataHandling/test/LoadRKHTest.h +++ b/Framework/DataHandling/test/LoadRKHTest.h @@ -22,7 +22,8 @@ public: // A sample file is in the repository LoadRKHTest() : dataFile(""), tempFile("LoadRKH_test_file_2D"), - tempFile2("LoadRKH_test_file_1D_with_DX") { + tempFile2("LoadRKH_test_file_1D_with_DX"), + tempFile3("LoadRKL_with_second_header") { dataFile = "DIRECT.041"; } @@ -187,7 +188,7 @@ public: TS_ASSERT(data->isHistogramData()) - remove(tempFile.c_str()); + // remove(tempFile.c_str()); } void test1DWithDx() { @@ -250,8 +251,61 @@ public: remove(tempFile2.c_str()); } + void test_LoadRKH_with_second_header() { + // Arrange + ConfigService::Instance().setString("default.facility", "ISIS"); + writeTestFileWithSecondHeader(); + std::string outputSpace = "rkh_with_second_header"; + + // Act + Mantid::DataHandling::LoadRKH rkhAlg; + rkhAlg.initialize(); + rkhAlg.setPropertyValue("Filename", tempFile3); + rkhAlg.setPropertyValue("OutputWorkspace", outputSpace); + + // Assert + std::string result; + TS_ASSERT_THROWS_NOTHING(result = rkhAlg.getPropertyValue("Filename")) + TS_ASSERT_THROWS_NOTHING(result = + rkhAlg.getPropertyValue("OutputWorkspace")) + TS_ASSERT(result == outputSpace); + TS_ASSERT_THROWS_NOTHING(rkhAlg.execute()); + TS_ASSERT(rkhAlg.isExecuted()); + + using namespace Mantid::API; + using namespace Mantid::DataObjects; + // Now need to test the resultant workspace, first retrieve it + Workspace_sptr rkhspace; + + TS_ASSERT_THROWS_NOTHING( + rkhspace = AnalysisDataService::Instance().retrieve(outputSpace)); + Workspace2D_sptr data = boost::dynamic_pointer_cast<Workspace2D>(rkhspace); + + TS_ASSERT_EQUALS(data->getNumberHistograms(), 1); + + TS_ASSERT_EQUALS(static_cast<int>(data->dataX(0).size()), 4); + TS_ASSERT_EQUALS(static_cast<int>(data->dataY(0).size()), 4); + TS_ASSERT_EQUALS(static_cast<int>(data->dataE(0).size()), 4); + + double tolerance(1e-06); + + TS_ASSERT_DELTA(data->dataX(0)[0], 0.00520, tolerance); + TS_ASSERT_DELTA(data->dataX(0)[1], 0.00562, tolerance); + TS_ASSERT_DELTA(data->dataX(0)[2], 0.00607, tolerance); + + TS_ASSERT_DELTA(data->dataY(0)[0], 1.055855e+00, tolerance); + TS_ASSERT_DELTA(data->dataY(0)[1], 9.784999e-01, tolerance); + TS_ASSERT_DELTA(data->dataY(0)[2], 1.239836e+00, tolerance); + + TS_ASSERT_DELTA(data->dataE(0)[0], 2.570181e-01, tolerance); + TS_ASSERT_DELTA(data->dataE(0)[1], 1.365013e-01, tolerance); + TS_ASSERT_DELTA(data->dataE(0)[2], 9.582824e-02, tolerance); + + remove(tempFile3.c_str()); + } + private: - std::string dataFile, tempFile, tempFile2; + std::string dataFile, tempFile, tempFile2, tempFile3; /** Create a tiny 2x2 workspace in a tempory file that should * be deleted @@ -296,6 +350,21 @@ private: file << " 9.50000 1.000000e+00 1.000000e+00 3.081139e+00\n"; file.close(); } + + void writeTestFileWithSecondHeader() { + std::ofstream file(tempFile3.c_str()); + file << " SANS2D Fri 08-JUL-2016 11:10 Workspace: " + "M3_42_3rd-MT_rear_cloned_temp\n"; + file << " M3-42_third_SANS\n"; + file << " 4 0 0 0 1 4 0\n"; + file << " 0 0 0 0\n"; + file << " 3 (F12.5,2E16.6)\n"; + file << " 0.00520 1.055855e+00 2.570181e-01\n"; + file << " 0.00562 9.784999e-01 1.365013e-01\n"; + file << " 0.00607 1.239836e+00 9.582824e-02\n"; + file << " 0.00655 1.260936e+00 7.041577e-02\n"; + file.close(); + } }; #endif // LOADRKHTEST_H_ diff --git a/Framework/DataObjects/inc/MantidDataObjects/DllConfig.h b/Framework/DataObjects/inc/MantidDataObjects/DllConfig.h index f1206f38ba2..52148c235fb 100644 --- a/Framework/DataObjects/inc/MantidDataObjects/DllConfig.h +++ b/Framework/DataObjects/inc/MantidDataObjects/DllConfig.h @@ -32,8 +32,10 @@ #ifdef IN_MANTID_DATAOBJECTS #define MANTID_DATAOBJECTS_DLL DLLExport +#define EXTERN_MANTID_DATAOBJECTS #else #define MANTID_DATAOBJECTS_DLL DLLImport +#define EXTERN_MANTID_DATAOBJECTS EXTERN_IMPORT #endif /* IN_MANTID_DATAOBJECTS*/ #endif // MANTID_DATAOBJECTS_DLLCONFIG_H_ diff --git a/Framework/DataObjects/inc/MantidDataObjects/MDBox.h b/Framework/DataObjects/inc/MantidDataObjects/MDBox.h index 2f6e83de79a..fcf58a8f83d 100644 --- a/Framework/DataObjects/inc/MantidDataObjects/MDBox.h +++ b/Framework/DataObjects/inc/MantidDataObjects/MDBox.h @@ -247,8 +247,8 @@ public: const std::vector<coord_t> &Coord, const std::vector<uint16_t> &runIndex, const std::vector<uint32_t> &detectorId, size_t nEvents) { for (size_t i = 0; i < nEvents; i++) { - data.push_back(MDE(sigErrSq[2 * i], sigErrSq[2 * i + 1], runIndex[i], - detectorId[i], &Coord[i * nd])); + data.emplace_back(sigErrSq[2 * i], sigErrSq[2 * i + 1], runIndex[i], + detectorId[i], &Coord[i * nd]); } } // create single generic event from event's data @@ -269,8 +269,7 @@ public: const std::vector<uint32_t> & /*detectorId*/, size_t nEvents) { for (size_t i = 0; i < nEvents; i++) { - data.push_back(MDLeanEvent<nd>(sigErrSq[2 * i], sigErrSq[2 * i + 1], - &Coord[i * nd])); + data.emplace_back(sigErrSq[2 * i], sigErrSq[2 * i + 1], &Coord[i * nd]); } } // create single lean event from event's data diff --git a/Framework/DataObjects/inc/MantidDataObjects/MDBoxBase.tcc b/Framework/DataObjects/inc/MantidDataObjects/MDBoxBase.tcc index 453dfa4df4d..99c8f9aab90 100644 --- a/Framework/DataObjects/inc/MantidDataObjects/MDBoxBase.tcc +++ b/Framework/DataObjects/inc/MantidDataObjects/MDBoxBase.tcc @@ -54,8 +54,7 @@ TMDE(MDBoxBase)::MDBoxBase( } //----------------------------------------------------------------------------------------------- -/** Copy constructor. Copies the extents, depth, etc. - * and recalculates the boxes' volume. +/** Copy constructor. Copies the extents, volume, depth, etc. * @param box :: incoming box to copy. * @param otherBC :: if present, other (different from the current one) box * controller pointer diff --git a/Framework/DataObjects/inc/MantidDataObjects/MDEvent.h b/Framework/DataObjects/inc/MantidDataObjects/MDEvent.h index e9ef368044c..e61d090f859 100644 --- a/Framework/DataObjects/inc/MantidDataObjects/MDEvent.h +++ b/Framework/DataObjects/inc/MantidDataObjects/MDEvent.h @@ -247,9 +247,10 @@ public: coord_t const *const centers = &(data[ii + 4]); // Create the event with signal, error squared, and the centers - events.push_back(MDEvent<nd>(signal_t(data[ii]), signal_t(data[ii + 1]), - uint16_t(data[ii + 2]), - int32_t(data[ii + 3]), centers)); + events.emplace_back(static_cast<signal_t>(data[ii]), + static_cast<signal_t>(data[ii + 1]), + static_cast<uint16_t>(data[ii + 2]), + static_cast<int32_t>(data[ii + 3]), centers); } } }; diff --git a/Framework/DataObjects/inc/MantidDataObjects/MDEventFactory.h b/Framework/DataObjects/inc/MantidDataObjects/MDEventFactory.h index f6d2bda641f..2bad03cb318 100644 --- a/Framework/DataObjects/inc/MantidDataObjects/MDEventFactory.h +++ b/Framework/DataObjects/inc/MantidDataObjects/MDEventFactory.h @@ -133,9 +133,8 @@ private: }; //### BEGIN AUTO-GENERATED CODE -//################################################################# /* Code below Auto-generated by 'generate_mdevent_declarations.py' - * on 2013-05-30 12:36:57.329000 + * on 2016-06-03 10:28:44.608989 * * DO NOT EDIT! */ @@ -149,51 +148,6 @@ private: #define CALL_MDEVENT_FUNCTION(funcname, workspace) \ { \ - MDEventWorkspace<MDEvent<1>, 1>::sptr MDEW_MDEVENT_1 = \ - boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<1>, 1>>( \ - workspace); \ - if (MDEW_MDEVENT_1) \ - funcname<MDEvent<1>, 1>(MDEW_MDEVENT_1); \ - MDEventWorkspace<MDEvent<2>, 2>::sptr MDEW_MDEVENT_2 = \ - boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<2>, 2>>( \ - workspace); \ - if (MDEW_MDEVENT_2) \ - funcname<MDEvent<2>, 2>(MDEW_MDEVENT_2); \ - MDEventWorkspace<MDEvent<3>, 3>::sptr MDEW_MDEVENT_3 = \ - boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<3>, 3>>( \ - workspace); \ - if (MDEW_MDEVENT_3) \ - funcname<MDEvent<3>, 3>(MDEW_MDEVENT_3); \ - MDEventWorkspace<MDEvent<4>, 4>::sptr MDEW_MDEVENT_4 = \ - boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<4>, 4>>( \ - workspace); \ - if (MDEW_MDEVENT_4) \ - funcname<MDEvent<4>, 4>(MDEW_MDEVENT_4); \ - MDEventWorkspace<MDEvent<5>, 5>::sptr MDEW_MDEVENT_5 = \ - boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<5>, 5>>( \ - workspace); \ - if (MDEW_MDEVENT_5) \ - funcname<MDEvent<5>, 5>(MDEW_MDEVENT_5); \ - MDEventWorkspace<MDEvent<6>, 6>::sptr MDEW_MDEVENT_6 = \ - boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<6>, 6>>( \ - workspace); \ - if (MDEW_MDEVENT_6) \ - funcname<MDEvent<6>, 6>(MDEW_MDEVENT_6); \ - MDEventWorkspace<MDEvent<7>, 7>::sptr MDEW_MDEVENT_7 = \ - boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<7>, 7>>( \ - workspace); \ - if (MDEW_MDEVENT_7) \ - funcname<MDEvent<7>, 7>(MDEW_MDEVENT_7); \ - MDEventWorkspace<MDEvent<8>, 8>::sptr MDEW_MDEVENT_8 = \ - boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<8>, 8>>( \ - workspace); \ - if (MDEW_MDEVENT_8) \ - funcname<MDEvent<8>, 8>(MDEW_MDEVENT_8); \ - MDEventWorkspace<MDEvent<9>, 9>::sptr MDEW_MDEVENT_9 = \ - boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<9>, 9>>( \ - workspace); \ - if (MDEW_MDEVENT_9) \ - funcname<MDEvent<9>, 9>(MDEW_MDEVENT_9); \ MDEventWorkspace<MDLeanEvent<1>, 1>::sptr MDEW_MDLEANEVENT_1 = \ boost::dynamic_pointer_cast<MDEventWorkspace<MDLeanEvent<1>, 1>>( \ workspace); \ @@ -239,17 +193,16 @@ private: workspace); \ if (MDEW_MDLEANEVENT_9) \ funcname<MDLeanEvent<9>, 9>(MDEW_MDLEANEVENT_9); \ - } - -/** Macro that makes it possible to call a templated method for - * a MDEventWorkspace using a IMDEventWorkspace_sptr as the input. - * - * @param funcname :: name of the function that will be called. - * @param workspace :: IMDEventWorkspace_sptr input workspace. -*/ - -#define CALL_MDEVENT_FUNCTION3(funcname, workspace) \ - { \ + MDEventWorkspace<MDEvent<1>, 1>::sptr MDEW_MDEVENT_1 = \ + boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<1>, 1>>( \ + workspace); \ + if (MDEW_MDEVENT_1) \ + funcname<MDEvent<1>, 1>(MDEW_MDEVENT_1); \ + MDEventWorkspace<MDEvent<2>, 2>::sptr MDEW_MDEVENT_2 = \ + boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<2>, 2>>( \ + workspace); \ + if (MDEW_MDEVENT_2) \ + funcname<MDEvent<2>, 2>(MDEW_MDEVENT_2); \ MDEventWorkspace<MDEvent<3>, 3>::sptr MDEW_MDEVENT_3 = \ boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<3>, 3>>( \ workspace); \ @@ -285,6 +238,17 @@ private: workspace); \ if (MDEW_MDEVENT_9) \ funcname<MDEvent<9>, 9>(MDEW_MDEVENT_9); \ + } + +/** Macro that makes it possible to call a templated method for + * a MDEventWorkspace using a IMDEventWorkspace_sptr as the input. + * + * @param funcname :: name of the function that will be called. + * @param workspace :: IMDEventWorkspace_sptr input workspace. +*/ + +#define CALL_MDEVENT_FUNCTION3(funcname, workspace) \ + { \ MDEventWorkspace<MDLeanEvent<3>, 3>::sptr MDEW_MDLEANEVENT_3 = \ boost::dynamic_pointer_cast<MDEventWorkspace<MDLeanEvent<3>, 3>>( \ workspace); \ @@ -320,6 +284,41 @@ private: workspace); \ if (MDEW_MDLEANEVENT_9) \ funcname<MDLeanEvent<9>, 9>(MDEW_MDLEANEVENT_9); \ + MDEventWorkspace<MDEvent<3>, 3>::sptr MDEW_MDEVENT_3 = \ + boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<3>, 3>>( \ + workspace); \ + if (MDEW_MDEVENT_3) \ + funcname<MDEvent<3>, 3>(MDEW_MDEVENT_3); \ + MDEventWorkspace<MDEvent<4>, 4>::sptr MDEW_MDEVENT_4 = \ + boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<4>, 4>>( \ + workspace); \ + if (MDEW_MDEVENT_4) \ + funcname<MDEvent<4>, 4>(MDEW_MDEVENT_4); \ + MDEventWorkspace<MDEvent<5>, 5>::sptr MDEW_MDEVENT_5 = \ + boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<5>, 5>>( \ + workspace); \ + if (MDEW_MDEVENT_5) \ + funcname<MDEvent<5>, 5>(MDEW_MDEVENT_5); \ + MDEventWorkspace<MDEvent<6>, 6>::sptr MDEW_MDEVENT_6 = \ + boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<6>, 6>>( \ + workspace); \ + if (MDEW_MDEVENT_6) \ + funcname<MDEvent<6>, 6>(MDEW_MDEVENT_6); \ + MDEventWorkspace<MDEvent<7>, 7>::sptr MDEW_MDEVENT_7 = \ + boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<7>, 7>>( \ + workspace); \ + if (MDEW_MDEVENT_7) \ + funcname<MDEvent<7>, 7>(MDEW_MDEVENT_7); \ + MDEventWorkspace<MDEvent<8>, 8>::sptr MDEW_MDEVENT_8 = \ + boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<8>, 8>>( \ + workspace); \ + if (MDEW_MDEVENT_8) \ + funcname<MDEvent<8>, 8>(MDEW_MDEVENT_8); \ + MDEventWorkspace<MDEvent<9>, 9>::sptr MDEW_MDEVENT_9 = \ + boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<9>, 9>>( \ + workspace); \ + if (MDEW_MDEVENT_9) \ + funcname<MDEvent<9>, 9>(MDEW_MDEVENT_9); \ } /** Macro that makes it possible to call a templated method for @@ -331,51 +330,6 @@ private: #define CONST_CALL_MDEVENT_FUNCTION(funcname, workspace) \ { \ - const MDEventWorkspace<MDEvent<1>, 1>::sptr CONST_MDEW_MDEVENT_1 = \ - boost::dynamic_pointer_cast<const MDEventWorkspace<MDEvent<1>, 1>>( \ - workspace); \ - if (CONST_MDEW_MDEVENT_1) \ - funcname<MDEvent<1>, 1>(CONST_MDEW_MDEVENT_1); \ - const MDEventWorkspace<MDEvent<2>, 2>::sptr CONST_MDEW_MDEVENT_2 = \ - boost::dynamic_pointer_cast<const MDEventWorkspace<MDEvent<2>, 2>>( \ - workspace); \ - if (CONST_MDEW_MDEVENT_2) \ - funcname<MDEvent<2>, 2>(CONST_MDEW_MDEVENT_2); \ - const MDEventWorkspace<MDEvent<3>, 3>::sptr CONST_MDEW_MDEVENT_3 = \ - boost::dynamic_pointer_cast<const MDEventWorkspace<MDEvent<3>, 3>>( \ - workspace); \ - if (CONST_MDEW_MDEVENT_3) \ - funcname<MDEvent<3>, 3>(CONST_MDEW_MDEVENT_3); \ - const MDEventWorkspace<MDEvent<4>, 4>::sptr CONST_MDEW_MDEVENT_4 = \ - boost::dynamic_pointer_cast<const MDEventWorkspace<MDEvent<4>, 4>>( \ - workspace); \ - if (CONST_MDEW_MDEVENT_4) \ - funcname<MDEvent<4>, 4>(CONST_MDEW_MDEVENT_4); \ - const MDEventWorkspace<MDEvent<5>, 5>::sptr CONST_MDEW_MDEVENT_5 = \ - boost::dynamic_pointer_cast<const MDEventWorkspace<MDEvent<5>, 5>>( \ - workspace); \ - if (CONST_MDEW_MDEVENT_5) \ - funcname<MDEvent<5>, 5>(CONST_MDEW_MDEVENT_5); \ - const MDEventWorkspace<MDEvent<6>, 6>::sptr CONST_MDEW_MDEVENT_6 = \ - boost::dynamic_pointer_cast<const MDEventWorkspace<MDEvent<6>, 6>>( \ - workspace); \ - if (CONST_MDEW_MDEVENT_6) \ - funcname<MDEvent<6>, 6>(CONST_MDEW_MDEVENT_6); \ - const MDEventWorkspace<MDEvent<7>, 7>::sptr CONST_MDEW_MDEVENT_7 = \ - boost::dynamic_pointer_cast<const MDEventWorkspace<MDEvent<7>, 7>>( \ - workspace); \ - if (CONST_MDEW_MDEVENT_7) \ - funcname<MDEvent<7>, 7>(CONST_MDEW_MDEVENT_7); \ - const MDEventWorkspace<MDEvent<8>, 8>::sptr CONST_MDEW_MDEVENT_8 = \ - boost::dynamic_pointer_cast<const MDEventWorkspace<MDEvent<8>, 8>>( \ - workspace); \ - if (CONST_MDEW_MDEVENT_8) \ - funcname<MDEvent<8>, 8>(CONST_MDEW_MDEVENT_8); \ - const MDEventWorkspace<MDEvent<9>, 9>::sptr CONST_MDEW_MDEVENT_9 = \ - boost::dynamic_pointer_cast<const MDEventWorkspace<MDEvent<9>, 9>>( \ - workspace); \ - if (CONST_MDEW_MDEVENT_9) \ - funcname<MDEvent<9>, 9>(CONST_MDEW_MDEVENT_9); \ const MDEventWorkspace<MDLeanEvent<1>, 1>::sptr CONST_MDEW_MDLEANEVENT_1 = \ boost::dynamic_pointer_cast< \ const MDEventWorkspace<MDLeanEvent<1>, 1>>(workspace); \ @@ -421,28 +375,55 @@ private: const MDEventWorkspace<MDLeanEvent<9>, 9>>(workspace); \ if (CONST_MDEW_MDLEANEVENT_9) \ funcname<MDLeanEvent<9>, 9>(CONST_MDEW_MDLEANEVENT_9); \ + const MDEventWorkspace<MDEvent<1>, 1>::sptr CONST_MDEW_MDEVENT_1 = \ + boost::dynamic_pointer_cast<const MDEventWorkspace<MDEvent<1>, 1>>( \ + workspace); \ + if (CONST_MDEW_MDEVENT_1) \ + funcname<MDEvent<1>, 1>(CONST_MDEW_MDEVENT_1); \ + const MDEventWorkspace<MDEvent<2>, 2>::sptr CONST_MDEW_MDEVENT_2 = \ + boost::dynamic_pointer_cast<const MDEventWorkspace<MDEvent<2>, 2>>( \ + workspace); \ + if (CONST_MDEW_MDEVENT_2) \ + funcname<MDEvent<2>, 2>(CONST_MDEW_MDEVENT_2); \ + const MDEventWorkspace<MDEvent<3>, 3>::sptr CONST_MDEW_MDEVENT_3 = \ + boost::dynamic_pointer_cast<const MDEventWorkspace<MDEvent<3>, 3>>( \ + workspace); \ + if (CONST_MDEW_MDEVENT_3) \ + funcname<MDEvent<3>, 3>(CONST_MDEW_MDEVENT_3); \ + const MDEventWorkspace<MDEvent<4>, 4>::sptr CONST_MDEW_MDEVENT_4 = \ + boost::dynamic_pointer_cast<const MDEventWorkspace<MDEvent<4>, 4>>( \ + workspace); \ + if (CONST_MDEW_MDEVENT_4) \ + funcname<MDEvent<4>, 4>(CONST_MDEW_MDEVENT_4); \ + const MDEventWorkspace<MDEvent<5>, 5>::sptr CONST_MDEW_MDEVENT_5 = \ + boost::dynamic_pointer_cast<const MDEventWorkspace<MDEvent<5>, 5>>( \ + workspace); \ + if (CONST_MDEW_MDEVENT_5) \ + funcname<MDEvent<5>, 5>(CONST_MDEW_MDEVENT_5); \ + const MDEventWorkspace<MDEvent<6>, 6>::sptr CONST_MDEW_MDEVENT_6 = \ + boost::dynamic_pointer_cast<const MDEventWorkspace<MDEvent<6>, 6>>( \ + workspace); \ + if (CONST_MDEW_MDEVENT_6) \ + funcname<MDEvent<6>, 6>(CONST_MDEW_MDEVENT_6); \ + const MDEventWorkspace<MDEvent<7>, 7>::sptr CONST_MDEW_MDEVENT_7 = \ + boost::dynamic_pointer_cast<const MDEventWorkspace<MDEvent<7>, 7>>( \ + workspace); \ + if (CONST_MDEW_MDEVENT_7) \ + funcname<MDEvent<7>, 7>(CONST_MDEW_MDEVENT_7); \ + const MDEventWorkspace<MDEvent<8>, 8>::sptr CONST_MDEW_MDEVENT_8 = \ + boost::dynamic_pointer_cast<const MDEventWorkspace<MDEvent<8>, 8>>( \ + workspace); \ + if (CONST_MDEW_MDEVENT_8) \ + funcname<MDEvent<8>, 8>(CONST_MDEW_MDEVENT_8); \ + const MDEventWorkspace<MDEvent<9>, 9>::sptr CONST_MDEW_MDEVENT_9 = \ + boost::dynamic_pointer_cast<const MDEventWorkspace<MDEvent<9>, 9>>( \ + workspace); \ + if (CONST_MDEW_MDEVENT_9) \ + funcname<MDEvent<9>, 9>(CONST_MDEW_MDEVENT_9); \ } // ------------- Typedefs for MDBox ------------------ -/// Typedef for a MDBox with 1 dimension -typedef MDBox<MDEvent<1>, 1> MDBox1; -/// Typedef for a MDBox with 2 dimensions -typedef MDBox<MDEvent<2>, 2> MDBox2; -/// Typedef for a MDBox with 3 dimensions -typedef MDBox<MDEvent<3>, 3> MDBox3; -/// Typedef for a MDBox with 4 dimensions -typedef MDBox<MDEvent<4>, 4> MDBox4; -/// Typedef for a MDBox with 5 dimensions -typedef MDBox<MDEvent<5>, 5> MDBox5; -/// Typedef for a MDBox with 6 dimensions -typedef MDBox<MDEvent<6>, 6> MDBox6; -/// Typedef for a MDBox with 7 dimensions -typedef MDBox<MDEvent<7>, 7> MDBox7; -/// Typedef for a MDBox with 8 dimensions -typedef MDBox<MDEvent<8>, 8> MDBox8; -/// Typedef for a MDBox with 9 dimensions -typedef MDBox<MDEvent<9>, 9> MDBox9; /// Typedef for a MDBox with 1 dimension typedef MDBox<MDLeanEvent<1>, 1> MDBox1Lean; /// Typedef for a MDBox with 2 dimensions @@ -461,27 +442,27 @@ typedef MDBox<MDLeanEvent<7>, 7> MDBox7Lean; typedef MDBox<MDLeanEvent<8>, 8> MDBox8Lean; /// Typedef for a MDBox with 9 dimensions typedef MDBox<MDLeanEvent<9>, 9> MDBox9Lean; +/// Typedef for a MDBox with 1 dimension +typedef MDBox<MDEvent<1>, 1> MDBox1; +/// Typedef for a MDBox with 2 dimensions +typedef MDBox<MDEvent<2>, 2> MDBox2; +/// Typedef for a MDBox with 3 dimensions +typedef MDBox<MDEvent<3>, 3> MDBox3; +/// Typedef for a MDBox with 4 dimensions +typedef MDBox<MDEvent<4>, 4> MDBox4; +/// Typedef for a MDBox with 5 dimensions +typedef MDBox<MDEvent<5>, 5> MDBox5; +/// Typedef for a MDBox with 6 dimensions +typedef MDBox<MDEvent<6>, 6> MDBox6; +/// Typedef for a MDBox with 7 dimensions +typedef MDBox<MDEvent<7>, 7> MDBox7; +/// Typedef for a MDBox with 8 dimensions +typedef MDBox<MDEvent<8>, 8> MDBox8; +/// Typedef for a MDBox with 9 dimensions +typedef MDBox<MDEvent<9>, 9> MDBox9; // ------------- Typedefs for MDBoxBase ------------------ -/// Typedef for a MDBoxBase with 1 dimension -typedef MDBoxBase<MDEvent<1>, 1> MDBoxBase1; -/// Typedef for a MDBoxBase with 2 dimensions -typedef MDBoxBase<MDEvent<2>, 2> MDBoxBase2; -/// Typedef for a MDBoxBase with 3 dimensions -typedef MDBoxBase<MDEvent<3>, 3> MDBoxBase3; -/// Typedef for a MDBoxBase with 4 dimensions -typedef MDBoxBase<MDEvent<4>, 4> MDBoxBase4; -/// Typedef for a MDBoxBase with 5 dimensions -typedef MDBoxBase<MDEvent<5>, 5> MDBoxBase5; -/// Typedef for a MDBoxBase with 6 dimensions -typedef MDBoxBase<MDEvent<6>, 6> MDBoxBase6; -/// Typedef for a MDBoxBase with 7 dimensions -typedef MDBoxBase<MDEvent<7>, 7> MDBoxBase7; -/// Typedef for a MDBoxBase with 8 dimensions -typedef MDBoxBase<MDEvent<8>, 8> MDBoxBase8; -/// Typedef for a MDBoxBase with 9 dimensions -typedef MDBoxBase<MDEvent<9>, 9> MDBoxBase9; /// Typedef for a MDBoxBase with 1 dimension typedef MDBoxBase<MDLeanEvent<1>, 1> MDBoxBase1Lean; /// Typedef for a MDBoxBase with 2 dimensions @@ -500,27 +481,27 @@ typedef MDBoxBase<MDLeanEvent<7>, 7> MDBoxBase7Lean; typedef MDBoxBase<MDLeanEvent<8>, 8> MDBoxBase8Lean; /// Typedef for a MDBoxBase with 9 dimensions typedef MDBoxBase<MDLeanEvent<9>, 9> MDBoxBase9Lean; +/// Typedef for a MDBoxBase with 1 dimension +typedef MDBoxBase<MDEvent<1>, 1> MDBoxBase1; +/// Typedef for a MDBoxBase with 2 dimensions +typedef MDBoxBase<MDEvent<2>, 2> MDBoxBase2; +/// Typedef for a MDBoxBase with 3 dimensions +typedef MDBoxBase<MDEvent<3>, 3> MDBoxBase3; +/// Typedef for a MDBoxBase with 4 dimensions +typedef MDBoxBase<MDEvent<4>, 4> MDBoxBase4; +/// Typedef for a MDBoxBase with 5 dimensions +typedef MDBoxBase<MDEvent<5>, 5> MDBoxBase5; +/// Typedef for a MDBoxBase with 6 dimensions +typedef MDBoxBase<MDEvent<6>, 6> MDBoxBase6; +/// Typedef for a MDBoxBase with 7 dimensions +typedef MDBoxBase<MDEvent<7>, 7> MDBoxBase7; +/// Typedef for a MDBoxBase with 8 dimensions +typedef MDBoxBase<MDEvent<8>, 8> MDBoxBase8; +/// Typedef for a MDBoxBase with 9 dimensions +typedef MDBoxBase<MDEvent<9>, 9> MDBoxBase9; // ------------- Typedefs for MDGridBox ------------------ -/// Typedef for a MDGridBox with 1 dimension -typedef MDGridBox<MDEvent<1>, 1> MDGridBox1; -/// Typedef for a MDGridBox with 2 dimensions -typedef MDGridBox<MDEvent<2>, 2> MDGridBox2; -/// Typedef for a MDGridBox with 3 dimensions -typedef MDGridBox<MDEvent<3>, 3> MDGridBox3; -/// Typedef for a MDGridBox with 4 dimensions -typedef MDGridBox<MDEvent<4>, 4> MDGridBox4; -/// Typedef for a MDGridBox with 5 dimensions -typedef MDGridBox<MDEvent<5>, 5> MDGridBox5; -/// Typedef for a MDGridBox with 6 dimensions -typedef MDGridBox<MDEvent<6>, 6> MDGridBox6; -/// Typedef for a MDGridBox with 7 dimensions -typedef MDGridBox<MDEvent<7>, 7> MDGridBox7; -/// Typedef for a MDGridBox with 8 dimensions -typedef MDGridBox<MDEvent<8>, 8> MDGridBox8; -/// Typedef for a MDGridBox with 9 dimensions -typedef MDGridBox<MDEvent<9>, 9> MDGridBox9; /// Typedef for a MDGridBox with 1 dimension typedef MDGridBox<MDLeanEvent<1>, 1> MDGridBox1Lean; /// Typedef for a MDGridBox with 2 dimensions @@ -539,27 +520,27 @@ typedef MDGridBox<MDLeanEvent<7>, 7> MDGridBox7Lean; typedef MDGridBox<MDLeanEvent<8>, 8> MDGridBox8Lean; /// Typedef for a MDGridBox with 9 dimensions typedef MDGridBox<MDLeanEvent<9>, 9> MDGridBox9Lean; +/// Typedef for a MDGridBox with 1 dimension +typedef MDGridBox<MDEvent<1>, 1> MDGridBox1; +/// Typedef for a MDGridBox with 2 dimensions +typedef MDGridBox<MDEvent<2>, 2> MDGridBox2; +/// Typedef for a MDGridBox with 3 dimensions +typedef MDGridBox<MDEvent<3>, 3> MDGridBox3; +/// Typedef for a MDGridBox with 4 dimensions +typedef MDGridBox<MDEvent<4>, 4> MDGridBox4; +/// Typedef for a MDGridBox with 5 dimensions +typedef MDGridBox<MDEvent<5>, 5> MDGridBox5; +/// Typedef for a MDGridBox with 6 dimensions +typedef MDGridBox<MDEvent<6>, 6> MDGridBox6; +/// Typedef for a MDGridBox with 7 dimensions +typedef MDGridBox<MDEvent<7>, 7> MDGridBox7; +/// Typedef for a MDGridBox with 8 dimensions +typedef MDGridBox<MDEvent<8>, 8> MDGridBox8; +/// Typedef for a MDGridBox with 9 dimensions +typedef MDGridBox<MDEvent<9>, 9> MDGridBox9; // ------------- Typedefs for MDEventWorkspace ------------------ -/// Typedef for a MDEventWorkspace with 1 dimension -typedef MDEventWorkspace<MDEvent<1>, 1> MDEventWorkspace1; -/// Typedef for a MDEventWorkspace with 2 dimensions -typedef MDEventWorkspace<MDEvent<2>, 2> MDEventWorkspace2; -/// Typedef for a MDEventWorkspace with 3 dimensions -typedef MDEventWorkspace<MDEvent<3>, 3> MDEventWorkspace3; -/// Typedef for a MDEventWorkspace with 4 dimensions -typedef MDEventWorkspace<MDEvent<4>, 4> MDEventWorkspace4; -/// Typedef for a MDEventWorkspace with 5 dimensions -typedef MDEventWorkspace<MDEvent<5>, 5> MDEventWorkspace5; -/// Typedef for a MDEventWorkspace with 6 dimensions -typedef MDEventWorkspace<MDEvent<6>, 6> MDEventWorkspace6; -/// Typedef for a MDEventWorkspace with 7 dimensions -typedef MDEventWorkspace<MDEvent<7>, 7> MDEventWorkspace7; -/// Typedef for a MDEventWorkspace with 8 dimensions -typedef MDEventWorkspace<MDEvent<8>, 8> MDEventWorkspace8; -/// Typedef for a MDEventWorkspace with 9 dimensions -typedef MDEventWorkspace<MDEvent<9>, 9> MDEventWorkspace9; /// Typedef for a MDEventWorkspace with 1 dimension typedef MDEventWorkspace<MDLeanEvent<1>, 1> MDEventWorkspace1Lean; /// Typedef for a MDEventWorkspace with 2 dimensions @@ -578,27 +559,27 @@ typedef MDEventWorkspace<MDLeanEvent<7>, 7> MDEventWorkspace7Lean; typedef MDEventWorkspace<MDLeanEvent<8>, 8> MDEventWorkspace8Lean; /// Typedef for a MDEventWorkspace with 9 dimensions typedef MDEventWorkspace<MDLeanEvent<9>, 9> MDEventWorkspace9Lean; +/// Typedef for a MDEventWorkspace with 1 dimension +typedef MDEventWorkspace<MDEvent<1>, 1> MDEventWorkspace1; +/// Typedef for a MDEventWorkspace with 2 dimensions +typedef MDEventWorkspace<MDEvent<2>, 2> MDEventWorkspace2; +/// Typedef for a MDEventWorkspace with 3 dimensions +typedef MDEventWorkspace<MDEvent<3>, 3> MDEventWorkspace3; +/// Typedef for a MDEventWorkspace with 4 dimensions +typedef MDEventWorkspace<MDEvent<4>, 4> MDEventWorkspace4; +/// Typedef for a MDEventWorkspace with 5 dimensions +typedef MDEventWorkspace<MDEvent<5>, 5> MDEventWorkspace5; +/// Typedef for a MDEventWorkspace with 6 dimensions +typedef MDEventWorkspace<MDEvent<6>, 6> MDEventWorkspace6; +/// Typedef for a MDEventWorkspace with 7 dimensions +typedef MDEventWorkspace<MDEvent<7>, 7> MDEventWorkspace7; +/// Typedef for a MDEventWorkspace with 8 dimensions +typedef MDEventWorkspace<MDEvent<8>, 8> MDEventWorkspace8; +/// Typedef for a MDEventWorkspace with 9 dimensions +typedef MDEventWorkspace<MDEvent<9>, 9> MDEventWorkspace9; // ------------- Typedefs for MDBin ------------------ -/// Typedef for a MDBin with 1 dimension -typedef MDBin<MDEvent<1>, 1> MDBin1; -/// Typedef for a MDBin with 2 dimensions -typedef MDBin<MDEvent<2>, 2> MDBin2; -/// Typedef for a MDBin with 3 dimensions -typedef MDBin<MDEvent<3>, 3> MDBin3; -/// Typedef for a MDBin with 4 dimensions -typedef MDBin<MDEvent<4>, 4> MDBin4; -/// Typedef for a MDBin with 5 dimensions -typedef MDBin<MDEvent<5>, 5> MDBin5; -/// Typedef for a MDBin with 6 dimensions -typedef MDBin<MDEvent<6>, 6> MDBin6; -/// Typedef for a MDBin with 7 dimensions -typedef MDBin<MDEvent<7>, 7> MDBin7; -/// Typedef for a MDBin with 8 dimensions -typedef MDBin<MDEvent<8>, 8> MDBin8; -/// Typedef for a MDBin with 9 dimensions -typedef MDBin<MDEvent<9>, 9> MDBin9; /// Typedef for a MDBin with 1 dimension typedef MDBin<MDLeanEvent<1>, 1> MDBin1Lean; /// Typedef for a MDBin with 2 dimensions @@ -617,6 +598,24 @@ typedef MDBin<MDLeanEvent<7>, 7> MDBin7Lean; typedef MDBin<MDLeanEvent<8>, 8> MDBin8Lean; /// Typedef for a MDBin with 9 dimensions typedef MDBin<MDLeanEvent<9>, 9> MDBin9Lean; +/// Typedef for a MDBin with 1 dimension +typedef MDBin<MDEvent<1>, 1> MDBin1; +/// Typedef for a MDBin with 2 dimensions +typedef MDBin<MDEvent<2>, 2> MDBin2; +/// Typedef for a MDBin with 3 dimensions +typedef MDBin<MDEvent<3>, 3> MDBin3; +/// Typedef for a MDBin with 4 dimensions +typedef MDBin<MDEvent<4>, 4> MDBin4; +/// Typedef for a MDBin with 5 dimensions +typedef MDBin<MDEvent<5>, 5> MDBin5; +/// Typedef for a MDBin with 6 dimensions +typedef MDBin<MDEvent<6>, 6> MDBin6; +/// Typedef for a MDBin with 7 dimensions +typedef MDBin<MDEvent<7>, 7> MDBin7; +/// Typedef for a MDBin with 8 dimensions +typedef MDBin<MDEvent<8>, 8> MDBin8; +/// Typedef for a MDBin with 9 dimensions +typedef MDBin<MDEvent<9>, 9> MDBin9; /* CODE ABOWE WAS AUTO-GENERATED BY generate_mdevent_declarations.py - DO NOT * EDIT! */ diff --git a/Framework/DataObjects/inc/MantidDataObjects/MDLeanEvent.h b/Framework/DataObjects/inc/MantidDataObjects/MDLeanEvent.h index f91764777ef..7da1bb3b3e5 100644 --- a/Framework/DataObjects/inc/MantidDataObjects/MDLeanEvent.h +++ b/Framework/DataObjects/inc/MantidDataObjects/MDLeanEvent.h @@ -297,8 +297,8 @@ public: const coord_t *centers = &(coord[ii + 2]); // Create the event with signal, error squared, and the centers - events.push_back(MDLeanEvent<nd>(signal_t(coord[ii]), - signal_t(coord[ii + 1]), centers)); + events.emplace_back(static_cast<signal_t>(coord[ii]), + static_cast<signal_t>(coord[ii + 1]), centers); } } }; diff --git a/Framework/DataObjects/inc/MantidDataObjects/TableColumn.h b/Framework/DataObjects/inc/MantidDataObjects/TableColumn.h index edefcc18e47..d0d16857279 100644 --- a/Framework/DataObjects/inc/MantidDataObjects/TableColumn.h +++ b/Framework/DataObjects/inc/MantidDataObjects/TableColumn.h @@ -216,7 +216,7 @@ protected: if (index < m_data.size()) m_data.insert(m_data.begin() + index, Type()); else - m_data.push_back(Type()); + m_data.emplace_back(); } /// Removes an item at index. void remove(size_t index) override { m_data.erase(m_data.begin() + index); } diff --git a/Framework/DataObjects/src/EventList.cpp b/Framework/DataObjects/src/EventList.cpp index aca4dcb9bd6..2f6d4e28e94 100644 --- a/Framework/DataObjects/src/EventList.cpp +++ b/Framework/DataObjects/src/EventList.cpp @@ -249,8 +249,7 @@ void EventList::createFromHistogram(const ISpectrum *inSpec, bool GenerateZeros, double tof = X[i] + tofStep * (0.5 + double(j)); // Create and add the event // TODO: try emplace_back() here. - weightedEventsNoTime.push_back( - WeightedEventNoTime(tof, weight, errorSquared)); + weightedEventsNoTime.emplace_back(tof, weight, errorSquared); } } else { // --------- Single event per bin ---------- @@ -260,8 +259,7 @@ void EventList::createFromHistogram(const ISpectrum *inSpec, bool GenerateZeros, double errorSquared = E[i]; errorSquared *= errorSquared; // Create and add the event - weightedEventsNoTime.push_back( - WeightedEventNoTime(tof, weight, errorSquared)); + weightedEventsNoTime.emplace_back(tof, weight, errorSquared); } } // error is nont NAN or infinite } // weight is non-zero, not NAN, and non-infinite @@ -308,11 +306,11 @@ EventList &EventList::operator+=(const TofEvent &event) { break; case WEIGHTED: - this->weightedEvents.push_back(WeightedEvent(event)); + this->weightedEvents.emplace_back(event); break; case WEIGHTED_NOTIME: - this->weightedEventsNoTime.push_back(WeightedEventNoTime(event)); + this->weightedEventsNoTime.emplace_back(event); break; } @@ -685,14 +683,9 @@ void EventList::switchToWeightedEvents() { break; case TOF: - weightedEvents.clear(); weightedEventsNoTime.clear(); // Convert and copy all TofEvents to the weightedEvents list. - std::vector<TofEvent>::const_iterator it; - std::vector<TofEvent>::const_iterator it_end = - events.end(); // Cache for speed - for (it = events.begin(); it != it_end; ++it) - this->weightedEvents.push_back(WeightedEvent(*it)); + this->weightedEvents.assign(events.cbegin(), events.cend()); // Get rid of the old events events.clear(); eventType = WEIGHTED; @@ -712,12 +705,7 @@ void EventList::switchToWeightedEventsNoTime() { case TOF: { // Convert and copy all TofEvents to the weightedEvents list. - weightedEventsNoTime.clear(); - std::vector<TofEvent>::const_iterator it; - std::vector<TofEvent>::const_iterator it_end = - events.end(); // Cache for speed - for (it = events.begin(); it != it_end; ++it) - this->weightedEventsNoTime.push_back(WeightedEventNoTime(*it)); + this->weightedEventsNoTime.assign(events.cbegin(), events.cend()); // Get rid of the old events events.clear(); weightedEvents.clear(); @@ -726,12 +714,8 @@ void EventList::switchToWeightedEventsNoTime() { case WEIGHTED: { // Convert and copy all TofEvents to the weightedEvents list. - weightedEventsNoTime.clear(); - std::vector<WeightedEvent>::const_iterator it; - std::vector<WeightedEvent>::const_iterator it_end = - weightedEvents.end(); // Cache for speed - for (it = weightedEvents.begin(); it != it_end; ++it) - this->weightedEventsNoTime.push_back(WeightedEventNoTime(*it)); + this->weightedEventsNoTime.assign(weightedEvents.cbegin(), + weightedEvents.cend()); // Get rid of the old events events.clear(); weightedEvents.clear(); @@ -1676,8 +1660,7 @@ EventList::compressEventsHelper(const std::vector<T> &events, if (num > 0) { // Create a new event with the average TOF and summed weights and // squared errors. - out.push_back( - WeightedEventNoTime(totalTof / num, weight, errorSquared)); + out.emplace_back(totalTof / num, weight, errorSquared); } // Start a new combined object num = 1; @@ -1692,7 +1675,7 @@ EventList::compressEventsHelper(const std::vector<T> &events, if (num > 0) { // Create a new event with the average TOF and summed weights and squared // errors. - out.push_back(WeightedEventNoTime(totalTof / num, weight, errorSquared)); + out.emplace_back(totalTof / num, weight, errorSquared); } // If you have over-allocated by more than 5%, reduce the size. @@ -1761,8 +1744,7 @@ void EventList::compressEventsParallelHelper( if (num > 0) { // Create a new event with the average TOF and summed weights and // squared errors. - localOut.push_back( - WeightedEventNoTime(totalTof / num, weight, errorSquared)); + localOut.emplace_back(totalTof / num, weight, errorSquared); } // Start a new combined object num = 1; @@ -1777,8 +1759,7 @@ void EventList::compressEventsParallelHelper( if (num > 0) { // Create a new event with the average TOF and summed weights and squared // errors. - localOut.push_back( - WeightedEventNoTime(totalTof / num, weight, errorSquared)); + localOut.emplace_back(totalTof / num, weight, errorSquared); } } diff --git a/Framework/DataObjects/src/EventWorkspace.cpp b/Framework/DataObjects/src/EventWorkspace.cpp index 72de1075f25..250b5734b27 100644 --- a/Framework/DataObjects/src/EventWorkspace.cpp +++ b/Framework/DataObjects/src/EventWorkspace.cpp @@ -879,8 +879,8 @@ void EventWorkspace::getIntegratedSpectra(std::vector<double> &out, } // namespace Mantid ///\cond TEMPLATE -template DLLExport class Mantid::API::WorkspaceProperty< - Mantid::DataObjects::EventWorkspace>; +template class DLLExport + Mantid::API::WorkspaceProperty<Mantid::DataObjects::EventWorkspace>; namespace Mantid { namespace Kernel { diff --git a/Framework/DataObjects/src/MDEventFactory.cpp b/Framework/DataObjects/src/MDEventFactory.cpp index ed506943b9a..7d61b921073 100644 --- a/Framework/DataObjects/src/MDEventFactory.cpp +++ b/Framework/DataObjects/src/MDEventFactory.cpp @@ -25,152 +25,151 @@ namespace Mantid { namespace DataObjects { //### BEGIN AUTO-GENERATED CODE -//################################################################# /* Code below Auto-generated by 'generate_mdevent_declarations.py' - * on 2013-05-30 12:36:57.329000 + * on 2016-06-03 10:28:44.608989 * * DO NOT EDIT! */ -// Instantiations for MDEvent -template DLLExport class MDEvent<1>; -template DLLExport class MDEvent<2>; -template DLLExport class MDEvent<3>; -template DLLExport class MDEvent<4>; -template DLLExport class MDEvent<5>; -template DLLExport class MDEvent<6>; -template DLLExport class MDEvent<7>; -template DLLExport class MDEvent<8>; -template DLLExport class MDEvent<9>; // Instantiations for MDLeanEvent -template DLLExport class MDLeanEvent<1>; -template DLLExport class MDLeanEvent<2>; -template DLLExport class MDLeanEvent<3>; -template DLLExport class MDLeanEvent<4>; -template DLLExport class MDLeanEvent<5>; -template DLLExport class MDLeanEvent<6>; -template DLLExport class MDLeanEvent<7>; -template DLLExport class MDLeanEvent<8>; -template DLLExport class MDLeanEvent<9>; +template class DLLExport MDLeanEvent<1>; +template class DLLExport MDLeanEvent<2>; +template class DLLExport MDLeanEvent<3>; +template class DLLExport MDLeanEvent<4>; +template class DLLExport MDLeanEvent<5>; +template class DLLExport MDLeanEvent<6>; +template class DLLExport MDLeanEvent<7>; +template class DLLExport MDLeanEvent<8>; +template class DLLExport MDLeanEvent<9>; +// Instantiations for MDEvent +template class DLLExport MDEvent<1>; +template class DLLExport MDEvent<2>; +template class DLLExport MDEvent<3>; +template class DLLExport MDEvent<4>; +template class DLLExport MDEvent<5>; +template class DLLExport MDEvent<6>; +template class DLLExport MDEvent<7>; +template class DLLExport MDEvent<8>; +template class DLLExport MDEvent<9>; // Instantiations for MDBoxBase -template DLLExport class MDBoxBase<MDEvent<1>, 1>; -template DLLExport class MDBoxBase<MDEvent<2>, 2>; -template DLLExport class MDBoxBase<MDEvent<3>, 3>; -template DLLExport class MDBoxBase<MDEvent<4>, 4>; -template DLLExport class MDBoxBase<MDEvent<5>, 5>; -template DLLExport class MDBoxBase<MDEvent<6>, 6>; -template DLLExport class MDBoxBase<MDEvent<7>, 7>; -template DLLExport class MDBoxBase<MDEvent<8>, 8>; -template DLLExport class MDBoxBase<MDEvent<9>, 9>; -template DLLExport class MDBoxBase<MDLeanEvent<1>, 1>; -template DLLExport class MDBoxBase<MDLeanEvent<2>, 2>; -template DLLExport class MDBoxBase<MDLeanEvent<3>, 3>; -template DLLExport class MDBoxBase<MDLeanEvent<4>, 4>; -template DLLExport class MDBoxBase<MDLeanEvent<5>, 5>; -template DLLExport class MDBoxBase<MDLeanEvent<6>, 6>; -template DLLExport class MDBoxBase<MDLeanEvent<7>, 7>; -template DLLExport class MDBoxBase<MDLeanEvent<8>, 8>; -template DLLExport class MDBoxBase<MDLeanEvent<9>, 9>; +template class DLLExport MDBoxBase<MDLeanEvent<1>, 1>; +template class DLLExport MDBoxBase<MDLeanEvent<2>, 2>; +template class DLLExport MDBoxBase<MDLeanEvent<3>, 3>; +template class DLLExport MDBoxBase<MDLeanEvent<4>, 4>; +template class DLLExport MDBoxBase<MDLeanEvent<5>, 5>; +template class DLLExport MDBoxBase<MDLeanEvent<6>, 6>; +template class DLLExport MDBoxBase<MDLeanEvent<7>, 7>; +template class DLLExport MDBoxBase<MDLeanEvent<8>, 8>; +template class DLLExport MDBoxBase<MDLeanEvent<9>, 9>; +template class DLLExport MDBoxBase<MDEvent<1>, 1>; +template class DLLExport MDBoxBase<MDEvent<2>, 2>; +template class DLLExport MDBoxBase<MDEvent<3>, 3>; +template class DLLExport MDBoxBase<MDEvent<4>, 4>; +template class DLLExport MDBoxBase<MDEvent<5>, 5>; +template class DLLExport MDBoxBase<MDEvent<6>, 6>; +template class DLLExport MDBoxBase<MDEvent<7>, 7>; +template class DLLExport MDBoxBase<MDEvent<8>, 8>; +template class DLLExport MDBoxBase<MDEvent<9>, 9>; // Instantiations for MDBox -template DLLExport class MDBox<MDEvent<1>, 1>; -template DLLExport class MDBox<MDEvent<2>, 2>; -template DLLExport class MDBox<MDEvent<3>, 3>; -template DLLExport class MDBox<MDEvent<4>, 4>; -template DLLExport class MDBox<MDEvent<5>, 5>; -template DLLExport class MDBox<MDEvent<6>, 6>; -template DLLExport class MDBox<MDEvent<7>, 7>; -template DLLExport class MDBox<MDEvent<8>, 8>; -template DLLExport class MDBox<MDEvent<9>, 9>; -template DLLExport class MDBox<MDLeanEvent<1>, 1>; -template DLLExport class MDBox<MDLeanEvent<2>, 2>; -template DLLExport class MDBox<MDLeanEvent<3>, 3>; -template DLLExport class MDBox<MDLeanEvent<4>, 4>; -template DLLExport class MDBox<MDLeanEvent<5>, 5>; -template DLLExport class MDBox<MDLeanEvent<6>, 6>; -template DLLExport class MDBox<MDLeanEvent<7>, 7>; -template DLLExport class MDBox<MDLeanEvent<8>, 8>; -template DLLExport class MDBox<MDLeanEvent<9>, 9>; +template class DLLExport MDBox<MDLeanEvent<1>, 1>; +template class DLLExport MDBox<MDLeanEvent<2>, 2>; +template class DLLExport MDBox<MDLeanEvent<3>, 3>; +template class DLLExport MDBox<MDLeanEvent<4>, 4>; +template class DLLExport MDBox<MDLeanEvent<5>, 5>; +template class DLLExport MDBox<MDLeanEvent<6>, 6>; +template class DLLExport MDBox<MDLeanEvent<7>, 7>; +template class DLLExport MDBox<MDLeanEvent<8>, 8>; +template class DLLExport MDBox<MDLeanEvent<9>, 9>; +template class DLLExport MDBox<MDEvent<1>, 1>; +template class DLLExport MDBox<MDEvent<2>, 2>; +template class DLLExport MDBox<MDEvent<3>, 3>; +template class DLLExport MDBox<MDEvent<4>, 4>; +template class DLLExport MDBox<MDEvent<5>, 5>; +template class DLLExport MDBox<MDEvent<6>, 6>; +template class DLLExport MDBox<MDEvent<7>, 7>; +template class DLLExport MDBox<MDEvent<8>, 8>; +template class DLLExport MDBox<MDEvent<9>, 9>; // Instantiations for MDEventWorkspace -template DLLExport class MDEventWorkspace<MDEvent<1>, 1>; -template DLLExport class MDEventWorkspace<MDEvent<2>, 2>; -template DLLExport class MDEventWorkspace<MDEvent<3>, 3>; -template DLLExport class MDEventWorkspace<MDEvent<4>, 4>; -template DLLExport class MDEventWorkspace<MDEvent<5>, 5>; -template DLLExport class MDEventWorkspace<MDEvent<6>, 6>; -template DLLExport class MDEventWorkspace<MDEvent<7>, 7>; -template DLLExport class MDEventWorkspace<MDEvent<8>, 8>; -template DLLExport class MDEventWorkspace<MDEvent<9>, 9>; -template DLLExport class MDEventWorkspace<MDLeanEvent<1>, 1>; -template DLLExport class MDEventWorkspace<MDLeanEvent<2>, 2>; -template DLLExport class MDEventWorkspace<MDLeanEvent<3>, 3>; -template DLLExport class MDEventWorkspace<MDLeanEvent<4>, 4>; -template DLLExport class MDEventWorkspace<MDLeanEvent<5>, 5>; -template DLLExport class MDEventWorkspace<MDLeanEvent<6>, 6>; -template DLLExport class MDEventWorkspace<MDLeanEvent<7>, 7>; -template DLLExport class MDEventWorkspace<MDLeanEvent<8>, 8>; -template DLLExport class MDEventWorkspace<MDLeanEvent<9>, 9>; +template class DLLExport MDEventWorkspace<MDLeanEvent<1>, 1>; +template class DLLExport MDEventWorkspace<MDLeanEvent<2>, 2>; +template class DLLExport MDEventWorkspace<MDLeanEvent<3>, 3>; +template class DLLExport MDEventWorkspace<MDLeanEvent<4>, 4>; +template class DLLExport MDEventWorkspace<MDLeanEvent<5>, 5>; +template class DLLExport MDEventWorkspace<MDLeanEvent<6>, 6>; +template class DLLExport MDEventWorkspace<MDLeanEvent<7>, 7>; +template class DLLExport MDEventWorkspace<MDLeanEvent<8>, 8>; +template class DLLExport MDEventWorkspace<MDLeanEvent<9>, 9>; +template class DLLExport MDEventWorkspace<MDEvent<1>, 1>; +template class DLLExport MDEventWorkspace<MDEvent<2>, 2>; +template class DLLExport MDEventWorkspace<MDEvent<3>, 3>; +template class DLLExport MDEventWorkspace<MDEvent<4>, 4>; +template class DLLExport MDEventWorkspace<MDEvent<5>, 5>; +template class DLLExport MDEventWorkspace<MDEvent<6>, 6>; +template class DLLExport MDEventWorkspace<MDEvent<7>, 7>; +template class DLLExport MDEventWorkspace<MDEvent<8>, 8>; +template class DLLExport MDEventWorkspace<MDEvent<9>, 9>; // Instantiations for MDGridBox -template DLLExport class MDGridBox<MDEvent<1>, 1>; -template DLLExport class MDGridBox<MDEvent<2>, 2>; -template DLLExport class MDGridBox<MDEvent<3>, 3>; -template DLLExport class MDGridBox<MDEvent<4>, 4>; -template DLLExport class MDGridBox<MDEvent<5>, 5>; -template DLLExport class MDGridBox<MDEvent<6>, 6>; -template DLLExport class MDGridBox<MDEvent<7>, 7>; -template DLLExport class MDGridBox<MDEvent<8>, 8>; -template DLLExport class MDGridBox<MDEvent<9>, 9>; -template DLLExport class MDGridBox<MDLeanEvent<1>, 1>; -template DLLExport class MDGridBox<MDLeanEvent<2>, 2>; -template DLLExport class MDGridBox<MDLeanEvent<3>, 3>; -template DLLExport class MDGridBox<MDLeanEvent<4>, 4>; -template DLLExport class MDGridBox<MDLeanEvent<5>, 5>; -template DLLExport class MDGridBox<MDLeanEvent<6>, 6>; -template DLLExport class MDGridBox<MDLeanEvent<7>, 7>; -template DLLExport class MDGridBox<MDLeanEvent<8>, 8>; -template DLLExport class MDGridBox<MDLeanEvent<9>, 9>; +template class DLLExport MDGridBox<MDLeanEvent<1>, 1>; +template class DLLExport MDGridBox<MDLeanEvent<2>, 2>; +template class DLLExport MDGridBox<MDLeanEvent<3>, 3>; +template class DLLExport MDGridBox<MDLeanEvent<4>, 4>; +template class DLLExport MDGridBox<MDLeanEvent<5>, 5>; +template class DLLExport MDGridBox<MDLeanEvent<6>, 6>; +template class DLLExport MDGridBox<MDLeanEvent<7>, 7>; +template class DLLExport MDGridBox<MDLeanEvent<8>, 8>; +template class DLLExport MDGridBox<MDLeanEvent<9>, 9>; +template class DLLExport MDGridBox<MDEvent<1>, 1>; +template class DLLExport MDGridBox<MDEvent<2>, 2>; +template class DLLExport MDGridBox<MDEvent<3>, 3>; +template class DLLExport MDGridBox<MDEvent<4>, 4>; +template class DLLExport MDGridBox<MDEvent<5>, 5>; +template class DLLExport MDGridBox<MDEvent<6>, 6>; +template class DLLExport MDGridBox<MDEvent<7>, 7>; +template class DLLExport MDGridBox<MDEvent<8>, 8>; +template class DLLExport MDGridBox<MDEvent<9>, 9>; // Instantiations for MDBin -template DLLExport class MDBin<MDEvent<1>, 1>; -template DLLExport class MDBin<MDEvent<2>, 2>; -template DLLExport class MDBin<MDEvent<3>, 3>; -template DLLExport class MDBin<MDEvent<4>, 4>; -template DLLExport class MDBin<MDEvent<5>, 5>; -template DLLExport class MDBin<MDEvent<6>, 6>; -template DLLExport class MDBin<MDEvent<7>, 7>; -template DLLExport class MDBin<MDEvent<8>, 8>; -template DLLExport class MDBin<MDEvent<9>, 9>; -template DLLExport class MDBin<MDLeanEvent<1>, 1>; -template DLLExport class MDBin<MDLeanEvent<2>, 2>; -template DLLExport class MDBin<MDLeanEvent<3>, 3>; -template DLLExport class MDBin<MDLeanEvent<4>, 4>; -template DLLExport class MDBin<MDLeanEvent<5>, 5>; -template DLLExport class MDBin<MDLeanEvent<6>, 6>; -template DLLExport class MDBin<MDLeanEvent<7>, 7>; -template DLLExport class MDBin<MDLeanEvent<8>, 8>; -template DLLExport class MDBin<MDLeanEvent<9>, 9>; +template class DLLExport MDBin<MDLeanEvent<1>, 1>; +template class DLLExport MDBin<MDLeanEvent<2>, 2>; +template class DLLExport MDBin<MDLeanEvent<3>, 3>; +template class DLLExport MDBin<MDLeanEvent<4>, 4>; +template class DLLExport MDBin<MDLeanEvent<5>, 5>; +template class DLLExport MDBin<MDLeanEvent<6>, 6>; +template class DLLExport MDBin<MDLeanEvent<7>, 7>; +template class DLLExport MDBin<MDLeanEvent<8>, 8>; +template class DLLExport MDBin<MDLeanEvent<9>, 9>; +template class DLLExport MDBin<MDEvent<1>, 1>; +template class DLLExport MDBin<MDEvent<2>, 2>; +template class DLLExport MDBin<MDEvent<3>, 3>; +template class DLLExport MDBin<MDEvent<4>, 4>; +template class DLLExport MDBin<MDEvent<5>, 5>; +template class DLLExport MDBin<MDEvent<6>, 6>; +template class DLLExport MDBin<MDEvent<7>, 7>; +template class DLLExport MDBin<MDEvent<8>, 8>; +template class DLLExport MDBin<MDEvent<9>, 9>; // Instantiations for MDBoxIterator -template DLLExport class MDBoxIterator<MDEvent<1>, 1>; -template DLLExport class MDBoxIterator<MDEvent<2>, 2>; -template DLLExport class MDBoxIterator<MDEvent<3>, 3>; -template DLLExport class MDBoxIterator<MDEvent<4>, 4>; -template DLLExport class MDBoxIterator<MDEvent<5>, 5>; -template DLLExport class MDBoxIterator<MDEvent<6>, 6>; -template DLLExport class MDBoxIterator<MDEvent<7>, 7>; -template DLLExport class MDBoxIterator<MDEvent<8>, 8>; -template DLLExport class MDBoxIterator<MDEvent<9>, 9>; -template DLLExport class MDBoxIterator<MDLeanEvent<1>, 1>; -template DLLExport class MDBoxIterator<MDLeanEvent<2>, 2>; -template DLLExport class MDBoxIterator<MDLeanEvent<3>, 3>; -template DLLExport class MDBoxIterator<MDLeanEvent<4>, 4>; -template DLLExport class MDBoxIterator<MDLeanEvent<5>, 5>; -template DLLExport class MDBoxIterator<MDLeanEvent<6>, 6>; -template DLLExport class MDBoxIterator<MDLeanEvent<7>, 7>; -template DLLExport class MDBoxIterator<MDLeanEvent<8>, 8>; -template DLLExport class MDBoxIterator<MDLeanEvent<9>, 9>; +template class DLLExport MDBoxIterator<MDLeanEvent<1>, 1>; +template class DLLExport MDBoxIterator<MDLeanEvent<2>, 2>; +template class DLLExport MDBoxIterator<MDLeanEvent<3>, 3>; +template class DLLExport MDBoxIterator<MDLeanEvent<4>, 4>; +template class DLLExport MDBoxIterator<MDLeanEvent<5>, 5>; +template class DLLExport MDBoxIterator<MDLeanEvent<6>, 6>; +template class DLLExport MDBoxIterator<MDLeanEvent<7>, 7>; +template class DLLExport MDBoxIterator<MDLeanEvent<8>, 8>; +template class DLLExport MDBoxIterator<MDLeanEvent<9>, 9>; +template class DLLExport MDBoxIterator<MDEvent<1>, 1>; +template class DLLExport MDBoxIterator<MDEvent<2>, 2>; +template class DLLExport MDBoxIterator<MDEvent<3>, 3>; +template class DLLExport MDBoxIterator<MDEvent<4>, 4>; +template class DLLExport MDBoxIterator<MDEvent<5>, 5>; +template class DLLExport MDBoxIterator<MDEvent<6>, 6>; +template class DLLExport MDBoxIterator<MDEvent<7>, 7>; +template class DLLExport MDBoxIterator<MDEvent<8>, 8>; +template class DLLExport MDBoxIterator<MDEvent<9>, 9>; /* CODE ABOWE WAS AUTO-GENERATED BY generate_mdevent_declarations.py - DO NOT * EDIT! */ diff --git a/Framework/DataObjects/src/Workspace2D.cpp b/Framework/DataObjects/src/Workspace2D.cpp index cae60d1028b..ace3bdc1dea 100644 --- a/Framework/DataObjects/src/Workspace2D.cpp +++ b/Framework/DataObjects/src/Workspace2D.cpp @@ -316,8 +316,8 @@ void Workspace2D::generateHistogram(const std::size_t index, const MantidVec &X, } // NamespaceMantid ///\cond TEMPLATE -template DLLExport class Mantid::API::WorkspaceProperty< - Mantid::DataObjects::Workspace2D>; +template class DLLExport + Mantid::API::WorkspaceProperty<Mantid::DataObjects::Workspace2D>; namespace Mantid { namespace Kernel { diff --git a/Framework/DataObjects/src/WorkspaceSingleValue.cpp b/Framework/DataObjects/src/WorkspaceSingleValue.cpp index 115a5a70cf7..26088dfd7f6 100644 --- a/Framework/DataObjects/src/WorkspaceSingleValue.cpp +++ b/Framework/DataObjects/src/WorkspaceSingleValue.cpp @@ -73,8 +73,8 @@ size_t WorkspaceSingleValue::getNumDims() const { return 0; } ///\cond TEMPLATE -template DLLExport class Mantid::API::WorkspaceProperty< - Mantid::DataObjects::WorkspaceSingleValue>; +template class DLLExport + Mantid::API::WorkspaceProperty<Mantid::DataObjects::WorkspaceSingleValue>; namespace Mantid { namespace Kernel { diff --git a/Framework/DataObjects/src/generate_mdevent_declarations.py b/Framework/DataObjects/src/generate_mdevent_declarations.py index 4f0eede0b83..0ba66aacd29 100644 --- a/Framework/DataObjects/src/generate_mdevent_declarations.py +++ b/Framework/DataObjects/src/generate_mdevent_declarations.py @@ -7,7 +7,7 @@ import datetime import re # List of every possible MDEvent or MDLeanEvent types. -mdevent_types = ["MDEvent", "MDLeanEvent"] +mdevent_types = ["MDLeanEvent", "MDEvent"] header = """/* Code below Auto-generated by '%s' * on %s @@ -160,8 +160,8 @@ def generate(): classes = classes_cpp + mdevent_types padding,lines,lines_after=parse_file("../inc/MantidDataObjects/MDEventFactory.h", - "//### BEGIN AUTO-GENERATED CODE ###", - "//### END AUTO-GENERATED CODE ###"); + "//### BEGIN AUTO-GENERATED CODE", + "//### END AUTO-GENERATED CODE"); nDim = int(find_num_dim(lines)); print " numDimensions to be generated: ",nDim @@ -189,18 +189,17 @@ def generate(): classes = ["MDBox", "MDBoxBase", "MDGridBox", "MDEventWorkspace", "MDBin"] for c in classes: lines.append("\n%s// ------------- Typedefs for %s ------------------\n" % (padding, c)); - mdevent_type = "MDEvent" - for nd in dimensions: - lines.append("%s/// Typedef for a %s with %d dimension%s " % (padding,c, nd, ['','s'][nd>1]) ) - lines.append("%stypedef %s<%s<%d>, %d> %s%d;" % (padding,c, mdevent_type, nd, nd, c, nd) ) mdevent_type = "MDLeanEvent" for nd in dimensions: lines.append("%s/// Typedef for a %s with %d dimension%s " % (padding,c, nd, ['','s'][nd>1]) ) lines.append("%s typedef %s<%s<%d>, %d> %s%dLean;" % (padding,c, mdevent_type, nd, nd, c, nd) ) - + mdevent_type = "MDEvent" + for nd in dimensions: + lines.append("%s/// Typedef for a %s with %d dimension%s " % (padding,c, nd, ['','s'][nd>1]) ) + lines.append("%stypedef %s<%s<%d>, %d> %s%d;" % (padding,c, mdevent_type, nd, nd, c, nd) ) + lines.append("\n"); - lines += footer_lines + lines_after f = open("../inc/MantidDataObjects/MDEventFactory.h", 'w') @@ -212,8 +211,8 @@ def generate(): # =========== Do the Source File =========== padding,lines,lines_after=parse_file("./MDEventFactory.cpp", - "//### BEGIN AUTO-GENERATED CODE ###", - "//### END AUTO-GENERATED CODE ###"); + "//### BEGIN AUTO-GENERATED CODE", + "//### END AUTO-GENERATED CODE"); header_lines = map(lambda x : padding+x,header.split("\n")); footer_lines = map(lambda x : padding+x,footer.split("\n")); @@ -224,14 +223,14 @@ def generate(): for c in mdevent_types: lines.append("%s// Instantiations for %s" % (padding,c)) for nd in dimensions: - lines.append("%s template DLLExport class %s<%d>;" % (padding,c, nd) ) + lines.append("%s template class DLLExport %s<%d>;" % (padding,c, nd) ) # Classes with MDLeanEvent<x>,x for c in classes_cpp: lines.append("%s// Instantiations for %s" %(padding, c) ) for mdevent_type in mdevent_types: for nd in dimensions: - lines.append("%s template DLLExport class %s<%s<%d>, %d>;" % (padding,c, mdevent_type, nd, nd) ) + lines.append("%s template class DLLExport %s<%s<%d>, %d>;" % (padding,c, mdevent_type, nd, nd) ) lines.append("\n ") diff --git a/Framework/Geometry/inc/MantidGeometry/Crystal/BraggScattererFactory.h b/Framework/Geometry/inc/MantidGeometry/Crystal/BraggScattererFactory.h index 46ef06832bf..a9782105dc3 100644 --- a/Framework/Geometry/inc/MantidGeometry/Crystal/BraggScattererFactory.h +++ b/Framework/Geometry/inc/MantidGeometry/Crystal/BraggScattererFactory.h @@ -85,18 +85,19 @@ private: BraggScattererFactoryImpl(); }; -// This is taken from FuncMinimizerFactory -#ifdef _WIN32 -template class MANTID_GEOMETRY_DLL - Mantid::Kernel::SingletonHolder<BraggScattererFactoryImpl>; -#endif - typedef Mantid::Kernel::SingletonHolder<BraggScattererFactoryImpl> BraggScattererFactory; } // namespace Geometry } // namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_GEOMETRY template class MANTID_GEOMETRY_DLL Mantid::Kernel:: + SingletonHolder<Mantid::Geometry::BraggScattererFactoryImpl>; +} +} + #define DECLARE_BRAGGSCATTERER(classname) \ namespace { \ Mantid::Kernel::RegistrationHelper register_scatterer_##classname( \ diff --git a/Framework/Geometry/inc/MantidGeometry/Crystal/CenteringGroup.h b/Framework/Geometry/inc/MantidGeometry/Crystal/CenteringGroup.h index 32a59668721..85c03b85504 100644 --- a/Framework/Geometry/inc/MantidGeometry/Crystal/CenteringGroup.h +++ b/Framework/Geometry/inc/MantidGeometry/Crystal/CenteringGroup.h @@ -94,15 +94,17 @@ private: friend struct Mantid::Kernel::CreateUsingNew<CenteringGroupCreatorImpl>; }; -#ifdef _WIN32 -template class MANTID_GEOMETRY_DLL - Mantid::Kernel::SingletonHolder<CenteringGroupCreatorImpl>; -#endif - typedef Mantid::Kernel::SingletonHolder<CenteringGroupCreatorImpl> CenteringGroupCreator; } // namespace Geometry } // namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_GEOMETRY template class MANTID_GEOMETRY_DLL Mantid::Kernel:: + SingletonHolder<Mantid::Geometry::CenteringGroupCreatorImpl>; +} +} + #endif /* MANTID_GEOMETRY_CENTERINGGROUP_H_ */ diff --git a/Framework/Geometry/inc/MantidGeometry/Crystal/PointGroupFactory.h b/Framework/Geometry/inc/MantidGeometry/Crystal/PointGroupFactory.h index bcdd02a8096..6e22e4a622a 100644 --- a/Framework/Geometry/inc/MantidGeometry/Crystal/PointGroupFactory.h +++ b/Framework/Geometry/inc/MantidGeometry/Crystal/PointGroupFactory.h @@ -120,18 +120,19 @@ private: boost::regex m_originChoiceRegex; }; -// This is taken from FuncMinimizerFactory -#ifdef _WIN32 -template class MANTID_GEOMETRY_DLL - Mantid::Kernel::SingletonHolder<PointGroupFactoryImpl>; -#endif - typedef Mantid::Kernel::SingletonHolder<PointGroupFactoryImpl> PointGroupFactory; } // namespace Geometry } // namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_GEOMETRY template class MANTID_GEOMETRY_DLL + Mantid::Kernel::SingletonHolder<Mantid::Geometry::PointGroupFactoryImpl>; +} +} + #define PGF_CONCAT_IMPL(x, y) x##y #define PGF_CONCAT(x, y) PGF_CONCAT_IMPL(x, y) diff --git a/Framework/Geometry/inc/MantidGeometry/Crystal/SpaceGroupFactory.h b/Framework/Geometry/inc/MantidGeometry/Crystal/SpaceGroupFactory.h index 40cb653cfcf..fd45198f439 100644 --- a/Framework/Geometry/inc/MantidGeometry/Crystal/SpaceGroupFactory.h +++ b/Framework/Geometry/inc/MantidGeometry/Crystal/SpaceGroupFactory.h @@ -265,18 +265,19 @@ private: friend struct Mantid::Kernel::CreateUsingNew<SpaceGroupFactoryImpl>; }; -// This is taken from FuncMinimizerFactory -#ifdef _WIN32 -template class MANTID_GEOMETRY_DLL - Mantid::Kernel::SingletonHolder<SpaceGroupFactoryImpl>; -#endif - typedef Mantid::Kernel::SingletonHolder<SpaceGroupFactoryImpl> SpaceGroupFactory; } // namespace Geometry } // namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_GEOMETRY template class MANTID_GEOMETRY_DLL + Mantid::Kernel::SingletonHolder<Mantid::Geometry::SpaceGroupFactoryImpl>; +} +} + /* Macros for compile time space group registration * * The macros are a bit different than in other factories, diff --git a/Framework/Geometry/inc/MantidGeometry/Crystal/SymmetryElementFactory.h b/Framework/Geometry/inc/MantidGeometry/Crystal/SymmetryElementFactory.h index 05a48e621d1..30dd5b1603e 100644 --- a/Framework/Geometry/inc/MantidGeometry/Crystal/SymmetryElementFactory.h +++ b/Framework/Geometry/inc/MantidGeometry/Crystal/SymmetryElementFactory.h @@ -257,17 +257,19 @@ private: friend struct Mantid::Kernel::CreateUsingNew<SymmetryElementFactoryImpl>; }; -#ifdef _WIN32 -template class MANTID_GEOMETRY_DLL - Mantid::Kernel::SingletonHolder<SymmetryElementFactoryImpl>; -#endif - typedef Mantid::Kernel::SingletonHolder<SymmetryElementFactoryImpl> SymmetryElementFactory; } // namespace Geometry } // namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_GEOMETRY template class MANTID_GEOMETRY_DLL Mantid::Kernel:: + SingletonHolder<Mantid::Geometry::SymmetryElementFactoryImpl>; +} +} + #define DECLARE_SYMMETRY_ELEMENT_GENERATOR(classname) \ namespace { \ Mantid::Kernel::RegistrationHelper \ diff --git a/Framework/Geometry/inc/MantidGeometry/Crystal/SymmetryOperationFactory.h b/Framework/Geometry/inc/MantidGeometry/Crystal/SymmetryOperationFactory.h index 7a348ca0714..e9fa3cb12de 100644 --- a/Framework/Geometry/inc/MantidGeometry/Crystal/SymmetryOperationFactory.h +++ b/Framework/Geometry/inc/MantidGeometry/Crystal/SymmetryOperationFactory.h @@ -78,18 +78,19 @@ private: SymmetryOperationFactoryImpl(); }; -// This is taken from FuncMinimizerFactory -#ifdef _WIN32 -template class MANTID_GEOMETRY_DLL - Mantid::Kernel::SingletonHolder<SymmetryOperationFactoryImpl>; -#endif - typedef Mantid::Kernel::SingletonHolder<SymmetryOperationFactoryImpl> SymmetryOperationFactory; } // namespace Geometry } // namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_GEOMETRY template class MANTID_GEOMETRY_DLL Mantid::Kernel:: + SingletonHolder<Mantid::Geometry::SymmetryOperationFactoryImpl>; +} +} + #define DECLARE_SYMMETRY_OPERATION(operation, name) \ namespace { \ Mantid::Kernel::RegistrationHelper register_symop_##name( \ diff --git a/Framework/Geometry/inc/MantidGeometry/DllConfig.h b/Framework/Geometry/inc/MantidGeometry/DllConfig.h index 6b9088226e1..432aa7bb7a8 100644 --- a/Framework/Geometry/inc/MantidGeometry/DllConfig.h +++ b/Framework/Geometry/inc/MantidGeometry/DllConfig.h @@ -32,8 +32,10 @@ #ifdef IN_MANTID_GEOMETRY #define MANTID_GEOMETRY_DLL DLLExport +#define EXTERN_MANTID_GEOMETRY #else #define MANTID_GEOMETRY_DLL DLLImport +#define EXTERN_MANTID_GEOMETRY EXTERN_IMPORT #endif /* IN_MANTID_GEOMETRY*/ #endif // MANTID_GEOMETRY_DLLCONFIG_H_ diff --git a/Framework/Geometry/inc/MantidGeometry/Instrument/Parameter.h b/Framework/Geometry/inc/MantidGeometry/Instrument/Parameter.h index c1ae2f418e7..47691bd9965 100644 --- a/Framework/Geometry/inc/MantidGeometry/Instrument/Parameter.h +++ b/Framework/Geometry/inc/MantidGeometry/Instrument/Parameter.h @@ -237,17 +237,17 @@ ParameterType<Type> &ParameterType<Type>::operator=(const Type &value) { /// Typedef for the shared pointer typedef boost::shared_ptr<Parameter> Parameter_sptr; /// Parameter of type int -typedef MANTID_GEOMETRY_DLL ParameterType<int> ParameterInt; +typedef ParameterType<int> ParameterInt; /// Parameter of type double -typedef MANTID_GEOMETRY_DLL ParameterType<double> ParameterDouble; +typedef ParameterType<double> ParameterDouble; /// Parameter of type bool -typedef MANTID_GEOMETRY_DLL ParameterType<bool> ParameterBool; +typedef ParameterType<bool> ParameterBool; /// Parameter of type std::string -typedef MANTID_GEOMETRY_DLL ParameterType<std::string> ParameterString; +typedef ParameterType<std::string> ParameterString; /// Parameter of type V3D -typedef MANTID_GEOMETRY_DLL ParameterType<Kernel::V3D> ParameterV3D; +typedef ParameterType<Kernel::V3D> ParameterV3D; /// Parameter of type Quat -typedef MANTID_GEOMETRY_DLL ParameterType<Kernel::Quat> ParameterQuat; +typedef ParameterType<Kernel::Quat> ParameterQuat; } // namespace Geometry } // namespace Mantid diff --git a/Framework/Geometry/inc/MantidGeometry/Instrument/ParameterFactory.h b/Framework/Geometry/inc/MantidGeometry/Instrument/ParameterFactory.h index 3fcf8fb646a..68738d6152c 100644 --- a/Framework/Geometry/inc/MantidGeometry/Instrument/ParameterFactory.h +++ b/Framework/Geometry/inc/MantidGeometry/Instrument/ParameterFactory.h @@ -12,16 +12,6 @@ #include <map> #include <vector> -#ifdef _WIN32 -#if (IN_MANTID_GEOMETRY) -#define GEOMETRY_DLL_EXPORT DLLExport -#else -#define GEOMETRY_DLL_EXPORT DLLImport -#endif -#else -#define GEOMETRY_DLL_EXPORT -#endif - namespace Mantid { namespace Kernel { @@ -61,7 +51,7 @@ class Parameter; File change history is stored at: <https://github.com/mantidproject/mantid> */ -class GEOMETRY_DLL_EXPORT ParameterFactory { +class MANTID_GEOMETRY_DLL ParameterFactory { public: template <class C> static void subscribe(const std::string &className); diff --git a/Framework/Geometry/inc/MantidGeometry/MDGeometry/MDGeometryXMLBuilder.h b/Framework/Geometry/inc/MantidGeometry/MDGeometry/MDGeometryXMLBuilder.h index f410f3be7db..15addeb2703 100644 --- a/Framework/Geometry/inc/MantidGeometry/MDGeometry/MDGeometryXMLBuilder.h +++ b/Framework/Geometry/inc/MantidGeometry/MDGeometry/MDGeometryXMLBuilder.h @@ -125,7 +125,7 @@ private: @date May 2011 @version 1.0 */ -struct StrictDimensionPolicy +struct MANTID_GEOMETRY_DLL StrictDimensionPolicy : public std::unary_function<IMDDimension_const_sptr, void> { public: StrictDimensionPolicy() {} @@ -147,7 +147,7 @@ public: @author Owen Arnold @date May 2011 */ -struct NoDimensionPolicy +struct MANTID_GEOMETRY_DLL NoDimensionPolicy : public std::unary_function<IMDDimension_const_sptr, void> { void operator()(IMDDimension_const_sptr) { // Do nothing. diff --git a/Framework/Geometry/src/Instrument/SampleEnvironmentFactory.cpp b/Framework/Geometry/src/Instrument/SampleEnvironmentFactory.cpp index 8c6bc107899..1e9e0e7598e 100644 --- a/Framework/Geometry/src/Instrument/SampleEnvironmentFactory.cpp +++ b/Framework/Geometry/src/Instrument/SampleEnvironmentFactory.cpp @@ -77,7 +77,7 @@ SampleEnvironment_uptr SampleEnvironmentFactory::create( } else { auto specUPtr = m_finder->find(facility, instrument, specName); spec = specUPtr.get(); - specCache.insert(std::make_pair(cacheKey, std::move(specUPtr))); + specCache.emplace(cacheKey, std::move(specUPtr)); } return spec->buildEnvironment(canName); } diff --git a/Framework/Geometry/src/Instrument/SampleEnvironmentSpec.cpp b/Framework/Geometry/src/Instrument/SampleEnvironmentSpec.cpp index 1ce9901a7cf..9d8200f5cc7 100644 --- a/Framework/Geometry/src/Instrument/SampleEnvironmentSpec.cpp +++ b/Framework/Geometry/src/Instrument/SampleEnvironmentSpec.cpp @@ -53,7 +53,7 @@ void SampleEnvironmentSpec::addContainer(const Container_const_sptr &can) { "SampleEnvironmentSpec::addContainer() - Container must " "have an id field. Empty string found."); } - m_cans.insert(std::make_pair(can->id(), can)); + m_cans.emplace(can->id(), can); } /** diff --git a/Framework/Geometry/src/Instrument/SampleEnvironmentSpecParser.cpp b/Framework/Geometry/src/Instrument/SampleEnvironmentSpecParser.cpp index 6bd8d38f0bf..4bd481f98a8 100644 --- a/Framework/Geometry/src/Instrument/SampleEnvironmentSpecParser.cpp +++ b/Framework/Geometry/src/Instrument/SampleEnvironmentSpecParser.cpp @@ -127,7 +127,7 @@ void SampleEnvironmentSpecParser::parseMaterials(Poco::XML::Element *element) { MaterialXMLParser parser; while (node) { auto material = parser.parse(static_cast<Poco::XML::Element *>(node)); - m_materials.insert(std::make_pair(material.name(), material)); + m_materials.emplace(material.name(), material); node = nodeIter.nextNode(); } } diff --git a/Framework/Geometry/src/Objects/Object.cpp b/Framework/Geometry/src/Objects/Object.cpp index da55d68945e..a899e1e293e 100644 --- a/Framework/Geometry/src/Objects/Object.cpp +++ b/Framework/Geometry/src/Objects/Object.cpp @@ -22,6 +22,7 @@ #include <boost/make_shared.hpp> +#include <array> #include <deque> #include <iostream> #include <stack> @@ -1828,17 +1829,10 @@ int Object::searchForObject(Kernel::V3D &point) const { Kernel::V3D testPt; if (isValid(point)) return 1; - std::vector<Kernel::V3D> axes; - axes.reserve(6); - axes.push_back(Kernel::V3D(1, 0, 0)); - axes.push_back(Kernel::V3D(-1, 0, 0)); - axes.push_back(Kernel::V3D(0, 1, 0)); - axes.push_back(Kernel::V3D(0, -1, 0)); - axes.push_back(Kernel::V3D(0, 0, 1)); - axes.push_back(Kernel::V3D(0, 0, -1)); - std::vector<Kernel::V3D>::const_iterator dir; - for (dir = axes.begin(); dir != axes.end(); ++dir) { - Geometry::Track tr(point, (*dir)); + for (const auto &dir : + {V3D(1., 0., 0.), V3D(-1., 0., 0.), V3D(0., 1., 0.), V3D(0., -1., 0.), + V3D(0., 0., 1.), V3D(0., 0., -1.)}) { + Geometry::Track tr(point, dir); if (this->interceptSurface(tr) > 0) { point = tr.cbegin()->entryPoint; return 1; diff --git a/Framework/ICat/inc/MantidICat/DllConfig.h b/Framework/ICat/inc/MantidICat/DllConfig.h index 04e784e0e43..08ae1527dac 100644 --- a/Framework/ICat/inc/MantidICat/DllConfig.h +++ b/Framework/ICat/inc/MantidICat/DllConfig.h @@ -32,8 +32,10 @@ #ifdef IN_MANTID_ICAT #define MANTID_ICAT_DLL DLLExport +#define EXTERN_MANTID_ICAT #else #define MANTID_ICAT_DLL DLLImport +#define EXTERN_MANTID_ICAT EXTERN_IMPORT #endif /* IN_MANTID_ICAT */ #endif // MANTID_ICAT_DLLCONFIG_H_ diff --git a/Framework/Kernel/CMakeLists.txt b/Framework/Kernel/CMakeLists.txt index 6861bb2a09d..6559043a037 100644 --- a/Framework/Kernel/CMakeLists.txt +++ b/Framework/Kernel/CMakeLists.txt @@ -32,6 +32,7 @@ set ( SRC_FILES src/FilteredTimeSeriesProperty.cpp src/FloatingPointComparison.cpp src/FreeBlock.cpp + src/GitHubApiHelper.cpp src/Glob.cpp src/ICatalogInfo.cpp src/IPropertyManager.cpp @@ -180,6 +181,7 @@ set ( INC_FILES inc/MantidKernel/FloatingPointComparison.h inc/MantidKernel/FreeBlock.h inc/MantidKernel/FunctionTask.h + inc/MantidKernel/GitHubApiHelper.h inc/MantidKernel/Glob.h inc/MantidKernel/ICatalogInfo.h inc/MantidKernel/IPropertyManager.h @@ -508,6 +510,20 @@ configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/inc/MantidKernel/PocoVersion.h.in configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/src/ParaViewVersion.cpp.in ${CMAKE_CURRENT_SOURCE_DIR}/src/ParaViewVersion.cpp ) +########################################################################### +# This section deals with creating the GithubApiHelper implementation +########################################################################### + +if ( WIN32 ) + set ( GITHUB_AUTHORIZATION_TOKEN "8ec7afc857540ee60af78cba1cf7779a6ed0b6b9") +elseif ( APPLE ) + set ( GITHUB_AUTHORIZATION_TOKEN "9f1c1acd61ecb87b21ad0382f6b403c8294992c5") +else() + set ( GITHUB_AUTHORIZATION_TOKEN "ccacbaf39a7ad8151fca03b4ea99a29b28f0993b") +endif() +configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/inc/MantidKernel/GitHubApiHelper.h.in + ${CMAKE_CURRENT_SOURCE_DIR}/inc/MantidKernel/GitHubApiHelper.h +) ########################################################################### # Manipulate the Mantid.properties file to work wherever you build to @@ -607,14 +623,7 @@ else () set ( MANTID_ROOT .. ) endif () -# Whether or not to check for updates is tied to a patch version being defined -# nighly/unstable is basically ISO8601 so it will be longer than 8 char. -# This affects Mantid.properties.install only. -string( LENGTH "VERSION_PATCH ${VERSION_PATCH}" VERSION_PATCH_LENGTH) -set (ENABLE_WEB_UPDATES 0) -if (${VERSION_PATCH_LENGTH} LESS 8) - set (ENABLE_WEB_UPDATES 1) -endif() +set (ENABLE_WEB_UPDATES 1) set ( PLUGINS ${MANTID_ROOT}/plugins ) set ( PYTHONPLUGIN_DIRS "${PLUGINS}/python" ) diff --git a/Framework/Kernel/inc/MantidKernel/ANN/ANN.h b/Framework/Kernel/inc/MantidKernel/ANN/ANN.h index 84db71c5ad2..11e2f98825f 100644 --- a/Framework/Kernel/inc/MantidKernel/ANN/ANN.h +++ b/Framework/Kernel/inc/MantidKernel/ANN/ANN.h @@ -96,9 +96,12 @@ #else #define DLL_API __declspec(dllimport) #endif -//---------------------------------------------------------------------- -// DLL_API is ignored for all other systems -//---------------------------------------------------------------------- +#elif defined(__GNUC__) && !defined(__clang__) +#ifdef IN_MANTID_KERNEL +#define DLL_API __attribute__((visibility("default"))) +#else +#define DLL_API +#endif #else #define DLL_API #endif diff --git a/Framework/Kernel/inc/MantidKernel/ConfigService.h b/Framework/Kernel/inc/MantidKernel/ConfigService.h index e405fd27394..3132f313e22 100644 --- a/Framework/Kernel/inc/MantidKernel/ConfigService.h +++ b/Framework/Kernel/inc/MantidKernel/ConfigService.h @@ -354,15 +354,9 @@ private: std::vector<std::string> m_filterChannels; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// AlgorithmFactoryImpl (needed for dllexport/dllimport) and a typedef for it. -#if defined(__APPLE__) && defined(__INTEL_COMPILER) -inline -#endif - template class MANTID_KERNEL_DLL - Mantid::Kernel::SingletonHolder<ConfigServiceImpl>; -typedef MANTID_KERNEL_DLL Mantid::Kernel::SingletonHolder<ConfigServiceImpl> - ConfigService; +EXTERN_MANTID_KERNEL template class MANTID_KERNEL_DLL + Mantid::Kernel::SingletonHolder<ConfigServiceImpl>; +typedef Mantid::Kernel::SingletonHolder<ConfigServiceImpl> ConfigService; typedef Mantid::Kernel::ConfigServiceImpl::ValueChanged ConfigValChangeNotification; diff --git a/Framework/Kernel/inc/MantidKernel/DllConfig.h b/Framework/Kernel/inc/MantidKernel/DllConfig.h index f7a6020c17f..d894bc1e0b1 100644 --- a/Framework/Kernel/inc/MantidKernel/DllConfig.h +++ b/Framework/Kernel/inc/MantidKernel/DllConfig.h @@ -32,8 +32,10 @@ #ifdef IN_MANTID_KERNEL #define MANTID_KERNEL_DLL DLLExport +#define EXTERN_MANTID_KERNEL #else #define MANTID_KERNEL_DLL DLLImport +#define EXTERN_MANTID_KERNEL EXTERN_IMPORT #endif /* IN_MANTID_KERNEL*/ #endif // MANTID_KERNEL_DLLCONFIG_H_ diff --git a/Framework/Kernel/inc/MantidKernel/GitHubApiHelper.h.in b/Framework/Kernel/inc/MantidKernel/GitHubApiHelper.h.in new file mode 100644 index 00000000000..d0840d40f87 --- /dev/null +++ b/Framework/Kernel/inc/MantidKernel/GitHubApiHelper.h.in @@ -0,0 +1,60 @@ +#ifndef MANTID_KERNEL_GitHubApiHelper_H_ +#define MANTID_KERNEL_GitHubApiHelper_H_ + +#include "MantidKernel/InternetHelper.h" + +namespace Mantid { +namespace Kernel { + +/** GitHubApiHelper : A helper class for supporting access to the github api +through HTTP and HTTPS, inherits from the InternetHelper. +This class automatically adds the authorization to a read only account. + +Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +National Laboratory & European Spallation Source + +This file is part of Mantid. + +Mantid is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +Mantid is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +File change history is stored at: <https://github.com/mantidproject/mantid> +Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ +class MANTID_KERNEL_DLL GitHubApiHelper : public InternetHelper { +public: + GitHubApiHelper(); + GitHubApiHelper(const Kernel::ProxyInfo &proxy); + virtual ~GitHubApiHelper() = default; + + void reset() override; + bool isAuthenticated(); + +protected: + virtual void processResponseHeaders(const Poco::Net::HTTPResponse &res) override; + virtual int sendRequestAndProcess(Poco::Net::HTTPClientSession &session, + Poco::URI &uri, std::ostream &responseStream) override; +private: + int processAnonymousRequest(const Poco::Net::HTTPResponse &response, + Poco::URI &uri, + std::ostream &responseStream); + void addAuthenticationToken() { + addHeader("Authorization", + "token @GITHUB_AUTHORIZATION_TOKEN@"); + } +}; + +} // namespace Kernel +} // namespace Mantid + +#endif /* MANTID_KERNEL_GitHubApiHelper_H_ */ diff --git a/Framework/Kernel/inc/MantidKernel/InternetHelper.h b/Framework/Kernel/inc/MantidKernel/InternetHelper.h index 771a819cc33..7e1f6e47e57 100644 --- a/Framework/Kernel/inc/MantidKernel/InternetHelper.h +++ b/Framework/Kernel/inc/MantidKernel/InternetHelper.h @@ -130,7 +130,7 @@ public: const std::string &getHeader(const std::string &key); void clearHeaders(); StringToStringMap &headers(); - void reset(); + virtual void reset(); // Proxy methods Kernel::ProxyInfo &getProxy(const std::string &url); @@ -147,15 +147,16 @@ protected: std::ostream &responseStream); virtual int sendHTTPRequest(const std::string &url, std::ostream &responseStream); + virtual void processResponseHeaders(const Poco::Net::HTTPResponse &res); virtual int processErrorStates(const Poco::Net::HTTPResponse &res, std::istream &rs, const std::string &url); + virtual int sendRequestAndProcess(Poco::Net::HTTPClientSession &session, + Poco::URI &uri, + std::ostream &responseStream); -private: void setupProxyOnSession(Poco::Net::HTTPClientSession &session, const std::string &proxyUrl); void createRequest(Poco::URI &uri); - int sendRequestAndProcess(Poco::Net::HTTPClientSession &session, - Poco::URI &uri, std::ostream &responseStream); int processRelocation(const Poco::Net::HTTPResponse &response, std::ostream &responseStream); bool isRelocated(const int response); diff --git a/Framework/Kernel/inc/MantidKernel/LibraryManager.h b/Framework/Kernel/inc/MantidKernel/LibraryManager.h index de77712ad2f..ae95398fc06 100644 --- a/Framework/Kernel/inc/MantidKernel/LibraryManager.h +++ b/Framework/Kernel/inc/MantidKernel/LibraryManager.h @@ -69,15 +69,9 @@ private: OpenLibs; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// LibraryManagerImpl (needed for dllexport/dllimport) and a typedef for it. -#if defined(__APPLE__) && defined(__INTEL_COMPILER) -inline -#endif - template class MANTID_KERNEL_DLL - Mantid::Kernel::SingletonHolder<LibraryManagerImpl>; -typedef MANTID_KERNEL_DLL Mantid::Kernel::SingletonHolder<LibraryManagerImpl> - LibraryManager; +EXTERN_MANTID_KERNEL template class MANTID_KERNEL_DLL + Mantid::Kernel::SingletonHolder<LibraryManagerImpl>; +typedef Mantid::Kernel::SingletonHolder<LibraryManagerImpl> LibraryManager; } // namespace Kernel } // namespace Mantid diff --git a/Framework/Kernel/inc/MantidKernel/PropertyManagerDataService.h b/Framework/Kernel/inc/MantidKernel/PropertyManagerDataService.h index 49aa7c28a21..6caae94d1fb 100644 --- a/Framework/Kernel/inc/MantidKernel/PropertyManagerDataService.h +++ b/Framework/Kernel/inc/MantidKernel/PropertyManagerDataService.h @@ -46,16 +46,10 @@ private: ~PropertyManagerDataServiceImpl() override = default; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// PropertyManagerDataServiceImpl (needed for dllexport/dllimport) and a -/// typedef for it. -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class MANTID_KERNEL_DLL +EXTERN_MANTID_KERNEL template class MANTID_KERNEL_DLL Mantid::Kernel::SingletonHolder<PropertyManagerDataServiceImpl>; -#endif /* _WIN32 */ -typedef MANTID_KERNEL_DLL Mantid::Kernel::SingletonHolder< - PropertyManagerDataServiceImpl> PropertyManagerDataService; +typedef Mantid::Kernel::SingletonHolder<PropertyManagerDataServiceImpl> + PropertyManagerDataService; } // Namespace Kernel } // Namespace Mantid diff --git a/Framework/Kernel/inc/MantidKernel/System.h b/Framework/Kernel/inc/MantidKernel/System.h index 0aee62559f1..65fbb9545cb 100644 --- a/Framework/Kernel/inc/MantidKernel/System.h +++ b/Framework/Kernel/inc/MantidKernel/System.h @@ -60,9 +60,15 @@ // Export/Import declarations #define DLLExport __declspec(dllexport) #define DLLImport __declspec(dllimport) +#define EXTERN_IMPORT extern +#elif defined(__GNUC__) && !defined(__clang__) +#define DLLExport __attribute__((visibility("default"))) +#define DLLImport +#define EXTERN_IMPORT extern #else #define DLLExport #define DLLImport +#define EXTERN_IMPORT #endif /** diff --git a/Framework/Kernel/inc/MantidKernel/ThreadPool.h b/Framework/Kernel/inc/MantidKernel/ThreadPool.h index c383d334d1b..256eacf6b68 100644 --- a/Framework/Kernel/inc/MantidKernel/ThreadPool.h +++ b/Framework/Kernel/inc/MantidKernel/ThreadPool.h @@ -93,7 +93,7 @@ private: // template class MANTID_KERNEL_DLL // Mantid::Kernel::SingletonHolder<ThreadPoolImpl>; //#endif /* _WIN32 */ -// typedef MANTID_KERNEL_DLL Mantid::Kernel::SingletonHolder<ThreadPoolImpl> +// typedef Mantid::Kernel::SingletonHolder<ThreadPoolImpl> // ThreadPool; } // namespace Kernel diff --git a/Framework/Kernel/inc/MantidKernel/Timer.h b/Framework/Kernel/inc/MantidKernel/Timer.h index 017452e4c90..195a8359766 100644 --- a/Framework/Kernel/inc/MantidKernel/Timer.h +++ b/Framework/Kernel/inc/MantidKernel/Timer.h @@ -63,7 +63,7 @@ private: m_start; ///< The starting time (implementation dependent format) }; -std::ostream &operator<<(std::ostream &, const Timer &); +MANTID_KERNEL_DLL std::ostream &operator<<(std::ostream &, const Timer &); } // namespace Kernel } // namespace Mantid diff --git a/Framework/Kernel/inc/MantidKernel/UnitFactory.h b/Framework/Kernel/inc/MantidKernel/UnitFactory.h index e3a0c045c25..d8de9c7e8fa 100644 --- a/Framework/Kernel/inc/MantidKernel/UnitFactory.h +++ b/Framework/Kernel/inc/MantidKernel/UnitFactory.h @@ -83,14 +83,9 @@ private: ~UnitFactoryImpl() override = default; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// AlgorithmFactoryImpl (needed for dllexport/dllimport) . -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class MANTID_KERNEL_DLL +EXTERN_MANTID_KERNEL template class MANTID_KERNEL_DLL Mantid::Kernel::SingletonHolder<UnitFactoryImpl>; -#endif /* _WIN32 */ -/// The specialisation of the SingletonHolder class that holds the UnitFactory + typedef SingletonHolder<UnitFactoryImpl> UnitFactory; } // namespace Kernel diff --git a/Framework/Kernel/inc/MantidKernel/UsageService.h b/Framework/Kernel/inc/MantidKernel/UsageService.h index f77ba2d5a15..c1310ec69e5 100644 --- a/Framework/Kernel/inc/MantidKernel/UsageService.h +++ b/Framework/Kernel/inc/MantidKernel/UsageService.h @@ -137,17 +137,11 @@ private: Poco::ActiveMethod<int, std::string, UsageServiceImpl> m_featureActiveMethod; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// AlgorithmFactoryImpl (needed for dllexport/dllimport) and a typedef for it. -#if defined(__APPLE__) && defined(__INTEL_COMPILER) -inline -#endif - template class MANTID_KERNEL_DLL - Mantid::Kernel::SingletonHolder<UsageServiceImpl>; -typedef MANTID_KERNEL_DLL Mantid::Kernel::SingletonHolder<UsageServiceImpl> - UsageService; - -} // namespace API +EXTERN_MANTID_KERNEL template class MANTID_KERNEL_DLL + Mantid::Kernel::SingletonHolder<UsageServiceImpl>; +typedef Mantid::Kernel::SingletonHolder<UsageServiceImpl> UsageService; + +} // namespace Kernel } // namespace Mantid #endif /* MANTID_KERNEL_USAGESERVICE_H_ */ diff --git a/Framework/Kernel/inc/MantidKernel/WarningSuppressions.h b/Framework/Kernel/inc/MantidKernel/WarningSuppressions.h index 25fadd77765..6240e9ee9c2 100644 --- a/Framework/Kernel/inc/MantidKernel/WarningSuppressions.h +++ b/Framework/Kernel/inc/MantidKernel/WarningSuppressions.h @@ -89,4 +89,10 @@ #endif // clang-format on +#ifdef GCC_VERSION +#define GCC_UNUSED_FUNCTION __attribute__((unused)) +#else +#define GCC_UNUSED_FUNCTION +#endif + #endif /*MANTID_KERNEL_WARNINGSUPPRESSIONS_H_*/ diff --git a/Framework/Kernel/inc/MantidKernel/cow_ptr.h b/Framework/Kernel/inc/MantidKernel/cow_ptr.h index 39083a92de7..6d90a463d59 100644 --- a/Framework/Kernel/inc/MantidKernel/cow_ptr.h +++ b/Framework/Kernel/inc/MantidKernel/cow_ptr.h @@ -64,22 +64,22 @@ private: std::mutex copyMutex; public: - cow_ptr(ptr_type &&resourceSptr); - cow_ptr(const ptr_type &resourceSptr); + cow_ptr(ptr_type &&resourceSptr) noexcept; + cow_ptr(const ptr_type &resourceSptr) noexcept; explicit cow_ptr(DataType *resourcePtr); cow_ptr(); /// Constructs a cow_ptr with no managed object, i.e. empty cow_ptr. - constexpr cow_ptr(std::nullptr_t) : Data(nullptr) {} - cow_ptr(const cow_ptr<DataType> &); + constexpr cow_ptr(std::nullptr_t) noexcept : Data(nullptr) {} + cow_ptr(const cow_ptr<DataType> &) noexcept; // Move is hand-written, since std::mutex member prevents auto-generation. cow_ptr(cow_ptr<DataType> &&other) noexcept : Data(std::move(other.Data)) {} - cow_ptr<DataType> &operator=(const cow_ptr<DataType> &); + cow_ptr<DataType> &operator=(const cow_ptr<DataType> &) noexcept; // Move is hand-written, since std::mutex member prevents auto-generation. cow_ptr<DataType> &operator=(cow_ptr<DataType> &&rhs) noexcept { Data = std::move(rhs.Data); return *this; } - cow_ptr<DataType> &operator=(const ptr_type &); + cow_ptr<DataType> &operator=(const ptr_type &) noexcept; /// Returns the stored pointer. const DataType *get() const noexcept { return Data.get(); } @@ -101,7 +101,7 @@ public: const DataType *operator->() const { return Data.get(); } ///<indirectrion dereference access - bool operator==(const cow_ptr<DataType> &A) { + bool operator==(const cow_ptr<DataType> &A) noexcept { return Data == A.Data; } ///< Based on ptr equality DataType &access(); @@ -128,8 +128,8 @@ cow_ptr<DataType>::cow_ptr() */ // Note: Need custom implementation, since std::mutex is not copyable. template <typename DataType> -cow_ptr<DataType>::cow_ptr(const cow_ptr<DataType> &A) - : Data(A.Data) {} +cow_ptr<DataType>::cow_ptr(const cow_ptr<DataType> &A) noexcept : Data(A.Data) { +} /** Assignment operator : double references the data object @@ -139,7 +139,8 @@ cow_ptr<DataType>::cow_ptr(const cow_ptr<DataType> &A) */ // Note: Need custom implementation, since std::mutex is not copyable. template <typename DataType> -cow_ptr<DataType> &cow_ptr<DataType>::operator=(const cow_ptr<DataType> &A) { +cow_ptr<DataType> &cow_ptr<DataType>:: +operator=(const cow_ptr<DataType> &A) noexcept { if (this != &A) { Data = A.Data; } @@ -153,7 +154,7 @@ cow_ptr<DataType> &cow_ptr<DataType>::operator=(const cow_ptr<DataType> &A) { @return *this */ template <typename DataType> -cow_ptr<DataType> &cow_ptr<DataType>::operator=(const ptr_type &A) { +cow_ptr<DataType> &cow_ptr<DataType>::operator=(const ptr_type &A) noexcept { if (this->Data != A) { Data = A; } @@ -187,12 +188,12 @@ template <typename DataType> DataType &cow_ptr<DataType>::access() { } template <typename DataType> -cow_ptr<DataType>::cow_ptr(ptr_type &&resourceSptr) { +cow_ptr<DataType>::cow_ptr(ptr_type &&resourceSptr) noexcept { this->Data = std::move(resourceSptr); } template <typename DataType> -cow_ptr<DataType>::cow_ptr(const ptr_type &resourceSptr) { +cow_ptr<DataType>::cow_ptr(const ptr_type &resourceSptr) noexcept { this->Data = resourceSptr; } diff --git a/Framework/Kernel/src/ArrayProperty.cpp b/Framework/Kernel/src/ArrayProperty.cpp index 0405a9b1f33..e1192f60a83 100644 --- a/Framework/Kernel/src/ArrayProperty.cpp +++ b/Framework/Kernel/src/ArrayProperty.cpp @@ -8,13 +8,13 @@ namespace Kernel { /// @cond -template DLLExport class ArrayProperty<int32_t>; -template DLLExport class ArrayProperty<int64_t>; -template DLLExport class ArrayProperty<size_t>; -template DLLExport class ArrayProperty<double>; -template DLLExport class ArrayProperty<std::string>; +template class DLLExport ArrayProperty<int32_t>; +template class DLLExport ArrayProperty<int64_t>; +template class DLLExport ArrayProperty<size_t>; +template class DLLExport ArrayProperty<double>; +template class DLLExport ArrayProperty<std::string>; -template DLLExport class ArrayProperty<std::vector<std::string>>; +template class DLLExport ArrayProperty<std::vector<std::string>>; /// @endcond diff --git a/Framework/Kernel/src/ConfigService.cpp b/Framework/Kernel/src/ConfigService.cpp index beac0703655..c9106861fe2 100644 --- a/Framework/Kernel/src/ConfigService.cpp +++ b/Framework/Kernel/src/ConfigService.cpp @@ -2048,6 +2048,7 @@ int ConfigServiceImpl::FindLowestFilterLevel() const { return lowestPriority; } + /// \cond TEMPLATE template DLLExport int ConfigServiceImpl::getValue(const std::string &, double &); diff --git a/Framework/Kernel/src/FilteredTimeSeriesProperty.cpp b/Framework/Kernel/src/FilteredTimeSeriesProperty.cpp index d9d361ec330..d470367a290 100644 --- a/Framework/Kernel/src/FilteredTimeSeriesProperty.cpp +++ b/Framework/Kernel/src/FilteredTimeSeriesProperty.cpp @@ -49,7 +49,7 @@ FilteredTimeSeriesProperty<HeldType>::unfiltered() const { // -------------------------- Macro to instantiation concrete types // -------------------------------- #define INSTANTIATE(TYPE) \ - template MANTID_KERNEL_DLL class FilteredTimeSeriesProperty<TYPE>; + template class MANTID_KERNEL_DLL FilteredTimeSeriesProperty<TYPE>; // -------------------------- Concrete instantiation // ----------------------------------------------- diff --git a/Framework/Kernel/src/GitHubApiHelper.cpp b/Framework/Kernel/src/GitHubApiHelper.cpp new file mode 100644 index 00000000000..0392c0d6e9b --- /dev/null +++ b/Framework/Kernel/src/GitHubApiHelper.cpp @@ -0,0 +1,115 @@ +#include "MantidKernel/GitHubApiHelper.h" +#include "MantidKernel/DateAndTime.h" +#include "MantidKernel/Logger.h" +#include <Poco/StreamCopier.h> +#include <Poco/URI.h> +#include <Poco/Net/HTTPRequest.h> +#include <Poco/Net/HTTPResponse.h> +#include <Poco/Net/HTTPSClientSession.h> + +namespace Mantid { +namespace Kernel { + +using namespace Poco::Net; +using std::map; +using std::string; + +namespace { +// anonymous namespace for some utility functions +/// static Logger object +Logger g_log("InternetHelper"); +} + +//---------------------------------------------------------------------------------------------- +/** Constructor +*/ +GitHubApiHelper::GitHubApiHelper() : InternetHelper() { + addAuthenticationToken(); +} + +//---------------------------------------------------------------------------------------------- +/** Constructor +*/ +GitHubApiHelper::GitHubApiHelper(const Kernel::ProxyInfo &proxy) + : InternetHelper(proxy) { + addAuthenticationToken(); +} + +void GitHubApiHelper::reset() { + InternetHelper::reset(); + addAuthenticationToken(); +} + +bool GitHubApiHelper::isAuthenticated() { + return (m_headers.find("Authorization") != m_headers.end()); +} + +void GitHubApiHelper::processResponseHeaders( + const Poco::Net::HTTPResponse &res) { + // get github api rate limit information if available; + int rateLimitRemaining = 0; + int rateLimitLimit; + DateAndTime rateLimitReset; + try { + rateLimitLimit = + boost::lexical_cast<int>(res.get("X-RateLimit-Limit", "-1")); + rateLimitRemaining = + boost::lexical_cast<int>(res.get("X-RateLimit-Remaining", "-1")); + rateLimitReset.set_from_time_t( + boost::lexical_cast<int>(res.get("X-RateLimit-Reset", "0"))); + } catch (boost::bad_lexical_cast const &) { + rateLimitLimit = -1; + } + if (rateLimitLimit > -1) { + g_log.debug() << "GitHub API " << rateLimitRemaining << " of " + << rateLimitLimit << " calls left. Resets at " + << rateLimitReset.toSimpleString() << " GMT\n"; + } +} + +int GitHubApiHelper::processAnonymousRequest( + const Poco::Net::HTTPResponse &response, Poco::URI &uri, + std::ostream &responseStream) { + if (isAuthenticated()) { + g_log.debug("Repeating API call anonymously\n"); + removeHeader("Authorization"); + return this->sendRequest(uri.toString(), responseStream); + } else { + g_log.warning("Authentication failed and anonymous access refused\n"); + return response.getStatus(); + } +} + +int GitHubApiHelper::sendRequestAndProcess(HTTPClientSession &session, + Poco::URI &uri, + std::ostream &responseStream) { + // create a request + this->createRequest(uri); + session.sendRequest(*m_request) << m_body; + + std::istream &rs = session.receiveResponse(*m_response); + int retStatus = m_response->getStatus(); + g_log.debug() << "Answer from web: " << retStatus << " " + << m_response->getReason() << "\n"; + + if (retStatus == HTTP_OK || + (retStatus == HTTP_CREATED && m_method == HTTPRequest::HTTP_POST)) { + Poco::StreamCopier::copyStream(rs, responseStream); + processResponseHeaders(*m_response); + return retStatus; + } else if ((retStatus == HTTP_FORBIDDEN && isAuthenticated()) || + (retStatus == HTTP_UNAUTHORIZED) || + (retStatus == HTTP_NOT_FOUND)) { + // If authentication fails you can get HTTP_UNAUTHORIZED or HTTP_NOT_FOUND + // If the limit runs out you can get HTTP_FORBIDDEN + return this->processAnonymousRequest(*m_response, uri, responseStream); + } else if (isRelocated(retStatus)) { + return this->processRelocation(*m_response, responseStream); + } else { + Poco::StreamCopier::copyStream(rs, responseStream); + return processErrorStates(*m_response, rs, uri.toString()); + } +} + +} // namespace Kernel +} // namespace Mantid diff --git a/Framework/Kernel/src/InternetHelper.cpp b/Framework/Kernel/src/InternetHelper.cpp index 9e9ba64ba5e..ac3d579f1f1 100644 --- a/Framework/Kernel/src/InternetHelper.cpp +++ b/Framework/Kernel/src/InternetHelper.cpp @@ -134,6 +134,7 @@ int InternetHelper::sendRequestAndProcess(HTTPClientSession &session, if (retStatus == HTTP_OK || (retStatus == HTTP_CREATED && m_method == HTTPRequest::HTTP_POST)) { Poco::StreamCopier::copyStream(rs, responseStream); + processResponseHeaders(*m_response); return retStatus; } else if (isRelocated(retStatus)) { return this->processRelocation(*m_response, responseStream); @@ -301,6 +302,11 @@ void InternetHelper::setProxy(const Kernel::ProxyInfo &proxy) { m_isProxySet = true; } +/** Process any headers from the response stream +Basic implementation does nothing. +*/ +void InternetHelper::processResponseHeaders(const Poco::Net::HTTPResponse &) {} + /** Process any HTTP errors states. @param res : The http response @@ -349,7 +355,7 @@ int InternetHelper::processErrorStates(const Poco::Net::HTTPResponse &res, } else if ((retStatus == HTTP_FORBIDDEN) && (rateLimitRemaining == 0)) { throw Exception::InternetError( "The Github API rate limit has been reached, try again after " + - rateLimitReset.toSimpleString(), + rateLimitReset.toSimpleString() + " GMT", retStatus); } else { std::stringstream info; diff --git a/Framework/Kernel/src/MaskedProperty.cpp b/Framework/Kernel/src/MaskedProperty.cpp index 527e148051c..71a17394590 100644 --- a/Framework/Kernel/src/MaskedProperty.cpp +++ b/Framework/Kernel/src/MaskedProperty.cpp @@ -77,7 +77,7 @@ template <typename TYPE> void MaskedProperty<TYPE>::doMasking() const { //--------------------------------------------------------------------------- ///@cond TEMPLATE -template MANTID_KERNEL_DLL class Mantid::Kernel::MaskedProperty<std::string>; +template class MANTID_KERNEL_DLL Mantid::Kernel::MaskedProperty<std::string>; ///@endcond TEMPLATE } // namespace API diff --git a/Framework/Kernel/src/Matrix.cpp b/Framework/Kernel/src/Matrix.cpp index b0febc89129..4037e3bd37b 100644 --- a/Framework/Kernel/src/Matrix.cpp +++ b/Framework/Kernel/src/Matrix.cpp @@ -1598,7 +1598,13 @@ void fillFromStream(std::istream &is, Kernel::Matrix<T> &in, // Symbol definitions for common types template class MANTID_KERNEL_DLL Matrix<double>; -template class MANTID_KERNEL_DLL Matrix<int>; +// The explicit template instantiation for int does not have an export macro +// since this produces a warning on "gcc: warning: type attributes ignored after +// type is already define" The reason for this is the use of Matrix<int> +// in a template specialization above, causing an implicit sepcialization. +// This, most likely, obtains a visibility setting from the general template +// definition. +template class Matrix<int>; template class MANTID_KERNEL_DLL Matrix<float>; template MANTID_KERNEL_DLL std::ostream &operator<<(std::ostream &, diff --git a/Framework/Kernel/src/PropertyWithValue.cpp b/Framework/Kernel/src/PropertyWithValue.cpp index b853a1196ae..ba8ba9cecf3 100644 --- a/Framework/Kernel/src/PropertyWithValue.cpp +++ b/Framework/Kernel/src/PropertyWithValue.cpp @@ -25,21 +25,40 @@ PROPERTYWITHVALUE_SAVEPROPERTY(std::vector<double>) PROPERTYWITHVALUE_SAVEPROPERTY(std::vector<int32_t>) /// @cond -#define INSTANTIATE(Type) \ - template DLLExport class PropertyWithValue<Type>; \ - template DLLExport class PropertyWithValue<std::vector<Type>>; +#define INSTANTIATE_WITH_EXPORT(Type) \ + template class DLLExport PropertyWithValue<Type>; // Explicit instantiations -INSTANTIATE(int32_t) -INSTANTIATE(int64_t) -INSTANTIATE(uint16_t) -INSTANTIATE(uint32_t) -INSTANTIATE(uint64_t) -INSTANTIATE(bool) -INSTANTIATE(OptionalBool) -INSTANTIATE(double) -INSTANTIATE(std::string) +INSTANTIATE_WITH_EXPORT(uint16_t) +INSTANTIATE_WITH_EXPORT(bool) +INSTANTIATE_WITH_EXPORT(OptionalBool) /// @endcond +#define INSTANTIATE_WITH_EXPORT_VECTOR(Type) \ + template class DLLExport PropertyWithValue<std::vector<Type>>; +INSTANTIATE_WITH_EXPORT_VECTOR(uint16_t) +INSTANTIATE_WITH_EXPORT_VECTOR(uint32_t) +INSTANTIATE_WITH_EXPORT_VECTOR(int64_t) +INSTANTIATE_WITH_EXPORT_VECTOR(uint64_t) +INSTANTIATE_WITH_EXPORT_VECTOR(bool) +INSTANTIATE_WITH_EXPORT_VECTOR(OptionalBool) +INSTANTIATE_WITH_EXPORT_VECTOR(std::string) + +// The explicit template instantiations for some types does not have an export +// macro +// since this produces a warning on "gcc: warning: type attributes ignored after +// type is already define". We can remove the issue, by removing the visibility +// attribute +template class PropertyWithValue<double>; +template class PropertyWithValue<std::vector<double>>; + +template class PropertyWithValue<int32_t>; +template class PropertyWithValue<std::vector<int32_t>>; + +template class PropertyWithValue<uint32_t>; +template class PropertyWithValue<int64_t>; +template class PropertyWithValue<uint64_t>; +template class PropertyWithValue<std::string>; + } // namespace Kernel } // namespace Mantid diff --git a/Framework/Kernel/src/TimeSeriesProperty.cpp b/Framework/Kernel/src/TimeSeriesProperty.cpp index d80ebe54607..791dbd219bc 100644 --- a/Framework/Kernel/src/TimeSeriesProperty.cpp +++ b/Framework/Kernel/src/TimeSeriesProperty.cpp @@ -368,12 +368,10 @@ void TimeSeriesProperty<TYPE>::filterByTimes( TimeValueUnit<TYPE> temp(t_start, m_values[tstartindex].value()); mp_copy.push_back(temp); } else { - mp_copy.push_back( - TimeValueUnit<TYPE>(t_start, m_values[tstartindex].value())); + mp_copy.emplace_back(t_start, m_values[tstartindex].value()); for (size_t im = size_t(tstartindex + 1); im <= size_t(tstopindex); ++im) { - mp_copy.push_back( - TimeValueUnit<TYPE>(m_values[im].time(), m_values[im].value())); + mp_copy.emplace_back(m_values[im].time(), m_values[im].value()); } } } // ENDFOR @@ -615,7 +613,7 @@ void TimeSeriesProperty<TYPE>::makeFilterByValue( // boundaries are centred. // Otherwise, use the first 'bad' time. stop = centre ? lastTime + tol : t; - split.push_back(SplittingInterval(start, stop, 0)); + split.emplace_back(start, stop, 0); // Reset the number of good ones, for next time numgood = 0; } @@ -627,7 +625,7 @@ void TimeSeriesProperty<TYPE>::makeFilterByValue( // The log ended on "good" so we need to close it using the last time we // found stop = t + tol; - split.push_back(SplittingInterval(start, stop, 0)); + split.emplace_back(start, stop, 0); } } @@ -678,7 +676,7 @@ void TimeSeriesProperty<TYPE>::expandFilterToRange( double val = firstValue(); if ((val >= min) && (val <= max)) { TimeSplitterType extraFilter; - extraFilter.push_back(SplittingInterval(range.begin(), firstTime(), 0)); + extraFilter.emplace_back(range.begin(), firstTime(), 0); // Include everything from the start of the run to the first time measured // (which may be a null time interval; this'll be ignored) split = split | extraFilter; @@ -688,7 +686,7 @@ void TimeSeriesProperty<TYPE>::expandFilterToRange( val = lastValue(); if ((val >= min) && (val <= max)) { TimeSplitterType extraFilter; - extraFilter.push_back(SplittingInterval(lastTime(), range.end(), 0)); + extraFilter.emplace_back(lastTime(), range.end(), 0); // Include everything from the start of the run to the first time measured // (which may be a null time interval; this'll be ignored) split = split | extraFilter; @@ -767,7 +765,7 @@ double TimeSeriesProperty<TYPE>::timeAverageValue() const { double retVal = 0.0; try { TimeSplitterType filter; - filter.push_back(SplittingInterval(this->firstTime(), this->lastTime())); + filter.emplace_back(this->firstTime(), this->lastTime()); retVal = this->averageValueInFilter(filter); } catch (std::exception &) { // just return nan @@ -2145,8 +2143,7 @@ void TimeSeriesProperty<TYPE>::saveProperty(::NeXus::File *file) { /// @cond // -------------------------- Macro to instantiation concrete types // -------------------------------- -#define INSTANTIATE(TYPE) \ - template MANTID_KERNEL_DLL class TimeSeriesProperty<TYPE>; +#define INSTANTIATE(TYPE) template class TimeSeriesProperty<TYPE>; // -------------------------- Concrete instantiation // ----------------------------------------------- diff --git a/Framework/Kernel/src/TimeSplitter.cpp b/Framework/Kernel/src/TimeSplitter.cpp index 2a3f0068b8c..f4bcd032e6d 100644 --- a/Framework/Kernel/src/TimeSplitter.cpp +++ b/Framework/Kernel/src/TimeSplitter.cpp @@ -168,6 +168,7 @@ TimeSplitterType operator&(const TimeSplitterType &a, */ TimeSplitterType removeFilterOverlap(const TimeSplitterType &a) { TimeSplitterType out; + out.reserve(a.size()); // Now we have to merge duplicate/overlapping intervals together auto it = a.cbegin(); @@ -186,7 +187,7 @@ TimeSplitterType removeFilterOverlap(const TimeSplitterType &a) { ++it; } // We've reached a gap point. Output this merged interval and move on. - out.push_back(SplittingInterval(start, stop, 0)); + out.emplace_back(start, stop, 0); } return out; @@ -242,8 +243,7 @@ TimeSplitterType operator~(const TimeSplitterType &a) { // No entries: then make a "filter" that keeps everything if ((temp.empty())) { - out.push_back( - SplittingInterval(DateAndTime::minimum(), DateAndTime::maximum(), 0)); + out.emplace_back(DateAndTime::minimum(), DateAndTime::maximum(), 0); return out; } @@ -251,7 +251,7 @@ TimeSplitterType operator~(const TimeSplitterType &a) { ait = temp.begin(); if (ait != temp.end()) { // First entry; start at -infinite time - out.push_back(SplittingInterval(DateAndTime::minimum(), ait->start(), 0)); + out.emplace_back(DateAndTime::minimum(), ait->start(), 0); // Now start at the second entry while (ait != temp.end()) { DateAndTime start, stop; @@ -262,7 +262,7 @@ TimeSplitterType operator~(const TimeSplitterType &a) { } else { // Stop at the start of the next entry stop = ait->start(); } - out.push_back(SplittingInterval(start, stop, 0)); + out.emplace_back(start, stop, 0); } } return out; diff --git a/Framework/Kernel/src/UsageService.cpp b/Framework/Kernel/src/UsageService.cpp index 36fcb194cbc..22184353c65 100644 --- a/Framework/Kernel/src/UsageService.cpp +++ b/Framework/Kernel/src/UsageService.cpp @@ -301,5 +301,5 @@ int UsageServiceImpl::sendReport(const std::string &message, return status; } -} // namespace API +} // namespace Kernel } // namespace Mantid diff --git a/Framework/Kernel/src/VMD.cpp b/Framework/Kernel/src/VMD.cpp index 18f55ed2133..2d0a526fff2 100644 --- a/Framework/Kernel/src/VMD.cpp +++ b/Framework/Kernel/src/VMD.cpp @@ -5,22 +5,6 @@ using namespace Mantid::Kernel; namespace Mantid { namespace Kernel { -/** - Prints a text representation of itself - @param os :: the Stream to output to - @param v :: the vector to output - @return the output stream - */ -std::ostream &operator<<(std::ostream &os, const VMDBase<double> &v) { - os << v.toString(); - return os; -} - -std::ostream &operator<<(std::ostream &os, const VMDBase<float> &v) { - os << v.toString(); - return os; -} - //------------------------------------------------------------------------------------------------- /** Make an orthogonal system with 2 input 3D vectors. * Currently only works in 3D! @@ -133,8 +117,24 @@ VMDBase<TYPE>::getNormalVector(const std::vector<VMDBase<TYPE>> &vectors) { } /// Instantiate VMDBase classes -template MANTID_KERNEL_DLL class VMDBase<double>; -template MANTID_KERNEL_DLL class VMDBase<float>; +template class MANTID_KERNEL_DLL VMDBase<double>; +template class MANTID_KERNEL_DLL VMDBase<float>; + +/** + Prints a text representation of itself + @param os :: the Stream to output to + @param v :: the vector to output + @return the output stream + */ +std::ostream &operator<<(std::ostream &os, const VMDBase<double> &v) { + os << v.toString(); + return os; +} + +std::ostream &operator<<(std::ostream &os, const VMDBase<float> &v) { + os << v.toString(); + return os; +} } // namespace Mantid } // namespace Kernel diff --git a/Framework/MDAlgorithms/CMakeLists.txt b/Framework/MDAlgorithms/CMakeLists.txt index a8c540120e6..375a9b07e1a 100644 --- a/Framework/MDAlgorithms/CMakeLists.txt +++ b/Framework/MDAlgorithms/CMakeLists.txt @@ -57,6 +57,7 @@ set ( SRC_FILES src/IntegrateMDHistoWorkspace.cpp src/IntegratePeaksMD.cpp src/IntegratePeaksMD2.cpp + src/IntegratePeaksMDHKL.cpp src/IntegratePeaksCWSD.cpp src/InvalidParameter.cpp src/InvalidParameterParser.cpp @@ -185,6 +186,7 @@ set ( INC_FILES inc/MantidMDAlgorithms/IntegrateMDHistoWorkspace.h inc/MantidMDAlgorithms/IntegratePeaksMD.h inc/MantidMDAlgorithms/IntegratePeaksMD2.h + inc/MantidMDAlgorithms/IntegratePeaksMDHKL.h inc/MantidMDAlgorithms/IntegratePeaksCWSD.h inc/MantidMDAlgorithms/InvalidParameter.h inc/MantidMDAlgorithms/InvalidParameterParser.h @@ -312,6 +314,7 @@ set ( TEST_FILES IntegrateFluxTest.h IntegrateMDHistoWorkspaceTest.h IntegratePeaksMD2Test.h + IntegratePeaksMDHKLTest.h IntegratePeaksMDTest.h IntegratePeaksCWSDTest.h InvalidParameterParserTest.h diff --git a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/CreateMDWorkspace.h b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/CreateMDWorkspace.h index 918b60de6ae..5b9c8aaa67b 100644 --- a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/CreateMDWorkspace.h +++ b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/CreateMDWorkspace.h @@ -6,10 +6,14 @@ #include "MantidDataObjects/MDEventFactory.h" #include "MantidDataObjects/MDEventWorkspace.h" #include "MantidGeometry/MDGeometry/MDFrame.h" +#include "MantidMDAlgorithms/DllConfig.h" namespace Mantid { namespace MDAlgorithms { +std::vector<std::string> MANTID_MDALGORITHMS_DLL +parseNames(const std::string &names_string); + /** CreateMDWorkspace : * * Algorithm to create an empty MDEventWorkspace with a given number of diff --git a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/DllConfig.h b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/DllConfig.h index db73b6e65b0..afcde3a7a0c 100644 --- a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/DllConfig.h +++ b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/DllConfig.h @@ -32,8 +32,10 @@ #ifdef IN_MANTID_MDALGORITHMS #define MANTID_MDALGORITHMS_DLL DLLExport +#define EXTERN_MANTID_MDALGORITHMS #else #define MANTID_MDALGORITHMS_DLL DLLImport +#define EXTERN_MANTID_MDALGORITHMS EXTERN_IMPORT #endif /* IN_MANTID_MDALGORITHMS*/ #endif // MANTID_MDALGORITHMS_DLLCONFIG_H_ diff --git a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/IntegratePeaksMDHKL.h b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/IntegratePeaksMDHKL.h new file mode 100644 index 00000000000..b97d605f74c --- /dev/null +++ b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/IntegratePeaksMDHKL.h @@ -0,0 +1,59 @@ +#ifndef MANTID_MDALGORITHMS_INTEGRATEPEAKSMDHKL_H_ +#define MANTID_MDALGORITHMS_INTEGRATEPEAKSMDHKL_H_ + +#include "MantidAPI/Algorithm.h" +#include "MantidAPI/IMDHistoWorkspace_fwd.h" +#include "MantidDataObjects/PeaksWorkspace.h" +#include "MantidKernel/System.h" +#include "MantidDataObjects/MDHistoWorkspace.h" +#include "MantidAPI/IMDEventWorkspace_fwd.h" +#include "MantidDataObjects/MDEventWorkspace.h" + +namespace Mantid { +namespace MDAlgorithms { + +/** Integrate single-crystal peaks in reciprocal-space. + * + * @author Vickie Lynch + * @date 2016-06-23 + */ +class DLLExport IntegratePeaksMDHKL : public API::Algorithm { +public: + /// Algorithm's name for identification + const std::string name() const override { return "IntegratePeaksMDHKL"; }; + /// Summary of algorithms purpose + const std::string summary() const override { + return "Integrate single-crystal peaks in reciprocal space, for " + "MDHistoWorkspaces."; + } + + /// Algorithm's version for identification + int version() const override { return 1; }; + /// Algorithm's category for identification + const std::string category() const override { return "MDAlgorithms\\Peaks"; } + +private: + /// Initialise the properties + void init() override; + /// Run the algorithm + void exec() override; + + DataObjects::MDHistoWorkspace_sptr + normalize(int h, int k, int l, double box, int gridPts, + const API::MatrixWorkspace_sptr &flux, + const API::MatrixWorkspace_sptr &sa, + const API::IMDEventWorkspace_sptr &ws); + DataObjects::MDHistoWorkspace_sptr binEvent(int h, int k, int l, double box, + int gridPts, + const API::IMDWorkspace_sptr &ws); + DataObjects::MDHistoWorkspace_sptr + cropHisto(int h, int k, int l, double box, const API::IMDWorkspace_sptr &ws); + void integratePeak(const int neighborPts, + DataObjects::MDHistoWorkspace_sptr out, double &intensity, + double &errorSquared); +}; + +} // namespace Mantid +} // namespace DataObjects + +#endif /* MANTID_MDALGORITHMS_INTEGRATEPEAKSMDHKL_H_ */ diff --git a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/MDTransfFactory.h b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/MDTransfFactory.h index a50b86a7cac..bfe1777de98 100644 --- a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/MDTransfFactory.h +++ b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/MDTransfFactory.h @@ -108,13 +108,6 @@ private: m_createdTransf; }; -/// Forward declaration of a specialization of SingletonHolder for -/// AlgorithmFactoryImpl (needed for dllexport/dllimport) . -#ifdef _WIN32 -// this breaks new namespace declaration rules; need to find a better fix -template class MANTID_MDALGORITHMS_DLL - Mantid::Kernel::SingletonHolder<MDTransfFactoryImpl>; -#endif /* _WIN32 */ /// The specialization of the SingletonHolder class that holds the /// MDTransformations Factory typedef Kernel::SingletonHolder<MDTransfFactoryImpl> MDTransfFactory; @@ -122,4 +115,11 @@ typedef Kernel::SingletonHolder<MDTransfFactoryImpl> MDTransfFactory; } // namespace MDAlgorithms } // namespace Mantid +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_MDALGORITHMS template class MANTID_MDALGORITHMS_DLL + Mantid::Kernel::SingletonHolder<Mantid::MDAlgorithms::MDTransfFactoryImpl>; +} +} + #endif diff --git a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/Quantification/ForegroundModelFactory.h b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/Quantification/ForegroundModelFactory.h index 5bb9e80788b..18c411cffe9 100644 --- a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/Quantification/ForegroundModelFactory.h +++ b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/Quantification/ForegroundModelFactory.h @@ -64,16 +64,16 @@ private: using BaseClass::createUnwrapped; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// ForegroundModelFactoryImpl (needed for dllexport/dllimport). -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class MANTID_MDALGORITHMS_DLL - Kernel::SingletonHolder<ForegroundModelFactoryImpl>; -#endif /* _WIN32 */ /// Typedef singleton instance to ForegroundFactory -typedef MANTID_MDALGORITHMS_DLL - Kernel::SingletonHolder<ForegroundModelFactoryImpl> ForegroundModelFactory; +typedef Kernel::SingletonHolder<ForegroundModelFactoryImpl> + ForegroundModelFactory; +} +} + +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_MDALGORITHMS template class MANTID_MDALGORITHMS_DLL + Kernel::SingletonHolder<Mantid::MDAlgorithms::ForegroundModelFactoryImpl>; } } diff --git a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/Quantification/MDResolutionConvolutionFactory.h b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/Quantification/MDResolutionConvolutionFactory.h index 005d9af1314..104df8efe99 100644 --- a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/Quantification/MDResolutionConvolutionFactory.h +++ b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/Quantification/MDResolutionConvolutionFactory.h @@ -63,16 +63,16 @@ private: using BaseClass::createUnwrapped; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// MDResolutionConvolutionFactoryImpl (needed for dllexport/dllimport). -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class MANTID_MDALGORITHMS_DLL - Kernel::SingletonHolder<MDResolutionConvolutionFactoryImpl>; -#endif /* _WIN32 */ /// Typedef singleton instance to MDResolutionConvolutionFactory -typedef MANTID_MDALGORITHMS_DLL Kernel::SingletonHolder< - MDResolutionConvolutionFactoryImpl> MDResolutionConvolutionFactory; +typedef Kernel::SingletonHolder<MDResolutionConvolutionFactoryImpl> + MDResolutionConvolutionFactory; +} +} + +namespace Mantid { +namespace Kernel { +EXTERN_MANTID_MDALGORITHMS template class MANTID_MDALGORITHMS_DLL Kernel:: + SingletonHolder<Mantid::MDAlgorithms::MDResolutionConvolutionFactoryImpl>; } } diff --git a/Framework/MDAlgorithms/src/CreateMDWorkspace.cpp b/Framework/MDAlgorithms/src/CreateMDWorkspace.cpp index e78104c9860..7a23dca48ea 100644 --- a/Framework/MDAlgorithms/src/CreateMDWorkspace.cpp +++ b/Framework/MDAlgorithms/src/CreateMDWorkspace.cpp @@ -14,6 +14,9 @@ #include "MantidKernel/ListValidator.h" #include "MantidKernel/Memory.h" #include "MantidKernel/System.h" +#include "MantidKernel/MandatoryValidator.h" +#include <boost/algorithm/string.hpp> +#include <boost/regex.hpp> #include <cmath> namespace Mantid { @@ -22,6 +25,32 @@ using namespace Mantid::Kernel; using namespace Mantid::API; using namespace Mantid::Geometry; using namespace Mantid::DataObjects; +using boost::regex; + +/* + * The list of dimension names often looks like "[H,0,0],[0,K,0]" with "[H,0,0]" + * being the first dimension but getProperty returns a vector of + * the string split on every comma + * This function parses the string, and does not split on commas within brackets + */ +std::vector<std::string> parseNames(const std::string &names_string) { + + // This regex has two parts which are separated by the "|" (or) + // The first part matches anything which is bounded by square brackets + // unless they contain square brackets (so that it only matches inner pairs) + // The second part matches anything that doesn't contain a comma + // NB, the order of the two parts matters + + regex expression("\\[([^\\[]*)\\]|[^,]+"); + + boost::sregex_token_iterator iter(names_string.begin(), names_string.end(), + expression, 0); + boost::sregex_token_iterator end; + + std::vector<std::string> names_result(iter, end); + + return names_result; +} // Register the algorithm into the AlgorithmFactory DECLARE_ALGORITHM(CreateMDWorkspace) @@ -43,8 +72,9 @@ void CreateMDWorkspace::init() { "A comma separated list of min, max for each dimension,\n" "specifying the extents of each dimension."); - declareProperty(make_unique<ArrayProperty<std::string>>("Names"), - "A comma separated list of the name of each dimension."); + declareProperty( + make_unique<ArrayProperty<std::string>>("Names", Direction::Input), + "A comma separated list of the name of each dimension."); declareProperty(make_unique<ArrayProperty<std::string>>("Units"), "A comma separated list of the units of each dimension."); @@ -131,7 +161,9 @@ void CreateMDWorkspace::exec() { size_t ndims = static_cast<size_t>(ndims_prop); std::vector<double> extents = getProperty("Extents"); - std::vector<std::string> names = getProperty("Names"); + std::string dimensions_string = getPropertyValue("Names"); + std::vector<std::string> names = parseNames(dimensions_string); + std::vector<std::string> units = getProperty("Units"); std::vector<std::string> frames = getProperty("Frames"); diff --git a/Framework/MDAlgorithms/src/IntegratePeaksMDHKL.cpp b/Framework/MDAlgorithms/src/IntegratePeaksMDHKL.cpp new file mode 100644 index 00000000000..b15a998f7b0 --- /dev/null +++ b/Framework/MDAlgorithms/src/IntegratePeaksMDHKL.cpp @@ -0,0 +1,314 @@ +#include "MantidMDAlgorithms/IntegratePeaksMDHKL.h" +#include "MantidDataObjects/MDFramesToSpecialCoordinateSystem.h" +#include "MantidAPI/CommonBinsValidator.h" +#include "MantidAPI/InstrumentValidator.h" +#include "MantidAPI/WorkspaceUnitValidator.h" +#include "MantidDataObjects/EventWorkspace.h" +#include "MantidDataObjects/MDEventWorkspace.h" +#include "MantidDataObjects/MDHistoWorkspace.h" +#include "MantidGeometry/Instrument.h" +#include "MantidKernel/CompositeValidator.h" +#include "MantidGeometry/Crystal/IPeak.h" +#include <boost/math/special_functions/round.hpp> +#include <algorithm> +#include <limits> + +namespace Mantid { +namespace MDAlgorithms { + +using Mantid::Kernel::Direction; +// using Mantid::API::WorkspaceProperty; +using namespace Mantid::DataObjects; +using namespace Mantid::API; +using namespace Mantid::Kernel; +using namespace Mantid::Geometry; + +// Register the algorithm into the AlgorithmFactory +DECLARE_ALGORITHM(IntegratePeaksMDHKL) + +//---------------------------------------------------------------------------------------------- +/** + * Initialize the algorithm's properties. + */ +void IntegratePeaksMDHKL::init() { + declareProperty( + make_unique<WorkspaceProperty<IMDWorkspace>>("InputWorkspace", "", + Direction::Input), + "An input Sample MDHistoWorkspace or MDEventWorkspace in HKL."); + declareProperty("DeltaHKL", 0.5, + "Distance from integer HKL to integrate peak."); + declareProperty("GridPoints", 201, + "Number of grid points for each dimension of HKL box."); + declareProperty("NeighborPoints", 10, "Number of points in 5^3 surrounding " + "points above intensity threshold for " + "point to be part of peak."); + auto fluxValidator = boost::make_shared<CompositeValidator>(); + fluxValidator->add<WorkspaceUnitValidator>("Momentum"); + fluxValidator->add<InstrumentValidator>(); + fluxValidator->add<CommonBinsValidator>(); + auto solidAngleValidator = fluxValidator->clone(); + + declareProperty( + make_unique<WorkspaceProperty<>>("FluxWorkspace", "", Direction::Input, + PropertyMode::Optional, fluxValidator), + "An optional input workspace containing momentum dependent flux for " + "normalization."); + declareProperty(make_unique<WorkspaceProperty<>>( + "SolidAngleWorkspace", "", Direction::Input, + PropertyMode::Optional, solidAngleValidator), + "An optional input workspace containing momentum integrated " + "vanadium for normalization " + "(a measure of the solid angle)."); + + declareProperty(make_unique<WorkspaceProperty<PeaksWorkspace>>( + "PeaksWorkspace", "", Direction::Input), + "A PeaksWorkspace containing the peaks to integrate."); + + declareProperty( + make_unique<WorkspaceProperty<PeaksWorkspace>>("OutputWorkspace", "", + Direction::Output), + "The output PeaksWorkspace will be a copy of the input PeaksWorkspace " + "with the peaks' integrated intensities."); +} + +//---------------------------------------------------------------------------------------------- +/** + * Execute the algorithm. + */ +void IntegratePeaksMDHKL::exec() { + IMDWorkspace_sptr m_inputWS = getProperty("InputWorkspace"); + Mantid::DataObjects::MDFramesToSpecialCoordinateSystem converter; + boost::optional<Mantid::Kernel::SpecialCoordinateSystem> coordinateSystem = + converter(m_inputWS.get()); + if (*coordinateSystem != Mantid::Kernel::SpecialCoordinateSystem::HKL) { + std::stringstream errmsg; + errmsg << "Input MDWorkspace's coordinate system is not HKL."; + throw std::invalid_argument(errmsg.str()); + } + + /// Peak workspace to integrate + PeaksWorkspace_sptr inPeakWS = getProperty("PeaksWorkspace"); + const double box = getProperty("DeltaHKL"); + const int gridPts = getProperty("GridPoints"); + const int neighborPts = getProperty("NeighborPoints"); + /// Output peaks workspace, create if needed + PeaksWorkspace_sptr peakWS = getProperty("OutputWorkspace"); + if (peakWS != inPeakWS) + peakWS = inPeakWS->clone(); + + MatrixWorkspace_sptr flux = getProperty("FluxWorkspace"); + MatrixWorkspace_sptr sa = getProperty("SolidAngleWorkspace"); + + IMDEventWorkspace_sptr m_eventWS = + boost::dynamic_pointer_cast<IMDEventWorkspace>(m_inputWS); + IMDHistoWorkspace_sptr m_histoWS = + boost::dynamic_pointer_cast<IMDHistoWorkspace>(m_inputWS); + int npeaks = peakWS->getNumberPeaks(); + + auto prog = make_unique<Progress>(this, 0.3, 1.0, npeaks); + PARALLEL_FOR1(peakWS) + for (int i = 0; i < npeaks; i++) { + PARALLEL_START_INTERUPT_REGION + + IPeak &p = peakWS->getPeak(i); + // round to integer + int h = static_cast<int>(boost::math::iround(p.getH())); + int k = static_cast<int>(boost::math::iround(p.getK())); + int l = static_cast<int>(boost::math::iround(p.getL())); + MDHistoWorkspace_sptr histoBox; + if (m_histoWS) { + histoBox = cropHisto(h, k, l, box, m_histoWS); + } else if (sa && flux) { + histoBox = normalize(h, k, l, box, gridPts, flux, sa, m_eventWS); + } else { + histoBox = binEvent(h, k, l, box, gridPts, m_eventWS); + } + double intensity = 0.0; + double errorSquared = 0.0; + integratePeak(neighborPts, histoBox, intensity, errorSquared); + p.setIntensity(intensity); + p.setSigmaIntensity(sqrt(errorSquared)); + prog->report(); + PARALLEL_END_INTERUPT_REGION + } + PARALLEL_CHECK_INTERUPT_REGION + // Save the output + setProperty("OutputWorkspace", peakWS); +} + +MDHistoWorkspace_sptr +IntegratePeaksMDHKL::normalize(int h, int k, int l, double box, int gridPts, + const MatrixWorkspace_sptr &flux, + const MatrixWorkspace_sptr &sa, + const IMDEventWorkspace_sptr &ws) { + IAlgorithm_sptr normAlg = createChildAlgorithm("MDNormSCD"); + normAlg->setProperty("InputWorkspace", ws); + normAlg->setProperty("AlignedDim0", + "[H,0,0]," + boost::lexical_cast<std::string>(h - box) + + "," + boost::lexical_cast<std::string>(h + box) + + "," + std::to_string(gridPts)); + normAlg->setProperty("AlignedDim1", + "[0,K,0]," + boost::lexical_cast<std::string>(k - box) + + "," + boost::lexical_cast<std::string>(k + box) + + "," + std::to_string(gridPts)); + normAlg->setProperty("AlignedDim2", + "[0,0,L]," + boost::lexical_cast<std::string>(l - box) + + "," + boost::lexical_cast<std::string>(l + box) + + "," + std::to_string(gridPts)); + normAlg->setProperty("FluxWorkspace", flux); + normAlg->setProperty("SolidAngleWorkspace", sa); + normAlg->setProperty("OutputWorkspace", "mdout"); + normAlg->setProperty("OutputNormalizationWorkspace", "mdnorm"); + normAlg->executeAsChildAlg(); + Workspace_sptr mdout = normAlg->getProperty("OutputWorkspace"); + Workspace_sptr mdnorm = normAlg->getProperty("OutputNormalizationWorkspace"); + + IAlgorithm_sptr alg = createChildAlgorithm("DivideMD"); + alg->setProperty("LHSWorkspace", mdout); + alg->setProperty("RHSWorkspace", mdnorm); + alg->setPropertyValue("OutputWorkspace", "out"); + alg->execute(); + IMDWorkspace_sptr out = alg->getProperty("OutputWorkspace"); + return boost::dynamic_pointer_cast<MDHistoWorkspace>(out); +} + +void IntegratePeaksMDHKL::integratePeak(const int neighborPts, + MDHistoWorkspace_sptr out, + double &intensity, + double &errorSquared) { + std::vector<int> gridPts; + const size_t dimensionality = out->getNumDims(); + for (size_t i = 0; i < dimensionality; ++i) { + gridPts.push_back(static_cast<int>(out->getDimension(i)->getNBins())); + } + + double *F = out->getSignalArray(); + double Fmax = 0.; + double Fmin = std::numeric_limits<double>::max(); + double sum = 0.0; + for (int i = 0; i < gridPts[0] * gridPts[1] * gridPts[2]; i++) { + if (std::isnormal(F[i])) { + sum += F[i]; + Fmin = std::min(Fmin, F[i]); + Fmax = std::max(Fmax, F[i]); + } + } + double *SqError = out->getErrorSquaredArray(); + + double minIntensity = Fmin + 0.01 * (Fmax - Fmin); + int measuredPoints = 0; + int peakPoints = 0; + double peakSum = 0.0; + double measuredSum = 0.0; + double errSqSum = 0.0; + double measuredErrSqSum = 0.0; + for (int Hindex = 0; Hindex < gridPts[0]; Hindex++) { + for (int Kindex = 0; Kindex < gridPts[1]; Kindex++) { + for (int Lindex = 0; Lindex < gridPts[2]; Lindex++) { + int iHKL = Hindex + gridPts[0] * (Kindex + gridPts[1] * Lindex); + if (std::isfinite(F[iHKL])) { + measuredPoints = measuredPoints + 1; + measuredSum = measuredSum + F[iHKL]; + measuredErrSqSum = measuredErrSqSum + SqError[iHKL]; + if (F[iHKL] > minIntensity) { + int neighborPoints = 0; + for (int Hj = -2; Hj < 3; Hj++) { + for (int Kj = -2; Kj < 3; Kj++) { + for (int Lj = -2; Lj < 3; Lj++) { + int jHKL = + Hindex + Hj + + gridPts[0] * (Kindex + Kj + gridPts[1] * (Lindex + Lj)); + if (Lindex + Lj >= 0 && Lindex + Lj < gridPts[2] && + Kindex + Kj >= 0 && Kindex + Kj < gridPts[1] && + Hindex + Hj >= 0 && Hindex + Hj < gridPts[0] && + F[jHKL] > minIntensity) { + neighborPoints = neighborPoints + 1; + } + } + } + } + if (neighborPoints >= neighborPts) { + peakPoints = peakPoints + 1; + peakSum = peakSum + F[iHKL]; + errSqSum = errSqSum + SqError[iHKL]; + } + } + } else { + double minR = + sqrt(std::pow(float(Hindex) / float(gridPts[0]) - 0.5, 2) + + std::pow(float(Kindex) / float(gridPts[1]) - 0.5, 2) + + std::pow(float(Lindex) / float(gridPts[0]) - 0.5, 2)); + if (minR < 0.05) { + intensity = 0.0; + errorSquared = 0.0; + return; + } + } + } + } + } + double ratio = float(peakPoints) / float(measuredPoints - peakPoints); + intensity = peakSum - ratio * (measuredSum - peakSum); + errorSquared = errSqSum + ratio * (measuredErrSqSum - errSqSum); + return; +} + +/** + * Runs the BinMD algorithm on the input to provide the output workspace + * All slicing algorithm properties are passed along + * @return MDHistoWorkspace as a result of the binning + */ +MDHistoWorkspace_sptr +IntegratePeaksMDHKL::binEvent(int h, int k, int l, double box, int gridPts, + const IMDWorkspace_sptr &ws) { + IAlgorithm_sptr binMD = createChildAlgorithm("BinMD", 0.0, 0.3); + binMD->setProperty("InputWorkspace", ws); + binMD->setProperty("AlignedDim0", + "[H,0,0]," + boost::lexical_cast<std::string>(h - box) + + "," + boost::lexical_cast<std::string>(h + box) + "," + + std::to_string(gridPts)); + binMD->setProperty("AlignedDim1", + "[0,K,0]," + boost::lexical_cast<std::string>(k - box) + + "," + boost::lexical_cast<std::string>(k + box) + "," + + std::to_string(gridPts)); + binMD->setProperty("AlignedDim2", + "[0,0,L]," + boost::lexical_cast<std::string>(l - box) + + "," + boost::lexical_cast<std::string>(l + box) + "," + + std::to_string(gridPts)); + binMD->setPropertyValue("AxisAligned", "1"); + binMD->setPropertyValue("OutputWorkspace", "out"); + binMD->executeAsChildAlg(); + Workspace_sptr outputWS = binMD->getProperty("OutputWorkspace"); + return boost::dynamic_pointer_cast<MDHistoWorkspace>(outputWS); +} + +/** + * Runs the BinMD algorithm on the input to provide the output workspace + * All slicing algorithm properties are passed along + * @return MDHistoWorkspace as a result of the binning + */ +MDHistoWorkspace_sptr +IntegratePeaksMDHKL::cropHisto(int h, int k, int l, double box, + const IMDWorkspace_sptr &ws) { + IAlgorithm_sptr cropMD = + createChildAlgorithm("IntegrateMDHistoWorkspace", 0.0, 0.3); + cropMD->setProperty("InputWorkspace", ws); + + cropMD->setProperty("P1Bin", boost::lexical_cast<std::string>(h - box) + + ",0," + + boost::lexical_cast<std::string>(h + box)); + cropMD->setProperty("P2Bin", boost::lexical_cast<std::string>(k - box) + + ",0," + + boost::lexical_cast<std::string>(k + box)); + cropMD->setProperty("P3Bin", boost::lexical_cast<std::string>(l - box) + + ",0," + + boost::lexical_cast<std::string>(l + box)); + + cropMD->setPropertyValue("OutputWorkspace", "out"); + cropMD->executeAsChildAlg(); + IMDHistoWorkspace_sptr outputWS = cropMD->getProperty("OutputWorkspace"); + return boost::dynamic_pointer_cast<MDHistoWorkspace>(outputWS); +} + +} // namespace MDAlgorithms +} // namespace Mantid diff --git a/Framework/MDAlgorithms/src/ReplicateMD.cpp b/Framework/MDAlgorithms/src/ReplicateMD.cpp index 3f58978075d..9966a1f2210 100644 --- a/Framework/MDAlgorithms/src/ReplicateMD.cpp +++ b/Framework/MDAlgorithms/src/ReplicateMD.cpp @@ -293,8 +293,24 @@ void ReplicateMD::exec() { the linear index -> linear index calculation below will not work correctly. */ MDHistoWorkspace_const_sptr transposedDataWS = dataWS; - if (dataWS->getNumDims() == shapeWS->getNumDims()) { + if (nDimsData <= nDimsShape) { auto axes = findAxes(*shapeWS, *dataWS); + // Check that the indices stored in axes are compatible with the + // dimensionality of the data workspace + const auto numberOfDimensionsOfDataWorkspace = static_cast<int>(nDimsData); + for (const auto &axis : axes) { + if (axis >= numberOfDimensionsOfDataWorkspace) { + std::string message = + "ReplicateMD: Cannot transpose the data workspace. Attempting to " + "swap dimension index " + + std::to_string( + std::distance(static_cast<const int *>(&axes[0]), &axis)) + + " with index " + std::to_string(axis) + + ", but the dimensionality of the data workspace is " + + std::to_string(nDimsData); + throw std::runtime_error(message); + } + } transposedDataWS = transposeMD(dataWS, axes); nDimsData = transposedDataWS->getNumDims(); } diff --git a/Framework/MDAlgorithms/test/IntegratePeaksMDHKLTest.h b/Framework/MDAlgorithms/test/IntegratePeaksMDHKLTest.h new file mode 100644 index 00000000000..13cc818f4c9 --- /dev/null +++ b/Framework/MDAlgorithms/test/IntegratePeaksMDHKLTest.h @@ -0,0 +1,192 @@ +#ifndef MANTID_MDAGORITHMS_INTEGRATEPEAKSMDHKLTEST_H_ +#define MANTID_MDAGORITHMS_INTEGRATEPEAKSMDHKLTEST_H_ + +#include "MantidAPI/AnalysisDataService.h" +#include "MantidAPI/IMDEventWorkspace.h" +#include "MantidAPI/FrameworkManager.h" +#include "MantidDataObjects/MDEventFactory.h" +#include "MantidDataObjects/PeaksWorkspace.h" +#include "MantidDataObjects/PeakShapeSpherical.h" +#include "MantidGeometry/MDGeometry/MDHistoDimension.h" +#include "MantidGeometry/MDGeometry/HKL.h" +#include "MantidMDAlgorithms/IntegratePeaksMDHKL.h" +#include "MantidMDAlgorithms/CreateMDWorkspace.h" +#include "MantidMDAlgorithms/FakeMDEventData.h" +#include "MantidTestHelpers/ComponentCreationHelper.h" +#include "MantidKernel/UnitLabelTypes.h" + +#include <boost/math/distributions/normal.hpp> +#include <boost/math/special_functions/fpclassify.hpp> +#include <boost/math/special_functions/pow.hpp> +#include <boost/random/linear_congruential.hpp> +#include <boost/random/mersenne_twister.hpp> +#include <boost/random/uniform_int.hpp> +#include <boost/random/uniform_real.hpp> +#include <boost/random/variate_generator.hpp> + +#include <cxxtest/TestSuite.h> + +#include <Poco/File.h> + +using Mantid::Geometry::MDHistoDimension; +using namespace Mantid::API; +using namespace Mantid::DataObjects; +using namespace Mantid::Geometry; +using namespace Mantid::MDAlgorithms; +using Mantid::Kernel::V3D; + +class IntegratePeaksMDHKLTest : public CxxTest::TestSuite { +public: + IntegratePeaksMDHKLTest() { Mantid::API::FrameworkManager::Instance(); } + ~IntegratePeaksMDHKLTest() override {} + + void test_Init() { + IntegratePeaksMDHKL alg; + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT(alg.isInitialized()) + } + + //------------------------------------------------------------------------------- + /** Run the IntegratePeaksMDHKL with the given peak radius integration param + */ + static void + doRun(std::string OutputWorkspace = "IntegratePeaksMDHKLTest_peaks") { + IntegratePeaksMDHKL alg; + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT(alg.isInitialized()) + TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue( + "InputWorkspace", "IntegratePeaksMDHKLTest_MDEWS")); + TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue( + "PeaksWorkspace", "IntegratePeaksMDHKLTest_peaks")); + TS_ASSERT_THROWS_NOTHING( + alg.setPropertyValue("OutputWorkspace", OutputWorkspace)); + TS_ASSERT_THROWS_NOTHING(alg.execute()); + TS_ASSERT(alg.isExecuted()); + } + + //------------------------------------------------------------------------------- + /** Create the (blank) MDEW */ + static void createMDEW() { + // ---- Start with empty MDEW ---- + + CreateMDWorkspace algC; + TS_ASSERT_THROWS_NOTHING(algC.initialize()) + TS_ASSERT(algC.isInitialized()) + TS_ASSERT_THROWS_NOTHING(algC.setProperty("Dimensions", "3")); + TS_ASSERT_THROWS_NOTHING( + algC.setProperty("Extents", "-10,10,-10,10,-10,10")); + + TS_ASSERT_THROWS_NOTHING( + algC.setProperty("Names", "[H,0,0],[0,K,0],[0,0,L]")); + std::string units = Mantid::Kernel::Units::Symbol::RLU.ascii() + "," + + Mantid::Kernel::Units::Symbol::RLU.ascii() + "," + + Mantid::Kernel::Units::Symbol::RLU.ascii(); + TS_ASSERT_THROWS_NOTHING(algC.setProperty("Units", units)); + TS_ASSERT_THROWS_NOTHING(algC.setProperty("SplitInto", "5")); + TS_ASSERT_THROWS_NOTHING(algC.setProperty("MaxRecursionDepth", "2")); + std::string frames = Mantid::Geometry::HKL::HKLName + "," + + Mantid::Geometry::HKL::HKLName + "," + + Mantid::Geometry::HKL::HKLName; + TS_ASSERT_THROWS_NOTHING(algC.setProperty("Frames", frames)); + TS_ASSERT_THROWS_NOTHING(algC.setPropertyValue( + "OutputWorkspace", "IntegratePeaksMDHKLTest_MDEWS")); + TS_ASSERT_THROWS_NOTHING(algC.execute()); + TS_ASSERT(algC.isExecuted()); + } + + //------------------------------------------------------------------------------- + /** Add a fake peak */ + static void addPeak(size_t num, double x, double y, double z, double radius) { + std::ostringstream mess; + mess << num << ", " << x << ", " << y << ", " << z << ", " << radius; + FakeMDEventData algF; + TS_ASSERT_THROWS_NOTHING(algF.initialize()) + TS_ASSERT(algF.isInitialized()) + TS_ASSERT_THROWS_NOTHING(algF.setPropertyValue( + "InputWorkspace", "IntegratePeaksMDHKLTest_MDEWS")); + TS_ASSERT_THROWS_NOTHING( + algF.setProperty("PeakParams", mess.str().c_str())); + TS_ASSERT_THROWS_NOTHING(algF.setProperty("RandomSeed", "63759")); + TS_ASSERT_THROWS_NOTHING(algF.setProperty("RandomizeSignal", "1")); + TS_ASSERT_THROWS_NOTHING(algF.execute()); + TS_ASSERT(algF.isExecuted()); + } + + //------------------------------------------------------------------------------- + /** Full test using faked-out peak data */ + void test_exec() { + // --- Fake workspace with 3 peaks ------ + createMDEW(); + addPeak(1000, 1., 1., 1., 0.1); + addPeak(1000, 2., 3., 4., 0.15); + addPeak(1000, 6., 6., 6., 0.2); + + MDEventWorkspace3Lean::sptr mdews = + AnalysisDataService::Instance().retrieveWS<MDEventWorkspace3Lean>( + "IntegratePeaksMDHKLTest_MDEWS"); + auto &frame = mdews->getDimension(0)->getMDFrame(); + TSM_ASSERT_EQUALS("Should be HKL", Mantid::Geometry::HKL::HKLName, + frame.name()); + TS_ASSERT_EQUALS(mdews->getNPoints(), 3000); + TS_ASSERT_DELTA(mdews->getBox()->getSignal(), 3021.7071, 1e-2); + + // Make a fake instrument - doesn't matter, we won't use it really + Instrument_sptr inst = + ComponentCreationHelper::createTestInstrumentRectangular(1, 100, 0.05); + + // --- Make a fake PeaksWorkspace --- + PeaksWorkspace_sptr peakWS0(new PeaksWorkspace()); + peakWS0->setInstrument(inst); + Peak Pin(inst, 15050, 1.0); + Pin.setHKL(V3D(1, 1, 1)); + peakWS0->addPeak(Pin); + + TS_ASSERT_EQUALS(peakWS0->getPeak(0).getIntensity(), 0.0); + AnalysisDataService::Instance().add("IntegratePeaksMDHKLTest_peaks", + peakWS0); + + // ------------- Integrating with cylinder ------------------------ + doRun("IntegratePeaksMDHKLTest_peaks"); + + TS_ASSERT_DELTA(peakWS0->getPeak(0).getIntensity(), 29.4284, 1e-2); + + // Error is also calculated + TS_ASSERT_DELTA(peakWS0->getPeak(0).getSigmaIntensity(), 5.2813, 1e-2); + } + + //------------------------------------------------------------------------------- + /// Integrate background between start/end background radius + void test_exec_shellBackground() { + createMDEW(); + /* Create 3 overlapping shells so that density goes like this: + * r < 1 : density 1.0 + * 1 < r < 2 : density 1/2 + * 2 < r < 3 : density 1/3 + */ + addPeak(1000, 1., 1., 1., 0.1); + addPeak(1000 * 4, 0., 0., 0., + 2.0); // 8 times the volume / 4 times the counts = 1/2 density + addPeak(1000 * 9, 0., 0., 0., + 3.0); // 27 times the volume / 9 times the counts = 1/3 density + + // --- Make a fake PeaksWorkspace --- + PeaksWorkspace_sptr peakWS(new PeaksWorkspace()); + Instrument_sptr inst = + ComponentCreationHelper::createTestInstrumentCylindrical(5); + Peak Pin(inst, 1, 1.0); + Pin.setHKL(V3D(1, 1, 1)); + peakWS->addPeak(Pin); + TS_ASSERT_EQUALS(peakWS->getPeak(0).getIntensity(), 0.0); + AnalysisDataService::Instance().addOrReplace( + "IntegratePeaksMDHKLTest_peaks", peakWS); + + // Set background from 2.0 to 3.0. + doRun("IntegratePeaksMDHKLTest_peaks"); + TS_ASSERT_DELTA(peakWS->getPeak(0).getIntensity(), 29.4275, 0.1); + // Error is larger, since it is error of peak + error of background + TSM_ASSERT_DELTA("Error has increased", + peakWS->getPeak(0).getSigmaIntensity(), 5.2814, 0.1); + } +}; + +#endif /* MANTID_MDEVENTS_INTEGRATEPEAKSMDHKLTEST_H_ */ diff --git a/Framework/PythonInterface/mantid/kernel/src/Converters/NDArrayToVector.cpp b/Framework/PythonInterface/mantid/kernel/src/Converters/NDArrayToVector.cpp index 513895f6a0c..849aa072f52 100644 --- a/Framework/PythonInterface/mantid/kernel/src/Converters/NDArrayToVector.cpp +++ b/Framework/PythonInterface/mantid/kernel/src/Converters/NDArrayToVector.cpp @@ -139,7 +139,7 @@ void NDArrayToVector<DestElementType>::typeCheck() { // Explicit instantiations //------------------------------------------------------------------------ #define INSTANTIATE_TOVECTOR(ElementType) \ - template DLLExport struct NDArrayToVector<ElementType>; + template struct DLLExport NDArrayToVector<ElementType>; ///@cond Doxygen doesn't seem to like this... INSTANTIATE_TOVECTOR(int) diff --git a/Framework/PythonInterface/mantid/kernel/src/Converters/NDArrayTypeIndex.cpp b/Framework/PythonInterface/mantid/kernel/src/Converters/NDArrayTypeIndex.cpp index 1f7250a6a35..71f5fb8ff70 100644 --- a/Framework/PythonInterface/mantid/kernel/src/Converters/NDArrayTypeIndex.cpp +++ b/Framework/PythonInterface/mantid/kernel/src/Converters/NDArrayTypeIndex.cpp @@ -17,7 +17,7 @@ namespace Converters { /// Macro to define mappings between the CType and Numpy enum #define DEFINE_TYPE_MAPPING(CType, NDTypeNum) \ template <> int NDArrayTypeIndex<CType>::typenum = NDTypeNum; \ - template PYTHON_KERNEL_DLL struct NDArrayTypeIndex<CType>; + template struct NDArrayTypeIndex<CType>; DEFINE_TYPE_MAPPING(int, NPY_INT) DEFINE_TYPE_MAPPING(long, NPY_LONG) diff --git a/Framework/PythonInterface/mantid/kernel/src/Registry/SequenceTypeHandler.cpp b/Framework/PythonInterface/mantid/kernel/src/Registry/SequenceTypeHandler.cpp index b7dab52f39d..2324e1ac3d1 100644 --- a/Framework/PythonInterface/mantid/kernel/src/Registry/SequenceTypeHandler.cpp +++ b/Framework/PythonInterface/mantid/kernel/src/Registry/SequenceTypeHandler.cpp @@ -117,7 +117,7 @@ std::unique_ptr<Kernel::Property> SequenceTypeHandler<ContainerType>::create( //----------------------------------------------------------------------- ///@cond #define INSTANTIATE(ElementType) \ - template DLLExport struct SequenceTypeHandler<std::vector<ElementType>>; + template struct DLLExport SequenceTypeHandler<std::vector<ElementType>>; INSTANTIATE(int) INSTANTIATE(long) diff --git a/Framework/PythonInterface/plugins/algorithms/CylinderPaalmanPingsCorrection2.py b/Framework/PythonInterface/plugins/algorithms/CylinderPaalmanPingsCorrection2.py index 42cac4b651b..6e1711c3be3 100644 --- a/Framework/PythonInterface/plugins/algorithms/CylinderPaalmanPingsCorrection2.py +++ b/Framework/PythonInterface/plugins/algorithms/CylinderPaalmanPingsCorrection2.py @@ -105,8 +105,8 @@ class CylinderPaalmanPingsCorrection(PythonAlgorithm): doc='Number of wavelengths for calculation') self.declareProperty(name='Emode', defaultValue='Elastic', - validator=StringListValidator(['Elastic', 'Indirect']), - doc='Emode: Elastic or Indirect') + validator=StringListValidator(['Elastic', 'Indirect', 'Direct']), + doc='Energy transfer mode') self.declareProperty(name='Efixed', defaultValue=1.0, doc='Analyser energy') @@ -358,9 +358,7 @@ class CylinderPaalmanPingsCorrection(PythonAlgorithm): if self._emode == 'Elastic': self._elastic = self._waves[int(len(self._waves) / 2)] - elif self._emode == 'Direct': - self._elastic = math.sqrt(81.787/self._efixed) # elastic wavelength - elif self._emode == 'Indirect': + else: self._elastic = math.sqrt(81.787/self._efixed) # elastic wavelength logger.information('Elastic lambda : %f' % (self._elastic)) diff --git a/Framework/PythonInterface/plugins/algorithms/ExportSpectraMask.py b/Framework/PythonInterface/plugins/algorithms/ExportSpectraMask.py new file mode 100644 index 00000000000..471d89b6d7e --- /dev/null +++ b/Framework/PythonInterface/plugins/algorithms/ExportSpectraMask.py @@ -0,0 +1,208 @@ +#pylint: disable=invalid-name, no-init +import os +from mantid import config +from mantid.api import PythonAlgorithm, AlgorithmFactory, WorkspaceProperty, mtd, FileProperty, FileAction +from mantid.kernel import Direction, logger, IntArrayProperty + +def export_masks(ws,fileName='',returnMasksOnly=False): + """Exports masks applied to Mantid workspace + (e.g. drawn using the instrument view) and write these masks + into the old fashioned ASCII .msk file containing masked spectra numbers. + + The file is Libisis/Mantid old ISIS format compatible and can be read by Libisis + or Mantid LoadMasks algorithm + + If optional parameter fileName is present, the masks are saved + in the file with this name + Otherwise, the file with the name equal to the workspace + name and the extension .msk is used. + + If returnMasks is set to True, the function does not write to file but returns + list of masks instead. + """ + # get pointer to the workspace + if type(ws) == str: + pws = mtd[ws] + else: + pws = ws + + + ws_name=pws.getName() + nhist = pws.getNumberHistograms() + + no_detectors = 0 + masks = [] + for i in range(nhist): + # set provisional spectra ID + ms = i+1 + try: + sp = pws.getSpectrum(i) + # got real spectra ID, which would correspond real spectra num to spectra ID map + ms = sp.getSpectrumNo() +#pylint: disable=W0703 + except Exception: + logger.notice("Can not retrieve spectra No: " + str(i) + ". Have masked it") + masks.append(ms) + continue + try: + det = pws.getDetector(i) +#pylint: disable=W0703 + except Exception: + no_detectors = no_detectors +1 + masks.append(ms) + continue + if det.isMasked(): + masks.append(ms) + + filename='' + if len(fileName)==0 : + filename = os.path.join(config.getString('defaultsave.directory'),ws_name+'.msk') + else: + filename = fileName + + + nMasks = len(masks) + if nMasks == 0: + if returnMasksOnly: + logger.warning("Workspace {0} have no masked spectra. File {1} have not been created".format(ws_name,filename)) + else: + logger.notice("Workspace "+ws_name+" have no masked spectra") + return masks + + logger.notice("Workspace {0} has {1} masked spectra, including {2} spectra without detectors".format(ws_name,nMasks,no_detectors)) + + + if not returnMasksOnly : + writeISISmasks(filename,masks,8) + return masks + + + +def flushOutString(f,OutString,BlockSize,BlockLimit): + """Internal function for writeISISmasks procedure, + which writes down specified number of mask blocks, + not to exceed the specified number of masks in row. + """ + BlockSize+=1 + if BlockSize >= BlockLimit: + if len(OutString)>0: + f.write(OutString+'\n') + OutString = '' + BlockSize = 0 + return (f,BlockSize,OutString) + + +def writeISISmasks(filename,masks,nSpectraInRow=8): + """Function writes input array in the form of ISSI mask file array + This is the helper function for export_mask procedure, + which can be used separately + + namely, if one have array 1,2,3,4, 20, 30,31,32 + file will have the following ASCII stings: + 1-4 20 30-32 + + nSpectaInRow indicates the number of the separate spectra ID (numbers) which the program + needs to fit into one row. For the example above the number has to be 5 or more + to fit all spectra into a single row. Setting it to one will produce 8 rows with single number in each. + + Usage: + >>writeISISmasks(fileName,masks) + where: + fileName -- the name of the output file + masks -- the array with data + """ + ext = os.path.splitext(filename)[1] + if len(ext) == 0 : + filename=filename+'.msk' + + OutString = '' + LastSpectraN= '' + BlockSize = 0 + iDash = 0 + im1=masks[0] + + with open(filename,'w') as f: + # prepare and write mask data in conventional msk format + # where adjusted spectra are separated by "-" sign + for i in masks: + if len(OutString)== 0: + OutString = str(i) + (f,BlockSize,OutString) = flushOutString(f,OutString,BlockSize,nSpectraInRow) + im1 = i + continue + # if the current spectra is different from the previous one by 1 only, we may want to skip it + if im1+1 == i : + LastSpectraN = str(i) + iDash += 1 + else : # it is different and should be dealt separately + if iDash > 0 : + OutString = OutString+'-'+LastSpectraN + iDash = 0 + LastSpectraN='' + # write the string if it is finished + (f,BlockSize,OutString) = flushOutString(f,OutString,BlockSize,nSpectraInRow) + + if len(OutString) == 0: + OutString = str(i) + else: + OutString = OutString + ' ' + str(i) + # write the string if it is finished + (f,BlockSize,OutString) = flushOutString(f,OutString,BlockSize,nSpectraInRow) + #endif + + # current spectra is the previous now + im1 = i + # end masks loop + if iDash > 0 : + OutString = OutString+'-'+LastSpectraN + (f,OutString,BlockSize)=flushOutString(f,OutString,BlockSize,0) + + + +class ExportSpectraMask(PythonAlgorithm): + """ Export workspace's mask + """ + def category(self): + """ Return category + """ + return "DataHandling\\Masking" + + def name(self): + """ Return name + """ + return "ExportSpectraMask" + + def summary(self): + return "Returns list of spectra numbers which are masked on a workspace"\ + " and can save these numbers as legacy .msk file." + + def PyInit(self): + """ Declare properties + """ + self.declareProperty(WorkspaceProperty("Workspace", "",Direction.Input), "The workspace to export masks from.") + + self.declareProperty(FileProperty(name="Filename",defaultValue="",action=FileAction.OptionalSave,\ + extensions = [".msk"],direction=Direction.Input),\ + doc="The name or full path to the file to save mask to."\ + " If empty, the name of the input workspace and default save directory are used.") + self.declareProperty("ExportMaskOnly",False,"If true, algorithm will not save mask in a file"\ + "and only returns the list containing numbers of masked spectra.",\ + Direction.Input) + self.declareProperty(IntArrayProperty(name="SpectraMasks",direction = Direction.Output),\ + doc="List of the masked spectra numbers.") + return + + def PyExec(self): + """ Main execution body + """ + #get parameters + ws = self.getProperty("Workspace").value + out_file_name = self.getProperty("Filename").value + export_masks_only = self.getProperty("ExportMaskOnly").value + + masks = export_masks(ws,out_file_name ,export_masks_only) + self.setProperty("SpectraMasks", masks) + return + + +AlgorithmFactory.subscribe(ExportSpectraMask) diff --git a/Framework/PythonInterface/plugins/algorithms/LoadPreNexusLive.py b/Framework/PythonInterface/plugins/algorithms/LoadPreNexusLive.py new file mode 100644 index 00000000000..cf2a3cccfac --- /dev/null +++ b/Framework/PythonInterface/plugins/algorithms/LoadPreNexusLive.py @@ -0,0 +1,118 @@ +from mantid import mtd +from mantid.api import AlgorithmFactory, DataProcessorAlgorithm, FileAction, \ + FileProperty, WorkspaceProperty +from mantid.kernel import Direction, EnabledWhenProperty, \ + PropertyCriterion, StringListValidator +from mantid.simpleapi import * +import os + + +class LoadPreNexusLive(DataProcessorAlgorithm): + def category(self): + return 'DataHandling' + + def findLivefile(self, instrument): + livepath = '/SNS/%s/shared/live/' % instrument + filenames = os.listdir(livepath) + + filenames = [name for name in filenames + if name.startswith(instrument)] + filenames = [name for name in filenames + if name.endswith('_live_neutron_event.dat')] + + if len(filenames) <= 0: + raise RuntimeError("Failed to find live file for '%s'" % instrument) + + filenames.sort() + + return os.path.join(livepath, filenames[-1]) + + def findLogfile(self, instrument, runNumber): + filename = self.getProperty('LogFilename').value + if len(filename) > 0 and os.path.exists(filename): + return filename + + try: + iptsdir = GetIPTS(Instrument=instrument, RunNumber=runNumber) + self.log().information('ipts %s' % iptsdir) + except RuntimeError: + msg = 'Failed to determine the IPTS containing %s_%d' % (instrument, runNumber) + self.log().warning(msg) + return '' + + direc = os.path.join(iptsdir, 'data') + + filenames = os.listdir(direc) + filenames = [name for name in filenames + if name.endswith('_event.nxs')] + + if len(filenames) <= 0: + raise RuntimeError("Failed to find existing nexus file in '%s'" % iptsdir) + + filenames.sort() + + return os.path.join(direc, filenames[-1]) + + def PyInit(self): + instruments = ['BSS', 'SNAP', 'REF_M', 'CNCS', 'EQSANS', 'VULCAN', + 'VENUS', 'MANDI', 'TOPAZ', 'ARCS'] + self.declareProperty('Instrument', '', + StringListValidator(instruments), + 'Empty uses default instrument') + + self.declareProperty(WorkspaceProperty('OutputWorkspace', '', + direction=Direction.Output)) + + self.declareProperty('NormalizeByCurrent', True, 'Normalize by current') + + self.declareProperty('LoadLogs', True, + 'Attempt to load logs from an existing file') + + self.declareProperty(FileProperty('LogFilename', '', + direction=Direction.Input, + action=FileAction.OptionalLoad, + extensions=['_event.nxs']), + doc='File containing logs to use (Optional)') + self.setPropertySettings('LogFilename', + EnabledWhenProperty('LoadLogs', + PropertyCriterion.IsDefault)) + + def PyExec(self): + instrument = self.getProperty('Instrument').value + + eventFilename = self.findLivefile(instrument) + + self.log().information("Loading '%s'" % eventFilename) + wkspName = self.getPropertyValue('OutputWorkspace') + LoadEventPreNexus(EventFilename=eventFilename, + OutputWorkspace=wkspName) + + # let people know what was just loaded + wksp = mtd[wkspName] + instrument = str(wksp.getInstrument().getName()) + runNumber = int(wksp.run()['run_number'].value) + startTime = str(wksp.run().startTime()) + self.log().information('Loaded %s live run %d - starttime=%s' + % (instrument, runNumber, startTime)) + + if self.getProperty('NormalizeByCurrent').value: + self.log().information('Normalising by current') + NormaliseByCurrent(InputWorkspace=wkspName, + Outputworkspace=wkspName) + + if self.getProperty('LoadLogs').value: + logFilename = self.findLogfile(instrument, runNumber) + if len(logFilename) > 0: + self.log().information('Loading logs from %s' % logFilename) + LoadNexusLogs(Workspace=wkspName, Filename=logFilename) + wksp = mtd[wkspName] + instrFilename = wksp.getInstrumentFilename(instrument, startTime) + LoadInstrument(Workspace=wkspName, Filename=instrFilename, + RewriteSpectraMap=True) + + # gets rid of many simple DAS errors + FilterByXValue(InputWorkspace=wkspName, XMin=1) + + self.setProperty('OutputWorkspace', mtd[wkspName]) + +AlgorithmFactory.subscribe(LoadPreNexusLive) diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/FlatPlatePaalmanPingsCorrection.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/FlatPlatePaalmanPingsCorrection.py index a0a9224d4a8..0991d85cf98 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/FlatPlatePaalmanPingsCorrection.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/FlatPlatePaalmanPingsCorrection.py @@ -87,8 +87,8 @@ class FlatPlatePaalmanPingsCorrection(PythonAlgorithm): doc='Interpolate the correction workspaces to match the sample workspace') self.declareProperty(name='Emode', defaultValue='Elastic', - validator=StringListValidator(['Elastic', 'Indirect']), - doc='Emode: Elastic or Indirect') + validator=StringListValidator(['Elastic', 'Indirect', 'Direct']), + doc='Energy transfer mode') self.declareProperty(name='Efixed', defaultValue=1.0, doc='Analyser energy') @@ -281,7 +281,7 @@ class FlatPlatePaalmanPingsCorrection(PythonAlgorithm): if self._emode == 'Elastic': self._elastic = self._waves[int(number_waves / 2)] - elif self._emode == 'Indirect': + else: self._elastic = math.sqrt(81.787 / self._efixed) # elastic wavelength logger.information('Elastic lambda %f' % self._elastic) diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt b/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt index 99fa1830558..884e808c89e 100644 --- a/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt +++ b/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt @@ -30,6 +30,7 @@ set ( TEST_PY_FILES EnggFitPeaksTest.py EnggFocusTest.py EnggVanadiumCorrectionsTest.py + ExportSpectraMaskTest.py FilterLogByTimeTest.py FindEPPTest.py FindReflectometryLinesTest.py diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/CylinderPaalmanPingsCorrection2Test.py b/Framework/PythonInterface/test/python/plugins/algorithms/CylinderPaalmanPingsCorrection2Test.py index 206e169f0d0..657864282ca 100644 --- a/Framework/PythonInterface/test/python/plugins/algorithms/CylinderPaalmanPingsCorrection2Test.py +++ b/Framework/PythonInterface/test/python/plugins/algorithms/CylinderPaalmanPingsCorrection2Test.py @@ -83,9 +83,9 @@ class CylinderPaalmanPingsCorrection2Test(unittest.TestCase): self._verify_workspace(workspace) - def test_sampleOnly(self): + def test_sampleOnly_Indirect(self): """ - Test simple run with sample workspace only. + Test simple run with sample workspace only for indirect mode """ CylinderPaalmanPingsCorrection(OutputWorkspace=self._corrections_ws_name, @@ -97,7 +97,23 @@ class CylinderPaalmanPingsCorrection2Test(unittest.TestCase): Efixed=1.845) ass_ws_name = self._corrections_ws_name + '_ass' - self. _verify_workspace(ass_ws_name) + self._verify_workspace(ass_ws_name) + + def test_sampleOnly_Direct(self): + """ + Test simple run with sample workspace only for direct mode + """ + + CylinderPaalmanPingsCorrection(OutputWorkspace=self._corrections_ws_name, + SampleWorkspace=self._sample_ws, + SampleChemicalFormula='H2-O', + SampleInnerRadius=0.05, + SampleOuterRadius=0.1, + Emode='Direct', + Efixed=1.845) + + ass_ws_name = self._corrections_ws_name + '_ass' + self._verify_workspace(ass_ws_name) def test_sampleAndCan(self): diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/ExportSpectraMaskTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/ExportSpectraMaskTest.py new file mode 100644 index 00000000000..2ec72d02986 --- /dev/null +++ b/Framework/PythonInterface/test/python/plugins/algorithms/ExportSpectraMaskTest.py @@ -0,0 +1,92 @@ +import os +import sys +import numpy as np +import unittest +import mantid +from mantid.simpleapi import ExportSpectraMask,DeleteWorkspace + +class ExportSpectraMaskTest(unittest.TestCase): + def __init__(self,method_name): + unittest.TestCase.__init__(self,method_name) + + self.this_path = os.path.dirname(os.path.realpath(__file__)) + test_path = self.this_path; + for i in xrange(0,4): + test_path,_ = os.path.split(test_path) + self.test_mod_path = os.path.join(test_path,'plugins/algorithms') + sys.path.append(self.test_mod_path) + + self.test_files_path = mantid.config.getString('defaultsave.directory') + self.test_file = os.path.join(self.test_files_path,'test_mask_file') + + + def setUp(self): + """ """ + + self.masks = [1,4,8,10,199,200] + if not 'test_ws' in mantid.api.mtd: + test_ws = mantid.simpleapi.CreateSampleWorkspace() + test_ws.maskDetectors(self.masks) + if not hasattr(self,'write_f'): + import ExportSpectraMask as amc + self.test_write_f = amc.writeISISmasks + self.test_export_f = amc.export_masks + + return super(ExportSpectraMaskTest, self).setUp() + + def tearDown(self): + if 'test_ws' in mantid.api.mtd: + DeleteWorkspace('test_ws') + test_file = self.test_file + '.msk' + if os.path.isfile(test_file ): + os.remove(test_file) + return super(ExportSpectraMaskTest, self).tearDown() + + def test_writeISISmasks(self): + masks = [1,20,30,40,41,42,43]; + + test_file = self.test_file + + # Test single row writing + self.test_write_f(test_file,masks) + + self.assertTrue(os.path.isfile(test_file + '.msk')) + with open(test_file + '.msk','r') as tf: + for line in tf: + self.assertEqual(line,'1 20 30 40-43\n') + os.remove(test_file + '.msk') + + # Test multiple row writing + test_file = test_file + '.msk' + masks = masks + [46,47,49,50] + self.test_write_f(test_file,masks,4) + self.assertTrue(os.path.isfile(test_file)) + + sample = ['1 20 30 40\n','41-43 46-47\n','49-50\n'] + with open(test_file,'r') as tf: + for line,s in zip(tf,sample): + self.assertEqual(line,s) + + def test_exportMasks(self): + r_masks = self.test_export_f('test_ws','',True) + self.assertEqual(self.masks,r_masks) + + def test_ExportAlgosWork(self): + r_masks = ExportSpectraMask('test_ws',ExportMaskOnly=True) + self.assertTrue((np.array(self.masks)==r_masks).all()) + + test_file = self.test_file + '.msk' + self.assertFalse(os.path.isfile(test_file)) + + r_masks = ExportSpectraMask('test_ws',Filename = test_file) + self.assertTrue(os.path.isfile(test_file)) + self.assertTrue((np.array(self.masks)==r_masks).all()) + + default_tf = os.path.join(mantid.config.getString('defaultsave.directory'),'test_ws.msk') + ExportSpectraMask('test_ws') + self.assertTrue(os.path.isfile(default_tf)) + os.remove(default_tf) + + +if __name__=="__main__": + unittest.main() diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/FlatPlatePaalmanPingsCorrectionTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/FlatPlatePaalmanPingsCorrectionTest.py index 8577eb0f1a3..e3d68386e57 100644 --- a/Framework/PythonInterface/test/python/plugins/algorithms/FlatPlatePaalmanPingsCorrectionTest.py +++ b/Framework/PythonInterface/test/python/plugins/algorithms/FlatPlatePaalmanPingsCorrectionTest.py @@ -82,9 +82,9 @@ class FlatPlatePaalmanPingsCorrectionTest(unittest.TestCase): self._verify_workspace(workspace) - def test_sampleOnly(self): + def test_sampleOnly_indirect(self): """ - Test simple run with sample workspace only. + Test simple run with sample workspace only for indirect mode """ FlatPlatePaalmanPingsCorrection(OutputWorkspace=self._corrections_ws_name, @@ -99,6 +99,23 @@ class FlatPlatePaalmanPingsCorrectionTest(unittest.TestCase): ass_ws_name = self._corrections_ws_name + '_ass' self. _verify_workspace(ass_ws_name) + def test_sampleOnly_direct(self): + """ + Test simple run with sample workspace only for direct mode + """ + + FlatPlatePaalmanPingsCorrection(OutputWorkspace=self._corrections_ws_name, + SampleWorkspace=self._sample_ws, + SampleChemicalFormula='H2-O', + SampleThickness=0.1, + SampleAngle=45, + NumberWavelengths=10, + Emode='Direct', + Efixed=1.845) + + ass_ws_name = self._corrections_ws_name + '_ass' + self. _verify_workspace(ass_ws_name) + def test_sampleAndCan(self): """ diff --git a/Framework/SINQ/inc/MantidSINQ/DllConfig.h b/Framework/SINQ/inc/MantidSINQ/DllConfig.h index 5cfc4e6ce41..ad53b637512 100644 --- a/Framework/SINQ/inc/MantidSINQ/DllConfig.h +++ b/Framework/SINQ/inc/MantidSINQ/DllConfig.h @@ -30,8 +30,10 @@ #ifdef IN_MANTID_SINQ #define MANTID_SINQ_DLL DLLExport +#define EXTERN_MANTID_SINQ #else #define MANTID_SINQ_DLL DLLImport +#define EXTERN_MANTID_SINQ EXTERN_IMPORT #endif /* IN_MANTID_SINQ */ #endif // MANTID_SINQ_DLLCONFIG_H_ diff --git a/Framework/ScriptRepository/CMakeLists.txt b/Framework/ScriptRepository/CMakeLists.txt index f16cbbf784a..c2bc2704c92 100644 --- a/Framework/ScriptRepository/CMakeLists.txt +++ b/Framework/ScriptRepository/CMakeLists.txt @@ -4,6 +4,7 @@ set ( SRC_FILES ) set ( INC_FILES + inc/MantidScriptRepository/DllConfig.h inc/MantidScriptRepository/ScriptRepositoryImpl.h ) diff --git a/Framework/ScriptRepository/inc/MantidScriptRepository/DllConfig.h b/Framework/ScriptRepository/inc/MantidScriptRepository/DllConfig.h new file mode 100644 index 00000000000..4f13d0ab515 --- /dev/null +++ b/Framework/ScriptRepository/inc/MantidScriptRepository/DllConfig.h @@ -0,0 +1,22 @@ +#ifndef MANTID_MANTIDSCRIPTREPOSITORY_DLLCONFIG_H_ +#define MANTID_MANTIDSCRIPTREPOSITORY_DLLCONFIG_H_ + +#include "MantidKernel/System.h" + +#ifdef _WIN32 +#if (IN_MANTID_SCRIPTREPO) +#define SCRIPT_DLL_EXPORT DLLExport +#else +#define SCRIPT_DLL_EXPORT DLLImport +#endif +#elif defined(__GNUC__) && !defined(__clang__) +#if (IN_MANTID_SCRIPTREPO) +#define SCRIPT_DLL_EXPORT DLLExport +#else +#define SCRIPT_DLL_EXPORT DLLImport +#endif +#else +#define SCRIPT_DLL_EXPORT +#endif + +#endif // MANTID_DATAOBJECTS_DLLCONFIG_H_ diff --git a/Framework/ScriptRepository/inc/MantidScriptRepository/ScriptRepositoryImpl.h b/Framework/ScriptRepository/inc/MantidScriptRepository/ScriptRepositoryImpl.h index b00c700e817..696d84d6413 100644 --- a/Framework/ScriptRepository/inc/MantidScriptRepository/ScriptRepositoryImpl.h +++ b/Framework/ScriptRepository/inc/MantidScriptRepository/ScriptRepositoryImpl.h @@ -3,19 +3,10 @@ #include "MantidAPI/ScriptRepository.h" #include "MantidKernel/DateAndTime.h" +#include "MantidScriptRepository/DllConfig.h" #include <map> #include <json/value.h> -#ifdef _WIN32 -#if (IN_MANTID_SCRIPTREPO) -#define SCRIPT_DLL_EXPORT DLLExport -#else -#define SCRIPT_DLL_EXPORT DLLImport -#endif -#else -#define SCRIPT_DLL_EXPORT -#endif - namespace Mantid { namespace API { diff --git a/Framework/TestHelpers/src/MDEventsTestHelper.cpp b/Framework/TestHelpers/src/MDEventsTestHelper.cpp index c899f51bb86..dad353bac42 100644 --- a/Framework/TestHelpers/src/MDEventsTestHelper.cpp +++ b/Framework/TestHelpers/src/MDEventsTestHelper.cpp @@ -193,9 +193,10 @@ MDBox<MDLeanEvent<3>, 3> *makeMDBox3() { */ std::vector<MDLeanEvent<1>> makeMDEvents1(size_t num) { std::vector<MDLeanEvent<1>> out; - for (std::size_t i = 0; i < num; i++) { - double coords[1] = {static_cast<double>(i) * 1.0 + 0.5}; - out.push_back(MDLeanEvent<1>(1.0, 1.0, coords)); + out.reserve(num); + for (std::size_t i = 0; i < num; ++i) { + float coords[1] = {static_cast<float>(i) + 0.5f}; + out.emplace_back(1.0f, 1.0f, coords); } return out; } diff --git a/MantidPlot/src/FloatingWindow.cpp b/MantidPlot/src/FloatingWindow.cpp index 070b8d56704..4b79f3ac5fb 100644 --- a/MantidPlot/src/FloatingWindow.cpp +++ b/MantidPlot/src/FloatingWindow.cpp @@ -39,6 +39,14 @@ FloatingWindow::FloatingWindow(ApplicationWindow *appWindow, Qt::WindowFlags f) // Instead, the ApplicationWindow->removeFloatingWindow() call takes care of // calling deleteLater(). setAttribute(Qt::WA_DeleteOnClose, false); + +#ifdef Q_OS_MAC + // Work around to ensure that floating windows remain on top of the main + // application window, but below other applications on Mac + Qt::WindowFlags flags = windowFlags(); + Qt::WindowFlags new_flags = flags | Qt::Tool; + setWindowFlags(new_flags); +#endif } FloatingWindow::~FloatingWindow() { diff --git a/MantidQt/API/inc/MantidQtAPI/AlgorithmInputHistory.h b/MantidQt/API/inc/MantidQtAPI/AlgorithmInputHistory.h index d44602964f2..52c28ce400c 100644 --- a/MantidQt/API/inc/MantidQtAPI/AlgorithmInputHistory.h +++ b/MantidQt/API/inc/MantidQtAPI/AlgorithmInputHistory.h @@ -96,14 +96,15 @@ private: friend struct Mantid::Kernel::CreateUsingNew<AlgorithmInputHistoryImpl>; }; -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class EXPORT_OPT_MANTIDQT_API - Mantid::Kernel::SingletonHolder<AlgorithmInputHistoryImpl>; -#endif /* _WIN32 */ -/// The specific instantiation of the templated type -typedef EXPORT_OPT_MANTIDQT_API Mantid::Kernel::SingletonHolder< - AlgorithmInputHistoryImpl> AlgorithmInputHistory; +typedef Mantid::Kernel::SingletonHolder<AlgorithmInputHistoryImpl> + AlgorithmInputHistory; +} +} + +namespace Mantid { +namespace Kernel { +EXTERN_MANTIDQT_API template class EXPORT_OPT_MANTIDQT_API + Mantid::Kernel::SingletonHolder<MantidQt::API::AlgorithmInputHistoryImpl>; } } diff --git a/MantidQt/API/inc/MantidQtAPI/DllOption.h b/MantidQt/API/inc/MantidQtAPI/DllOption.h index 2d64b43438a..6f9368b5568 100644 --- a/MantidQt/API/inc/MantidQtAPI/DllOption.h +++ b/MantidQt/API/inc/MantidQtAPI/DllOption.h @@ -5,8 +5,10 @@ #ifdef IN_MANTIDQT_API #define EXPORT_OPT_MANTIDQT_API DLLExport +#define EXTERN_MANTIDQT_API #else #define EXPORT_OPT_MANTIDQT_API DLLImport +#define EXTERN_MANTIDQT_API extern #endif /* IN_MANTIDQT_API */ #endif // MANTIDQT_API_DLLOPTION_H_ diff --git a/MantidQt/API/inc/MantidQtAPI/InterfaceFactory.h b/MantidQt/API/inc/MantidQtAPI/InterfaceFactory.h index f57fbe104c3..ff9b7a0247a 100644 --- a/MantidQt/API/inc/MantidQtAPI/InterfaceFactory.h +++ b/MantidQt/API/inc/MantidQtAPI/InterfaceFactory.h @@ -69,14 +69,9 @@ private: ~AlgorithmDialogFactoryImpl() override = default; }; -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class EXPORT_OPT_MANTIDQT_API - Mantid::Kernel::SingletonHolder<AlgorithmDialogFactoryImpl>; -#endif /* _WIN32 */ /// The specific instantiation of the templated type -typedef EXPORT_OPT_MANTIDQT_API Mantid::Kernel::SingletonHolder< - AlgorithmDialogFactoryImpl> AlgorithmDialogFactory; +typedef Mantid::Kernel::SingletonHolder<AlgorithmDialogFactoryImpl> + AlgorithmDialogFactory; /** The UserSubWindowFactory is responsible for creating concrete instances of @@ -184,14 +179,18 @@ void UserSubWindowFactoryImpl::saveAliasNames(const std::string &realName) { } } -#ifdef _WIN32 -// this breaks new namespace declaraion rules; need to find a better fix -template class EXPORT_OPT_MANTIDQT_API - Mantid::Kernel::SingletonHolder<UserSubWindowFactoryImpl>; -#endif /* _WIN32 */ /// The specific instantiation of the templated type -typedef EXPORT_OPT_MANTIDQT_API Mantid::Kernel::SingletonHolder< - UserSubWindowFactoryImpl> UserSubWindowFactory; +typedef Mantid::Kernel::SingletonHolder<UserSubWindowFactoryImpl> + UserSubWindowFactory; +} +} + +namespace Mantid { +namespace Kernel { +EXTERN_MANTIDQT_API template class EXPORT_OPT_MANTIDQT_API + Mantid::Kernel::SingletonHolder<MantidQt::API::AlgorithmDialogFactoryImpl>; +EXTERN_MANTIDQT_API template class EXPORT_OPT_MANTIDQT_API + Mantid::Kernel::SingletonHolder<MantidQt::API::UserSubWindowFactoryImpl>; } } diff --git a/MantidQt/API/inc/MantidQtAPI/SelectionNotificationService.h b/MantidQt/API/inc/MantidQtAPI/SelectionNotificationService.h index f0d06640beb..37a55319fd9 100644 --- a/MantidQt/API/inc/MantidQtAPI/SelectionNotificationService.h +++ b/MantidQt/API/inc/MantidQtAPI/SelectionNotificationService.h @@ -63,16 +63,14 @@ private: SelectionNotificationServiceImpl>; }; -/// Forward declaration of a specialisation of SingletonHolder for -/// SelectionNotificationServiceImpl -/// (needed for dllexport/dllimport) and a typedef for it. -#ifdef _WIN32 -template class EXPORT_OPT_MANTIDQT_API - Mantid::Kernel::SingletonHolder<SelectionNotificationServiceImpl>; -#endif /* _WIN32 */ - -typedef EXPORT_OPT_MANTIDQT_API Mantid::Kernel::SingletonHolder< - SelectionNotificationServiceImpl> SelectionNotificationService; +typedef Mantid::Kernel::SingletonHolder<SelectionNotificationServiceImpl> + SelectionNotificationService; +} +} +namespace Mantid { +namespace Kernel { +EXTERN_MANTIDQT_API template class EXPORT_OPT_MANTIDQT_API Mantid::Kernel:: + SingletonHolder<MantidQt::API::SelectionNotificationServiceImpl>; } } diff --git a/MantidQt/API/src/SignalBlocker.cpp b/MantidQt/API/src/SignalBlocker.cpp index bb1ac18c91a..7423758ddc4 100644 --- a/MantidQt/API/src/SignalBlocker.cpp +++ b/MantidQt/API/src/SignalBlocker.cpp @@ -40,10 +40,10 @@ template <typename Type> Type *SignalBlocker<Type>::operator->() { template <typename Type> void SignalBlocker<Type>::release() { m_obj = NULL; } // Template instances we need. -template class SignalBlocker<QObject>; -template class SignalBlocker<QAction>; -template class SignalBlocker<QPushButton>; -template class SignalBlocker<QComboBox>; +template class EXPORT_OPT_MANTIDQT_API SignalBlocker<QObject>; +template class EXPORT_OPT_MANTIDQT_API SignalBlocker<QAction>; +template class EXPORT_OPT_MANTIDQT_API SignalBlocker<QPushButton>; +template class EXPORT_OPT_MANTIDQT_API SignalBlocker<QComboBox>; } // namespace API } // namespace Mantid diff --git a/MantidQt/CustomDialogs/src/ConvertTableToMatrixWorkspaceDialog.cpp b/MantidQt/CustomDialogs/src/ConvertTableToMatrixWorkspaceDialog.cpp index 4541e225351..982808cb9d9 100644 --- a/MantidQt/CustomDialogs/src/ConvertTableToMatrixWorkspaceDialog.cpp +++ b/MantidQt/CustomDialogs/src/ConvertTableToMatrixWorkspaceDialog.cpp @@ -63,9 +63,9 @@ void ConvertTableToMatrixWorkspaceDialog::fillColumnNames( for (std::vector<std::string>::const_iterator column = columns.begin(); column != columns.end(); ++column) { QString qName = QString::fromStdString(*column); - m_form.cbColumnX->insertItem(-1, qName); - m_form.cbColumnY->insertItem(-1, qName); - m_form.cbColumnE->insertItem(-1, qName); + m_form.cbColumnX->addItem(qName); + m_form.cbColumnY->addItem(qName); + m_form.cbColumnE->addItem(qName); Mantid::API::Column_sptr col = tws->getColumn(*column); if (col->getPlotType() == 1 && defaultXColumn.isEmpty()) // type X { diff --git a/MantidQt/CustomInterfaces/CMakeLists.txt b/MantidQt/CustomInterfaces/CMakeLists.txt index 9df3b315ab8..2d6e0604e5a 100644 --- a/MantidQt/CustomInterfaces/CMakeLists.txt +++ b/MantidQt/CustomInterfaces/CMakeLists.txt @@ -9,6 +9,8 @@ set ( SRC_FILES src/DynamicPDF/DPDFInputDataControl.cpp src/DynamicPDF/DisplayCurveFitTest.cpp src/DynamicPDF/SliceSelector.cpp + src/EnggDiffraction/EnggDiffFittingPresenter.cpp + src/EnggDiffraction/EnggDiffFittingViewQtWidget.cpp src/EnggDiffraction/EnggDiffractionPresenter.cpp src/EnggDiffraction/EnggDiffractionViewQtGUI.cpp src/Homer.cpp @@ -147,9 +149,13 @@ set ( INC_FILES inc/MantidQtCustomInterfaces/DynamicPDF/DisplayCurveFitTest.h inc/MantidQtCustomInterfaces/DynamicPDF/SliceSelector.h inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffCalibSettings.h + inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingPresenter.h + inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingPresWorker.h + inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingViewQtWidget.h inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresWorker.h inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresenter.h inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionViewQtGUI.h + inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffFittingPresenter.h inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionPresenter.h inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionView.h inc/MantidQtCustomInterfaces/Homer.h @@ -305,6 +311,9 @@ set ( MOC_FILES inc/MantidQtCustomInterfaces/Background.h inc/MantidQtCustomInterfaces/DynamicPDF/DPDFFourierTransform.h inc/MantidQtCustomInterfaces/DynamicPDF/DPDFInputDataControl.h inc/MantidQtCustomInterfaces/DynamicPDF/SliceSelector.h + inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingPresenter.h + inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingPresWorker.h + inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingViewQtWidget.h inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresenter.h inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresWorker.h inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionViewQtGUI.h @@ -480,6 +489,7 @@ set ( TEST_FILES ALCLatestFileFinderTest.h ALCPeakFittingModelTest.h ALCPeakFittingPresenterTest.h + EnggDiffFittingPresenterTest.h EnggDiffractionPresenterTest.h IO_MuonGroupingTest.h ImageROIPresenterTest.h diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/DllConfig.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/DllConfig.h index b2a8a6eb63d..0b29436adda 100644 --- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/DllConfig.h +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/DllConfig.h @@ -30,8 +30,10 @@ */ #ifdef IN_MANTIDQT_CUSTOMINTERFACES #define MANTIDQT_CUSTOMINTERFACES_DLL DLLExport +#define EXTERN_MANTIDQT_CUSTOMINTERFACES #else #define MANTIDQT_CUSTOMINTERFACES_DLL DLLImport +#define EXTERN_MANTIDQT_CUSTOMINTERFACES EXTERN_IMPORT #endif #endif // MANTIDQTCUSTOMINTERFACES_DLLCONFIG_H_ diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingPresWorker.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingPresWorker.h new file mode 100644 index 00000000000..0998bbafcd5 --- /dev/null +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingPresWorker.h @@ -0,0 +1,69 @@ +#ifndef MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_ENGGDIFFFITTINGPRESWORKER_H_ +#define MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_ENGGDIFFFITTINGPRESWORKER_H_ + +#include "MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingPresenter.h" + +#include <QThread> + +namespace MantidQt { +namespace CustomInterfaces { + +/** +Worker to run long tasks for the presenter of the fitting tab of the +EnggDiffraction GUI. It has a finished() signal, and it is expected to +emit it when the hard/long-work methods finish. + +Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD +Oak Ridge National Laboratory & European Spallation Source + +This file is part of Mantid. + +Mantid is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +Mantid is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +File change history is stored at: <https://github.com/mantidproject/mantid> +Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ +class EnggDiffFittingWorker : public QObject { + Q_OBJECT + +public: + // for fitting (single peak fits) + EnggDiffFittingWorker(EnggDiffFittingPresenter *pres, + const std::string &focusedRunNo, + const std::string &ExpectedPeaks) + : m_pres(pres), m_runNo(focusedRunNo), m_expectedPeaks(ExpectedPeaks) {} + +private slots: + + void fitting() { + m_pres->doFitting(m_runNo, m_expectedPeaks); + emit finished(); + } + +signals: + void finished(); + +private: + EnggDiffFittingPresenter *m_pres; + + /// sample run to process + const std::string m_runNo; + // parameters for fitting, list of peaks + const std::string m_expectedPeaks; +}; + +} // namespace CustomInterfaces +} // namespace MantidQt + +#endif // MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_ENGGDIFFFITTINGPRESWORKER_H_ diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingPresenter.h new file mode 100644 index 00000000000..12f12f4eb9f --- /dev/null +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingPresenter.h @@ -0,0 +1,167 @@ +#ifndef MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_ENGGDIFFFITTINGPRESENTER_H_ +#define MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_ENGGDIFFFITTINGPRESENTER_H_ + +#include "MantidAPI/ITableWorkspace_fwd.h" +#include "MantidAPI/MatrixWorkspace_fwd.h" +#include "MantidQtCustomInterfaces/DllConfig.h" +#include "MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionCalibration.h" +#include "MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffFittingPresenter.h" +#include "MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffFittingView.h" + +#include <string> +#include <vector> + +#include <QObject> + +class QThread; + +namespace MantidQt { +namespace CustomInterfaces { + +/** +Presenter for the fitting tab/widget of the enggineering diffraction +GUI (presenter as in the MVP Model-View-Presenter pattern). + +Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD +Oak Ridge National Laboratory & European Spallation Source + +This file is part of Mantid. + +Mantid is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +Mantid is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +File change history is stored at: <https://github.com/mantidproject/mantid> +Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ +// needs to be dll-exported for the tests +class MANTIDQT_CUSTOMINTERFACES_DLL EnggDiffFittingPresenter + : public QObject, + public IEnggDiffFittingPresenter, + public IEnggDiffractionCalibration { + // Q_OBJECT for 'connect' with thread/worker + Q_OBJECT + +public: + EnggDiffFittingPresenter( + IEnggDiffFittingView *view, + boost::shared_ptr<IEnggDiffractionCalibration> mainCalib); + ~EnggDiffFittingPresenter() override; + + void notify(IEnggDiffFittingPresenter::Notification notif) override; + + /// From the IEnggDiffractionCalibration interface + //@{ + std::vector<GSASCalibrationParms> currentCalibration() const override; + //@} + + /// the fitting hard work that a worker / thread will run + void doFitting(const std::string &focusedRunNo, + const std::string &expectedPeaks); + + void runFittingAlgs(std::string FocusedFitPeaksTableName, + std::string FocusedWSName); + + std::string + functionStrFactory(Mantid::API::ITableWorkspace_sptr ¶mTableWS, + std::string tableName, size_t row, std::string &startX, + std::string &endX); + + void plotFitPeaksCurves(); + + void runEvaluateFunctionAlg(const std::string &bk2BkExpFunction, + const std::string &InputName, + const std::string &OutputName, + const std::string &startX, + const std::string &endX); + + void runCropWorkspaceAlg(std::string workspaceName); + + void runAppendSpectraAlg(std::string workspace1Name, + std::string workspace2Name); + + void runRebinToWorkspaceAlg(std::string workspaceName); + + void convertUnits(std::string workspaceName); + void runConvertUnitsAlg(std::string workspaceName); + void runAlignDetectorsAlg(std::string workspaceName); + + void setDifcTzero(Mantid::API::MatrixWorkspace_sptr wks) const; + void getDifcTzero(Mantid::API::MatrixWorkspace_const_sptr wks, double &difc, + double &difa, double &tzero) const; + + void runCloneWorkspaceAlg(std::string inputWorkspace, + const std::string &outputWorkspace); + + void setDataToClonedWS(std::string ¤t_WS, const std::string &cloned_WS); + + void setBankItems(); + + void setRunNoItems(std::vector<std::string> runNumVector, bool multiRun); + + void setDefaultBank(const std::vector<std::string> &splittedBaseName, + const std::string &selectedFile); + +protected: + void processStart(); + void processFitPeaks(); + void processShutDown(); + void processLogMsg(); + + /// clean shut down of model, view, etc. + void cleanup(); + +protected slots: + + void fittingFinished(); + void fittingRunNoChanged(); + +private: + bool isDigit(std::string text); + + // Methods related single peak fits + virtual void startAsyncFittingWorker(const std::string &focusedRunNo, + const std::string &expectedPeaks); + + std::string validateFittingexpectedPeaks(std::string &expectedPeaks) const; + + void inputChecksBeforeFitting(const std::string &focusedRunNo, + const std::string &expectedPeaks); + + void updateFittingDirVec(const std::string &bankDir, + const std::string &focusedFile, const bool multi_run, + std::vector<std::string> &fittingRunNoDirVec); + + void enableMultiRun(std::string firstRun, std::string lastRun, + std::vector<std::string> &fittingRunNoDirVec); + + // whether to use AlignDetectors to convert units + static const bool g_useAlignDetectors; + + // name of the workspace with the focused ws being used for fitting + static const std::string g_focusedFittingWSName; + + /// true if the last fitting completed successfully + bool m_fittingFinishedOK; + + QThread *m_workerThread; + + /// interface for the 'current' calibration + boost::shared_ptr<IEnggDiffractionCalibration> m_mainCalib; + + /// Associated view for this presenter (MVP pattern) + IEnggDiffFittingView *const m_view; +}; + +} // namespace CustomInterfaces +} // namespace MantidQt +#endif // MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_ENGGDIFFFITTINGPRESENTER_H_ diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingViewQtWidget.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingViewQtWidget.h new file mode 100644 index 00000000000..64cc5084a8b --- /dev/null +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingViewQtWidget.h @@ -0,0 +1,239 @@ +#ifndef MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_IENGGDIFFFITTINGVIEWQTWIDGET_H_ +#define MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_IENGGDIFFFITTINGVIEWQTWIDGET_H_ + +#include "MantidAPI/IPeakFunction.h" +#include "MantidQtCustomInterfaces/DllConfig.h" +#include "MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffFittingPresenter.h" +#include "MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffFittingView.h" + +#include "ui_EnggDiffractionQtTabFitting.h" + +#include <boost/scoped_ptr.hpp> + +// Qt classes forward declarations +class QMessageBox; +class QMutex; + +class QwtPlotCurve; +class QwtPlotZoomer; + +namespace MantidQt { + +namespace MantidWidgets { +class PeakPicker; +} + +namespace CustomInterfaces { + +/** +Qt-based view of the Engineering Diffraction (EnggDiff) fitting +widget/tab. Provides a concrete view that is Qt-based and is probably +the only one that will be implemented in a foreseeable horizon. The +interface of this class is given by IEnggDiffFittingView so that it +fits in the MVP (Model-View-Presenter) design of this GUI. + +Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD +Oak Ridge National Laboratory & European Spallation Source + +This file is part of Mantid. + +Mantid is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +Mantid is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +File change history is stored at: <https://github.com/mantidproject/mantid> +Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ +class MANTIDQT_CUSTOMINTERFACES_DLL EnggDiffFittingViewQtWidget + : public QWidget, + public IEnggDiffFittingView { + Q_OBJECT + +public: + EnggDiffFittingViewQtWidget( + QWidget *parent, boost::shared_ptr<IEnggDiffractionUserMsg> mainMsg, + boost::shared_ptr<IEnggDiffractionSettings> mainSettings, + boost::shared_ptr<IEnggDiffractionCalibration> mainCalib, + boost::shared_ptr<IEnggDiffractionPythonRunner> mainPyhonRunner); + ~EnggDiffFittingViewQtWidget() override; + + /// From the IEnggDiffractionUserMsg interface + //@{ + void showStatus(const std::string &sts) override; + + void userWarning(const std::string &warn, + const std::string &description) override; + + void userError(const std::string &err, + const std::string &description) override; + void enableCalibrateFocusFitUserActions(bool enable) override; + //@} + + /// From the IEnggDiffractionSettings interface + //@{ + EnggDiffCalibSettings currentCalibSettings() const override; + + std::string focusingDir() const override; + //@} + + /// From the IEnggDiffractionPythonRunner interface + //@{ + virtual std::string enggRunPythonCode(const std::string &pyCode) override; + //@} + + void enable(bool enable); + + std::vector<std::string> logMsgs() const override { return m_logMsgs; } + + void setFittingRunNo(const std::string &path) override; + + std::string getFittingRunNo() const override; + + void clearFittingComboBox() const override; + + void enableFittingComboBox(bool enable) const override; + + int getFittingComboIdx(std::string bank) const override; + + void clearFittingListWidget() const override; + + void enableFittingListWidget(bool enable) const override; + + int getFittingListWidgetCurrentRow() const override; + + void setFittingListWidgetCurrentRow(int idx) const override; + + std::string fittingPeaksData() const override; + + void setPeakList(const std::string &peakList) const override; + + std::vector<std::string> + splitFittingDirectory(std::string &selectedfPath) override; + + void setBankEmit() override; + + void setDataVector(std::vector<boost::shared_ptr<QwtData>> &data, + bool focused, bool plotSinglePeaks) override; + + void addBankItem(std::string bankID) override; + + void addRunNoItem(std::string runNo) override; + + std::vector<std::string> getFittingRunNumVec() override; + + void setFittingRunNumVec(std::vector<std::string> assignVec) override; + + bool getFittingMultiRunMode() override; + + void setFittingMultiRunMode(bool mode) override; + + std::string fittingRunNoFactory(std::string bank, std::string fileName, + std::string &bankDir, std::string fileDir); + + std::string readPeaksFile(std::string fileDir); + + void dataCurvesFactory(std::vector<boost::shared_ptr<QwtData>> &data, + std::vector<QwtPlotCurve *> &dataVector, bool focused); + + void setPeakPickerEnabled(bool enabled); + + void setPeakPicker(const Mantid::API::IPeakFunction_const_sptr &peak); + + double getPeakCentre() const; + + void fittingWriteFile(const std::string &fileDir); + + void setZoomTool(bool enabled); + + void resetView(); + +protected: + void initLayout(); + +signals: + void getBanks(); + void setBank(); + +private slots: + // slot of the fitting peaks per part of the interface + void browseFitFocusedRun(); + void resetFittingMultiMode(); + void setBankIdComboBox(int idx) override; + void browsePeaksToFit(); + void setPeakPick(); + void addPeakToList(); + void savePeakList(); + void clearPeakList(); + void fitClicked(); + void FittingRunNo(); + void plotSeparateWindow(); + void setBankDir(int idx); + void listViewFittingRun(); + +private: + /// Setup the interface (tab UI) + void doSetup(); + + /// Load saved/default interface settings + void readSettings(); + /// save settings (before closing) + void saveSettings() const override; + + /// converts QList to a vector + std::vector<std::string> qListToVector(QStringList list, + bool validator) const; + + // path/name for the persistent settings group of this interface + static const std::string g_settingsGroup; + + static const std::string g_peaksListExt; + + /// indentifier for fitting multi-run or single run input + static bool m_fittingMutliRunMode; + + // vector holding directory of focused bank file + static std::vector<std::string> m_fitting_runno_dir_vec; + + Ui::EnggDiffractionQtTabFitting m_ui; + + // here the view puts messages before notifying the presenter to show them + std::vector<std::string> m_logMsgs; + + /// Loaded focused workspace + std::vector<QwtPlotCurve *> m_focusedDataVector; + + /// Loaded data curves + std::vector<QwtPlotCurve *> m_fittedDataVector; + + /// Peak picker tool for fitting - only one on the plot at any given moment + MantidWidgets::PeakPicker *m_peakPicker = nullptr; + + /// zoom-in/zoom-out tool for fitting + QwtPlotZoomer *m_zoomTool = nullptr; + + /// user messages interface provided by a main view/widget + boost::shared_ptr<IEnggDiffractionUserMsg> m_mainMsgProvider; + + /// settings from the user + boost::shared_ptr<IEnggDiffractionSettings> m_mainSettings; + + /// interface for the Python runner + boost::shared_ptr<IEnggDiffractionPythonRunner> m_mainPythonRunner; + + /// presenter as in the model-view-presenter + boost::scoped_ptr<IEnggDiffFittingPresenter> m_presenter; +}; + +} // namespace CustomInterfaces +} // namespace MantidQt + +#endif // MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_IENGGDIFFFITTINGVIEWQTWIDGET_H_ diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresWorker.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresWorker.h index 526b85e4aa4..4ccdbe570d3 100644 --- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresWorker.h +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresWorker.h @@ -67,13 +67,6 @@ public: : m_pres(pres), m_runNo(runNo), m_bin(timeStep), m_nperiods(nperiods), m_outWSName(outWSName) {} - // for fitting (single peak fits) - EnggDiffWorker(EnggDiffractionPresenter *pres, - const std::string &focusedRunNo, - const std::string &ExpectedPeaks) - : m_pres(pres), m_runNo(focusedRunNo), m_expectedPeaks(ExpectedPeaks), - m_bin(.0), m_nperiods(0) {} - private slots: /** @@ -110,11 +103,6 @@ private slots: emit finished(); } - void fitting() { - m_pres->doFitting(m_runNo, m_expectedPeaks); - emit finished(); - } - signals: void finished(); @@ -139,8 +127,6 @@ private: const std::string m_SpectrumNos; // for focusing "texture" const std::string m_dgFile; - // parameters for fitting - const std::string m_expectedPeaks; // parameters for pre-processing/rebinning const double m_bin; const size_t m_nperiods; diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresenter.h index 5b3fdcaa5c4..fc7097609e2 100644 --- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresenter.h +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresenter.h @@ -5,11 +5,10 @@ #include "MantidAPI/MatrixWorkspace_fwd.h" #include "MantidAPI/Workspace_fwd.h" #include "MantidQtCustomInterfaces/DllConfig.h" +#include "MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionCalibration.h" #include "MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionPresenter.h" #include "MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionView.h" -// #include "MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionModel.h" - #include <boost/scoped_ptr.hpp> #include <QObject> @@ -23,8 +22,6 @@ class QThread; namespace MantidQt { namespace CustomInterfaces { -struct GSASCalibrationParms; - /** Presenter for the Enggineering Diffraction GUI (presenter as in the MVP Model-View-Presenter pattern). In principle, in a strict MVP @@ -55,12 +52,12 @@ Code Documentation is available at: <http://doxygen.mantidproject.org> // needs to be dll-exported for the tests class MANTIDQT_CUSTOMINTERFACES_DLL EnggDiffractionPresenter : public QObject, - public IEnggDiffractionPresenter { + public IEnggDiffractionPresenter, + public IEnggDiffractionCalibration { // Q_OBJECT for 'connect' with thread/worker Q_OBJECT public: - /// Default constructor - normally used from the concrete view EnggDiffractionPresenter(IEnggDiffractionView *view); ~EnggDiffractionPresenter() override; @@ -92,55 +89,6 @@ public: void doRebinningPulses(const std::string &runNo, size_t nperiods, double bin, const std::string &outWSName); - /// the fitting hard work that a worker / thread will run - void doFitting(const std::string &focusedRunNo, - const std::string &expectedPeaks); - - void runFittingAlgs(std::string FocusedFitPeaksTableName, - std::string FocusedWSName); - - std::string - functionStrFactory(Mantid::API::ITableWorkspace_sptr ¶mTableWS, - std::string tableName, size_t row, std::string &startX, - std::string &endX); - - void plotFitPeaksCurves(); - - void runEvaluateFunctionAlg(const std::string &bk2BkExpFunction, - const std::string &InputName, - const std::string &OutputName, - const std::string &startX, - const std::string &endX); - - void runCropWorkspaceAlg(std::string workspaceName); - - void runAppendSpectraAlg(std::string workspace1Name, - std::string workspace2Name); - - void runRebinToWorkspaceAlg(std::string workspaceName); - - void convertUnits(std::string workspaceName); - void runConvertUnitsAlg(std::string workspaceName); - void runAlignDetectorsAlg(std::string workspaceName); - - void setDifcTzero(Mantid::API::MatrixWorkspace_sptr wks) const; - void getDifcTzero(Mantid::API::MatrixWorkspace_const_sptr wks, double &difc, - double &difa, double &tzero) const; - - void runCloneWorkspaceAlg(std::string inputWorkspace, - const std::string &outputWorkspace); - - void setDataToClonedWS(std::string ¤t_WS, const std::string &cloned_WS); - - void setBankItems(); - - void setRunNoItems(std::vector<std::string> runNumVector, bool multiRun); - - void setDefaultBank(std::vector<std::string> splittedBaseName, - QString selectedFile); - - bool isDigit(std::string text); - protected: void initialize(); @@ -157,7 +105,6 @@ protected: void processResetFocus(); void processRebinTime(); void processRebinMultiperiod(); - void processFitPeaks(); void processLogMsg(); void processInstChange(); void processRBNumberChange(); @@ -168,8 +115,6 @@ protected slots: void calibrationFinished(); void focusingFinished(); void rebinningFinished(); - void fittingFinished(); - void fittingRunNoChanged(); private: bool validateRBNumber(const std::string &rbn) const; @@ -207,6 +152,7 @@ private: const std::string &ceriaNo, const std::string &bankName = "") const; + std::vector<GSASCalibrationParms> currentCalibration() const override; //@} /// @name Focusing related private methods @@ -298,22 +244,6 @@ private: const std::string &outWSName); //@} - // Methods related single peak fits - virtual void startAsyncFittingWorker(const std::string &focusedRunNo, - const std::string &expectedPeaks); - - std::string validateFittingexpectedPeaks(std::string &expectedPeaks) const; - - void inputChecksBeforeFitting(const std::string &focusedRunNo, - const std::string &expectedPeaks); - - void updateFittingDirVec(const std::string &bankDir, - const std::string &focusedFile, const bool multi_run, - std::vector<std::string> &fittingRunNoDirVec); - - void enableMultiRun(std::string firstRun, std::string lastRun, - std::vector<std::string> &fittingRunNoDirVec); - // plots workspace according to the user selection void plotFocusedWorkspace(std::string outWSName); @@ -386,9 +316,6 @@ private: // name of the workspace with the vanadium (smoothed) curves static const std::string g_vanCurvesWSName; - // name of the workspace with the focused ws being used for fitting - static const std::string g_focusedFittingWSName; - // for the GSAS parameters (difc, difa, tzero) of the banks static const std::string g_calibBanksParms; @@ -422,11 +349,6 @@ private: bool m_focusFinishedOK; /// true if the last pre-processing/re-binning completed successfully bool m_rebinningFinishedOK; - /// true if the last fitting completed successfully - bool m_fittingFinishedOK; - - // whether to use AlignDetectors to convert units - static bool g_useAlignDetectors; /// Counter for the cropped output files static int g_croppedCounter; diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionViewQtGUI.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionViewQtGUI.h index bebbdb4c7d5..dcd0e181eb8 100644 --- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionViewQtGUI.h +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionViewQtGUI.h @@ -4,24 +4,26 @@ #include "MantidAPI/IPeakFunction.h" #include "MantidQtAPI/UserSubWindow.h" #include "MantidQtCustomInterfaces/DllConfig.h" +#include "MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingViewQtWidget.h" #include "MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionPresenter.h" #include "MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionView.h" #include "MantidQtMantidWidgets/PeakPicker.h" #include "ui_EnggDiffractionQtGUI.h" #include "ui_EnggDiffractionQtTabCalib.h" -#include "ui_EnggDiffractionQtTabFitting.h" #include "ui_EnggDiffractionQtTabFocus.h" #include "ui_EnggDiffractionQtTabPreproc.h" #include "ui_EnggDiffractionQtTabSettings.h" #include <boost/scoped_ptr.hpp> -#include <qwt_plot_zoomer.h> // Qt classes forward declarations class QMessageBox; class QMutex; +class QwtPlotCurve; +class QwtPlotZoomer; + namespace MantidQt { namespace CustomInterfaces { @@ -106,8 +108,6 @@ public: std::vector<std::string> newCeriaNo() const override; - std::string outCalibFilename() const override { return m_outCalibFilename; } - int currentCropCalibBankName() const override { return m_currentCropCalibBankName; } @@ -123,7 +123,7 @@ public: void enableTabs(bool enable) override; - void enableCalibrateAndFocusActions(bool enable) override; + void enableCalibrateFocusFitUserActions(bool enable) override; std::string focusingDir() const override; @@ -153,70 +153,6 @@ public: double rebinningPulsesTime() const override; - void setFittingRunNo(QString path) override; - - std::string getFittingRunNo() const override; - - void clearFittingComboBox() const override; - - void enableFittingComboBox(bool enable) const override; - - int getFittingComboIdx(std::string bank) const override; - - void clearFittingListWidget() const override; - - void enableFittingListWidget(bool enable) const override; - - int getFittingListWidgetCurrentRow() const override; - - void setFittingListWidgetCurrentRow(int idx) const override; - - std::string fittingPeaksData() const override; - - void setPeakList(std::string peakList) const override; - - std::vector<std::string> - splitFittingDirectory(std::string &selectedfPath) override; - - void setBankEmit() override; - - std::string getFocusDir() override; - - void setDataVector(std::vector<boost::shared_ptr<QwtData>> &data, - bool focused, bool plotSinglePeaks) override; - - void addBankItem(std::string bankID) override; - - void addRunNoItem(std::string runNo) override; - - std::vector<std::string> getFittingRunNumVec() override; - - void setFittingRunNumVec(std::vector<std::string> assignVec) override; - - bool getFittingMultiRunMode() override; - - void setFittingMultiRunMode(bool mode) override; - - std::string fittingRunNoFactory(std::string bank, std::string fileName, - std::string &bankDir, std::string fileDir); - - std::string readPeaksFile(std::string fileDir); - - void dataCurvesFactory(std::vector<boost::shared_ptr<QwtData>> &data, - std::vector<QwtPlotCurve *> &dataVector, bool focused); - - void setPeakPickerEnabled(bool enabled); - - void setPeakPicker(const Mantid::API::IPeakFunction_const_sptr &peak); - - double getPeakCentre() const; - - void fittingWriteFile(const std::string &fileDir); - - void setZoomTool(bool enabled); - - void resetView(); - void plotFocusedSpectrum(const std::string &wsName) override; void plotWaterfallSpectrum(const std::string &wsName) override; @@ -282,21 +218,6 @@ private slots: // enables the text field when appropriate bank name is selected void enableSpecNos(); - // slot of the fitting peaks per part of the interface - void browseFitFocusedRun(); - void resetFittingMultiMode(); - void setBankIdComboBox(int idx) override; - void browsePeaksToFit(); - void setPeakPick(); - void addPeakToList(); - void savePeakList(); - void clearPeakList(); - void fitClicked(); - void FittingRunNo(); - void plotSeparateWindow(); - void setBankDir(int idx); - void listViewFittingRun(); - // show the standard Mantid help window with this interface's help void openHelpWin(); @@ -308,7 +229,6 @@ private: void doSetupTabCalib(); void doSetupTabFocus(); void doSetupTabPreproc(); - void doSetupTabFitting(); void doSetupTabSettings(); std::string guessGSASTemplatePath() const; @@ -323,7 +243,7 @@ private: void closeEvent(QCloseEvent *ev) override; // path/name for the persistent settings group of this interface - const static std::string m_settingsGroup; + const static std::string g_settingsGroup; // here the view puts messages before notifying the presenter to show them std::vector<std::string> m_logMsgs; @@ -336,7 +256,8 @@ private: Ui::EnggDiffractionQtTabCalib m_uiTabCalib; Ui::EnggDiffractionQtTabFocus m_uiTabFocus; Ui::EnggDiffractionQtTabPreproc m_uiTabPreproc; - Ui::EnggDiffractionQtTabFitting m_uiTabFitting; + // Ui::EnggDiffractionQtTabFitting m_uiTabFitting; + EnggDiffFittingViewQtWidget *m_fittingWidget; Ui::EnggDiffractionQtTabSettings m_uiTabSettings; /// converts QList to a vector @@ -361,17 +282,8 @@ private: // multi-run focus mode type selected int static m_currentRunMode; - /// indentifier for fitting multi-run or single run input - bool static m_fittingMutliRunMode; - - // vector holding directory of focused bank file - std::vector<std::string> static m_fitting_runno_dir_vec; - - /// current calibration produced in the 'Calibration' tab - std::string m_currentCalibFilename; /// calibration settings - from/to the 'settings' tab EnggDiffCalibSettings m_calibSettings; - std::string m_outCalibFilename; /// To show important non-modal messages QMessageBox *m_splashMsg; @@ -391,20 +303,8 @@ private: /// (focusing) static const std::string g_DetGrpExtStr; - /// Loaded focused workspace - std::vector<QwtPlotCurve *> m_focusedDataVector; - - /// Loaded data curves - std::vector<QwtPlotCurve *> m_fittedDataVector; - - /// Peak picker tool for fitting - only one on the plot at any given moment - MantidWidgets::PeakPicker *m_peakPicker; - - /// zoom-in/zoom-out tool for fitting - QwtPlotZoomer *m_zoomTool; - /// presenter as in the model-view-presenter - boost::scoped_ptr<IEnggDiffractionPresenter> m_presenter; + boost::shared_ptr<IEnggDiffractionPresenter> m_presenter; }; } // namespace CustomInterfaces diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffFittingPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffFittingPresenter.h new file mode 100644 index 00000000000..7faec353e39 --- /dev/null +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffFittingPresenter.h @@ -0,0 +1,64 @@ +#ifndef MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_IENGGDIFFFITTINGPRESENTER_H_ +#define MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_IENGGDIFFFITTINGPRESENTER_H_ + +#include "MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionCalibration.h" + +namespace MantidQt { +namespace CustomInterfaces { + +/** +Interface of the presenter of the fitting widget/tab of the Engg +Diffraction GUI. Here the term presenter is used as in the MVP +(Model-View-Presenter) pattern. The view should be as passive as +possible and just notify any user actions. + +Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD +Oak Ridge National Laboratory & European Spallation Source + +This file is part of Mantid. + +Mantid is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +Mantid is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +File change history is stored at: <https://github.com/mantidproject/mantid> +Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ +class IEnggDiffFittingPresenter { + +public: + virtual ~IEnggDiffFittingPresenter() = default; + + /// These are user actions, triggered from the (passive) view, that need + /// handling by the presenter + enum Notification { + Start, ///< Start and setup interface + FittingRunNo, ///< Creates widgets and handles multi/run numbers + FitPeaks, ///< Preforms single peak fits + ShutDown, ///< closing the interface + LogMsg, ///< need to send a message to the Mantid log system + }; + + /** + * Notifications sent through the presenter when something changes + * in the view. This plays the role of signals emitted by the view + * to this presenter. + * + * @param notif Type of notification to process. + */ + virtual void notify(IEnggDiffFittingPresenter::Notification notif) = 0; +}; + +} // namespace CustomInterfaces +} // namespace MantidQt + +#endif // MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_IENGGDIFFFITTINGPRESENTER_H_ diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffFittingView.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffFittingView.h new file mode 100644 index 00000000000..0b26ab575c9 --- /dev/null +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffFittingView.h @@ -0,0 +1,222 @@ +#ifndef MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_IENGGDIFFFITTINGVIEW_H_ +#define MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_IENGGDIFFFITTINGVIEW_H_ + +#include "MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionUserMsg.h" +#include "MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionSettings.h" +#include "MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionPythonRunner.h" + +#include <string> +#include <vector> + +class QwtData; + +namespace MantidQt { +namespace CustomInterfaces { + +/** +Engineering diffraction custom interface / GUI. This is the base class +(interface) for the view of the the fitting tab/widget (view in the +sense of the Model-View-Presenter, MVP pattern). This class is +Qt-free. Qt specific functionality/dependencies are added in a class +derived from this. + +Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD +Oak Ridge National Laboratory & European Spallation Source + +This file is part of Mantid. + +Mantid is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +Mantid is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +File change history is stored at: <https://github.com/mantidproject/mantid> +Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ +class IEnggDiffFittingView : public IEnggDiffractionUserMsg, + public IEnggDiffractionSettings, + public IEnggDiffractionPythonRunner { + +public: + virtual ~IEnggDiffFittingView() = default; + + /** + * returns directory of the file name to preform fitting on + * + * @return directory as std::string + */ + virtual std::string getFittingRunNo() const = 0; + + /** + * A list of dSpacing values to be translated into TOF + * to find expected peaks. + * + * @return list of dSpacing values as std::string + */ + virtual std::string fittingPeaksData() const = 0; + + /** + * Sets the peak list according to the string given + * + * @param peakList list of expected peaks to be fitted as std::string + */ + virtual void setPeakList(const std::string &peakList) const = 0; + + /** + * Splits the file name in to sections of '_' and 'ENGINX' text + * within the filename + * + * @param selectedfPath is the selected file's path + * + * @return std::vector<std::string> of splitted file name with run + * number & bank + */ + virtual std::vector<std::string> + splitFittingDirectory(std::string &selectedfPath) = 0; + + /** + * adds the number of banks to the combo-box widget on the interface + * + * @param bankID the bank number to add to combo-box + */ + virtual void addBankItem(std::string bankID) = 0; + + /** + * adds the run number to the list view widget on the interface + * + * @param runNo run number which needs to be added to + * the list widget + */ + virtual void addRunNoItem(std::string runNo) = 0; + + /** + * emits the signal within view when run number/bank changed + */ + virtual void setBankEmit() = 0; + + /** + * sets the bank combo-box according to given index + * + * @param idx as int of the bank to set + */ + virtual void setBankIdComboBox(int idx) = 0; + + /** + * Deletes all items from the fitting combo-box widget + */ + virtual void clearFittingComboBox() const = 0; + + /** + * Enables or disables the fitting combo-box + * + * @param enable or disable the fitting combo-box widget + */ + virtual void enableFittingComboBox(bool enable) const = 0; + + /** + * gets the index of the bank according to text found + * + * @param bank as a std::string to find in widget + * + * @returns int index of the combo-box where the + * string is found + */ + virtual int getFittingComboIdx(std::string bank) const = 0; + + /** + * Deletes all items from the fitting list widget + */ + virtual void clearFittingListWidget() const = 0; + + /** + * Enables or disables the fitting list widget + * + * @param enable or disable the fitting list widget + */ + virtual void enableFittingListWidget(bool enable) const = 0; + + /** + * @return idx of current selected row of list widget + */ + virtual int getFittingListWidgetCurrentRow() const = 0; + + /** + * Sets the current row of the fitting list widget + * + * @param idx number to set as for the list widget + */ + virtual void setFittingListWidgetCurrentRow(int idx) const = 0; + + /** + * sets the fitting run number according to path + * + * @param path of the selected focused run file + */ + virtual void setFittingRunNo(const std::string &path) = 0; + + /** + * gets the global vector in view containing focused file directory + * + * @return std::vector<std::string> containing the focused bank files + */ + virtual std::vector<std::string> getFittingRunNumVec() = 0; + + /** + * sets the global vector in view containing focused file directory + * + * @param assignVec of the all the focused bank files + * per run number + */ + virtual void setFittingRunNumVec(std::vector<std::string> assignVec) = 0; + + /** + * to determine whether the current loop is multi-run or single to avoid + * regenerating the list-view widget when not required + * + * @return bool whether given multi-run or singular file + */ + virtual bool getFittingMultiRunMode() = 0; + + /** + * sets the fitting mode to multi-run or single to avoid + * regenerating the list-view widget when not required + * + * @param mode true if its multi-run + */ + virtual void setFittingMultiRunMode(bool mode) = 0; + + /** + * generates and sets the curves on the fitting tab + * + * @param data of the workspace to be passed as QwtData + * @param focused to check whether focused workspace + * @param plotSinglePeaks whether to plot single peak fitting ws + */ + virtual void setDataVector(std::vector<boost::shared_ptr<QwtData>> &data, + bool focused, bool plotSinglePeaks) = 0; + + /** + * Messages that this view wants to send to the logging system. + * + * @return list of messages to log, one by one. + */ + virtual std::vector<std::string> logMsgs() const = 0; + + /** + * Save user settings (normally when closing the interface). + */ + virtual void saveSettings() const = 0; +}; + +} // namespace CustomInterfaces +} // namespace MantidQt + +#endif // MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_IENGGDIFFFITTINGVIEW_H_ diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionCalibration.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionCalibration.h new file mode 100644 index 00000000000..2ac34269ac0 --- /dev/null +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionCalibration.h @@ -0,0 +1,64 @@ +#ifndef MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_IENGGDIFFRACTIONCALIBRATION_H_ +#define MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_IENGGDIFFRACTIONCALIBRATION_H_ + +#include <vector> + +namespace MantidQt { +namespace CustomInterfaces { + +/** + * Parameters from a GSAS calibration. They define a conversion of + * units time-of-flight<->d-spacing that can be calculated with the + * algorithm AlignDetectors for example. + */ +struct GSASCalibrationParms { + GSASCalibrationParms(size_t bid, double dc, double da, double tz) + : bankid(bid), difc(dc), difa(da), tzero(tz) {} + + size_t bankid{0}; + double difc{0}; + double difa{0}; + double tzero{0}; +}; + +/** +Interface to the current calibration functionality of the Engineering +Diffraction (EnggDiffraction) GUI. This can be used in different +tabs/widgets as well as in the main/central view. Normally this +interface will be provided by the presenters of the widgets (assuming +an MVP design). The individual / area specific tabs/widgets (their +presenters) will forward to the widget responsible for the +calibration. + +Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD +Oak Ridge National Laboratory & European Spallation Source + +This file is part of Mantid. + +Mantid is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +Mantid is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +File change history is stored at: <https://github.com/mantidproject/mantid> +Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ +class IEnggDiffractionCalibration { +public: + virtual ~IEnggDiffractionCalibration() = default; + + virtual std::vector<GSASCalibrationParms> currentCalibration() const = 0; +}; + +} // namespace CustomInterfaces +} // namespace MantidQt + +#endif // MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_IENGGDIFFRACTIOPYTHONRUNNER_H_ diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionPresenter.h index 22d6277c6a7..0152a1bd15c 100644 --- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionPresenter.h +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionPresenter.h @@ -32,8 +32,9 @@ File change history is stored at: <https://github.com/mantidproject/mantid> Code Documentation is available at: <http://doxygen.mantidproject.org> */ class IEnggDiffractionPresenter { + public: - virtual ~IEnggDiffractionPresenter() {} + virtual ~IEnggDiffractionPresenter() = default; /// These are user actions, triggered from the (passive) view, that need /// handling by the presenter @@ -48,8 +49,6 @@ public: ResetFocus, ///< Re-set / clear all focus inputs and options RebinTime, ///< From event to histo, with a time bin RebinMultiperiod, ///< From event to histo, multiperiod event data - FittingRunNo, ///< Creates widgets and handles multi/run numbers - FitPeaks, ///< Preforms single peak fits LogMsg, ///< need to send a message to the Mantid log system InstrumentChange, ///< Instrument selection updated RBNumberChange, ///< RBNumber filled-in/changed diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionPythonRunner.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionPythonRunner.h new file mode 100644 index 00000000000..dd105e318f8 --- /dev/null +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionPythonRunner.h @@ -0,0 +1,56 @@ +#ifndef MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_IENGGDIFFRACTIONPYTHONRUNNER_H_ +#define MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_IENGGDIFFRACTIONPYTHONRUNNER_H_ + +namespace MantidQt { +namespace CustomInterfaces { + +/** +Interface to the python script runner functionality of the Engineering +Diffraction (EnggDiffraction) GUI. This can be used in different +tabs/widgets as well as in the main/central view. Normally the +individual / area specific tabs/widgets will forward to the main view. + +Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD +Oak Ridge National Laboratory & European Spallation Source + +This file is part of Mantid. + +Mantid is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +Mantid is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +File change history is stored at: <https://github.com/mantidproject/mantid> +Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ +class IEnggDiffractionPythonRunner { +public: + virtual ~IEnggDiffractionPythonRunner() = default; + + /** + * Run Python code received as a script string. This is used for + * example to write GSAS instrument parameters file, to plot using + * the 'plotSpectrum' python functions, or other code included with + * the Engg scripts. In the first case, this is done temporarily + * here until we have a more final way of generating these files. A + * SaveGSAS algorithm that can handle ENGIN-X files would be ideal. + * + * @param pyCode Python script as a string + * + * @return status string from running the code + */ + virtual std::string enggRunPythonCode(const std::string &pyCode) = 0; +}; + +} // namespace CustomInterfaces +} // namespace MantidQt + +#endif // MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_IENGGDIFFRACTIOPYTHONRUNNER_H_ diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionSettings.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionSettings.h new file mode 100644 index 00000000000..729f852d322 --- /dev/null +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionSettings.h @@ -0,0 +1,60 @@ +#ifndef MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_IENGGDIFFRACTIONSETTINGS_H_ +#define MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_IENGGDIFFRACTIONSETTINGS_H_ + +#include <string> + +#include "MantidQtCustomInterfaces/EnggDiffraction/EnggDiffCalibSettings.h" + +namespace MantidQt { +namespace CustomInterfaces { + +/** +Interface to settings of the Engineering Diffraction (EnggDiffraction) +GUI. This can be used in different tabs/widgets as well as in the +main/central view. Normally the individual / area specific +tabs/widgets will forward to the main view. + +Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD +Oak Ridge National Laboratory & European Spallation Source + +This file is part of Mantid. + +Mantid is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +Mantid is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +File change history is stored at: <https://github.com/mantidproject/mantid> +Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ +class IEnggDiffractionSettings { +public: + virtual ~IEnggDiffractionSettings() = default; + + /** + * Calibration settings as defined by the user. + * + * @return calibration settings object with current user settings + */ + virtual EnggDiffCalibSettings currentCalibSettings() const = 0; + + /** + * Directory set for outputs from focusing calculations. + * + * @return directory path as a string + */ + virtual std::string focusingDir() const = 0; +}; + +} // namespace CustomInterfaces +} // namespace MantidQt + +#endif // MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_IENGGDIFFRACTIONSETTINGS_H_ diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionUserMsg.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionUserMsg.h new file mode 100644 index 00000000000..85383d10076 --- /dev/null +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionUserMsg.h @@ -0,0 +1,92 @@ +#ifndef MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_IENGGDIFFRACTIONUSERMSG_H_ +#define MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_IENGGDIFFRACTIONUSERMSG_H_ + +#include <string> +#include <vector> + +namespace MantidQt { +namespace CustomInterfaces { + +/** +Interface for user message related functionality in the engineering +diffraction custom interface / GUI view(s). This can be used in +different tabs/widgets as well as in the main/central view. Normally +the individual / area specific tabs/widgets will forward to the main +view. + +Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD +Oak Ridge National Laboratory & European Spallation Source + +This file is part of Mantid. + +Mantid is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +Mantid is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +File change history is stored at: <https://github.com/mantidproject/mantid> +Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ +class IEnggDiffractionUserMsg { + +public: + virtual ~IEnggDiffractionUserMsg() = default; + + /** + * Display the current status (running some algorithms, finished, + * ready, etc.), in a status bar or similar. + * + * @param sts status message which should be concise + */ + virtual void showStatus(const std::string &sts) = 0; + + /// @name Direct (and usually modal, or at least top/pop-up level) user + /// interaction + //@{ + /** + * Display a warning to the user (for example as a pop-up window). + * + * @param warn warning title, should be short and would normally be + * shown as the title of the window or a big banner. + * + * @param description longer, free form description of the issue. + */ + virtual void userWarning(const std::string &warn, + const std::string &description) = 0; + + /** + * Display an error message (for example as a pop-up window). + * + * @param err Error title, should be short and would normally be + * shown as the title of the window or a big banner. + * + * @param description longer, free form description of the issue. + */ + virtual void userError(const std::string &err, + const std::string &description) = 0; + //@} + + /** + * Enable/disable all user actions to + * calibrate+focus+fitting+.... The idea is that actions / buttons + * like 'calibrate', 'load calibration', 'focus', 'fit' can be + * disabled while other work is done (be it calibration, focusing, + * fitting or anything). + * + * @param enable true to enable actions (default initial state) + */ + virtual void enableCalibrateFocusFitUserActions(bool enable) = 0; +}; + +} // namespace CustomInterfaces +} // namespace MantidQt + +#endif // MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_IENGGDIFFRACTIONUSERMSG_H_ diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionView.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionView.h index b33289bcda5..e8fa79fc098 100644 --- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionView.h +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionView.h @@ -1,14 +1,12 @@ #ifndef MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_IENGGDIFFRACTIONVIEW_H_ #define MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_IENGGDIFFRACTIONVIEW_H_ -#include <QStringList> -#include <qwt_plot_curve.h> #include <string> #include <vector> -#include "MantidAPI/IPeakFunction.h" -#include "MantidAPI/MatrixWorkspace_fwd.h" -#include "MantidQtCustomInterfaces/EnggDiffraction/EnggDiffCalibSettings.h" +#include "MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionUserMsg.h" +#include "MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionSettings.h" +#include "MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionPythonRunner.h" namespace MantidQt { namespace CustomInterfaces { @@ -41,11 +39,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. File change history is stored at: <https://github.com/mantidproject/mantid> Code Documentation is available at: <http://doxygen.mantidproject.org> */ -class IEnggDiffractionView { +class IEnggDiffractionView : public IEnggDiffractionUserMsg, + public IEnggDiffractionSettings, + public IEnggDiffractionPythonRunner { public: - IEnggDiffractionView(){}; - virtual ~IEnggDiffractionView(){}; + virtual ~IEnggDiffractionView() = default; /// @name Direct (and usually modal, or at least top/pop-up level) user /// interaction @@ -64,36 +63,6 @@ public: virtual void splashMessage(bool visible, const std::string &shortMsg, const std::string &description) = 0; - /** - * Display the current status (running some algorithms, finished, - * ready, etc.), in a status bar or similar. - * - * @param sts status message which should be concise - */ - virtual void showStatus(const std::string &sts) = 0; - - /** - * Display a warning to the user (for example as a pop-up window). - * - * @param warn warning title, should be short and would normally be - * shown as the title of the window or a big banner. - * - * @param description longer, free form description of the issue. - */ - virtual void userWarning(const std::string &warn, - const std::string &description) = 0; - - /** - * Display an error message (for example as a pop-up window). - * - * @param err Error title, should be short and would normally be - * shown as the title of the window or a big banner. - * - * @param description longer, free form description of the issue. - */ - virtual void userError(const std::string &err, - const std::string &description) = 0; - /** * Gets a filename from the user, to use for a new calibration file. * @@ -128,12 +97,6 @@ public: */ virtual std::string getRBNumber() const = 0; - /** - * - * @return calibration settings object with current user settings - */ - virtual EnggDiffCalibSettings currentCalibSettings() const = 0; - /** * What's the instrument this interface is using? * @@ -216,13 +179,6 @@ public: */ virtual std::vector<std::string> newCeriaNo() const = 0; - /** - * The filename (can be full path) selected to write a calibration - * - * @return file name - */ - virtual std::string outCalibFilename() const = 0; - /** * A new calibration is calculated or loaded => update display and * widgets. This becomes the new 'current' calibration. @@ -235,19 +191,6 @@ public: const std::string &ceriaNo, const std::string &fname) = 0; - /** - * Run Python code received as a script string. This is used for - * example to write GSAS instrument parameters file, or other code - * included with the Engg scripts. Temporarily here until we have a - * more final way of generating these files. A SaveGSAS algorithm - * that can handle ENGIN-X files would be ideal. - * - * @param pyCode Python script as a string - * - * @return status string from running the code - */ - virtual std::string enggRunPythonCode(const std::string &pyCode) = 0; - /** * Enable/disable all the sections or tabs of the interface. To be * used with required parameters, like a valid instrument, a valid @@ -258,22 +201,6 @@ public: */ virtual void enableTabs(bool enable) = 0; - /** - * Enable/disable calibrate+focus actions. The idea is that actions - * / buttons like 'calibrate', 'load calibration', or 'focus' can be - * disabled while a calibration of a focusing is being calculated. - * - * @param enable true to enable actions (default initial state) - */ - virtual void enableCalibrateAndFocusActions(bool enable) = 0; - - /** - * Directory set for focusing outputs - * - * @return directory path as a string - */ - virtual std::string focusingDir() const = 0; - /** * A (sample) run to focus * @@ -371,167 +298,6 @@ public: */ virtual double rebinningPulsesTime() const = 0; - /** - * returns directory of the file name to preform fitting on - * - * @return directory as std::string - */ - virtual std::string getFittingRunNo() const = 0; - - /** - * A list of dSpacing values to be translated into TOF - * to find expected peaks. - * - * @return list of dSpacing values as std::string - */ - virtual std::string fittingPeaksData() const = 0; - - /** - * Sets the peak list according to the QString given - * - * @param peakList list of expected peaks to be fitted as std::string - */ - virtual void setPeakList(std::string peakList) const = 0; - - /** - * Splits the file name in to sections of '_' and 'ENGINX' text - * within the filename - * - * @param selectedfPath is the selected file's path - * - * @return std::vector<std::string> of splitted file name with run - * number & bank - */ - virtual std::vector<std::string> - splitFittingDirectory(std::string &selectedfPath) = 0; - - /** - * adds the number of banks to the combo-box widget on the interface - * - * @param bankID the bank number to add to combo-box - */ - virtual void addBankItem(std::string bankID) = 0; - - /** - * adds the run number to the list view widget on the interface - * - * @param runNo run number which needs to be added to - * the list widget - */ - virtual void addRunNoItem(std::string runNo) = 0; - - /** - * emits the signal within view when run number/bank changed - */ - virtual void setBankEmit() = 0; - - /** - * sets the bank combo-box according to given index - * - * @param idx as int of the bank to set - */ - virtual void setBankIdComboBox(int idx) = 0; - - /** - * deletes all items from the fitting combo-box widget - */ - virtual void clearFittingComboBox() const = 0; - - /** - * enables or disables the fitting combo-box - * - * @param enable or disable the fitting combo-box widget - */ - virtual void enableFittingComboBox(bool enable) const = 0; - - /** - * gets the index of the bank according to text found - * - * @param bank as a std::string to find in widget - * - * @returns int index of the combo-box where the - * string is found - */ - virtual int getFittingComboIdx(std::string bank) const = 0; - - /* - * deletes all items from the fitting list widget - */ - virtual void clearFittingListWidget() const = 0; - - /** - * enables or disables the fitting list widget - * - * @param enable or disable the fitting list widget - */ - virtual void enableFittingListWidget(bool enable) const = 0; - - /* - * @return idx of current selected row of list widget - */ - virtual int getFittingListWidgetCurrentRow() const = 0; - - /** - * sets the current row of the fitting list widget - * - * @param idx number to set as for the list widget - */ - virtual void setFittingListWidgetCurrentRow(int idx) const = 0; - - /** - * gets the set focus directory within the setting tab - * - * @return std::string of focus directory - */ - virtual std::string getFocusDir() = 0; - - /** - * sets the fitting run number according to path - * - * @param path of the selected focused run file - */ - virtual void setFittingRunNo(QString path) = 0; - - /** - * gets the global vector in view containing focused file directory - * - * @return std::vector<std::string> containing the focused bank files - */ - virtual std::vector<std::string> getFittingRunNumVec() = 0; - - /** - * sets the global vector in view containing focused file directory - * - * @param assignVec of the all the focused bank files - * per run number - */ - virtual void setFittingRunNumVec(std::vector<std::string> assignVec) = 0; - - /** - * to determine whether the current loop is multi-run or single to avoid - * regenerating the list-view widget when not required - * - * @return bool whether given multi-run or singular file - */ - virtual bool getFittingMultiRunMode() = 0; - - /** - * sets the fitting mode to multi-run or single to avoid - * regenerating the list-view widget when not required - * - * @param mode true if its multi-run - */ - virtual void setFittingMultiRunMode(bool mode) = 0; - - /** - * generates and sets the curves on the fitting tab - * @param data of the workspace to be passed as QwtData - * @param focused to check whether focused workspace - * @param plotSinglePeaks whether to plot single peak fitting ws - * - */ - virtual void setDataVector(std::vector<boost::shared_ptr<QwtData>> &data, - bool focused, bool plotSinglePeaks) = 0; //@} /** diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/Elwin.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/Elwin.h index ca203d47165..87fdeae8fdf 100644 --- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/Elwin.h +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/Elwin.h @@ -33,7 +33,8 @@ private slots: void unGroupInput(bool error); private: - void addSaveAlgorithm(QString workspaceName, QString filename = ""); + void addSaveAlgorithm(const std::string &workspaceName, + std::string filename = ""); Ui::Elwin m_uiForm; QtTreePropertyBrowser *m_elwTree; diff --git a/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffFittingPresenter.cpp b/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffFittingPresenter.cpp new file mode 100644 index 00000000000..9cb0fda741e --- /dev/null +++ b/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffFittingPresenter.cpp @@ -0,0 +1,1126 @@ +#include "MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingPresenter.h" +#include "MantidAPI/AlgorithmManager.h" +#include "MantidAPI/ITableWorkspace.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidAPI/TableRow.h" +#include "MantidAPI/WorkspaceFactory.h" +#include "MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingPresWorker.h" +#include "MantidQtCustomInterfaces/Muon/ALCHelper.h" + +#include <boost/lexical_cast.hpp> + +#include <Poco/DirectoryIterator.h> +#include <Poco/File.h> + +using namespace Mantid::API; +using namespace MantidQt::CustomInterfaces; + +namespace MantidQt { +namespace CustomInterfaces { + +namespace { +Mantid::Kernel::Logger g_log("EngineeringDiffractionGUI"); +} + +const bool EnggDiffFittingPresenter::g_useAlignDetectors = true; + +const std::string EnggDiffFittingPresenter::g_focusedFittingWSName = + "engggui_fitting_focused_ws"; + +/** + * Constructs a presenter for a fitting tab/widget view, which has a + * handle on the current calibration (produced and updated elsewhere). + * + * @param view the view that is attached to this presenter + * @param mainCalib provides the current calibration parameters/status + */ +EnggDiffFittingPresenter::EnggDiffFittingPresenter( + IEnggDiffFittingView *view, + boost::shared_ptr<IEnggDiffractionCalibration> mainCalib) + : m_fittingFinishedOK(false), m_workerThread(nullptr), + m_mainCalib(mainCalib), m_view(view) {} + +EnggDiffFittingPresenter::~EnggDiffFittingPresenter() { cleanup(); } + +/** +* Close open sessions, kill threads etc., for a graceful window +* close/destruction +*/ +void EnggDiffFittingPresenter::cleanup() { + // m_model->cleanup(); + + // this may still be running + if (m_workerThread) { + if (m_workerThread->isRunning()) { + g_log.notice() << "A fitting process is currently running, shutting " + "it down immediately...\n"; + m_workerThread->wait(10); + } + delete m_workerThread; + m_workerThread = nullptr; + } +} + +void EnggDiffFittingPresenter::notify( + IEnggDiffFittingPresenter::Notification notif) { + switch (notif) { + + case IEnggDiffFittingPresenter::Start: + processStart(); + break; + + case IEnggDiffFittingPresenter::FittingRunNo: + fittingRunNoChanged(); + break; + + case IEnggDiffFittingPresenter::FitPeaks: + processFitPeaks(); + break; + + case IEnggDiffFittingPresenter::ShutDown: + processShutDown(); + break; + + case IEnggDiffFittingPresenter::LogMsg: + processLogMsg(); + break; + } +} + +std::vector<GSASCalibrationParms> +EnggDiffFittingPresenter::currentCalibration() const { + return m_mainCalib->currentCalibration(); +} + +void EnggDiffFittingPresenter::startAsyncFittingWorker( + const std::string &focusedRunNo, const std::string &expectedPeaks) { + + delete m_workerThread; + m_workerThread = new QThread(this); + EnggDiffFittingWorker *worker = + new EnggDiffFittingWorker(this, focusedRunNo, expectedPeaks); + worker->moveToThread(m_workerThread); + + connect(m_workerThread, SIGNAL(started()), worker, SLOT(fitting())); + connect(worker, SIGNAL(finished()), this, SLOT(fittingFinished())); + // early delete of thread and worker + connect(m_workerThread, SIGNAL(finished()), m_workerThread, + SLOT(deleteLater()), Qt::DirectConnection); + connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater())); + m_workerThread->start(); +} + +void EnggDiffFittingPresenter::fittingFinished() { + if (!m_view) + return; + + if (!m_fittingFinishedOK) { + g_log.warning() << "The single peak fitting did not finish correctly.\n"; + if (m_workerThread) { + delete m_workerThread; + m_workerThread = nullptr; + } + + m_view->showStatus( + "Single peak fitting process did not complete successfully"); + } else { + g_log.notice() << "The single peak fitting finished - the output " + "workspace is ready.\n"; + + m_view->showStatus("Single peak fittin process finished. Ready"); + if (m_workerThread) { + delete m_workerThread; + m_workerThread = nullptr; + } + } + + try { + // should now plot the focused workspace when single peak fitting + // process fails + plotFitPeaksCurves(); + + } catch (std::runtime_error &re) { + g_log.error() << "Unable to finish the plotting of the graph for " + "engggui_fitting_focused_fitpeaks workspace. Error " + "description: " + + static_cast<std::string>(re.what()) + + " Please check also the log message for detail."; + throw; + } + g_log.notice() << "EnggDiffraction GUI: plotting of peaks for single peak " + "fits has completed. \n"; + + // enable the GUI + m_view->enableCalibrateFocusFitUserActions(true); +} + +// Fitting Tab Run Number & Bank handling here +void EnggDiffFittingPresenter::fittingRunNoChanged() { + + try { + auto strFocusedFile = m_view->getFittingRunNo(); + auto focusedFile = strFocusedFile; + // file name + Poco::Path selectedfPath(strFocusedFile); + Poco::Path bankDir; + + // handling of vectors + auto runnoDirVector = m_view->getFittingRunNumVec(); + runnoDirVector.clear(); + + std::string strFPath = selectedfPath.toString(); + // returns empty if no directory is found + std::vector<std::string> splitBaseName = + m_view->splitFittingDirectory(strFPath); + // runNo when single focused file selected + std::vector<std::string> runNoVec; + + if (selectedfPath.isFile() && !splitBaseName.empty()) { + +#ifdef __unix__ + bankDir = selectedfPath.parent(); +#else + bankDir = (bankDir).expand(selectedfPath.parent().toString()); +#endif + if (!splitBaseName.empty() && splitBaseName.size() > 3) { + std::string foc_file = splitBaseName[0] + "_" + splitBaseName[1] + "_" + + splitBaseName[2] + "_" + splitBaseName[3]; + std::string strBankDir = bankDir.toString(); + + if (strBankDir.empty()) { + m_view->userWarning( + "Invalid Input", + "Please check that a valid directory is " + "set for Output Folder under Focusing Settings on the " + "settings tab. " + "Please try again"); + } else { + + updateFittingDirVec(strBankDir, foc_file, false, runnoDirVector); + m_view->setFittingRunNumVec(runnoDirVector); + + // add bank to the combo-box and list view + setBankItems(); + setDefaultBank(splitBaseName, focusedFile); + runNoVec.clear(); + runNoVec.push_back(splitBaseName[1]); + auto fittingMultiRunMode = m_view->getFittingMultiRunMode(); + if (!fittingMultiRunMode) + setRunNoItems(runNoVec, false); + } + } + // assuming that no directory is found so look for number + // if run number length greater + } else if (focusedFile.size() > 4) { + if (strFocusedFile.find("-") != std::string::npos) { + std::vector<std::string> firstLastRunNoVec; + boost::split(firstLastRunNoVec, strFocusedFile, boost::is_any_of("-")); + std::string firstRun; + std::string lastRun; + if (!firstLastRunNoVec.empty()) { + firstRun = firstLastRunNoVec[0]; + lastRun = firstLastRunNoVec[1]; + + m_view->setFittingMultiRunMode(true); + enableMultiRun(firstRun, lastRun, runnoDirVector); + } + + } else { + // if given a single run number instead + auto focusDir = m_view->focusingDir(); + + if (focusDir.empty()) { + m_view->userWarning( + "Invalid Input", + "Please check that a valid directory is " + "set for Output Folder under Focusing Settings on the " + "settings tab. " + "Please try again"); + } else { + + updateFittingDirVec(focusDir, strFocusedFile, false, runnoDirVector); + m_view->setFittingRunNumVec(runnoDirVector); + + // add bank to the combo-box and list view + setBankItems(); + setDefaultBank(splitBaseName, focusedFile); + runNoVec.clear(); + runNoVec.push_back(strFocusedFile); + + auto fittingMultiRunMode = m_view->getFittingMultiRunMode(); + if (!fittingMultiRunMode) + setRunNoItems(runNoVec, false); + } + } + } + // set the directory here to the first in the vector if its not empty + if (!runnoDirVector.empty() && !selectedfPath.isFile()) { + auto firstDir = runnoDirVector[0]; + m_view->setFittingRunNo(firstDir); + + } else if (m_view->getFittingRunNo().empty()) { + m_view->userWarning("Invalid Input", + "Invalid directory or run number given. " + "Please try again"); + } + + } catch (std::runtime_error &re) { + m_view->userWarning("Invalid file", + "Unable to select the file; " + + static_cast<std::string>(re.what())); + return; + } +} + +void EnggDiffFittingPresenter::updateFittingDirVec( + const std::string &bankDir, const std::string &focusedFile, bool multi_run, + std::vector<std::string> &fittingRunNoDirVec) { + + try { + std::string cwd(bankDir); + Poco::DirectoryIterator it(cwd); + Poco::DirectoryIterator end; + while (it != end) { + if (it->isFile()) { + std::string itFilePath = it->path(); + Poco::Path itBankfPath(itFilePath); + + std::string itbankFileName = itBankfPath.getBaseName(); + // check if it not any other file.. e.g: texture + if (itbankFileName.find(focusedFile) != std::string::npos) { + fittingRunNoDirVec.push_back(itFilePath); + if (multi_run) + return; + } + } + ++it; + } + } catch (std::runtime_error &re) { + m_view->userWarning("Invalid file", + "File not found in the following directory; " + + bankDir + ". " + + static_cast<std::string>(re.what())); + } +} + +void EnggDiffFittingPresenter::enableMultiRun( + std::string firstRun, std::string lastRun, + std::vector<std::string> &fittingRunNoDirVec) { + + bool firstDig = isDigit(firstRun); + bool lastDig = isDigit(lastRun); + + std::vector<std::string> RunNumberVec; + if (firstDig && lastDig) { + int firstNum = std::stoi(firstRun); + int lastNum = std::stoi(lastRun); + + if ((lastNum - firstNum) > 200) { + m_view->userWarning( + "Please try again", + "The specified run number range is " + "far to big, please try a smaller range of consecutive run numbers."); + } + + else if (firstNum <= lastNum) { + + for (int i = firstNum; i <= lastNum; i++) { + RunNumberVec.push_back(std::to_string(i)); + } + + auto focusDir = m_view->focusingDir(); + if (focusDir.empty()) { + m_view->userWarning( + "Invalid Input", + "Please check that a valid directory is " + "set for Output Folder under Focusing Settings on the " + "settings tab. " + "Please try again"); + } else { + // if given a single run number instead + for (size_t i = 0; i < RunNumberVec.size(); i++) { + updateFittingDirVec(focusDir, RunNumberVec[i], true, + fittingRunNoDirVec); + } + int diff = (lastNum - firstNum) + 1; + auto global_vec_size = fittingRunNoDirVec.size(); + if (size_t(diff) == global_vec_size) { + + setRunNoItems(RunNumberVec, true); + + m_view->setBankEmit(); + } + } + } else { + m_view->userWarning("Invalid Run Number", + "One or more run file not found " + "from the specified range of runs." + "Please try again"); + } + } else { + m_view->userWarning("Invalid Run Number", + "The specfied range of run number " + "entered is invalid. Please try again"); + } +} + +void EnggDiffFittingPresenter::processStart() {} + +void EnggDiffFittingPresenter::processShutDown() { + m_view->saveSettings(); + cleanup(); +} + +void EnggDiffFittingPresenter::processLogMsg() { + std::vector<std::string> msgs = m_view->logMsgs(); + for (size_t i = 0; i < msgs.size(); i++) { + g_log.information() << msgs[i] << '\n'; + } +} + +void EnggDiffFittingPresenter::processFitPeaks() { + const std::string focusedRunNo = m_view->getFittingRunNo(); + std::string fittingPeaks = m_view->fittingPeaksData(); + + const std::string fitPeaksData = validateFittingexpectedPeaks(fittingPeaks); + + g_log.debug() << "the expected peaks are: " << fitPeaksData << '\n'; + + try { + inputChecksBeforeFitting(focusedRunNo, fitPeaksData); + } catch (std::invalid_argument &ia) { + m_view->userWarning("Error in the inputs required for fitting", ia.what()); + return; + } + + const std::string outWSName = "engggui_fitting_fit_peak_ws"; + g_log.notice() << "EnggDiffraction GUI: starting new " + "single peak fits into workspace '" + + outWSName + "'. This " + "may take some seconds... \n"; + + m_view->showStatus("Fitting single peaks..."); + // disable GUI to avoid any double threads + m_view->enableCalibrateFocusFitUserActions(false); + // startAsyncFittingWorker + // doFitting() + startAsyncFittingWorker(focusedRunNo, fitPeaksData); +} + +void EnggDiffFittingPresenter::inputChecksBeforeFitting( + const std::string &focusedRunNo, const std::string &expectedPeaks) { + if (focusedRunNo.size() == 0) { + throw std::invalid_argument( + "Focused Run " + "cannot be empty and must be a valid directory"); + } + + Poco::File file(focusedRunNo); + if (!file.exists()) { + throw std::invalid_argument("The focused workspace file for single peak " + "fitting could not be found: " + + focusedRunNo); + } + + if (expectedPeaks.empty()) { + g_log.warning() << "Expected peaks were not passed, via fitting interface, " + "the default list of " + "expected peaks will be utilised instead.\n"; + } + bool contains_non_digits = + expectedPeaks.find_first_not_of("0123456789,. ") != std::string::npos; + if (contains_non_digits) { + throw std::invalid_argument("The expected peaks provided " + expectedPeaks + + " is invalid, " + "fitting process failed. Please try again!"); + } +} + +std::string EnggDiffFittingPresenter::validateFittingexpectedPeaks( + std::string &expectedPeaks) const { + + if (!expectedPeaks.empty()) { + + g_log.debug() << "Validating the expected peak list.\n"; + + auto *comma = ","; + + for (size_t i = 0; i < expectedPeaks.size() - 1; i++) { + size_t j = i + 1; + + if (expectedPeaks[i] == *comma && expectedPeaks[i] == expectedPeaks[j]) { + expectedPeaks.erase(j, 1); + i--; + + } else { + ++j; + } + } + + size_t strLength = expectedPeaks.length() - 1; + if (expectedPeaks.at(size_t(0)) == ',') { + expectedPeaks.erase(size_t(0), 1); + strLength -= size_t(1); + } + + if (expectedPeaks.at(strLength) == ',') { + expectedPeaks.erase(strLength, 1); + } + + m_view->setPeakList(expectedPeaks); + } + + return expectedPeaks; +} + +void EnggDiffFittingPresenter::setDifcTzero(MatrixWorkspace_sptr wks) const { + size_t bankID = 1; + // attempt to guess bankID - this should be done in code that is currently + // in the view + auto fittingFilename = m_view->getFittingRunNo(); + Poco::File fittingFile(fittingFilename); + if (fittingFile.exists()) { + Poco::Path path(fittingFile.path()); + auto name = path.getBaseName(); + std::vector<std::string> chunks; + boost::split(chunks, name, boost::is_any_of("_")); + if (!chunks.empty()) { + try { + bankID = boost::lexical_cast<size_t>(chunks.back()); + } catch (std::runtime_error &) { + } + } + } + + const std::string units = "none"; + auto &run = wks->mutableRun(); + + std::vector<GSASCalibrationParms> calibParms = currentCalibration(); + if (calibParms.empty()) { + run.addProperty<int>("bankid", 1, units, true); + run.addProperty<double>("difc", 18400.0, units, true); + run.addProperty<double>("difa", 0.0, units, true); + run.addProperty<double>("tzero", 4.0, units, true); + } else { + GSASCalibrationParms parms(0, 0.0, 0.0, 0.0); + for (const auto &p : calibParms) { + if (p.bankid == bankID) { + parms = p; + break; + } + } + if (0 == parms.difc) + parms = calibParms.front(); + + run.addProperty<int>("bankid", static_cast<int>(parms.bankid), units, true); + run.addProperty<double>("difc", parms.difc, units, true); + run.addProperty<double>("difa", parms.difa, units, true); + run.addProperty<double>("tzero", parms.tzero, units, true); + } +} + +void EnggDiffFittingPresenter::doFitting(const std::string &focusedRunNo, + const std::string &expectedPeaks) { + g_log.notice() << "EnggDiffraction GUI: starting new fitting with file " + << focusedRunNo << ". This may take a few seconds... \n"; + + MatrixWorkspace_sptr focusedWS; + m_fittingFinishedOK = false; + + // load the focused workspace file to perform single peak fits + try { + auto load = + Mantid::API::AlgorithmManager::Instance().createUnmanaged("Load"); + load->initialize(); + load->setPropertyValue("Filename", focusedRunNo); + load->setPropertyValue("OutputWorkspace", g_focusedFittingWSName); + load->execute(); + + AnalysisDataServiceImpl &ADS = Mantid::API::AnalysisDataService::Instance(); + focusedWS = ADS.retrieveWS<MatrixWorkspace>(g_focusedFittingWSName); + } catch (std::runtime_error &re) { + g_log.error() + << "Error while loading focused data. " + "Could not run the algorithm Load succesfully for the Fit " + "peaks (file name: " + + focusedRunNo + "). Error description: " + re.what() + + " Please check also the previous log messages for details."; + return; + } + + setDifcTzero(focusedWS); + + // run the algorithm EnggFitPeaks with workspace loaded above + // requires unit in Time of Flight + auto enggFitPeaks = + Mantid::API::AlgorithmManager::Instance().createUnmanaged("EnggFitPeaks"); + const std::string focusedFitPeaksTableName = + "engggui_fitting_fitpeaks_params"; + + // delete existing table workspace to avoid confusion + AnalysisDataServiceImpl &ADS = Mantid::API::AnalysisDataService::Instance(); + if (ADS.doesExist(focusedFitPeaksTableName)) { + ADS.remove(focusedFitPeaksTableName); + } + + try { + enggFitPeaks->initialize(); + enggFitPeaks->setProperty("InputWorkspace", focusedWS); + if (!expectedPeaks.empty()) { + enggFitPeaks->setProperty("expectedPeaks", expectedPeaks); + } + enggFitPeaks->setProperty("FittedPeaks", focusedFitPeaksTableName); + enggFitPeaks->execute(); + } catch (std::exception &re) { + g_log.error() << "Could not run the algorithm EnggFitPeaks " + "successfully for bank, " + // bank name + "Error description: " + + static_cast<std::string>(re.what()) + + " Please check also the log message for detail.\n"; + } + + try { + runFittingAlgs(focusedFitPeaksTableName, g_focusedFittingWSName); + + } catch (std::invalid_argument &ia) { + g_log.error() << "Error, Fitting could not finish off correctly, " + + std::string(ia.what()) << '\n'; + return; + } +} + +void EnggDiffFittingPresenter::runFittingAlgs( + std::string focusedFitPeaksTableName, std::string focusedWSName) { + // retrieve the table with parameters + auto &ADS = Mantid::API::AnalysisDataService::Instance(); + if (!ADS.doesExist(focusedFitPeaksTableName)) { + // convert units so valid dSpacing peaks can still be added to gui + if (ADS.doesExist(g_focusedFittingWSName)) { + convertUnits(g_focusedFittingWSName); + } + + throw std::invalid_argument( + focusedFitPeaksTableName + + " workspace could not be found. " + "Please check the log messages for more details."); + } + + auto table = ADS.retrieveWS<ITableWorkspace>(focusedFitPeaksTableName); + size_t rowCount = table->rowCount(); + const std::string single_peak_out_WS = "engggui_fitting_single_peaks"; + std::string currentPeakOutWS; + + std::string Bk2BkExpFunctionStr; + std::string startX = ""; + std::string endX = ""; + for (size_t i = 0; i < rowCount; i++) { + // get the functionStrFactory to generate the string for function + // property, returns the string with i row from table workspace + // table is just passed so it works? + Bk2BkExpFunctionStr = + functionStrFactory(table, focusedFitPeaksTableName, i, startX, endX); + + g_log.debug() << "startX: " + startX + " . endX: " + endX << '\n'; + + currentPeakOutWS = "__engggui_fitting_single_peaks" + std::to_string(i); + + // run EvaluateFunction algorithm with focused workspace to produce + // the correct fit function + // focusedWSName is not going to change as its always going to be from + // single workspace + runEvaluateFunctionAlg(Bk2BkExpFunctionStr, focusedWSName, currentPeakOutWS, + startX, endX); + + // crop workspace so only the correct workspace index is plotted + runCropWorkspaceAlg(currentPeakOutWS); + + // apply the same binning as a focused workspace + runRebinToWorkspaceAlg(currentPeakOutWS); + + // if the first peak + if (i == size_t(0)) { + + // create a workspace clone of bank focus file + // this will import all information of the previous file + runCloneWorkspaceAlg(focusedWSName, single_peak_out_WS); + + setDataToClonedWS(currentPeakOutWS, single_peak_out_WS); + ADS.remove(currentPeakOutWS); + } else { + const std::string currentPeakClonedWS = + "__engggui_fitting_cloned_peaks" + std::to_string(i); + + runCloneWorkspaceAlg(focusedWSName, currentPeakClonedWS); + + setDataToClonedWS(currentPeakOutWS, currentPeakClonedWS); + + // append all peaks in to single workspace & remove + runAppendSpectraAlg(single_peak_out_WS, currentPeakClonedWS); + ADS.remove(currentPeakOutWS); + ADS.remove(currentPeakClonedWS); + } + } + + convertUnits(g_focusedFittingWSName); + + // convert units for both workspaces to dSpacing from ToF + if (rowCount > size_t(0)) { + auto swks = ADS.retrieveWS<MatrixWorkspace>(single_peak_out_WS); + setDifcTzero(swks); + convertUnits(single_peak_out_WS); + } else { + g_log.error() << "The engggui_fitting_fitpeaks_params table produced is" + "empty. Please try again!\n"; + } + + m_fittingFinishedOK = true; +} + +std::string EnggDiffFittingPresenter::functionStrFactory( + Mantid::API::ITableWorkspace_sptr ¶mTableWS, std::string tableName, + size_t row, std::string &startX, std::string &endX) { + const double windowLeft = 9; + const double windowRight = 12; + + AnalysisDataServiceImpl &ADS = Mantid::API::AnalysisDataService::Instance(); + paramTableWS = ADS.retrieveWS<ITableWorkspace>(tableName); + + double A0 = paramTableWS->cell<double>(row, size_t(1)); + double A1 = paramTableWS->cell<double>(row, size_t(3)); + double I = paramTableWS->cell<double>(row, size_t(13)); + double A = paramTableWS->cell<double>(row, size_t(7)); + double B = paramTableWS->cell<double>(row, size_t(9)); + double X0 = paramTableWS->cell<double>(row, size_t(5)); + double S = paramTableWS->cell<double>(row, size_t(11)); + + startX = boost::lexical_cast<std::string>(X0 - (windowLeft * S)); + endX = boost::lexical_cast<std::string>(X0 + (windowRight * S)); + + std::string functionStr = + "name=LinearBackground,A0=" + boost::lexical_cast<std::string>(A0) + + ",A1=" + boost::lexical_cast<std::string>(A1) + + ";name=BackToBackExponential,I=" + boost::lexical_cast<std::string>(I) + + ",A=" + boost::lexical_cast<std::string>(A) + ",B=" + + boost::lexical_cast<std::string>(B) + ",X0=" + + boost::lexical_cast<std::string>(X0) + ",S=" + + boost::lexical_cast<std::string>(S); + + return functionStr; +} + +void EnggDiffFittingPresenter::runEvaluateFunctionAlg( + const std::string &bk2BkExpFunction, const std::string &InputName, + const std::string &OutputName, const std::string &startX, + const std::string &endX) { + + auto evalFunc = Mantid::API::AlgorithmManager::Instance().createUnmanaged( + "EvaluateFunction"); + g_log.notice() << "EvaluateFunction algorithm has started\n"; + try { + evalFunc->initialize(); + evalFunc->setProperty("Function", bk2BkExpFunction); + evalFunc->setProperty("InputWorkspace", InputName); + evalFunc->setProperty("OutputWorkspace", OutputName); + evalFunc->setProperty("StartX", startX); + evalFunc->setProperty("EndX", endX); + evalFunc->execute(); + } catch (std::runtime_error &re) { + g_log.error() << "Could not run the algorithm EvaluateFunction, " + "Error description: " + + static_cast<std::string>(re.what()) << '\n'; + } +} + +void EnggDiffFittingPresenter::runCropWorkspaceAlg(std::string workspaceName) { + auto cropWS = Mantid::API::AlgorithmManager::Instance().createUnmanaged( + "CropWorkspace"); + try { + cropWS->initialize(); + cropWS->setProperty("InputWorkspace", workspaceName); + cropWS->setProperty("OutputWorkspace", workspaceName); + cropWS->setProperty("StartWorkspaceIndex", 1); + cropWS->setProperty("EndWorkspaceIndex", 1); + cropWS->execute(); + } catch (std::runtime_error &re) { + g_log.error() << "Could not run the algorithm CropWorkspace, " + "Error description: " + + static_cast<std::string>(re.what()) << '\n'; + } +} + +void EnggDiffFittingPresenter::runAppendSpectraAlg(std::string workspace1Name, + std::string workspace2Name) { + auto appendSpec = Mantid::API::AlgorithmManager::Instance().createUnmanaged( + "AppendSpectra"); + try { + appendSpec->initialize(); + appendSpec->setProperty("InputWorkspace1", workspace1Name); + appendSpec->setProperty("InputWorkspace2", workspace2Name); + appendSpec->setProperty("OutputWorkspace", workspace1Name); + appendSpec->execute(); + } catch (std::runtime_error &re) { + g_log.error() << "Could not run the algorithm AppendWorkspace, " + "Error description: " + + static_cast<std::string>(re.what()) << '\n'; + } +} + +void EnggDiffFittingPresenter::runRebinToWorkspaceAlg( + std::string workspaceName) { + auto RebinToWs = Mantid::API::AlgorithmManager::Instance().createUnmanaged( + "RebinToWorkspace"); + try { + RebinToWs->initialize(); + RebinToWs->setProperty("WorkspaceToRebin", workspaceName); + RebinToWs->setProperty("WorkspaceToMatch", g_focusedFittingWSName); + RebinToWs->setProperty("OutputWorkspace", workspaceName); + RebinToWs->execute(); + } catch (std::runtime_error &re) { + g_log.error() << "Could not run the algorithm RebinToWorkspace, " + "Error description: " + + static_cast<std::string>(re.what()) << '\n'; + } +} + +/** + * Converts from time-of-flight to d-spacing + * + * @param workspaceName name of the workspace to convert (in place) + */ +void EnggDiffFittingPresenter::convertUnits(std::string workspaceName) { + // Here using the GSAS (DIFC, TZERO) parameters seems preferred + if (g_useAlignDetectors) { + runAlignDetectorsAlg(workspaceName); + } else { + runConvertUnitsAlg(workspaceName); + } +} + +void EnggDiffFittingPresenter::getDifcTzero(MatrixWorkspace_const_sptr wks, + double &difc, double &difa, + double &tzero) const { + + try { + const auto run = wks->run(); + // long, step by step way: + // auto propC = run.getLogData("difc"); + // auto doubleC = + // dynamic_cast<Mantid::Kernel::PropertyWithValue<double> *>(propC); + // if (!doubleC) + // throw Mantid::Kernel::Exception::NotFoundError( + // "Required difc property not found in workspace.", "difc"); + difc = run.getPropertyValueAsType<double>("difc"); + difa = run.getPropertyValueAsType<double>("difa"); + tzero = run.getPropertyValueAsType<double>("tzero"); + + } catch (std::runtime_error &rexc) { + // fallback to something reasonable / approximate values so + // the fitting tab can work minimally + difa = tzero = 0.0; + difc = 18400; + g_log.warning() + << "Could not retrieve the DIFC, DIFA, TZERO values from the workspace " + << wks->name() << ". Using default, which is not adjusted for this " + "workspace/run: DIFA: " << difa << ", DIFC: " << difc + << ", TZERO: " << tzero << ". Error details: " << rexc.what() << '\n'; + } +} + +/** + * Converts units from time-of-flight to d-spacing, using + * AlignDetectors. This is the GSAS-style alternative to using the + * algorithm ConvertUnits. Needs to make sure that the workspace is + * not of distribution type (and use the algorithm + * ConvertFromDistribution if it is). This is a requirement of + * AlignDetectors. + * + * @param workspaceName name of the workspace to convert + */ +void EnggDiffFittingPresenter::runAlignDetectorsAlg(std::string workspaceName) { + const std::string targetUnit = "dSpacing"; + const std::string algName = "AlignDetectors"; + + const auto &ADS = Mantid::API::AnalysisDataService::Instance(); + auto inputWS = ADS.retrieveWS<MatrixWorkspace>(workspaceName); + if (!inputWS) + return; + + double difc, difa, tzero; + getDifcTzero(inputWS, difc, difa, tzero); + + // create a table with the GSAS calibration parameters + ITableWorkspace_sptr difcTable; + try { + difcTable = Mantid::API::WorkspaceFactory::Instance().createTable(); + if (!difcTable) { + return; + } + difcTable->addColumn("int", "detid"); + difcTable->addColumn("double", "difc"); + difcTable->addColumn("double", "difa"); + difcTable->addColumn("double", "tzero"); + TableRow row = difcTable->appendRow(); + auto &spec = inputWS->getSpectrum(0); + Mantid::detid_t detID = *(spec.getDetectorIDs().cbegin()); + + row << detID << difc << difa << tzero; + } catch (std::runtime_error &rexc) { + g_log.error() << "Failed to prepare calibration table input to convert " + "units with the algorithm " << algName + << ". Error details: " << rexc.what() << '\n'; + return; + } + + // AlignDetectors doesn't take distribution workspaces (it enforces + // RawCountValidator) + if (inputWS->isDistribution()) { + try { + auto alg = Mantid::API::AlgorithmManager::Instance().createUnmanaged( + "ConvertFromDistribution"); + alg->initialize(); + alg->setProperty("Workspace", workspaceName); + alg->execute(); + } catch (std::runtime_error &rexc) { + g_log.error() << "Could not run ConvertFromDistribution. Error: " + << rexc.what() << '\n'; + return; + } + } + + try { + auto alg = + Mantid::API::AlgorithmManager::Instance().createUnmanaged(algName); + alg->initialize(); + alg->setProperty("InputWorkspace", workspaceName); + alg->setProperty("OutputWorkspace", workspaceName); + alg->setProperty("CalibrationWorkspace", difcTable); + alg->execute(); + } catch (std::runtime_error &rexc) { + g_log.error() << "Could not run the algorithm " << algName + << " to convert workspace to " << targetUnit + << ", Error details: " + static_cast<std::string>(rexc.what()) + << '\n'; + } +} + +void EnggDiffFittingPresenter::runConvertUnitsAlg(std::string workspaceName) { + const std::string targetUnit = "dSpacing"; + auto ConvertUnits = + Mantid::API::AlgorithmManager::Instance().createUnmanaged("ConvertUnits"); + try { + ConvertUnits->initialize(); + ConvertUnits->setProperty("InputWorkspace", workspaceName); + ConvertUnits->setProperty("OutputWorkspace", workspaceName); + ConvertUnits->setProperty("Target", targetUnit); + ConvertUnits->setPropertyValue("EMode", "Elastic"); + ConvertUnits->execute(); + } catch (std::runtime_error &re) { + g_log.error() << "Could not run the algorithm ConvertUnits to convert " + "workspace to " << targetUnit + << ", Error description: " + + static_cast<std::string>(re.what()) << '\n'; + } +} + +void EnggDiffFittingPresenter::runCloneWorkspaceAlg( + std::string inputWorkspace, const std::string &outputWorkspace) { + + auto cloneWorkspace = + Mantid::API::AlgorithmManager::Instance().createUnmanaged( + "CloneWorkspace"); + try { + cloneWorkspace->initialize(); + cloneWorkspace->setProperty("InputWorkspace", inputWorkspace); + cloneWorkspace->setProperty("OutputWorkspace", outputWorkspace); + cloneWorkspace->execute(); + } catch (std::runtime_error &re) { + g_log.error() << "Could not run the algorithm CreateWorkspace, " + "Error description: " + + static_cast<std::string>(re.what()) << '\n'; + } +} + +void EnggDiffFittingPresenter::setDataToClonedWS(std::string ¤t_WS, + const std::string &cloned_WS) { + AnalysisDataServiceImpl &ADS = Mantid::API::AnalysisDataService::Instance(); + auto currentPeakWS = ADS.retrieveWS<MatrixWorkspace>(current_WS); + auto currentClonedWS = ADS.retrieveWS<MatrixWorkspace>(cloned_WS); + currentClonedWS->dataY(0) = currentPeakWS->readY(0); + currentClonedWS->dataE(0) = currentPeakWS->readE(0); +} + +void EnggDiffFittingPresenter::setBankItems() { + try { + auto fitting_runno_vector = m_view->getFittingRunNumVec(); + + if (!fitting_runno_vector.empty()) { + + // delete previous bank added to the list + m_view->clearFittingComboBox(); + + for (size_t i = 0; i < fitting_runno_vector.size(); i++) { + Poco::Path vecFile(fitting_runno_vector[i]); + std::string strVecFile = vecFile.toString(); + // split the directory from m_fitting_runno_dir_vec + std::vector<std::string> vecFileSplit = + m_view->splitFittingDirectory(strVecFile); + + // get the last split in vector which will be bank + std::string bankID = (vecFileSplit.back()); + + bool digit = isDigit(bankID); + + if (digit || bankID == "cropped") { + m_view->addBankItem(bankID); + } else { + QString qBank = QString("Bank %1").arg(i + 1); + m_view->addBankItem(qBank.toStdString()); + } + } + + m_view->enableFittingComboBox(true); + } else { + // upon invalid file + // disable the widgets when only one related file found + m_view->enableFittingComboBox(false); + + m_view->clearFittingComboBox(); + } + + } catch (std::runtime_error &re) { + m_view->userWarning("Unable to insert items: ", + "Could not add banks to " + "combo-box or list widget; " + + static_cast<std::string>(re.what()) + + ". Please try again"); + } +} + +void EnggDiffFittingPresenter::setRunNoItems( + std::vector<std::string> runNumVector, bool multiRun) { + try { + if (!runNumVector.empty()) { + + // delete previous bank added to the list + m_view->clearFittingListWidget(); + + for (size_t i = 0; i < runNumVector.size(); i++) { + + // get the last split in vector which will be bank + std::string currentRun = (runNumVector[i]); + + m_view->addRunNoItem(currentRun); + } + + if (multiRun) { + m_view->enableFittingListWidget(true); + + auto currentIndex = m_view->getFittingListWidgetCurrentRow(); + if (currentIndex == -1) + m_view->setFittingListWidgetCurrentRow(0); + } else { + m_view->enableFittingListWidget(false); + } + } + + else { + // upon invalid file + // disable the widgets when only one related file found + m_view->enableFittingListWidget(false); + + m_view->clearFittingListWidget(); + } + + } catch (std::runtime_error &re) { + m_view->userWarning("Unable to insert items: ", + "Could not add list widget; " + + static_cast<std::string>(re.what()) + + ". Please try again"); + } +} + +void EnggDiffFittingPresenter::setDefaultBank( + const std::vector<std::string> &splittedBaseName, + const std::string &selectedFile) { + + if (!splittedBaseName.empty()) { + + std::string bankID = (splittedBaseName.back()); + auto combo_data = m_view->getFittingComboIdx(bankID); + + if (combo_data > -1) { + m_view->setBankIdComboBox(combo_data); + } else { + m_view->setFittingRunNo(selectedFile); + } + } + // check if the vector is not empty so that the first directory + // can be assigned to text-field when number is given + else if (!m_view->getFittingRunNumVec().empty()) { + auto firstDir = m_view->getFittingRunNumVec().at(0); + auto intialDir = firstDir; + m_view->setFittingRunNo(intialDir); + } + // if nothing found related to text-field input + else if (!m_view->getFittingRunNo().empty()) + m_view->setFittingRunNo(selectedFile); +} + +bool EnggDiffFittingPresenter::isDigit(std::string text) { + for (size_t i = 0; i < text.size(); i++) { + char *str = &text[i]; + if (std::isdigit(*str)) { + return true; + } + } + return false; +} + +void EnggDiffFittingPresenter::plotFitPeaksCurves() { + AnalysisDataServiceImpl &ADS = Mantid::API::AnalysisDataService::Instance(); + std::string singlePeaksWs = "engggui_fitting_single_peaks"; + + if (!ADS.doesExist(singlePeaksWs) && !ADS.doesExist(g_focusedFittingWSName)) { + g_log.error() << "Fitting results could not be plotted as there is no " + + singlePeaksWs + " or " + g_focusedFittingWSName + + " workspace found.\n"; + m_view->showStatus("Error while fitting peaks"); + return; + } + + try { + auto focusedPeaksWS = + ADS.retrieveWS<MatrixWorkspace>(g_focusedFittingWSName); + auto focusedData = ALCHelper::curveDataFromWs(focusedPeaksWS); + m_view->setDataVector(focusedData, true, m_fittingFinishedOK); + + if (m_fittingFinishedOK) { + g_log.debug() << "single peaks fitting being plotted now.\n"; + auto singlePeaksWS = ADS.retrieveWS<MatrixWorkspace>(singlePeaksWs); + auto singlePeaksData = ALCHelper::curveDataFromWs(singlePeaksWS); + m_view->setDataVector(singlePeaksData, false, true); + m_view->showStatus("Peaks fitted successfully"); + + } else { + g_log.notice() + << "Focused workspace has been plotted to the " + "graph; further peaks can be adding using Peak Tools.\n"; + g_log.warning() << "Peaks could not be plotted as the fitting process " + "did not finish correctly.\n"; + m_view->showStatus("No peaks could be fitted"); + } + + } catch (std::runtime_error) { + g_log.error() + << "Unable to finish of the plotting of the graph for " + "engggui_fitting_focused_fitpeaks workspace. Error " + "description. Please check also the log message for detail."; + + m_view->showStatus("Error while plotting the peaks fitted"); + throw; + } +} + +} // namespace CustomInterfaces +} // namespace MantidQt diff --git a/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffFittingViewQtWidget.cpp b/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffFittingViewQtWidget.cpp new file mode 100644 index 00000000000..396f0e9435d --- /dev/null +++ b/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffFittingViewQtWidget.cpp @@ -0,0 +1,666 @@ +#include "MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingViewQtWidget.h" +#include "MantidAPI/IPeakFunction.h" +#include "MantidAPI/FunctionFactory.h" +#include "MantidQtAPI/AlgorithmInputHistory.h" +#include "MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingPresenter.h" +#include "MantidQtMantidWidgets/PeakPicker.h" + +#include <array> +#include <fstream> +#include <iomanip> +#include <random> +#include <sstream> + +#include <boost/algorithm/string.hpp> + +#include <Poco/Path.h> + +#include <QFileDialog> +#include <QSettings> + +#include <qwt_plot_curve.h> +#include <qwt_plot_zoomer.h> +#include <qwt_symbol.h> + +using namespace Mantid::API; +using namespace MantidQt::CustomInterfaces; + +namespace MantidQt { +namespace CustomInterfaces { + +const std::string EnggDiffFittingViewQtWidget::g_settingsGroup = + "CustomInterfaces/EnggDiffraction/FittingView"; + +const std::string EnggDiffFittingViewQtWidget::g_peaksListExt = + "Peaks list File: CSV " + "(*.csv *.txt);;" + "Other extensions/all files (*.*)"; + +bool EnggDiffFittingViewQtWidget::m_fittingMutliRunMode = false; +std::vector<std::string> EnggDiffFittingViewQtWidget::m_fitting_runno_dir_vec; + +EnggDiffFittingViewQtWidget::EnggDiffFittingViewQtWidget( + QWidget * /*parent*/, boost::shared_ptr<IEnggDiffractionUserMsg> mainMsg, + boost::shared_ptr<IEnggDiffractionSettings> mainSettings, + boost::shared_ptr<IEnggDiffractionCalibration> mainCalib, + boost::shared_ptr<IEnggDiffractionPythonRunner> mainPythonRunner) + : IEnggDiffFittingView(), m_fittedDataVector(), m_mainMsgProvider(mainMsg), + m_mainSettings(mainSettings), m_mainPythonRunner(mainPythonRunner), + m_presenter(nullptr) { + + initLayout(); + + m_presenter.reset(new EnggDiffFittingPresenter(this, mainCalib)); + m_presenter->notify(IEnggDiffFittingPresenter::Start); +} + +EnggDiffFittingViewQtWidget::~EnggDiffFittingViewQtWidget() { + m_presenter->notify(IEnggDiffFittingPresenter::ShutDown); + + for (auto curves : m_focusedDataVector) { + curves->detach(); + delete curves; + } + + for (auto curves : m_fittedDataVector) { + curves->detach(); + delete curves; + } +} + +void EnggDiffFittingViewQtWidget::initLayout() { + m_ui.setupUi(this); + + readSettings(); + doSetup(); +} + +void EnggDiffFittingViewQtWidget::doSetup() { + connect(m_ui.pushButton_fitting_browse_run_num, SIGNAL(released()), this, + SLOT(browseFitFocusedRun())); + + connect(m_ui.lineEdit_pushButton_run_num, SIGNAL(textEdited(const QString &)), + this, SLOT(resetFittingMultiMode())); + + connect(m_ui.lineEdit_pushButton_run_num, SIGNAL(editingFinished()), this, + SLOT(FittingRunNo())); + + connect(m_ui.lineEdit_pushButton_run_num, SIGNAL(returnPressed()), this, + SLOT(FittingRunNo())); + + connect(this, SIGNAL(getBanks()), this, SLOT(FittingRunNo())); + + connect(this, SIGNAL(setBank()), this, SLOT(listViewFittingRun())); + + connect(m_ui.listWidget_fitting_run_num, SIGNAL(itemSelectionChanged()), this, + SLOT(listViewFittingRun())); + + connect(m_ui.comboBox_bank, SIGNAL(currentIndexChanged(int)), this, + SLOT(setBankDir(int))); + + connect(m_ui.pushButton_fitting_browse_peaks, SIGNAL(released()), this, + SLOT(browsePeaksToFit())); + + connect(m_ui.pushButton_fit, SIGNAL(released()), this, SLOT(fitClicked())); + + // add peak by clicking the button + connect(m_ui.pushButton_select_peak, SIGNAL(released()), SLOT(setPeakPick())); + + connect(m_ui.pushButton_add_peak, SIGNAL(released()), SLOT(addPeakToList())); + + connect(m_ui.pushButton_save_peak_list, SIGNAL(released()), + SLOT(savePeakList())); + + connect(m_ui.pushButton_clear_peak_list, SIGNAL(released()), + SLOT(clearPeakList())); + + connect(m_ui.pushButton_plot_separate_window, SIGNAL(released()), + SLOT(plotSeparateWindow())); + + m_ui.dataPlot->setCanvasBackground(Qt::white); + m_ui.dataPlot->setAxisTitle(QwtPlot::xBottom, "d-Spacing (A)"); + m_ui.dataPlot->setAxisTitle(QwtPlot::yLeft, "Counts (us)^-1"); + QFont font("MS Shell Dlg 2", 8); + m_ui.dataPlot->setAxisFont(QwtPlot::xBottom, font); + m_ui.dataPlot->setAxisFont(QwtPlot::yLeft, font); + + // constructor of the peakPicker + // XXX: Being a QwtPlotItem, should get deleted when m_ui.plot gets deleted + // (auto-delete option) + m_peakPicker = new MantidWidgets::PeakPicker(m_ui.dataPlot, Qt::red); + setPeakPickerEnabled(false); + + m_zoomTool = + new QwtPlotZoomer(QwtPlot::xBottom, QwtPlot::yLeft, + QwtPicker::DragSelection | QwtPicker::CornerToCorner, + QwtPicker::AlwaysOff, m_ui.dataPlot->canvas()); + m_zoomTool->setRubberBandPen(QPen(Qt::black)); + setZoomTool(false); +} + +void EnggDiffFittingViewQtWidget::readSettings() { + QSettings qs; + qs.beginGroup(QString::fromStdString(g_settingsGroup)); + + // user params + m_ui.lineEdit_pushButton_run_num->setText( + qs.value("user-params-fitting-focused-file", "").toString()); + m_ui.comboBox_bank->setCurrentIndex(0); + m_ui.lineEdit_fitting_peaks->setText( + qs.value("user-params-fitting-peaks-to-fit", "").toString()); + + qs.endGroup(); +} + +void EnggDiffFittingViewQtWidget::saveSettings() const { + QSettings qs; + qs.beginGroup(QString::fromStdString(g_settingsGroup)); + + qs.setValue("user-params-fitting-focused-file", + m_ui.lineEdit_pushButton_run_num->text()); + qs.setValue("user-params-fitting-peaks-to-fit", + m_ui.lineEdit_fitting_peaks->text()); + + qs.endGroup(); +} + +void EnggDiffFittingViewQtWidget::enable(bool enable) { + m_ui.pushButton_fitting_browse_run_num->setEnabled(enable); + m_ui.lineEdit_pushButton_run_num->setEnabled(enable); + m_ui.pushButton_fitting_browse_peaks->setEnabled(enable); + m_ui.lineEdit_fitting_peaks->setEnabled(enable); + m_ui.pushButton_fit->setEnabled(enable); + m_ui.pushButton_clear_peak_list->setEnabled(enable); + m_ui.pushButton_save_peak_list->setEnabled(enable); + m_ui.comboBox_bank->setEnabled(enable); + m_ui.groupBox_fititng_preview->setEnabled(enable); +} + +void EnggDiffFittingViewQtWidget::showStatus(const std::string &sts) { + m_mainMsgProvider->showStatus(sts); +} + +void EnggDiffFittingViewQtWidget::userWarning(const std::string &err, + const std::string &description) { + m_mainMsgProvider->userWarning(err, description); +} + +void EnggDiffFittingViewQtWidget::userError(const std::string &err, + const std::string &description) { + m_mainMsgProvider->userError(err, description); +} + +void EnggDiffFittingViewQtWidget::enableCalibrateFocusFitUserActions( + bool enable) { + m_mainMsgProvider->enableCalibrateFocusFitUserActions(enable); +} + +EnggDiffCalibSettings +EnggDiffFittingViewQtWidget::currentCalibSettings() const { + return m_mainSettings->currentCalibSettings(); +} + +std::string EnggDiffFittingViewQtWidget::focusingDir() const { + return m_mainSettings->focusingDir(); +} + +std::string +EnggDiffFittingViewQtWidget::enggRunPythonCode(const std::string &pyCode) { + return m_mainPythonRunner->enggRunPythonCode(pyCode); +} + +void EnggDiffFittingViewQtWidget::fitClicked() { + m_presenter->notify(IEnggDiffFittingPresenter::FitPeaks); +} + +void EnggDiffFittingViewQtWidget::FittingRunNo() { + m_presenter->notify(IEnggDiffFittingPresenter::FittingRunNo); +} + +void EnggDiffFittingViewQtWidget::setBankDir(int idx) { + + if (m_fitting_runno_dir_vec.size() >= size_t(idx)) { + + std::string bankDir = m_fitting_runno_dir_vec[idx]; + Poco::Path fpath(bankDir); + + setFittingRunNo(bankDir); + } +} + +void EnggDiffFittingViewQtWidget::listViewFittingRun() { + + if (m_fittingMutliRunMode) { + auto listView = m_ui.listWidget_fitting_run_num; + auto currentRow = listView->currentRow(); + auto item = listView->item(currentRow); + QString itemText = item->text(); + + setFittingRunNo(itemText.toStdString()); + FittingRunNo(); + } +} + +void EnggDiffFittingViewQtWidget::resetFittingMultiMode() { + // resets the global variable so the list view widgets + // adds the run number to for single runs too + m_fittingMutliRunMode = false; +} + +std::string EnggDiffFittingViewQtWidget::fittingRunNoFactory( + std::string bank, std::string fileName, std::string &bankDir, + std::string fileDir) { + + std::string genDir = fileName.substr(0, fileName.size() - 1); + Poco::Path bankFile(genDir + bank + ".nxs"); + if (bankFile.isFile()) { + bankDir = fileDir + genDir + bank + ".nxs"; + } + return bankDir; +} + +std::string EnggDiffFittingViewQtWidget::readPeaksFile(std::string fileDir) { + std::string fileData = ""; + std::string line; + std::string comma = ", "; + + std::ifstream peakFile(fileDir); + + if (peakFile.is_open()) { + while (std::getline(peakFile, line)) { + fileData += line; + if (!peakFile.eof()) + fileData += comma; + } + peakFile.close(); + } + + else + fileData = ""; + + return fileData; +} + +void EnggDiffFittingViewQtWidget::setDataVector( + std::vector<boost::shared_ptr<QwtData>> &data, bool focused, + bool plotSinglePeaks) { + + if (!plotSinglePeaks) { + // clear vector and detach curves to avoid plot crash + // when only plotting focused workspace + for (auto curves : m_fittedDataVector) { + if (curves) { + curves->detach(); + delete curves; + } + } + + if (m_fittedDataVector.size() > 0) + m_fittedDataVector.clear(); + + // set it as false as there will be no valid workspace to plot + m_ui.pushButton_plot_separate_window->setEnabled(false); + } + + if (focused) { + dataCurvesFactory(data, m_focusedDataVector, focused); + } else { + dataCurvesFactory(data, m_fittedDataVector, focused); + } +} + +void EnggDiffFittingViewQtWidget::dataCurvesFactory( + std::vector<boost::shared_ptr<QwtData>> &data, + std::vector<QwtPlotCurve *> &dataVector, bool focused) { + + // clear vector + for (auto curves : dataVector) { + if (curves) { + curves->detach(); + delete curves; + } + } + + if (dataVector.size() > 0) + dataVector.clear(); + resetView(); + + // dark colours could be removed so that the coloured peaks stand out more + const std::array<QColor, 16> QPenList{ + {Qt::white, Qt::red, Qt::darkRed, Qt::green, Qt::darkGreen, Qt::blue, + Qt::darkBlue, Qt::cyan, Qt::darkCyan, Qt::magenta, Qt::darkMagenta, + Qt::yellow, Qt::darkYellow, Qt::gray, Qt::lightGray, Qt::black}}; + + std::mt19937 gen; + std::uniform_int_distribution<std::size_t> dis(0, QPenList.size() - 1); + + for (size_t i = 0; i < data.size(); i++) { + auto *peak = data[i].get(); + + QwtPlotCurve *dataCurve = new QwtPlotCurve(); + if (!focused) { + dataCurve->setStyle(QwtPlotCurve::Lines); + auto randIndex = dis(gen); + dataCurve->setPen(QPen(QPenList[randIndex], 2)); + + // only set enabled when single peak workspace plotted + m_ui.pushButton_plot_separate_window->setEnabled(true); + } else { + dataCurve->setStyle(QwtPlotCurve::NoCurve); + // focused workspace in bg set as darkGrey crosses insted of line + dataCurve->setSymbol(QwtSymbol(QwtSymbol::XCross, QBrush(), + QPen(Qt::darkGray, 1), QSize(3, 3))); + } + dataCurve->setRenderHint(QwtPlotItem::RenderAntialiased, true); + + dataVector.push_back(dataCurve); + + dataVector[i]->setData(*peak); + dataVector[i]->attach(m_ui.dataPlot); + } + + m_ui.dataPlot->replot(); + m_zoomTool->setZoomBase(); + // enable zoom & select peak btn after the plotting on graph + setZoomTool(true); + m_ui.pushButton_select_peak->setEnabled(true); + data.clear(); +} + +void EnggDiffFittingViewQtWidget::setPeakPickerEnabled(bool enabled) { + m_peakPicker->setEnabled(enabled); + m_peakPicker->setVisible(enabled); + m_ui.dataPlot->replot(); // PeakPicker might get hidden/shown + m_ui.pushButton_add_peak->setEnabled(enabled); + if (enabled) { + QString btnText = "Reset Peak Selector"; + m_ui.pushButton_select_peak->setText(btnText); + } +} + +void EnggDiffFittingViewQtWidget::setPeakPicker( + const IPeakFunction_const_sptr &peak) { + m_peakPicker->setPeak(peak); + m_ui.dataPlot->replot(); +} + +double EnggDiffFittingViewQtWidget::getPeakCentre() const { + auto peak = m_peakPicker->peak(); + auto centre = peak->centre(); + return centre; +} + +void EnggDiffFittingViewQtWidget::fittingWriteFile(const std::string &fileDir) { + std::ofstream outfile(fileDir.c_str()); + if (!outfile) { + userWarning("File not found", + "File " + fileDir + " , could not be found. Please try again!"); + } else { + auto expPeaks = m_ui.lineEdit_fitting_peaks->text(); + outfile << expPeaks.toStdString(); + } +} + +void EnggDiffFittingViewQtWidget::setZoomTool(bool enabled) { + m_zoomTool->setEnabled(enabled); +} + +void EnggDiffFittingViewQtWidget::resetView() { + // Resets the view to a sensible default + // Auto scale the axis + m_ui.dataPlot->setAxisAutoScale(QwtPlot::xBottom); + m_ui.dataPlot->setAxisAutoScale(QwtPlot::yLeft); + + // Set this as the default zoom level + m_zoomTool->setZoomBase(true); +} + +void EnggDiffFittingViewQtWidget::browsePeaksToFit() { + + // TODO: the logic, checks and decision on what message to show should be + // moved to the presenter + + try { + QString prevPath = QString::fromStdString(focusingDir()); + if (prevPath.isEmpty()) { + prevPath = MantidQt::API::AlgorithmInputHistory::Instance() + .getPreviousDirectory(); + } + + QString path( + QFileDialog::getOpenFileName(this, tr("Open Peaks To Fit"), prevPath, + QString::fromStdString(g_peaksListExt))); + + if (path.isEmpty()) { + return; + } + + MantidQt::API::AlgorithmInputHistory::Instance().setPreviousDirectory(path); + + std::string peaksData = readPeaksFile(path.toStdString()); + + m_ui.lineEdit_fitting_peaks->setText(QString::fromStdString(peaksData)); + } catch (...) { + userWarning("Unable to import the peaks from a file: ", + "File corrupted or could not be opened. Please try again"); + return; + } +} + +void EnggDiffFittingViewQtWidget::browseFitFocusedRun() { + resetFittingMultiMode(); + QString prevPath = QString::fromStdString(focusingDir()); + if (prevPath.isEmpty()) { + prevPath = + MantidQt::API::AlgorithmInputHistory::Instance().getPreviousDirectory(); + } + std::string nexusFormat = "Nexus file with calibration table: NXS, NEXUS" + "(*.nxs *.nexus);;"; + + QString path( + QFileDialog::getOpenFileName(this, tr("Open Focused File "), prevPath, + QString::fromStdString(nexusFormat))); + + if (path.isEmpty()) { + return; + } + + MantidQt::API::AlgorithmInputHistory::Instance().setPreviousDirectory(path); + setFittingRunNo(path.toStdString()); + getBanks(); +} + +void EnggDiffFittingViewQtWidget::setFittingRunNo(const std::string &path) { + m_ui.lineEdit_pushButton_run_num->setText(QString::fromStdString(path)); +} + +std::string EnggDiffFittingViewQtWidget::getFittingRunNo() const { + return m_ui.lineEdit_pushButton_run_num->text().toStdString(); +} + +void EnggDiffFittingViewQtWidget::clearFittingComboBox() const { + m_ui.comboBox_bank->clear(); +} + +void EnggDiffFittingViewQtWidget::enableFittingComboBox(bool enable) const { + m_ui.comboBox_bank->setEnabled(enable); +} + +void EnggDiffFittingViewQtWidget::clearFittingListWidget() const { + m_ui.listWidget_fitting_run_num->clear(); +} + +void EnggDiffFittingViewQtWidget::enableFittingListWidget(bool enable) const { + m_ui.listWidget_fitting_run_num->setEnabled(enable); +} + +int EnggDiffFittingViewQtWidget::getFittingListWidgetCurrentRow() const { + return m_ui.listWidget_fitting_run_num->currentRow(); +} + +void EnggDiffFittingViewQtWidget::setFittingListWidgetCurrentRow( + int idx) const { + m_ui.listWidget_fitting_run_num->setCurrentRow(idx); +} + +int EnggDiffFittingViewQtWidget::getFittingComboIdx(std::string bank) const { + return m_ui.comboBox_bank->findText(QString::fromStdString(bank)); +} + +void EnggDiffFittingViewQtWidget::plotSeparateWindow() { + std::string pyCode = + + "fitting_single_peaks_twin_ws = \"__engggui_fitting_single_peaks_twin\"\n" + "if (mtd.doesExist(fitting_single_peaks_twin_ws)):\n" + " DeleteWorkspace(fitting_single_peaks_twin_ws)\n" + + "single_peak_ws = CloneWorkspace(InputWorkspace = " + "\"engggui_fitting_single_peaks\", OutputWorkspace = " + "fitting_single_peaks_twin_ws)\n" + "tot_spec = single_peak_ws.getNumberHistograms()\n" + + "spec_list = []\n" + "for i in range(0, tot_spec):\n" + " spec_list.append(i)\n" + + "fitting_plot = plotSpectrum(single_peak_ws, spec_list).activeLayer()\n" + "fitting_plot.setTitle(\"Engg GUI Single Peaks Fitting Workspace\")\n"; + + std::string status = m_mainPythonRunner->enggRunPythonCode(pyCode); + m_logMsgs.emplace_back("Plotted output focused data, with status string " + + status); + m_presenter->notify(IEnggDiffFittingPresenter::LogMsg); +} + +std::string EnggDiffFittingViewQtWidget::fittingPeaksData() const { + + return m_ui.lineEdit_fitting_peaks->text().toStdString(); +} + +void EnggDiffFittingViewQtWidget::setPeakList( + const std::string &peakList) const { + m_ui.lineEdit_fitting_peaks->setText(QString::fromStdString(peakList)); +} + +std::vector<std::string> +EnggDiffFittingViewQtWidget::splitFittingDirectory(std::string &selectedfPath) { + + Poco::Path PocofPath(selectedfPath); + std::string selectedbankfName = PocofPath.getBaseName(); + std::vector<std::string> splitBaseName; + if (selectedbankfName.find("ENGINX_") != std::string::npos) { + boost::split(splitBaseName, selectedbankfName, boost::is_any_of("_.")); + } + return splitBaseName; +} + +void EnggDiffFittingViewQtWidget::setBankEmit() { emit setBank(); } + +void EnggDiffFittingViewQtWidget::setBankIdComboBox(int idx) { + QComboBox *bankName = m_ui.comboBox_bank; + bankName->setCurrentIndex(idx); +} + +void EnggDiffFittingViewQtWidget::addBankItem(std::string bankID) { + + m_ui.comboBox_bank->addItem(QString::fromStdString(bankID)); +} + +void EnggDiffFittingViewQtWidget::addRunNoItem(std::string runNo) { + m_ui.listWidget_fitting_run_num->addItem(QString::fromStdString(runNo)); +} + +std::vector<std::string> EnggDiffFittingViewQtWidget::getFittingRunNumVec() { + return m_fitting_runno_dir_vec; +} + +void EnggDiffFittingViewQtWidget::setFittingRunNumVec( + std::vector<std::string> assignVec) { + m_fitting_runno_dir_vec.clear(); + m_fitting_runno_dir_vec = assignVec; +} + +void EnggDiffFittingViewQtWidget::setFittingMultiRunMode(bool mode) { + m_fittingMutliRunMode = mode; +} + +bool EnggDiffFittingViewQtWidget::getFittingMultiRunMode() { + return m_fittingMutliRunMode; +} + +void EnggDiffFittingViewQtWidget::setPeakPick() { + auto bk2bk = + FunctionFactory::Instance().createFunction("BackToBackExponential"); + auto bk2bkFunc = boost::dynamic_pointer_cast<IPeakFunction>(bk2bk); + // set the peak to BackToBackExponential function + setPeakPicker(bk2bkFunc); + setPeakPickerEnabled(true); +} + +void EnggDiffFittingViewQtWidget::addPeakToList() { + + if (m_peakPicker->isEnabled()) { + auto peakCentre = getPeakCentre(); + + std::stringstream stream; + stream << std::fixed << std::setprecision(4) << peakCentre; + auto strPeakCentre = stream.str(); + + auto curExpPeaksList = m_ui.lineEdit_fitting_peaks->text(); + QString comma = ","; + + if (!curExpPeaksList.isEmpty()) { + // when further peak added to list + std::string expPeakStr = curExpPeaksList.toStdString(); + std::string lastTwoChr = expPeakStr.substr(expPeakStr.size() - 2); + auto lastChr = expPeakStr.back(); + if (lastChr == ',' || lastTwoChr == ", ") { + curExpPeaksList.append(QString::fromStdString(strPeakCentre)); + } else { + curExpPeaksList.append(comma + QString::fromStdString(strPeakCentre)); + } + m_ui.lineEdit_fitting_peaks->setText(curExpPeaksList); + } else { + // when new peak given when list is empty + curExpPeaksList.append(QString::fromStdString(strPeakCentre)); + curExpPeaksList.append(comma); + m_ui.lineEdit_fitting_peaks->setText(curExpPeaksList); + } + } +} + +void EnggDiffFittingViewQtWidget::savePeakList() { + // call function in EnggPresenter.. + + // TODO: the logic, checks and decision on what message to show should be + // moved to the presenter + + try { + QString prevPath = QString::fromStdString(focusingDir()); + if (prevPath.isEmpty()) { + prevPath = MantidQt::API::AlgorithmInputHistory::Instance() + .getPreviousDirectory(); + } + + QString path(QFileDialog::getSaveFileName( + this, tr("Save Expected Peaks List"), prevPath, + QString::fromStdString(g_peaksListExt))); + + if (path.isEmpty()) { + return; + } + const std::string strPath = path.toStdString(); + fittingWriteFile(strPath); + } catch (...) { + userWarning("Unable to save the peaks file: ", + "Invalid file path or or could not be saved. Please try again"); + return; + } +} + +void EnggDiffFittingViewQtWidget::clearPeakList() { + m_ui.lineEdit_fitting_peaks->clear(); +} + +} // namespace CustomInterfaces +} // namespace MantidQt diff --git a/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionPresenter.cpp b/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionPresenter.cpp index b6f8c78ff6d..18e9d1e52e7 100644 --- a/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionPresenter.cpp +++ b/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionPresenter.cpp @@ -1,24 +1,22 @@ +#include "MantidAPI/AlgorithmManager.h" #include "MantidAPI/ITableWorkspace.h" #include "MantidAPI/MatrixWorkspace.h" #include "MantidAPI/TableRow.h" -#include "MantidAPI/WorkspaceFactory.h" #include "MantidKernel/Property.h" +#include "MantidKernel/StringTokenizer.h" #include "MantidQtAPI/PythonRunner.h" -#include <MantidKernel/StringTokenizer.h> // #include "MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionModel.h" #include "MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresWorker.h" #include "MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresenter.h" #include "MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionView.h" -#include "MantidQtCustomInterfaces/Muon/ALCHelper.h" #include <fstream> #include <boost/lexical_cast.hpp> -#include "Poco/DirectoryIterator.h" #include <Poco/File.h> +#include <Poco/Path.h> -#include <MantidAPI/AlgorithmManager.h> #include <QThread> using namespace Mantid::API; @@ -27,21 +25,6 @@ using namespace MantidQt::CustomInterfaces; namespace MantidQt { namespace CustomInterfaces { -/** - * Parameters from a GSAS calibration. They define a conversion of - * units time-of-flight<->d-spacing that can be calculated with the - * algorithm AlignDetectors for example. - */ -struct GSASCalibrationParms { - GSASCalibrationParms(size_t bid, double dc, double da, double tz) - : bankid(bid), difc(dc), difa(da), tzero(tz) {} - - size_t bankid{0}; - double difc{0}; - double difa{0}; - double tzero{0}; -}; - namespace { Mantid::Kernel::Logger g_log("EngineeringDiffractionGUI"); } @@ -70,13 +53,9 @@ const std::string EnggDiffractionPresenter::g_vanIntegrationWSName = const std::string EnggDiffractionPresenter::g_vanCurvesWSName = "engggui_vanadium_curves_ws"; -const std::string EnggDiffractionPresenter::g_focusedFittingWSName = - "engggui_fitting_focused_ws"; - const std::string EnggDiffractionPresenter::g_calibBanksParms = "engggui_calibration_banks_parameters"; -bool EnggDiffractionPresenter::g_useAlignDetectors = true; int EnggDiffractionPresenter::g_croppedCounter = 0; int EnggDiffractionPresenter::g_plottingCounter = 0; bool EnggDiffractionPresenter::g_abortThread = false; @@ -85,8 +64,8 @@ std::string EnggDiffractionPresenter::g_calibCropIdentifier = "SpectrumNumbers"; std::string EnggDiffractionPresenter::g_sumOfFilesFocus = ""; EnggDiffractionPresenter::EnggDiffractionPresenter(IEnggDiffractionView *view) - : m_workerThread(NULL), m_calibFinishedOK(false), m_focusFinishedOK(false), - m_rebinningFinishedOK(false), m_fittingFinishedOK(false), + : m_workerThread(nullptr), m_calibFinishedOK(false), + m_focusFinishedOK(false), m_rebinningFinishedOK(false), m_view(view) /*, m_model(new EnggDiffractionModel()), */ { if (!m_view) { throw std::runtime_error( @@ -113,7 +92,7 @@ void EnggDiffractionPresenter::cleanup() { m_workerThread->wait(10); } delete m_workerThread; - m_workerThread = NULL; + m_workerThread = nullptr; } } @@ -162,15 +141,6 @@ void EnggDiffractionPresenter::notify( processRebinMultiperiod(); break; - case IEnggDiffractionPresenter::FittingRunNo: - fittingRunNoChanged(); - break; - - case IEnggDiffractionPresenter::FitPeaks: - processFitPeaks(); - - break; - case IEnggDiffractionPresenter::LogMsg: processLogMsg(); break; @@ -349,7 +319,7 @@ void EnggDiffractionPresenter::processCalcCalib() { const std::string outFilename = outputCalibFilename(vanNo, ceriaNo); m_view->showStatus("Calculating calibration..."); - m_view->enableCalibrateAndFocusActions(false); + m_view->enableCalibrateFocusFitUserActions(false); // alternatively, this would be GUI-blocking: // doNewCalibration(outFilename, vanNo, ceriaNo, specNos); // calibrationFinished() @@ -397,7 +367,7 @@ void EnggDiffractionPresenter::ProcessCropCalib() { } m_view->showStatus("Calculating cropped calibration..."); - m_view->enableCalibrateAndFocusActions(false); + m_view->enableCalibrateFocusFitUserActions(false); // alternatively, this would be GUI-blocking: // doNewCalibration(outFilename, vanNo, ceriaNo, specNo/bankName); // calibrationFinished() @@ -547,7 +517,7 @@ void EnggDiffractionPresenter::startFocusing( const std::string focusDir = m_view->focusingDir(); m_view->showStatus("Focusing..."); - m_view->enableCalibrateAndFocusActions(false); + m_view->enableCalibrateFocusFitUserActions(false); // GUI-blocking alternative: // doFocusRun(focusDir, outFilenames, runNo, banks, specNos, dgFile) // focusingFinished() @@ -576,7 +546,7 @@ void EnggDiffractionPresenter::processRebinTime() { "may take some seconds... \n"; m_view->showStatus("Rebinning by time..."); - m_view->enableCalibrateAndFocusActions(false); + m_view->enableCalibrateFocusFitUserActions(false); // GUI-blocking alternative: // doRebinningTime(runNo, bin, outWSName) // rebinningFinished() @@ -603,1030 +573,13 @@ void EnggDiffractionPresenter::processRebinMultiperiod() { "may take some seconds... \n"; m_view->showStatus("Rebinning by pulses..."); - m_view->enableCalibrateAndFocusActions(false); + m_view->enableCalibrateFocusFitUserActions(false); // GUI-blocking alternative: // doRebinningPulses(runNo, nperiods, timeStep, outWSName) // rebinningFinished() startAsyncRebinningPulsesWorker(runNo, nperiods, timeStep, outWSName); } -// Fitting Tab Run Number & Bank handling here -void MantidQt::CustomInterfaces::EnggDiffractionPresenter:: - fittingRunNoChanged() { - - try { - std::string strFocusedFile = m_view->getFittingRunNo(); - QString focusedFile = QString::fromStdString(strFocusedFile); - // file name - Poco::Path selectedfPath(strFocusedFile); - Poco::Path bankDir; - - // handling of vectors - auto runnoDirVector = m_view->getFittingRunNumVec(); - runnoDirVector.clear(); - - std::string strFPath = selectedfPath.toString(); - // returns empty if no directory is found - std::vector<std::string> splitBaseName = - m_view->splitFittingDirectory(strFPath); - // runNo when single focused file selected - std::vector<std::string> runNoVec; - - if (selectedfPath.isFile() && !splitBaseName.empty()) { - -#ifdef __unix__ - bankDir = selectedfPath.parent(); -#else - bankDir = (bankDir).expand(selectedfPath.parent().toString()); -#endif - if (!splitBaseName.empty() && splitBaseName.size() > 3) { - std::string foc_file = splitBaseName[0] + "_" + splitBaseName[1] + "_" + - splitBaseName[2] + "_" + splitBaseName[3]; - std::string strBankDir = bankDir.toString(); - - if (strBankDir.empty()) { - m_view->userWarning( - "Invalid Input", - "Please check that a valid directory is " - "set for Output Folder under Focusing Settings on the " - "settings tab. " - "Please try again"); - } else { - - updateFittingDirVec(strBankDir, foc_file, false, runnoDirVector); - m_view->setFittingRunNumVec(runnoDirVector); - - // add bank to the combo-box and list view - setBankItems(); - setDefaultBank(splitBaseName, focusedFile); - runNoVec.clear(); - runNoVec.push_back(splitBaseName[1]); - auto fittingMultiRunMode = m_view->getFittingMultiRunMode(); - if (!fittingMultiRunMode) - setRunNoItems(runNoVec, false); - } - } - // assuming that no directory is found so look for number - // if run number length greater - } else if (focusedFile.count() > 4) { - if (strFocusedFile.find("-") != std::string::npos) { - std::vector<std::string> firstLastRunNoVec; - boost::split(firstLastRunNoVec, strFocusedFile, boost::is_any_of("-")); - std::string firstRun; - std::string lastRun; - if (!firstLastRunNoVec.empty()) { - firstRun = firstLastRunNoVec[0]; - lastRun = firstLastRunNoVec[1]; - - m_view->setFittingMultiRunMode(true); - enableMultiRun(firstRun, lastRun, runnoDirVector); - } - - } else { - // if given a single run number instead - auto focusDir = m_view->getFocusDir(); - - if (focusDir.empty()) { - m_view->userWarning( - "Invalid Input", - "Please check that a valid directory is " - "set for Output Folder under Focusing Settings on the " - "settings tab. " - "Please try again"); - } else { - - updateFittingDirVec(focusDir, strFocusedFile, false, runnoDirVector); - m_view->setFittingRunNumVec(runnoDirVector); - - // add bank to the combo-box and list view - setBankItems(); - setDefaultBank(splitBaseName, focusedFile); - runNoVec.clear(); - runNoVec.push_back(strFocusedFile); - - auto fittingMultiRunMode = m_view->getFittingMultiRunMode(); - if (!fittingMultiRunMode) - setRunNoItems(runNoVec, false); - } - } - } - // set the directory here to the first in the vector if its not empty - if (!runnoDirVector.empty() && !selectedfPath.isFile()) { - QString firstDir = QString::fromStdString(runnoDirVector[0]); - m_view->setFittingRunNo(firstDir); - - } else if (m_view->getFittingRunNo().empty()) { - m_view->userWarning("Invalid Input", - "Invalid directory or run number given. " - "Please try again"); - } - - } catch (std::runtime_error &re) { - m_view->userWarning("Invalid file", - "Unable to select the file; " + - static_cast<std::string>(re.what())); - return; - } -} - -void EnggDiffractionPresenter::updateFittingDirVec( - const std::string &bankDir, const std::string &focusedFile, bool multi_run, - std::vector<std::string> &fittingRunNoDirVec) { - - try { - std::string cwd(bankDir); - Poco::DirectoryIterator it(cwd); - Poco::DirectoryIterator end; - while (it != end) { - if (it->isFile()) { - std::string itFilePath = it->path(); - Poco::Path itBankfPath(itFilePath); - - std::string itbankFileName = itBankfPath.getBaseName(); - // check if it not any other file.. e.g: texture - if (itbankFileName.find(focusedFile) != std::string::npos) { - fittingRunNoDirVec.push_back(itFilePath); - if (multi_run) - return; - } - } - ++it; - } - } catch (std::runtime_error &re) { - m_view->userWarning("Invalid file", - "File not found in the following directory; " + - bankDir + ". " + - static_cast<std::string>(re.what())); - } -} - -void EnggDiffractionPresenter::enableMultiRun( - std::string firstRun, std::string lastRun, - std::vector<std::string> &fittingRunNoDirVec) { - - bool firstDig = isDigit(firstRun); - bool lastDig = isDigit(lastRun); - - std::vector<std::string> RunNumberVec; - if (firstDig && lastDig) { - int firstNum = std::stoi(firstRun); - int lastNum = std::stoi(lastRun); - - if ((lastNum - firstNum) > 200) { - m_view->userWarning( - "Please try again", - "The specified run number range is " - "far to big, please try a smaller range of consecutive run numbers."); - } - - else if (firstNum <= lastNum) { - - for (int i = firstNum; i <= lastNum; i++) { - RunNumberVec.push_back(std::to_string(i)); - } - - auto focusDir = m_view->getFocusDir(); - if (focusDir.empty()) { - m_view->userWarning( - "Invalid Input", - "Please check that a valid directory is " - "set for Output Folder under Focusing Settings on the " - "settings tab. " - "Please try again"); - } else { - // if given a single run number instead - for (size_t i = 0; i < RunNumberVec.size(); i++) { - updateFittingDirVec(focusDir, RunNumberVec[i], true, - fittingRunNoDirVec); - } - int diff = (lastNum - firstNum) + 1; - auto global_vec_size = fittingRunNoDirVec.size(); - if (size_t(diff) == global_vec_size) { - - setRunNoItems(RunNumberVec, true); - - m_view->setBankEmit(); - } - } - } else { - m_view->userWarning("Invalid Run Number", - "One or more run file not found " - "from the specified range of runs." - "Please try again"); - } - } else { - m_view->userWarning("Invalid Run Number", - "The specfied range of run number " - "entered is invalid. Please try again"); - } -} - -// Process Fitting Peaks begins here - -void EnggDiffractionPresenter::processFitPeaks() { - const std::string focusedRunNo = m_view->getFittingRunNo(); - std::string fittingPeaks = m_view->fittingPeaksData(); - - const std::string fitPeaksData = validateFittingexpectedPeaks(fittingPeaks); - - g_log.debug() << "the expected peaks are: " << fitPeaksData << '\n'; - - try { - inputChecksBeforeFitting(focusedRunNo, fitPeaksData); - } catch (std::invalid_argument &ia) { - m_view->userWarning("Error in the inputs required for fitting", ia.what()); - return; - } - - const std::string outWSName = "engggui_fitting_fit_peak_ws"; - g_log.notice() << "EnggDiffraction GUI: starting new " - "single peak fits into workspace '" + - outWSName + "'. This " - "may take some seconds... \n"; - - m_view->showStatus("Fitting single peaks..."); - // disable GUI to avoid any double threads - m_view->enableCalibrateAndFocusActions(false); - // startAsyncFittingWorker - // doFitting() - startAsyncFittingWorker(focusedRunNo, fitPeaksData); -} - -void EnggDiffractionPresenter::inputChecksBeforeFitting( - const std::string &focusedRunNo, const std::string &expectedPeaks) { - if (focusedRunNo.size() == 0) { - throw std::invalid_argument( - "Focused Run " - "cannot be empty and must be a valid directory"); - } - - Poco::File file(focusedRunNo); - if (!file.exists()) { - throw std::invalid_argument("The focused workspace file for single peak " - "fitting could not be found: " + - focusedRunNo); - } - - if (expectedPeaks.empty()) { - g_log.warning() << "Expected peaks were not passed, via fitting interface, " - "the default list of " - "expected peaks will be utilised instead.\n"; - } - bool contains_non_digits = - expectedPeaks.find_first_not_of("0123456789,. ") != std::string::npos; - if (contains_non_digits) { - throw std::invalid_argument("The expected peaks provided " + expectedPeaks + - " is invalid, " - "fitting process failed. Please try again!"); - } -} - -std::string EnggDiffractionPresenter::validateFittingexpectedPeaks( - std::string &expectedPeaks) const { - - if (!expectedPeaks.empty()) { - - g_log.debug() << "Validating the expected peak list.\n"; - - auto *comma = ","; - - for (size_t i = 0; i < expectedPeaks.size() - 1; i++) { - size_t j = i + 1; - - if (expectedPeaks[i] == *comma && expectedPeaks[i] == expectedPeaks[j]) { - expectedPeaks.erase(j, 1); - i--; - - } else { - ++j; - } - } - - size_t strLength = expectedPeaks.length() - 1; - if (expectedPeaks.at(size_t(0)) == ',') { - expectedPeaks.erase(size_t(0), 1); - strLength -= size_t(1); - } - - if (expectedPeaks.at(strLength) == ',') { - expectedPeaks.erase(strLength, 1); - } - - m_view->setPeakList(expectedPeaks); - } - - return expectedPeaks; -} - -void EnggDiffractionPresenter::startAsyncFittingWorker( - const std::string &focusedRunNo, const std::string &expectedPeaks) { - - delete m_workerThread; - m_workerThread = new QThread(this); - EnggDiffWorker *worker = - new EnggDiffWorker(this, focusedRunNo, expectedPeaks); - worker->moveToThread(m_workerThread); - - connect(m_workerThread, SIGNAL(started()), worker, SLOT(fitting())); - connect(worker, SIGNAL(finished()), this, SLOT(fittingFinished())); - // early delete of thread and worker - connect(m_workerThread, SIGNAL(finished()), m_workerThread, - SLOT(deleteLater()), Qt::DirectConnection); - connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater())); - m_workerThread->start(); -} - -void EnggDiffractionPresenter::setDifcTzero(MatrixWorkspace_sptr wks) const { - size_t bankID = 1; - // attempt to guess bankID - this should be done in code that is currently - // in the view - auto fittingFilename = m_view->getFittingRunNo(); - Poco::File fittingFile(fittingFilename); - if (fittingFile.exists()) { - Poco::Path path(fittingFile.path()); - auto name = path.getBaseName(); - std::vector<std::string> chunks; - boost::split(chunks, name, boost::is_any_of("_")); - if (!chunks.empty()) { - try { - bankID = boost::lexical_cast<size_t>(chunks.back()); - } catch (std::runtime_error &) { - } - } - } - - const std::string units = "none"; - auto &run = wks->mutableRun(); - - if (m_currentCalibParms.empty()) { - run.addProperty<int>("bankid", 1, units, true); - run.addProperty<double>("difc", 18400.0, units, true); - run.addProperty<double>("difa", 0.0, units, true); - run.addProperty<double>("tzero", 4.0, units, true); - } else { - GSASCalibrationParms parms(0, 0.0, 0.0, 0.0); - for (const auto &p : m_currentCalibParms) { - if (p.bankid == bankID) { - parms = p; - break; - } - } - if (0 == parms.difc) - parms = m_currentCalibParms.front(); - - run.addProperty<int>("bankid", static_cast<int>(parms.bankid), units, true); - run.addProperty<double>("difc", parms.difc, units, true); - run.addProperty<double>("difa", parms.difa, units, true); - run.addProperty<double>("tzero", parms.tzero, units, true); - } -} - -void EnggDiffractionPresenter::doFitting(const std::string &focusedRunNo, - const std::string &expectedPeaks) { - g_log.notice() << "EnggDiffraction GUI: starting new fitting with file " - << focusedRunNo << ". This may take a few seconds... \n"; - - MatrixWorkspace_sptr focusedWS; - m_fittingFinishedOK = false; - - // load the focused workspace file to perform single peak fits - try { - auto load = - Mantid::API::AlgorithmManager::Instance().createUnmanaged("Load"); - load->initialize(); - load->setPropertyValue("Filename", focusedRunNo); - load->setPropertyValue("OutputWorkspace", g_focusedFittingWSName); - load->execute(); - - AnalysisDataServiceImpl &ADS = Mantid::API::AnalysisDataService::Instance(); - focusedWS = ADS.retrieveWS<MatrixWorkspace>(g_focusedFittingWSName); - } catch (std::runtime_error &re) { - g_log.error() - << "Error while loading focused data. " - "Could not run the algorithm Load succesfully for the Fit " - "peaks (file name: " + - focusedRunNo + "). Error description: " + re.what() + - " Please check also the previous log messages for details."; - return; - } - - setDifcTzero(focusedWS); - - // run the algorithm EnggFitPeaks with workspace loaded above - // requires unit in Time of Flight - auto enggFitPeaks = - Mantid::API::AlgorithmManager::Instance().createUnmanaged("EnggFitPeaks"); - const std::string focusedFitPeaksTableName = - "engggui_fitting_fitpeaks_params"; - - // delete existing table workspace to avoid confusion - AnalysisDataServiceImpl &ADS = Mantid::API::AnalysisDataService::Instance(); - if (ADS.doesExist(focusedFitPeaksTableName)) { - ADS.remove(focusedFitPeaksTableName); - } - - try { - enggFitPeaks->initialize(); - enggFitPeaks->setProperty("InputWorkspace", focusedWS); - if (!expectedPeaks.empty()) { - enggFitPeaks->setProperty("expectedPeaks", expectedPeaks); - } - enggFitPeaks->setProperty("FittedPeaks", focusedFitPeaksTableName); - enggFitPeaks->execute(); - } catch (std::exception &re) { - g_log.error() << "Could not run the algorithm EnggFitPeaks " - "successfully for bank, " - // bank name - "Error description: " + - static_cast<std::string>(re.what()) + - " Please check also the log message for detail.\n"; - } - - try { - runFittingAlgs(focusedFitPeaksTableName, g_focusedFittingWSName); - - } catch (std::invalid_argument &ia) { - g_log.error() << "Error, Fitting could not finish off correctly, " + - std::string(ia.what()) << '\n'; - return; - } -} - -void EnggDiffractionPresenter::runFittingAlgs( - std::string focusedFitPeaksTableName, std::string focusedWSName) { - // retrieve the table with parameters - auto &ADS = Mantid::API::AnalysisDataService::Instance(); - if (!ADS.doesExist(focusedFitPeaksTableName)) { - // convert units so valid dSpacing peaks can still be added to gui - if (ADS.doesExist(g_focusedFittingWSName)) { - convertUnits(g_focusedFittingWSName); - } - - throw std::invalid_argument( - focusedFitPeaksTableName + - " workspace could not be found. " - "Please check the log messages for more details."); - } - - auto table = ADS.retrieveWS<ITableWorkspace>(focusedFitPeaksTableName); - size_t rowCount = table->rowCount(); - const std::string single_peak_out_WS = "engggui_fitting_single_peaks"; - std::string currentPeakOutWS; - - std::string Bk2BkExpFunctionStr; - std::string startX = ""; - std::string endX = ""; - for (size_t i = 0; i < rowCount; i++) { - // get the functionStrFactory to generate the string for function - // property, returns the string with i row from table workspace - // table is just passed so it works? - Bk2BkExpFunctionStr = - functionStrFactory(table, focusedFitPeaksTableName, i, startX, endX); - - g_log.debug() << "startX: " + startX + " . endX: " + endX << '\n'; - - currentPeakOutWS = "__engggui_fitting_single_peaks" + std::to_string(i); - - // run EvaluateFunction algorithm with focused workspace to produce - // the correct fit function - // focusedWSName is not going to change as its always going to be from - // single workspace - runEvaluateFunctionAlg(Bk2BkExpFunctionStr, focusedWSName, currentPeakOutWS, - startX, endX); - - // crop workspace so only the correct workspace index is plotted - runCropWorkspaceAlg(currentPeakOutWS); - - // apply the same binning as a focused workspace - runRebinToWorkspaceAlg(currentPeakOutWS); - - // if the first peak - if (i == size_t(0)) { - - // create a workspace clone of bank focus file - // this will import all information of the previous file - runCloneWorkspaceAlg(focusedWSName, single_peak_out_WS); - - setDataToClonedWS(currentPeakOutWS, single_peak_out_WS); - ADS.remove(currentPeakOutWS); - } else { - const std::string currentPeakClonedWS = - "__engggui_fitting_cloned_peaks" + std::to_string(i); - - runCloneWorkspaceAlg(focusedWSName, currentPeakClonedWS); - - setDataToClonedWS(currentPeakOutWS, currentPeakClonedWS); - - // append all peaks in to single workspace & remove - runAppendSpectraAlg(single_peak_out_WS, currentPeakClonedWS); - ADS.remove(currentPeakOutWS); - ADS.remove(currentPeakClonedWS); - } - } - - convertUnits(g_focusedFittingWSName); - - // convert units for both workspaces to dSpacing from ToF - if (rowCount > size_t(0)) { - auto swks = ADS.retrieveWS<MatrixWorkspace>(single_peak_out_WS); - setDifcTzero(swks); - convertUnits(single_peak_out_WS); - } else { - g_log.error() << "The engggui_fitting_fitpeaks_params table produced is" - "empty. Please try again!\n"; - } - - m_fittingFinishedOK = true; -} - -std::string EnggDiffractionPresenter::functionStrFactory( - Mantid::API::ITableWorkspace_sptr ¶mTableWS, std::string tableName, - size_t row, std::string &startX, std::string &endX) { - const double windowLeft = 9; - const double windowRight = 12; - - AnalysisDataServiceImpl &ADS = Mantid::API::AnalysisDataService::Instance(); - paramTableWS = ADS.retrieveWS<ITableWorkspace>(tableName); - - double A0 = paramTableWS->cell<double>(row, size_t(1)); - double A1 = paramTableWS->cell<double>(row, size_t(3)); - double I = paramTableWS->cell<double>(row, size_t(13)); - double A = paramTableWS->cell<double>(row, size_t(7)); - double B = paramTableWS->cell<double>(row, size_t(9)); - double X0 = paramTableWS->cell<double>(row, size_t(5)); - double S = paramTableWS->cell<double>(row, size_t(11)); - - startX = boost::lexical_cast<std::string>(X0 - (windowLeft * S)); - endX = boost::lexical_cast<std::string>(X0 + (windowRight * S)); - - std::string functionStr = - "name=LinearBackground,A0=" + boost::lexical_cast<std::string>(A0) + - ",A1=" + boost::lexical_cast<std::string>(A1) + - ";name=BackToBackExponential,I=" + boost::lexical_cast<std::string>(I) + - ",A=" + boost::lexical_cast<std::string>(A) + ",B=" + - boost::lexical_cast<std::string>(B) + ",X0=" + - boost::lexical_cast<std::string>(X0) + ",S=" + - boost::lexical_cast<std::string>(S); - - return functionStr; -} - -void EnggDiffractionPresenter::runEvaluateFunctionAlg( - const std::string &bk2BkExpFunction, const std::string &InputName, - const std::string &OutputName, const std::string &startX, - const std::string &endX) { - - auto evalFunc = Mantid::API::AlgorithmManager::Instance().createUnmanaged( - "EvaluateFunction"); - g_log.notice() << "EvaluateFunction algorithm has started\n"; - try { - evalFunc->initialize(); - evalFunc->setProperty("Function", bk2BkExpFunction); - evalFunc->setProperty("InputWorkspace", InputName); - evalFunc->setProperty("OutputWorkspace", OutputName); - evalFunc->setProperty("StartX", startX); - evalFunc->setProperty("EndX", endX); - evalFunc->execute(); - } catch (std::runtime_error &re) { - g_log.error() << "Could not run the algorithm EvaluateFunction, " - "Error description: " + - static_cast<std::string>(re.what()) << '\n'; - } -} - -void EnggDiffractionPresenter::runCropWorkspaceAlg(std::string workspaceName) { - auto cropWS = Mantid::API::AlgorithmManager::Instance().createUnmanaged( - "CropWorkspace"); - try { - cropWS->initialize(); - cropWS->setProperty("InputWorkspace", workspaceName); - cropWS->setProperty("OutputWorkspace", workspaceName); - cropWS->setProperty("StartWorkspaceIndex", 1); - cropWS->setProperty("EndWorkspaceIndex", 1); - cropWS->execute(); - } catch (std::runtime_error &re) { - g_log.error() << "Could not run the algorithm CropWorkspace, " - "Error description: " + - static_cast<std::string>(re.what()) << '\n'; - } -} - -void EnggDiffractionPresenter::runAppendSpectraAlg(std::string workspace1Name, - std::string workspace2Name) { - auto appendSpec = Mantid::API::AlgorithmManager::Instance().createUnmanaged( - "AppendSpectra"); - try { - appendSpec->initialize(); - appendSpec->setProperty("InputWorkspace1", workspace1Name); - appendSpec->setProperty("InputWorkspace2", workspace2Name); - appendSpec->setProperty("OutputWorkspace", workspace1Name); - appendSpec->execute(); - } catch (std::runtime_error &re) { - g_log.error() << "Could not run the algorithm AppendWorkspace, " - "Error description: " + - static_cast<std::string>(re.what()) << '\n'; - } -} - -void EnggDiffractionPresenter::runRebinToWorkspaceAlg( - std::string workspaceName) { - auto RebinToWs = Mantid::API::AlgorithmManager::Instance().createUnmanaged( - "RebinToWorkspace"); - try { - RebinToWs->initialize(); - RebinToWs->setProperty("WorkspaceToRebin", workspaceName); - RebinToWs->setProperty("WorkspaceToMatch", g_focusedFittingWSName); - RebinToWs->setProperty("OutputWorkspace", workspaceName); - RebinToWs->execute(); - } catch (std::runtime_error &re) { - g_log.error() << "Could not run the algorithm RebinToWorkspace, " - "Error description: " + - static_cast<std::string>(re.what()) << '\n'; - } -} - -/** - * Converts from time-of-flight to d-spacing - * - * @param workspaceName name of the workspace to convert (in place) - */ -void EnggDiffractionPresenter::convertUnits(std::string workspaceName) { - // Here using the GSAS (DIFC, TZERO) parameters seems preferred - if (g_useAlignDetectors) { - runAlignDetectorsAlg(workspaceName); - } else { - runConvertUnitsAlg(workspaceName); - } -} - -void EnggDiffractionPresenter::getDifcTzero(MatrixWorkspace_const_sptr wks, - double &difc, double &difa, - double &tzero) const { - - try { - const auto run = wks->run(); - // long, step by step way: - // auto propC = run.getLogData("difc"); - // auto doubleC = - // dynamic_cast<Mantid::Kernel::PropertyWithValue<double> *>(propC); - // if (!doubleC) - // throw Mantid::Kernel::Exception::NotFoundError( - // "Required difc property not found in workspace.", "difc"); - difc = run.getPropertyValueAsType<double>("difc"); - difa = run.getPropertyValueAsType<double>("difa"); - tzero = run.getPropertyValueAsType<double>("tzero"); - - } catch (std::runtime_error &rexc) { - // fallback to something reasonable / approximate values so - // the fitting tab can work minimally - difa = tzero = 0.0; - difc = 18400; - g_log.warning() - << "Could not retrieve the DIFC, DIFA, TZERO values from the workspace " - << wks->name() << ". Using default, which is not adjusted for this " - "workspace/run: DIFA: " << difa << ", DIFC: " << difc - << ", TZERO: " << tzero << ". Error details: " << rexc.what() << '\n'; - } -} - -/** - * Converts units from time-of-flight to d-spacing, using - * AlignDetectors. This is the GSAS-style alternative to using the - * algorithm ConvertUnits. Needs to make sure that the workspace is - * not of distribution type (and use the algorithm - * ConvertFromDistribution if it is). This is a requirement of - * AlignDetectors. - * - * @param workspaceName name of the workspace to convert - */ -void EnggDiffractionPresenter::runAlignDetectorsAlg(std::string workspaceName) { - const std::string targetUnit = "dSpacing"; - const std::string algName = "AlignDetectors"; - - const auto &ADS = Mantid::API::AnalysisDataService::Instance(); - auto inputWS = ADS.retrieveWS<MatrixWorkspace>(workspaceName); - if (!inputWS) - return; - - double difc, difa, tzero; - getDifcTzero(inputWS, difc, difa, tzero); - - // create a table with the GSAS calibration parameters - ITableWorkspace_sptr difcTable; - try { - difcTable = Mantid::API::WorkspaceFactory::Instance().createTable(); - if (!difcTable) { - return; - } - difcTable->addColumn("int", "detid"); - difcTable->addColumn("double", "difc"); - difcTable->addColumn("double", "difa"); - difcTable->addColumn("double", "tzero"); - TableRow row = difcTable->appendRow(); - auto &spec = inputWS->getSpectrum(0); - Mantid::detid_t detID = *(spec.getDetectorIDs().cbegin()); - - row << detID << difc << difa << tzero; - } catch (std::runtime_error &rexc) { - g_log.error() << "Failed to prepare calibration table input to convert " - "units with the algorithm " << algName - << ". Error details: " << rexc.what() << '\n'; - return; - } - - // AlignDetectors doesn't take distribution workspaces (it enforces - // RawCountValidator) - if (inputWS->isDistribution()) { - try { - auto alg = Mantid::API::AlgorithmManager::Instance().createUnmanaged( - "ConvertFromDistribution"); - alg->initialize(); - alg->setProperty("Workspace", workspaceName); - alg->execute(); - } catch (std::runtime_error &rexc) { - g_log.error() << "Could not run ConvertFromDistribution. Error: " - << rexc.what() << '\n'; - return; - } - } - - try { - auto alg = - Mantid::API::AlgorithmManager::Instance().createUnmanaged(algName); - alg->initialize(); - alg->setProperty("InputWorkspace", workspaceName); - alg->setProperty("OutputWorkspace", workspaceName); - alg->setProperty("CalibrationWorkspace", difcTable); - alg->execute(); - } catch (std::runtime_error &rexc) { - g_log.error() << "Could not run the algorithm " << algName - << " to convert workspace to " << targetUnit - << ", Error details: " + static_cast<std::string>(rexc.what()) - << '\n'; - } -} - -void EnggDiffractionPresenter::runConvertUnitsAlg(std::string workspaceName) { - const std::string targetUnit = "dSpacing"; - auto ConvertUnits = - Mantid::API::AlgorithmManager::Instance().createUnmanaged("ConvertUnits"); - try { - ConvertUnits->initialize(); - ConvertUnits->setProperty("InputWorkspace", workspaceName); - ConvertUnits->setProperty("OutputWorkspace", workspaceName); - ConvertUnits->setProperty("Target", targetUnit); - ConvertUnits->setPropertyValue("EMode", "Elastic"); - ConvertUnits->execute(); - } catch (std::runtime_error &re) { - g_log.error() << "Could not run the algorithm ConvertUnits to convert " - "workspace to " << targetUnit - << ", Error description: " + - static_cast<std::string>(re.what()) << '\n'; - } -} - -void EnggDiffractionPresenter::runCloneWorkspaceAlg( - std::string inputWorkspace, const std::string &outputWorkspace) { - - auto cloneWorkspace = - Mantid::API::AlgorithmManager::Instance().createUnmanaged( - "CloneWorkspace"); - try { - cloneWorkspace->initialize(); - cloneWorkspace->setProperty("InputWorkspace", inputWorkspace); - cloneWorkspace->setProperty("OutputWorkspace", outputWorkspace); - cloneWorkspace->execute(); - } catch (std::runtime_error &re) { - g_log.error() << "Could not run the algorithm CreateWorkspace, " - "Error description: " + - static_cast<std::string>(re.what()) << '\n'; - } -} - -void EnggDiffractionPresenter::setDataToClonedWS(std::string ¤t_WS, - const std::string &cloned_WS) { - AnalysisDataServiceImpl &ADS = Mantid::API::AnalysisDataService::Instance(); - auto currentPeakWS = ADS.retrieveWS<MatrixWorkspace>(current_WS); - auto currentClonedWS = ADS.retrieveWS<MatrixWorkspace>(cloned_WS); - currentClonedWS->dataY(0) = currentPeakWS->readY(0); - currentClonedWS->dataE(0) = currentPeakWS->readE(0); -} - -void EnggDiffractionPresenter::setBankItems() { - try { - auto fitting_runno_vector = m_view->getFittingRunNumVec(); - - if (!fitting_runno_vector.empty()) { - - // delete previous bank added to the list - m_view->clearFittingComboBox(); - - for (size_t i = 0; i < fitting_runno_vector.size(); i++) { - Poco::Path vecFile(fitting_runno_vector[i]); - std::string strVecFile = vecFile.toString(); - // split the directory from m_fitting_runno_dir_vec - std::vector<std::string> vecFileSplit = - m_view->splitFittingDirectory(strVecFile); - - // get the last split in vector which will be bank - std::string bankID = (vecFileSplit.back()); - - bool digit = isDigit(bankID); - - if (digit || bankID == "cropped") { - m_view->addBankItem(bankID); - } else { - QString qBank = QString("Bank %1").arg(i + 1); - m_view->addBankItem(qBank.toStdString()); - } - } - - m_view->enableFittingComboBox(true); - } else { - // upon invalid file - // disable the widgets when only one related file found - m_view->enableFittingComboBox(false); - - m_view->clearFittingComboBox(); - } - - } catch (std::runtime_error &re) { - m_view->userWarning("Unable to insert items: ", - "Could not add banks to " - "combo-box or list widget; " + - static_cast<std::string>(re.what()) + - ". Please try again"); - } -} - -void EnggDiffractionPresenter::setRunNoItems( - std::vector<std::string> runNumVector, bool multiRun) { - try { - if (!runNumVector.empty()) { - - // delete previous bank added to the list - m_view->clearFittingListWidget(); - - for (size_t i = 0; i < runNumVector.size(); i++) { - - // get the last split in vector which will be bank - std::string currentRun = (runNumVector[i]); - - m_view->addRunNoItem(currentRun); - } - - if (multiRun) { - m_view->enableFittingListWidget(true); - - auto currentIndex = m_view->getFittingListWidgetCurrentRow(); - if (currentIndex == -1) - m_view->setFittingListWidgetCurrentRow(0); - } else { - m_view->enableFittingListWidget(false); - } - } - - else { - // upon invalid file - // disable the widgets when only one related file found - m_view->enableFittingListWidget(false); - - m_view->clearFittingListWidget(); - } - - } catch (std::runtime_error &re) { - m_view->userWarning("Unable to insert items: ", - "Could not add list widget; " + - static_cast<std::string>(re.what()) + - ". Please try again"); - } -} - -void EnggDiffractionPresenter::setDefaultBank( - std::vector<std::string> splittedBaseName, QString selectedFile) { - - if (!splittedBaseName.empty()) { - - std::string bankID = (splittedBaseName.back()); - auto combo_data = m_view->getFittingComboIdx(bankID); - - if (combo_data > -1) { - m_view->setBankIdComboBox(combo_data); - } else { - m_view->setFittingRunNo(selectedFile); - } - } - // check if the vector is not empty so that the first directory - // can be assigned to text-field when number is given - else if (!m_view->getFittingRunNumVec().empty()) { - auto firstDir = m_view->getFittingRunNumVec().at(0); - auto intialDir = QString::fromStdString(firstDir); - m_view->setFittingRunNo(intialDir); - } - // if nothing found related to text-field input - else if (!m_view->getFittingRunNo().empty()) - m_view->setFittingRunNo(selectedFile); -} - -bool EnggDiffractionPresenter::isDigit(std::string text) { - for (size_t i = 0; i < text.size(); i++) { - char *str = &text[i]; - if (std::isdigit(*str)) { - return true; - } - } - return false; -} - -void EnggDiffractionPresenter::plotFitPeaksCurves() { - AnalysisDataServiceImpl &ADS = Mantid::API::AnalysisDataService::Instance(); - std::string singlePeaksWs = "engggui_fitting_single_peaks"; - - if (!ADS.doesExist(singlePeaksWs) && !ADS.doesExist(g_focusedFittingWSName)) { - g_log.error() << "Fitting results could not be plotted as there is no " + - singlePeaksWs + " or " + g_focusedFittingWSName + - " workspace found.\n"; - m_view->showStatus("Error while fitting peaks"); - return; - } - - try { - auto focusedPeaksWS = - ADS.retrieveWS<MatrixWorkspace>(g_focusedFittingWSName); - auto focusedData = ALCHelper::curveDataFromWs(focusedPeaksWS); - m_view->setDataVector(focusedData, true, m_fittingFinishedOK); - - if (m_fittingFinishedOK) { - g_log.debug() << "single peaks fitting being plotted now.\n"; - auto singlePeaksWS = ADS.retrieveWS<MatrixWorkspace>(singlePeaksWs); - auto singlePeaksData = ALCHelper::curveDataFromWs(singlePeaksWS); - m_view->setDataVector(singlePeaksData, false, true); - m_view->showStatus("Peaks fitted successfully"); - - } else { - g_log.notice() - << "Focused workspace has been plotted to the " - "graph; further peaks can be adding using Peak Tools.\n"; - g_log.warning() << "Peaks could not be plotted as the fitting process " - "did not finish correctly.\n"; - m_view->showStatus("No peaks could be fitted"); - } - - } catch (std::runtime_error) { - g_log.error() - << "Unable to finish of the plotting of the graph for " - "engggui_fitting_focused_fitpeaks workspace. Error " - "description. Please check also the log message for detail."; - - m_view->showStatus("Error while plotting the peaks fitted"); - throw; - } -} - -void EnggDiffractionPresenter::fittingFinished() { - if (!m_view) - return; - - if (!m_fittingFinishedOK) { - g_log.warning() << "The single peak fitting did not finish correctly.\n"; - if (m_workerThread) { - delete m_workerThread; - m_workerThread = NULL; - } - - m_view->showStatus( - "Single peak fitting process did not complete successfully"); - } else { - g_log.notice() << "The single peak fitting finished - the output " - "workspace is ready.\n"; - - m_view->showStatus("Single peak fittin process finished. Ready"); - if (m_workerThread) { - delete m_workerThread; - m_workerThread = NULL; - } - } - - try { - // should now plot the focused workspace when single peak fitting - // process fails - plotFitPeaksCurves(); - - } catch (std::runtime_error &re) { - g_log.error() << "Unable to finish the plotting of the graph for " - "engggui_fitting_focused_fitpeaks workspace. Error " - "description: " + - static_cast<std::string>(re.what()) + - " Please check also the log message for detail."; - throw; - } - g_log.notice() << "EnggDiffraction GUI: plotting of peaks for single peak " - "fits has completed. \n"; - - // enable the GUI - m_view->enableCalibrateAndFocusActions(true); -} - void EnggDiffractionPresenter::processLogMsg() { std::vector<std::string> msgs = m_view->logMsgs(); for (size_t i = 0; i < msgs.size(); i++) { @@ -2025,7 +978,7 @@ void EnggDiffractionPresenter::calibrationFinished() { if (!m_view) return; - m_view->enableCalibrateAndFocusActions(true); + m_view->enableCalibrateFocusFitUserActions(true); if (!m_calibFinishedOK) { g_log.warning() << "The calibration did not finish correctly. Please " "check previous log messages for details.\n"; @@ -2081,6 +1034,11 @@ std::string EnggDiffractionPresenter::buildCalibrateSuggestedFilename( return sugg; } +std::vector<GSASCalibrationParms> +EnggDiffractionPresenter::currentCalibration() const { + return m_currentCalibParms; +} + /** * Calculate a calibration, responding the the "new calibration" * action/button. @@ -2653,10 +1611,10 @@ void EnggDiffractionPresenter::focusingFinished() { } if (m_workerThread) { delete m_workerThread; - m_workerThread = NULL; + m_workerThread = nullptr; } - m_view->enableCalibrateAndFocusActions(true); + m_view->enableCalibrateFocusFitUserActions(true); // display warning and information to the users regarding Stop Focus if (g_abortThread) { @@ -3365,10 +2323,10 @@ void EnggDiffractionPresenter::rebinningFinished() { } if (m_workerThread) { delete m_workerThread; - m_workerThread = NULL; + m_workerThread = nullptr; } - m_view->enableCalibrateAndFocusActions(true); + m_view->enableCalibrateFocusFitUserActions(true); } /** diff --git a/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionViewQtGUI.cpp b/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionViewQtGUI.cpp index cbc1a2e1880..f9ab409f329 100644 --- a/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionViewQtGUI.cpp +++ b/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionViewQtGUI.cpp @@ -1,22 +1,13 @@ #include "MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionViewQtGUI.h" -#include "MantidAPI/FunctionFactory.h" #include "MantidKernel/ConfigService.h" #include "MantidQtAPI/AlgorithmInputHistory.h" #include "MantidQtAPI/AlgorithmRunner.h" #include "MantidQtAPI/HelpWindow.h" #include "MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresenter.h" #include "MantidQtMantidWidgets/MWRunFiles.h" -#include "Poco/DirectoryIterator.h" - -using namespace Mantid::API; -using namespace MantidQt::CustomInterfaces; - -#include <array> -#include <fstream> -#include <random> +#include <Poco/DirectoryIterator.h> #include <Poco/Path.h> -#include <boost/lexical_cast.hpp> #include <QCheckBox> #include <QCloseEvent> @@ -24,7 +15,8 @@ using namespace MantidQt::CustomInterfaces; #include <QMessageBox> #include <QSettings> -#include <qwt_symbol.h> +using namespace Mantid::API; +using namespace MantidQt::CustomInterfaces; namespace MantidQt { namespace CustomInterfaces { @@ -36,9 +28,7 @@ const double EnggDiffractionViewQtGUI::g_defaultRebinWidth = -0.0005; int EnggDiffractionViewQtGUI::m_currentType = 0; int EnggDiffractionViewQtGUI::m_currentRunMode = 0; -bool EnggDiffractionViewQtGUI::m_fittingMutliRunMode = false; int EnggDiffractionViewQtGUI::m_currentCropCalibBankName = 0; -std::vector<std::string> EnggDiffractionViewQtGUI::m_fitting_runno_dir_vec; const std::string EnggDiffractionViewQtGUI::g_iparmExtStr = "GSAS instrument parameters, IPARM file: PRM, PAR, IPAR, IPARAM " @@ -59,7 +49,7 @@ const std::string EnggDiffractionViewQtGUI::g_DetGrpExtStr = "(*.csv *.txt);;" "Other extensions/all files (*.*)"; -const std::string EnggDiffractionViewQtGUI::m_settingsGroup = +const std::string EnggDiffractionViewQtGUI::g_settingsGroup = "CustomInterfaces/EnggDiffractionView"; /** @@ -69,25 +59,20 @@ const std::string EnggDiffractionViewQtGUI::m_settingsGroup = */ EnggDiffractionViewQtGUI::EnggDiffractionViewQtGUI(QWidget *parent) : UserSubWindow(parent), IEnggDiffractionView(), m_currentInst("ENGINX"), - m_currentCalibFilename(""), m_splashMsg(nullptr), m_focusedDataVector(), - m_fittedDataVector(), m_peakPicker(nullptr), m_zoomTool(nullptr), - m_presenter(nullptr) {} - -EnggDiffractionViewQtGUI::~EnggDiffractionViewQtGUI() { - for (auto curves : m_focusedDataVector) { - curves->detach(); - delete curves; - } + m_splashMsg(nullptr), m_presenter(nullptr) {} - for (auto curves : m_fittedDataVector) { - curves->detach(); - delete curves; - } -} +EnggDiffractionViewQtGUI::~EnggDiffractionViewQtGUI() {} void EnggDiffractionViewQtGUI::initLayout() { // setup container ui m_ui.setupUi(this); + + // presenter that knows how to handle a IEnggDiffractionView should + // take care of all the logic. Note that the view needs to know the + // concrete presenter + auto fullPres = boost::make_shared<EnggDiffractionPresenter>(this); + m_presenter = fullPres; + // add tab contents and set up their ui's QWidget *wCalib = new QWidget(m_ui.tabMain); m_uiTabCalib.setupUi(wCalib); @@ -101,9 +86,13 @@ void EnggDiffractionViewQtGUI::initLayout() { m_uiTabPreproc.setupUi(wPreproc); m_ui.tabMain->addTab(wPreproc, QString("Pre-processing")); - QWidget *wFitting = new QWidget(m_ui.tabMain); - m_uiTabFitting.setupUi(wFitting); - m_ui.tabMain->addTab(wFitting, QString("Fitting")); + // This is created from a QWidget* -> use null-deleter to prevent double-free + // with Qt + boost::shared_ptr<EnggDiffractionViewQtGUI> sharedView( + this, [](EnggDiffractionViewQtGUI *) {}); + m_fittingWidget = new EnggDiffFittingViewQtWidget( + m_ui.tabMain, sharedView, sharedView, fullPres, sharedView); + m_ui.tabMain->addTab(m_fittingWidget, QString("Fitting")); QWidget *wSettings = new QWidget(m_ui.tabMain); m_uiTabSettings.setupUi(wSettings); @@ -124,16 +113,8 @@ void EnggDiffractionViewQtGUI::initLayout() { doSetupTabCalib(); doSetupTabFocus(); doSetupTabPreproc(); - doSetupTabFitting(); doSetupTabSettings(); - // presenter that knows how to handle a IEnggDiffractionView should take care - // of all the logic - // note that the view needs to know the concrete presenter - m_presenter.reset(new EnggDiffractionPresenter(this)); - - // it will know what compute resources and tools we have available: - // This view doesn't even know the names of compute resources, etc. m_presenter->notify(IEnggDiffractionPresenter::Start); m_presenter->notify(IEnggDiffractionPresenter::RBNumberChange); } @@ -175,7 +156,7 @@ void EnggDiffractionViewQtGUI::doSetupTabCalib() { connect(m_uiTabCalib.comboBox_calib_cropped_bank_name, SIGNAL(currentIndexChanged(int)), this, SLOT(enableSpecNos())); - enableCalibrateAndFocusActions(true); + enableCalibrateFocusFitUserActions(true); } void EnggDiffractionViewQtGUI::doSetupTabFocus() { @@ -216,75 +197,6 @@ void EnggDiffractionViewQtGUI::doSetupTabPreproc() { SLOT(rebinMultiperiodClicked())); } -void EnggDiffractionViewQtGUI::doSetupTabFitting() { - - connect(m_uiTabFitting.pushButton_fitting_browse_run_num, SIGNAL(released()), - this, SLOT(browseFitFocusedRun())); - - connect(m_uiTabFitting.lineEdit_pushButton_run_num, - SIGNAL(textEdited(const QString &)), this, - SLOT(resetFittingMultiMode())); - - connect(m_uiTabFitting.lineEdit_pushButton_run_num, SIGNAL(editingFinished()), - this, SLOT(FittingRunNo())); - - connect(m_uiTabFitting.lineEdit_pushButton_run_num, SIGNAL(returnPressed()), - this, SLOT(FittingRunNo())); - - connect(this, SIGNAL(getBanks()), this, SLOT(FittingRunNo())); - - connect(this, SIGNAL(setBank()), this, SLOT(listViewFittingRun())); - - connect(m_uiTabFitting.listWidget_fitting_run_num, - SIGNAL(itemSelectionChanged()), this, SLOT(listViewFittingRun())); - - connect(m_uiTabFitting.comboBox_bank, SIGNAL(currentIndexChanged(int)), this, - SLOT(setBankDir(int))); - - connect(m_uiTabFitting.pushButton_fitting_browse_peaks, SIGNAL(released()), - this, SLOT(browsePeaksToFit())); - - connect(m_uiTabFitting.pushButton_fit, SIGNAL(released()), this, - SLOT(fitClicked())); - - // add peak by clicking the button - connect(m_uiTabFitting.pushButton_select_peak, SIGNAL(released()), - SLOT(setPeakPick())); - - connect(m_uiTabFitting.pushButton_add_peak, SIGNAL(released()), - SLOT(addPeakToList())); - - connect(m_uiTabFitting.pushButton_save_peak_list, SIGNAL(released()), - SLOT(savePeakList())); - - connect(m_uiTabFitting.pushButton_clear_peak_list, SIGNAL(released()), - SLOT(clearPeakList())); - - connect(m_uiTabFitting.pushButton_plot_separate_window, SIGNAL(released()), - SLOT(plotSeparateWindow())); - - m_uiTabFitting.dataPlot->setCanvasBackground(Qt::white); - m_uiTabFitting.dataPlot->setAxisTitle(QwtPlot::xBottom, "d-Spacing (A)"); - m_uiTabFitting.dataPlot->setAxisTitle(QwtPlot::yLeft, "Counts (us)^-1"); - QFont font("MS Shell Dlg 2", 8); - m_uiTabFitting.dataPlot->setAxisFont(QwtPlot::xBottom, font); - m_uiTabFitting.dataPlot->setAxisFont(QwtPlot::yLeft, font); - - // constructor of the peakPicker - // XXX: Being a QwtPlotItem, should get deleted when m_ui.plot gets deleted - // (auto-delete option) - m_peakPicker = - new MantidWidgets::PeakPicker(m_uiTabFitting.dataPlot, Qt::red); - setPeakPickerEnabled(false); - - m_zoomTool = new QwtPlotZoomer( - QwtPlot::xBottom, QwtPlot::yLeft, - QwtPicker::DragSelection | QwtPicker::CornerToCorner, - QwtPicker::AlwaysOff, m_uiTabFitting.dataPlot->canvas()); - m_zoomTool->setRubberBandPen(QPen(Qt::black)); - setZoomTool(false); -} - void EnggDiffractionViewQtGUI::doSetupTabSettings() { // line edits that display paths and the like m_uiTabSettings.lineEdit_input_dir_calib->setText( @@ -357,7 +269,7 @@ void EnggDiffractionViewQtGUI::doSetupSplashMsg() { void EnggDiffractionViewQtGUI::readSettings() { QSettings qs; - qs.beginGroup(QString::fromStdString(m_settingsGroup)); + qs.beginGroup(QString::fromStdString(g_settingsGroup)); m_ui.lineEdit_RBNumber->setText( qs.value("user-params-RBNumber", "").toString()); @@ -368,7 +280,6 @@ void EnggDiffractionViewQtGUI::readSettings() { qs.value("user-params-current-ceria-num", "").toString()); QString calibFname = qs.value("current-calib-filename", "").toString(); m_uiTabCalib.lineEdit_current_calib_filename->setText(calibFname); - m_currentCalibFilename = calibFname.toStdString(); m_uiTabCalib.MWRunFiles_new_vanadium_num->setUserInput( qs.value("user-params-new-vanadium-num", "").toString()); @@ -447,13 +358,6 @@ void EnggDiffractionViewQtGUI::readSettings() { m_uiTabPreproc.doubleSpinBox_step_time->setValue( qs.value("user-params-step-time", 1).toDouble()); - // user params - fitting - m_uiTabFitting.lineEdit_pushButton_run_num->setText( - qs.value("user-params-fitting-focused-file", "").toString()); - m_uiTabFitting.comboBox_bank->setCurrentIndex(0); - m_uiTabFitting.lineEdit_fitting_peaks->setText( - qs.value("user-params-fitting-peaks-to-fit", "").toString()); - // settings QString lastPath = MantidQt::API::AlgorithmInputHistory::Instance().getPreviousDirectory(); @@ -490,7 +394,7 @@ void EnggDiffractionViewQtGUI::readSettings() { void EnggDiffractionViewQtGUI::saveSettings() const { QSettings qs; - qs.beginGroup(QString::fromStdString(m_settingsGroup)); + qs.beginGroup(QString::fromStdString(g_settingsGroup)); qs.setValue("user-params-RBNumber", m_ui.lineEdit_RBNumber->text()); @@ -569,13 +473,6 @@ void EnggDiffractionViewQtGUI::saveSettings() const { qs.value("user-params-step-time", m_uiTabPreproc.doubleSpinBox_step_time->value()); - // fitting tab - - qs.setValue("user-params-fitting-focused-file", - m_uiTabFitting.lineEdit_pushButton_run_num->text()); - qs.setValue("user-params-fitting-peaks-to-fit", - m_uiTabFitting.lineEdit_fitting_peaks->text()); - // TODO: this should become << >> operators on EnggDiffCalibSettings qs.setValue("input-dir-calib-files", QString::fromStdString(m_calibSettings.m_inputDirCalib)); @@ -718,7 +615,7 @@ void EnggDiffractionViewQtGUI::newCalibLoaded(const std::string &vanadiumNo, } } -void EnggDiffractionViewQtGUI::enableCalibrateAndFocusActions(bool enable) { +void EnggDiffractionViewQtGUI::enableCalibrateFocusFitUserActions(bool enable) { // calibrate m_uiTabCalib.groupBox_make_new_calib->setEnabled(enable); m_uiTabCalib.groupBox_current_calib->setEnabled(enable); @@ -744,15 +641,7 @@ void EnggDiffractionViewQtGUI::enableCalibrateAndFocusActions(bool enable) { m_uiTabPreproc.pushButton_rebin_multiperiod->setEnabled(enable); // fitting - m_uiTabFitting.pushButton_fitting_browse_run_num->setEnabled(enable); - m_uiTabFitting.lineEdit_pushButton_run_num->setEnabled(enable); - m_uiTabFitting.pushButton_fitting_browse_peaks->setEnabled(enable); - m_uiTabFitting.lineEdit_fitting_peaks->setEnabled(enable); - m_uiTabFitting.pushButton_fit->setEnabled(enable); - m_uiTabFitting.pushButton_clear_peak_list->setEnabled(enable); - m_uiTabFitting.pushButton_save_peak_list->setEnabled(enable); - m_uiTabFitting.comboBox_bank->setEnabled(enable); - m_uiTabFitting.groupBox_fititng_preview->setEnabled(enable); + m_fittingWidget->enable(enable); } void EnggDiffractionViewQtGUI::enableTabs(bool enable) { @@ -779,207 +668,6 @@ double EnggDiffractionViewQtGUI::rebinningPulsesTime() const { return m_uiTabPreproc.doubleSpinBox_step_time->value(); } -void EnggDiffractionViewQtGUI::setBankDir(int idx) { - - if (m_fitting_runno_dir_vec.size() >= size_t(idx)) { - - std::string bankDir = m_fitting_runno_dir_vec[idx]; - Poco::Path fpath(bankDir); - - setFittingRunNo(QString::fromUtf8(bankDir.c_str())); - } -} - -void MantidQt::CustomInterfaces::EnggDiffractionViewQtGUI:: - listViewFittingRun() { - - if (m_fittingMutliRunMode) { - auto listView = m_uiTabFitting.listWidget_fitting_run_num; - auto currentRow = listView->currentRow(); - auto item = listView->item(currentRow); - QString itemText = item->text(); - - setFittingRunNo(itemText); - FittingRunNo(); - } -} - -void MantidQt::CustomInterfaces::EnggDiffractionViewQtGUI:: - resetFittingMultiMode() { - // resets the global variable so the list view widgets - // adds the run number to for single runs too - m_fittingMutliRunMode = false; -} - -std::string EnggDiffractionViewQtGUI::fittingRunNoFactory(std::string bank, - std::string fileName, - std::string &bankDir, - std::string fileDir) { - - std::string genDir = fileName.substr(0, fileName.size() - 1); - Poco::Path bankFile(genDir + bank + ".nxs"); - if (bankFile.isFile()) { - bankDir = fileDir + genDir + bank + ".nxs"; - } - return bankDir; -} - -std::string EnggDiffractionViewQtGUI::readPeaksFile(std::string fileDir) { - std::string fileData = ""; - std::string line; - std::string comma = ", "; - - std::ifstream peakFile(fileDir); - - if (peakFile.is_open()) { - while (std::getline(peakFile, line)) { - fileData += line; - if (!peakFile.eof()) - fileData += comma; - } - peakFile.close(); - } - - else - fileData = ""; - - return fileData; -} - -void EnggDiffractionViewQtGUI::setDataVector( - std::vector<boost::shared_ptr<QwtData>> &data, bool focused, - bool plotSinglePeaks) { - - if (!plotSinglePeaks) { - // clear vector and detach curves to avoid plot crash - // when only plotting focused workspace - for (auto curves : m_fittedDataVector) { - if (curves) { - curves->detach(); - delete curves; - } - } - - if (m_fittedDataVector.size() > 0) - m_fittedDataVector.clear(); - - // set it as false as there will be no valid workspace to plot - m_uiTabFitting.pushButton_plot_separate_window->setEnabled(false); - } - - if (focused) { - dataCurvesFactory(data, m_focusedDataVector, focused); - } else { - dataCurvesFactory(data, m_fittedDataVector, focused); - } -} - -void EnggDiffractionViewQtGUI::dataCurvesFactory( - std::vector<boost::shared_ptr<QwtData>> &data, - std::vector<QwtPlotCurve *> &dataVector, bool focused) { - - // clear vector - for (auto curves : dataVector) { - if (curves) { - curves->detach(); - delete curves; - } - } - - if (dataVector.size() > 0) - dataVector.clear(); - resetView(); - - // dark colours could be removed so that the coloured peaks stand out more - const std::array<QColor, 16> QPenList{ - {Qt::white, Qt::red, Qt::darkRed, Qt::green, Qt::darkGreen, Qt::blue, - Qt::darkBlue, Qt::cyan, Qt::darkCyan, Qt::magenta, Qt::darkMagenta, - Qt::yellow, Qt::darkYellow, Qt::gray, Qt::lightGray, Qt::black}}; - - std::mt19937 gen; - std::uniform_int_distribution<std::size_t> dis(0, QPenList.size() - 1); - - for (size_t i = 0; i < data.size(); i++) { - auto *peak = data[i].get(); - - QwtPlotCurve *dataCurve = new QwtPlotCurve(); - if (!focused) { - dataCurve->setStyle(QwtPlotCurve::Lines); - auto randIndex = dis(gen); - dataCurve->setPen(QPen(QPenList[randIndex], 2)); - - // only set enabled when single peak workspace plotted - m_uiTabFitting.pushButton_plot_separate_window->setEnabled(true); - } else { - dataCurve->setStyle(QwtPlotCurve::NoCurve); - // focused workspace in bg set as darkGrey crosses insted of line - dataCurve->setSymbol(QwtSymbol(QwtSymbol::XCross, QBrush(), - QPen(Qt::darkGray, 1), QSize(3, 3))); - } - dataCurve->setRenderHint(QwtPlotItem::RenderAntialiased, true); - - dataVector.push_back(dataCurve); - - dataVector[i]->setData(*peak); - dataVector[i]->attach(m_uiTabFitting.dataPlot); - } - - m_uiTabFitting.dataPlot->replot(); - m_zoomTool->setZoomBase(); - // enable zoom & select peak btn after the plotting on graph - setZoomTool(true); - m_uiTabFitting.pushButton_select_peak->setEnabled(true); - data.clear(); -} - -void EnggDiffractionViewQtGUI::setPeakPickerEnabled(bool enabled) { - m_peakPicker->setEnabled(enabled); - m_peakPicker->setVisible(enabled); - m_uiTabFitting.dataPlot->replot(); // PeakPicker might get hidden/shown - m_uiTabFitting.pushButton_add_peak->setEnabled(enabled); - if (enabled) { - QString btnText = "Reset Peak Selector"; - m_uiTabFitting.pushButton_select_peak->setText(btnText); - } -} - -void EnggDiffractionViewQtGUI::setPeakPicker( - const IPeakFunction_const_sptr &peak) { - m_peakPicker->setPeak(peak); - m_uiTabFitting.dataPlot->replot(); -} - -double EnggDiffractionViewQtGUI::getPeakCentre() const { - auto peak = m_peakPicker->peak(); - auto centre = peak->centre(); - return centre; -} - -void EnggDiffractionViewQtGUI::fittingWriteFile(const std::string &fileDir) { - std::ofstream outfile(fileDir.c_str()); - if (!outfile) { - userWarning("File not found", - "File " + fileDir + " , could not be found. Please try again!"); - } else { - auto expPeaks = m_uiTabFitting.lineEdit_fitting_peaks->text(); - outfile << expPeaks.toStdString(); - } -} - -void EnggDiffractionViewQtGUI::setZoomTool(bool enabled) { - m_zoomTool->setEnabled(enabled); -} - -void EnggDiffractionViewQtGUI::resetView() { - // Resets the view to a sensible default - // Auto scale the axis - m_uiTabFitting.dataPlot->setAxisAutoScale(QwtPlot::xBottom); - m_uiTabFitting.dataPlot->setAxisAutoScale(QwtPlot::yLeft); - - // Set this as the default zoom level - m_zoomTool->setZoomBase(true); -} - void EnggDiffractionViewQtGUI::plotFocusedSpectrum(const std::string &wsName) { std::string pyCode = "win=plotSpectrum('" + wsName + "', 0, error_bars=False, type=0)"; @@ -1111,14 +799,6 @@ void EnggDiffractionViewQtGUI::rebinMultiperiodClicked() { m_presenter->notify(IEnggDiffractionPresenter::RebinMultiperiod); } -void EnggDiffractionViewQtGUI::fitClicked() { - m_presenter->notify(IEnggDiffractionPresenter::FitPeaks); -} - -void EnggDiffractionViewQtGUI::FittingRunNo() { - m_presenter->notify(IEnggDiffractionPresenter::FittingRunNo); -} - void EnggDiffractionViewQtGUI::browseInputDirCalib() { QString prevPath = QString::fromStdString(m_calibSettings.m_inputDirCalib); if (prevPath.isEmpty()) { @@ -1211,8 +891,7 @@ void EnggDiffractionViewQtGUI::browseDirFocusing() { MantidQt::API::AlgorithmInputHistory::Instance().setPreviousDirectory(dir); m_focusDir = dir.toStdString(); - m_uiTabSettings.lineEdit_dir_focusing->setText( - QString::fromStdString(m_focusDir)); + m_uiTabSettings.lineEdit_dir_focusing->setText(dir); } void EnggDiffractionViewQtGUI::browseTextureDetGroupingFile() { @@ -1234,59 +913,6 @@ void EnggDiffractionViewQtGUI::browseTextureDetGroupingFile() { m_uiTabFocus.lineEdit_texture_grouping_file->setText(path); } -void EnggDiffractionViewQtGUI::browseFitFocusedRun() { - resetFittingMultiMode(); - QString prevPath = QString::fromStdString(m_focusDir); - if (prevPath.isEmpty()) { - prevPath = - MantidQt::API::AlgorithmInputHistory::Instance().getPreviousDirectory(); - } - std::string nexusFormat = "Nexus file with calibration table: NXS, NEXUS" - "(*.nxs *.nexus);;"; - - QString path( - QFileDialog::getOpenFileName(this, tr("Open Focused File "), prevPath, - QString::fromStdString(nexusFormat))); - - if (path.isEmpty()) { - return; - } - - MantidQt::API::AlgorithmInputHistory::Instance().setPreviousDirectory(path); - setFittingRunNo(path); - getBanks(); -} - -void EnggDiffractionViewQtGUI::browsePeaksToFit() { - - try { - QString prevPath = QString::fromStdString(m_focusDir); - if (prevPath.isEmpty()) { - prevPath = MantidQt::API::AlgorithmInputHistory::Instance() - .getPreviousDirectory(); - } - - QString path( - QFileDialog::getOpenFileName(this, tr("Open Peaks To Fit"), prevPath, - QString::fromStdString(g_DetGrpExtStr))); - - if (path.isEmpty()) { - return; - } - - MantidQt::API::AlgorithmInputHistory::Instance().setPreviousDirectory(path); - - std::string peaksData = readPeaksFile(path.toStdString()); - - m_uiTabFitting.lineEdit_fitting_peaks->setText( - QString::fromStdString(peaksData)); - } catch (...) { - userWarning("Unable to import the peaks from a file: ", - "File corrupted or could not be opened. Please try again"); - return; - } -} - std::vector<std::string> EnggDiffractionViewQtGUI::focusingRunNo() const { return qListToVector(m_uiTabFocus.MWRunFiles_run_num->getFilenames(), m_uiTabFocus.MWRunFiles_run_num->isValid()); @@ -1394,211 +1020,6 @@ void EnggDiffractionViewQtGUI::plotRepChanged(int /*idx*/) { m_currentType = plotType->currentIndex(); } -void EnggDiffractionViewQtGUI::setBankIdComboBox(int idx) { - QComboBox *bankName = m_uiTabFitting.comboBox_bank; - bankName->setCurrentIndex(idx); -} - -void EnggDiffractionViewQtGUI::setFittingRunNo(QString path) { - m_uiTabFitting.lineEdit_pushButton_run_num->setText(path); -} - -std::string EnggDiffractionViewQtGUI::getFittingRunNo() const { - return m_uiTabFitting.lineEdit_pushButton_run_num->text().toStdString(); -} - -void MantidQt::CustomInterfaces::EnggDiffractionViewQtGUI:: - clearFittingComboBox() const { - m_uiTabFitting.comboBox_bank->clear(); -} - -void MantidQt::CustomInterfaces::EnggDiffractionViewQtGUI:: - enableFittingComboBox(bool enable) const { - m_uiTabFitting.comboBox_bank->setEnabled(enable); -} - -void MantidQt::CustomInterfaces::EnggDiffractionViewQtGUI:: - clearFittingListWidget() const { - m_uiTabFitting.listWidget_fitting_run_num->clear(); -} - -void MantidQt::CustomInterfaces::EnggDiffractionViewQtGUI:: - enableFittingListWidget(bool enable) const { - m_uiTabFitting.listWidget_fitting_run_num->setEnabled(enable); -} - -int MantidQt::CustomInterfaces::EnggDiffractionViewQtGUI:: - getFittingListWidgetCurrentRow() const { - return m_uiTabFitting.listWidget_fitting_run_num->currentRow(); -} - -void MantidQt::CustomInterfaces::EnggDiffractionViewQtGUI:: - setFittingListWidgetCurrentRow(int idx) const { - m_uiTabFitting.listWidget_fitting_run_num->setCurrentRow(idx); -} - -int EnggDiffractionViewQtGUI::getFittingComboIdx(std::string bank) const { - return m_uiTabFitting.comboBox_bank->findText(QString::fromStdString(bank)); -} - -void EnggDiffractionViewQtGUI::plotSeparateWindow() { - std::string pyCode = - - "fitting_single_peaks_twin_ws = \"__engggui_fitting_single_peaks_twin\"\n" - "if (mtd.doesExist(fitting_single_peaks_twin_ws)):\n" - " DeleteWorkspace(fitting_single_peaks_twin_ws)\n" - - "single_peak_ws = CloneWorkspace(InputWorkspace = " - "\"engggui_fitting_single_peaks\", OutputWorkspace = " - "fitting_single_peaks_twin_ws)\n" - "tot_spec = single_peak_ws.getNumberHistograms()\n" - - "spec_list = []\n" - "for i in range(0, tot_spec):\n" - " spec_list.append(i)\n" - - "fitting_plot = plotSpectrum(single_peak_ws, spec_list).activeLayer()\n" - "fitting_plot.setTitle(\"Engg GUI Single Peaks Fitting Workspace\")\n"; - - std::string status = - runPythonCode(QString::fromStdString(pyCode), false).toStdString(); - m_logMsgs.emplace_back("Plotted output focused data, with status string " + - status); - m_presenter->notify(IEnggDiffractionPresenter::LogMsg); -} - -std::string EnggDiffractionViewQtGUI::fittingPeaksData() const { - - return m_uiTabFitting.lineEdit_fitting_peaks->text().toStdString(); -} - -void MantidQt::CustomInterfaces::EnggDiffractionViewQtGUI::setPeakList( - std::string peakList) const { - m_uiTabFitting.lineEdit_fitting_peaks->setText( - QString::fromStdString(peakList)); -} - -std::vector<std::string> -EnggDiffractionViewQtGUI::splitFittingDirectory(std::string &selectedfPath) { - - Poco::Path PocofPath(selectedfPath); - std::string selectedbankfName = PocofPath.getBaseName(); - std::vector<std::string> splitBaseName; - if (selectedbankfName.find("ENGINX_") != std::string::npos) { - boost::split(splitBaseName, selectedbankfName, boost::is_any_of("_.")); - } - return splitBaseName; -} - -void MantidQt::CustomInterfaces::EnggDiffractionViewQtGUI::setBankEmit() { - emit setBank(); -} - -std::string -MantidQt::CustomInterfaces::EnggDiffractionViewQtGUI::getFocusDir() { - return m_focusDir; -} - -void EnggDiffractionViewQtGUI::addBankItem(std::string bankID) { - - m_uiTabFitting.comboBox_bank->addItem(QString::fromStdString(bankID)); -} - -void MantidQt::CustomInterfaces::EnggDiffractionViewQtGUI::addRunNoItem( - std::string runNo) { - m_uiTabFitting.listWidget_fitting_run_num->addItem( - QString::fromStdString(runNo)); -} - -std::vector<std::string> EnggDiffractionViewQtGUI::getFittingRunNumVec() { - return m_fitting_runno_dir_vec; -} - -void EnggDiffractionViewQtGUI::setFittingRunNumVec( - std::vector<std::string> assignVec) { - m_fitting_runno_dir_vec.clear(); - m_fitting_runno_dir_vec = assignVec; -} - -void EnggDiffractionViewQtGUI::setFittingMultiRunMode(bool mode) { - m_fittingMutliRunMode = mode; -} - -bool EnggDiffractionViewQtGUI::getFittingMultiRunMode() { - return m_fittingMutliRunMode; -} - -void MantidQt::CustomInterfaces::EnggDiffractionViewQtGUI::setPeakPick() { - auto bk2bk = - FunctionFactory::Instance().createFunction("BackToBackExponential"); - auto bk2bkFunc = boost::dynamic_pointer_cast<IPeakFunction>(bk2bk); - // set the peak to BackToBackExponential function - setPeakPicker(bk2bkFunc); - setPeakPickerEnabled(true); -} - -void MantidQt::CustomInterfaces::EnggDiffractionViewQtGUI::addPeakToList() { - - if (m_peakPicker->isEnabled()) { - auto peakCentre = getPeakCentre(); - - std::stringstream stream; - stream << std::fixed << std::setprecision(4) << peakCentre; - auto strPeakCentre = stream.str(); - - auto curExpPeaksList = m_uiTabFitting.lineEdit_fitting_peaks->text(); - QString comma = ","; - - if (!curExpPeaksList.isEmpty()) { - // when further peak added to list - std::string expPeakStr = curExpPeaksList.toStdString(); - std::string lastTwoChr = expPeakStr.substr(expPeakStr.size() - 2); - auto lastChr = expPeakStr.back(); - if (lastChr == ',' || lastTwoChr == ", ") { - curExpPeaksList.append(QString::fromStdString(strPeakCentre)); - } else { - curExpPeaksList.append(comma + QString::fromStdString(strPeakCentre)); - } - m_uiTabFitting.lineEdit_fitting_peaks->setText(curExpPeaksList); - } else { - // when new peak given when list is empty - curExpPeaksList.append(QString::fromStdString(strPeakCentre)); - curExpPeaksList.append(comma); - m_uiTabFitting.lineEdit_fitting_peaks->setText(curExpPeaksList); - } - } -} - -void MantidQt::CustomInterfaces::EnggDiffractionViewQtGUI::savePeakList() { - // call function in EnggPresenter.. - - try { - QString prevPath = QString::fromStdString(m_focusDir); - if (prevPath.isEmpty()) { - prevPath = MantidQt::API::AlgorithmInputHistory::Instance() - .getPreviousDirectory(); - } - - QString path(QFileDialog::getSaveFileName( - this, tr("Save Expected Peaks List"), prevPath, - QString::fromStdString(g_DetGrpExtStr))); - - if (path.isEmpty()) { - return; - } - const std::string strPath = path.toStdString(); - fittingWriteFile(strPath); - } catch (...) { - userWarning("Unable to save the peaks file: ", - "Invalid file path or or could not be saved. Please try again"); - return; - } -} - -void MantidQt::CustomInterfaces::EnggDiffractionViewQtGUI::clearPeakList() { - m_uiTabFitting.lineEdit_fitting_peaks->clear(); -} - void EnggDiffractionViewQtGUI::instrumentChanged(int /*idx*/) { QComboBox *inst = m_ui.comboBox_instrument; if (!inst) @@ -1665,7 +1086,7 @@ void EnggDiffractionViewQtGUI::closeEvent(QCloseEvent *event) { void EnggDiffractionViewQtGUI::openHelpWin() { MantidQt::API::HelpWindow::showCustomInterface( - NULL, QString("Engineering_Diffraction")); + nullptr, QString("Engineering_Diffraction")); } } // namespace CustomInterfaces diff --git a/MantidQt/CustomInterfaces/src/Indirect/Elwin.cpp b/MantidQt/CustomInterfaces/src/Indirect/Elwin.cpp index 2ca587d79c0..ccb4027fb16 100644 --- a/MantidQt/CustomInterfaces/src/Indirect/Elwin.cpp +++ b/MantidQt/CustomInterfaces/src/Indirect/Elwin.cpp @@ -115,17 +115,43 @@ void Elwin::run() { std::string inputGroupWsName = "IDA_Elwin_Input"; QFileInfo firstFileInfo(inputFilenames[0]); - QString filename = firstFileInfo.baseName(); - QString workspaceBaseName = - filename.left(filename.lastIndexOf("_")) + "_elwin_"; + const auto filename = firstFileInfo.baseName(); + + auto workspaceBaseName = filename.left(filename.lastIndexOf("_")); + + if (inputFilenames.size() > 1) { + QFileInfo fileInfo(inputFilenames[inputFilenames.length() - 1]); + auto runNumber = fileInfo.baseName().toStdString(); + runNumber = runNumber.substr(0, runNumber.find_first_of("_")); + size_t runNumberStart = 0; + const auto strLength = runNumber.length(); + for (size_t i = 0; i < strLength; i++) { + if (std::isdigit(runNumber[i])) { + runNumberStart = i; + break; + } + } + // reassemble workspace base name with additional run number + runNumber = runNumber.substr(runNumberStart, strLength); + auto baseName = firstFileInfo.baseName(); + const auto prefix = baseName.left(baseName.indexOf("_")); + auto testPre = prefix.toStdString(); + const auto suffix = + baseName.right(baseName.length() - baseName.indexOf("_")); + auto testsuf = suffix.toStdString(); + workspaceBaseName = + prefix + QString::fromStdString("-" + runNumber) + suffix; + } - QString qWorkspace = workspaceBaseName + "eq"; - QString qSquaredWorkspace = workspaceBaseName + "eq2"; - QString elfWorkspace = workspaceBaseName + "elf"; - QString eltWorkspace = workspaceBaseName + "elt"; + workspaceBaseName += "_elwin_"; + + const auto qWorkspace = (workspaceBaseName + "eq").toStdString(); + const auto qSquaredWorkspace = (workspaceBaseName + "eq2").toStdString(); + const auto elfWorkspace = (workspaceBaseName + "elf").toStdString(); + const auto eltWorkspace = (workspaceBaseName + "elt").toStdString(); // Load input files - std::vector<std::string> inputWorkspaceNames; + std::string inputWorkspacesString; for (auto it = inputFilenames.begin(); it != inputFilenames.end(); ++it) { QFileInfo inputFileInfo(*it); @@ -137,17 +163,18 @@ void Elwin::run() { loadAlg->setProperty("OutputWorkspace", workspaceName); m_batchAlgoRunner->addAlgorithm(loadAlg); - inputWorkspaceNames.push_back(workspaceName); + inputWorkspacesString += workspaceName + ","; } // Group input workspaces IAlgorithm_sptr groupWsAlg = AlgorithmManager::Instance().create("GroupWorkspaces"); groupWsAlg->initialize(); - groupWsAlg->setProperty("InputWorkspaces", inputWorkspaceNames); + API::BatchAlgorithmRunner::AlgorithmRuntimeProps runTimeProps; + runTimeProps["InputWorkspaces"] = inputWorkspacesString; groupWsAlg->setProperty("OutputWorkspace", inputGroupWsName); - m_batchAlgoRunner->addAlgorithm(groupWsAlg); + m_batchAlgoRunner->addAlgorithm(groupWsAlg, runTimeProps); // Configure ElasticWindowMultiple algorithm IAlgorithm_sptr elwinMultAlg = @@ -156,10 +183,9 @@ void Elwin::run() { elwinMultAlg->setProperty("Plot", m_uiForm.ckPlot->isChecked()); - elwinMultAlg->setProperty("OutputInQ", qWorkspace.toStdString()); - elwinMultAlg->setProperty("OutputInQSquared", - qSquaredWorkspace.toStdString()); - elwinMultAlg->setProperty("OutputELF", elfWorkspace.toStdString()); + elwinMultAlg->setProperty("OutputInQ", qWorkspace); + elwinMultAlg->setProperty("OutputInQSquared", qSquaredWorkspace); + elwinMultAlg->setProperty("OutputELF", elfWorkspace); elwinMultAlg->setProperty("SampleEnvironmentLogName", m_uiForm.leLogName->text().toStdString()); @@ -183,7 +209,7 @@ void Elwin::run() { } if (m_blnManager->value(m_properties["Normalise"])) { - elwinMultAlg->setProperty("OutputELT", eltWorkspace.toStdString()); + elwinMultAlg->setProperty("OutputELT", eltWorkspace); } BatchAlgorithmRunner::AlgorithmRuntimeProps elwinInputProps; @@ -206,7 +232,7 @@ void Elwin::run() { m_batchAlgoRunner->executeBatchAsync(); // Set the result workspace for Python script export - m_pythonExportWsName = qSquaredWorkspace.toStdString(); + m_pythonExportWsName = qSquaredWorkspace; } /** @@ -232,18 +258,19 @@ void Elwin::unGroupInput(bool error) { * @param workspaceName Name of the workspace to save * @param filename Name of the file to save it as */ -void Elwin::addSaveAlgorithm(QString workspaceName, QString filename) { +void Elwin::addSaveAlgorithm(const std::string &workspaceName, + std::string filename) { // Set a default filename if none provided - if (filename.isEmpty()) + if (filename.length() == 0) filename = workspaceName + ".nxs"; // Configure the algorithm IAlgorithm_sptr loadAlg = AlgorithmManager::Instance().create("SaveNexus"); loadAlg->initialize(); - loadAlg->setProperty("Filename", filename.toStdString()); + loadAlg->setProperty("Filename", filename); BatchAlgorithmRunner::AlgorithmRuntimeProps saveAlgProps; - saveAlgProps["InputWorkspace"] = workspaceName.toStdString(); + saveAlgProps["InputWorkspace"] = workspaceName; // Add it to the batch runner m_batchAlgoRunner->addAlgorithm(loadAlg, saveAlgProps); diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/TransferResults.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/TransferResults.cpp index 6fee46731d1..e5edd5f2e56 100644 --- a/MantidQt/CustomInterfaces/src/Reflectometry/TransferResults.cpp +++ b/MantidQt/CustomInterfaces/src/Reflectometry/TransferResults.cpp @@ -24,12 +24,7 @@ void TransferResults::addTransferRow(const COLUMN_MAP_TYPE &row) { } void TransferResults::addErrorRow(COLUMN_NAME_TYPE id, COLUMN_VALUE_TYPE error) { - - COLUMN_MAP_TYPE row; - std::pair<COLUMN_NAME_TYPE, COLUMN_VALUE_TYPE> pair(id, error); - row.insert(pair); - m_errorRuns.push_back(row); - // m_errorRuns.push_back(row); + m_errorRuns.push_back({{id, error}}); } } } diff --git a/MantidQt/CustomInterfaces/test/EnggDiffFittingPresenterTest.h b/MantidQt/CustomInterfaces/test/EnggDiffFittingPresenterTest.h new file mode 100644 index 00000000000..c424c0315e4 --- /dev/null +++ b/MantidQt/CustomInterfaces/test/EnggDiffFittingPresenterTest.h @@ -0,0 +1,419 @@ +#ifndef MANTID_CUSTOMINTERFACES_ENGGDIFFFITTINGPRESENTERTEST_H +#define MANTID_CUSTOMINTERFACES_ENGGDIFFFITTINGPRESENTERTEST_H + +#include "MantidAPI/FrameworkManager.h" +#include "MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingPresenter.h" + +#include "EnggDiffFittingViewMock.h" +#include <cxxtest/TestSuite.h> + +using namespace MantidQt::CustomInterfaces; +using testing::TypedEq; +using testing::Return; + +// Use this mocked presenter for tests that will start the focusing +// workers/threads. Otherwise you'll run into trouble with issues like +// "QEventLoop: Cannot be used without QApplication", as there is not +// Qt application here and the normal Qt thread used by the presenter +// uses signals/slots. +class EnggDiffFittingPresenterNoThread : public EnggDiffFittingPresenter { +public: + EnggDiffFittingPresenterNoThread(IEnggDiffFittingView *view) + : EnggDiffFittingPresenter(view, nullptr) {} + +private: + // not async at all + void startAsyncFittingWorker(const std::string &focusedRunNo, + const std::string &ExpectedPeaks) override { + doFitting(focusedRunNo, ExpectedPeaks); + fittingFinished(); + } +}; + +class EnggDiffFittingPresenterTest : public CxxTest::TestSuite { + +public: + // This pair of boilerplate methods prevent tghe suite being created + // statically + // This means the constructor isn't called when running other tests + static EnggDiffFittingPresenterTest *createSuite() { + return new EnggDiffFittingPresenterTest(); + } + + static void destroySuite(EnggDiffFittingPresenterTest *suite) { + delete suite; + } + + EnggDiffFittingPresenterTest() { + Mantid::API::FrameworkManager::Instance(); // make sure framework is + // initialized + } + + void setUp() override { + m_view.reset(new testing::NiceMock<MockEnggDiffFittingView>()); + m_presenter.reset(new MantidQt::CustomInterfaces::EnggDiffFittingPresenter( + m_view.get(), nullptr)); + + // default banks + m_ex_enginx_banks.push_back(true); + m_ex_enginx_banks.push_back(false); + + // default run number + m_ex_empty_run_num.emplace_back(""); + m_invalid_run_number.emplace_back(""); + m_ex_run_number.push_back(g_validRunNo); + g_vanNo.emplace_back("8899999988"); + g_ceriaNo.emplace_back("9999999999"); + + // provide personal directories in order to carry out the full disable tests + m_basicCalibSettings.m_inputDirCalib = "GUI_calib_folder/"; + m_basicCalibSettings.m_inputDirRaw = "GUI_calib_folder/"; + + m_basicCalibSettings.m_pixelCalibFilename = + "ENGINX_full_pixel_calibration.csv"; + + m_basicCalibSettings.m_templateGSAS_PRM = "GUI_calib_folder/" + "template_ENGINX_241391_236516_" + "North_and_South_banks.prm"; + + m_basicCalibSettings.m_forceRecalcOverwrite = false; + m_basicCalibSettings.m_rebinCalibrate = 1; + } + + void tearDown() override { + TS_ASSERT(testing::Mock::VerifyAndClearExpectations(m_view.get())); + } + + void test_fitting_with_missing_param() { + testing::NiceMock<MockEnggDiffFittingView> mockView; + MantidQt::CustomInterfaces::EnggDiffFittingPresenter pres(&mockView, + nullptr); + + EXPECT_CALL(mockView, getFittingRunNo()).Times(1).WillOnce(Return("")); + EXPECT_CALL(mockView, fittingPeaksData()).Times(1).WillOnce(Return("")); + + EXPECT_CALL(mockView, setPeakList(testing::_)).Times(0); + + // should not get to the point where the status is updated + EXPECT_CALL(mockView, showStatus(testing::_)).Times(0); + + // No errors/1 warnings. There will be an error log from the algorithms + EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); + EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(1); + + pres.notify(IEnggDiffFittingPresenter::FitPeaks); + TSM_ASSERT( + "Mock not used as expected. Some EXPECT_CALL conditions were not " + "satisfied.", + testing::Mock::VerifyAndClearExpectations(&mockView)) + } + + // This would test the fitting tab with no focused workspace + // which should produce a warning + void test_fitting_without_focused_run() { + testing::NiceMock<MockEnggDiffFittingView> mockView; + EnggDiffFittingPresenterNoThread pres(&mockView); + + // inputs from user + const std::string mockFname = ""; + EXPECT_CALL(mockView, getFittingRunNo()) + .Times(1) + .WillOnce(Return(mockFname)); + EXPECT_CALL(mockView, fittingPeaksData()) + .Times(1) + .WillOnce(Return("2.57,,4.88,5.78")); + + EXPECT_CALL(mockView, setPeakList(testing::_)).Times(1); + + // should not get to the point where the status is updated + EXPECT_CALL(mockView, showStatus(testing::_)).Times(0); + + // No errors/1 warnings. There will be an error log from the algorithms + EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); + EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(1); + + pres.notify(IEnggDiffFittingPresenter::FitPeaks); + TSM_ASSERT( + "Mock not used as expected. Some EXPECT_CALL conditions were not " + "satisfied.", + testing::Mock::VerifyAndClearExpectations(&mockView)) + } + + // This would test the fitting tab with invalid expected peaks but should only + // produce a warning + void test_fitting_with_invalid_expected_peaks() { + testing::NiceMock<MockEnggDiffFittingView> mockView; + EnggDiffFittingPresenterNoThread pres(&mockView); + + // inputs from user + EXPECT_CALL(mockView, getFittingRunNo()) + .Times(1) + .WillOnce(Return(g_focusedRun)); + EXPECT_CALL(mockView, fittingPeaksData()) + .Times(1) + .WillOnce(Return(",3.5,7.78,r43d")); + EXPECT_CALL(mockView, setPeakList(testing::_)).Times(1); + + // should not get to the point where the status is updated + EXPECT_CALL(mockView, showStatus(testing::_)).Times(0); + + // No errors/1 warnings. There will be an error log from the algorithms + EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); + EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(1); + + pres.notify(IEnggDiffFittingPresenter::FitPeaks); + TSM_ASSERT( + "Mock not used as expected. Some EXPECT_CALL conditions were not " + "satisfied.", + testing::Mock::VerifyAndClearExpectations(&mockView)) + } + + // Fitting test begin here + void test_fitting_runno_valid_single_run() { + testing::NiceMock<MockEnggDiffFittingView> mockView; + EnggDiffFittingPresenterNoThread pres(&mockView); + + // inputs from user + EXPECT_CALL(mockView, getFittingRunNo()) + .Times(2) + .WillRepeatedly(Return(std::string(g_focusedBankFile))); + + EXPECT_CALL(mockView, getFittingRunNumVec()) + .Times(1) + .WillOnce(Return(m_ex_run_number)); + + EXPECT_CALL(mockView, splitFittingDirectory(testing::_)) + .Times(1) + .WillOnce(Return(m_ex_run_number)); + + // should not get to the point where the status is updated + EXPECT_CALL(mockView, showStatus(testing::_)).Times(0); + + // No errors/0 warnings. There will be no errors or warnings + EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); + EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(1); + + pres.notify(IEnggDiffFittingPresenter::FittingRunNo); + } + + void test_fitting_runno_invalid_run() { + testing::NiceMock<MockEnggDiffFittingView> mockView; + EnggDiffFittingPresenterNoThread pres(&mockView); + + // inputs from user - empty run number given + EXPECT_CALL(mockView, getFittingRunNo()) + .Times(2) + .WillRepeatedly(Return(std::string(""))); + + EXPECT_CALL(mockView, getFittingRunNumVec()) + .Times(1) + .WillOnce(Return(m_ex_run_number)); + + EXPECT_CALL(mockView, splitFittingDirectory(testing::_)) + .Times(1) + .WillOnce(Return(m_ex_run_number)); + + // should not get to the point where the status is updated + EXPECT_CALL(mockView, showStatus(testing::_)).Times(0); + + // No errors/1 warnings. There will be an warning for invalid run number + EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); + EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(1); + + pres.notify(IEnggDiffFittingPresenter::FittingRunNo); + } + + void test_fitting_runno_multiple_run() { + testing::NiceMock<MockEnggDiffFittingView> mockView; + EnggDiffFittingPresenterNoThread pres(&mockView); + // 23931-23934 + std::vector<std::string> RunNumDir; + RunNumDir.emplace_back("241391"); + RunNumDir.emplace_back("241392"); + RunNumDir.emplace_back("241393"); + RunNumDir.emplace_back("241394"); + + // empty vector + std::vector<std::string> splittedFileVec; + + // inputs from user - given multiple run + EXPECT_CALL(mockView, getFittingRunNo()) + .Times(2) + .WillRepeatedly(Return(g_focusedFittingRunNo)); + + EXPECT_CALL(mockView, getFittingRunNumVec()) + .Times(1) + .WillOnce(Return(RunNumDir)); + + EXPECT_CALL(mockView, splitFittingDirectory(testing::_)) + .Times(1) + .WillOnce(Return(splittedFileVec)); + + // could possibly feature to create unique path + EXPECT_CALL(mockView, focusingDir()).Times(1); + + // should not get to the point where the status is updated + EXPECT_CALL(mockView, showStatus(testing::_)).Times(0); + + // No errors/1 warnings. The warning will be produced because there + // is no focus output directory within the settings tab + EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); + EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(1); + + pres.notify(IEnggDiffFittingPresenter::FittingRunNo); + } + + void diable_test_fitting_runno_single_run() { + testing::NiceMock<MockEnggDiffFittingView> mockView; + EnggDiffFittingPresenterNoThread pres(&mockView); + + // focus directory need to be set for this in the settings + + // 23931-23934 + std::vector<std::string> RunNumDir; + RunNumDir.emplace_back("241391"); + + // empty vector + std::vector<std::string> splittedFileVec; + + // inputs from user - given multiple run + EXPECT_CALL(mockView, getFittingRunNo()) + .Times(2) + .WillRepeatedly(Return("241391")); + + EXPECT_CALL(mockView, getFittingRunNumVec()) + .Times(1) + .WillOnce(Return(RunNumDir)); + + EXPECT_CALL(mockView, splitFittingDirectory(testing::_)) + .Times(1) + .WillOnce(Return(splittedFileVec)); + + EXPECT_CALL(mockView, getFittingMultiRunMode()) + .Times(1) + .WillOnce(Return(false)); + + EXPECT_CALL(mockView, setFittingRunNumVec(testing::_)).Times(1); + + EXPECT_CALL(mockView, addRunNoItem(testing::_)).Times(1); + + EXPECT_CALL(mockView, addBankItem(testing::_)).Times(1); + + EXPECT_CALL(mockView, focusingDir()).Times(0); + + // should not get to the point where the status is updated + EXPECT_CALL(mockView, showStatus(testing::_)).Times(0); + + // No errors/0 warnings. + EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); + EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0); + + pres.notify(IEnggDiffFittingPresenter::FittingRunNo); + } + + void test_fitting_runno_browsed_run_add_run_item() { + testing::NiceMock<MockEnggDiffFittingView> mockView; + EnggDiffFittingPresenterNoThread pres(&mockView); + // Tests the browse directory file + std::vector<std::string> RunNumDir; + RunNumDir.emplace_back("241395"); + + std::vector<std::string> splittedFileVec; + splittedFileVec.emplace_back("ENGINX"); + splittedFileVec.emplace_back("241395"); + splittedFileVec.emplace_back("focused"); + splittedFileVec.emplace_back("bank"); + splittedFileVec.emplace_back("1"); + + // inputs from user - given multiple run + EXPECT_CALL(mockView, getFittingRunNo()) + .Times(2) + .WillRepeatedly(Return(g_focusedBankFile)); + + EXPECT_CALL(mockView, getFittingRunNumVec()) + .Times(1) + .WillOnce(Return(RunNumDir)); + + EXPECT_CALL(mockView, splitFittingDirectory(testing::_)) + .Times(1) + .WillOnce(Return(splittedFileVec)); + + EXPECT_CALL(mockView, getFittingMultiRunMode()).Times(0); + + EXPECT_CALL(mockView, setFittingRunNumVec(testing::_)).Times(0); + + EXPECT_CALL(mockView, addBankItem(testing::_)).Times(0); + + EXPECT_CALL(mockView, setBankIdComboBox(testing::_)).Times(0); + + EXPECT_CALL(mockView, addRunNoItem(testing::_)).Times(0); + + EXPECT_CALL(mockView, setFittingListWidgetCurrentRow(testing::_)).Times(0); + + EXPECT_CALL(mockView, focusingDir()).Times(0); + + // No errors/0 warnings. File entered is not found + EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); + EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(1); + + pres.notify(IEnggDiffFittingPresenter::FittingRunNo); + } + + void test_shutDown() { + testing::NiceMock<MockEnggDiffFittingView> mockView; + MantidQt::CustomInterfaces::EnggDiffFittingPresenter pres(&mockView, + nullptr); + + EXPECT_CALL(mockView, setPeakList(testing::_)).Times(0); + EXPECT_CALL(mockView, getFittingRunNo()).Times(0); + EXPECT_CALL(mockView, getFittingRunNumVec()).Times(0); + EXPECT_CALL(mockView, splitFittingDirectory(testing::_)).Times(0); + EXPECT_CALL(mockView, focusingDir()).Times(0); + + EXPECT_CALL(mockView, getFittingMultiRunMode()).Times(0); + + EXPECT_CALL(mockView, showStatus(testing::_)).Times(0); + + EXPECT_CALL(mockView, saveSettings()).Times(1); + // No errors, no warnings + EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); + EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0); + + pres.notify(IEnggDiffFittingPresenter::ShutDown); + TSM_ASSERT( + "Mock not used as expected. Some EXPECT_CALL conditions were not " + "satisfied.", + testing::Mock::VerifyAndClearExpectations(&mockView)) + } + +private: + std::unique_ptr<testing::NiceMock<MockEnggDiffFittingView>> m_view; + std::unique_ptr<MantidQt::CustomInterfaces::EnggDiffFittingPresenter> + m_presenter; + + std::vector<bool> m_ex_enginx_banks; + const static std::string g_validRunNo; + const static std::string g_focusedRun; + const static std::string g_focusedBankFile; + const static std::string g_focusedFittingRunNo; + EnggDiffCalibSettings m_basicCalibSettings; + + std::vector<std::string> m_ex_empty_run_num; + std::vector<std::string> m_invalid_run_number; + std::vector<std::string> m_ex_run_number; + std::vector<std::string> g_vanNo; + std::vector<std::string> g_ceriaNo; +}; + +const std::string EnggDiffFittingPresenterTest::g_focusedRun = + "focused_texture_bank_1"; + +const std::string EnggDiffFittingPresenterTest::g_validRunNo = "228061"; + +const std::string EnggDiffFittingPresenterTest::g_focusedBankFile = + "ENGINX_241395_focused_texture_bank_1"; + +const std::string EnggDiffFittingPresenterTest::g_focusedFittingRunNo = + "241391-241394"; + +#endif // MANTID_CUSTOMINTERFACES_ENGGDIFFFITTINGPRESENTERTEST_H diff --git a/MantidQt/CustomInterfaces/test/EnggDiffFittingViewMock.h b/MantidQt/CustomInterfaces/test/EnggDiffFittingViewMock.h new file mode 100644 index 00000000000..1436ff427ce --- /dev/null +++ b/MantidQt/CustomInterfaces/test/EnggDiffFittingViewMock.h @@ -0,0 +1,122 @@ +#ifndef MANTID_CUSTOMINTERFACES_ENGGDIFFFITTINGVIEWMOCK_H +#define MANTID_CUSTOMINTERFACES_ENGGDIFFFITTINGVIEWMOCK_H + +#include "MantidKernel/WarningSuppressions.h" +#include "MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffFittingView.h" + +#include <gmock/gmock.h> + +GCC_DIAG_OFF_SUGGEST_OVERRIDE + +// This is a simple mock for the tomo interface view when using SCARF. +class MockEnggDiffFittingView + : public MantidQt::CustomInterfaces::IEnggDiffFittingView { + +public: + // virtual void showStatus(const std::string &sts); + MOCK_METHOD1(showStatus, void(const std::string &sts)); + + // virtual void userWarning(const std::string &warn, const std::string + // &description); + MOCK_METHOD2(userWarning, + void(const std::string &warn, const std::string &description)); + + // virtual void userError(const std::string &err, const std::string + // &description); + MOCK_METHOD2(userError, + void(const std::string &err, const std::string &description)); + + // virtual void enableCalibrateFocusFitUserActions(bool enable); + MOCK_METHOD1(enableCalibrateFocusFitUserActions, void(bool)); + + // virtual EnggDiffCalibSettings currentCalibSettings() const; + MOCK_CONST_METHOD0(currentCalibSettings, + MantidQt::CustomInterfaces::EnggDiffCalibSettings()); + + // virtual std::string focusingDir() const; + MOCK_CONST_METHOD0(focusingDir, std::string()); + + // virtual std::string enggRunPythonCode(const std::string &pyCode) + MOCK_METHOD1(enggRunPythonCode, std::string(const std::string &)); + + // virtual std::string fittingRunNo() const; + MOCK_CONST_METHOD0(getFittingRunNo, std::string()); + + // virtual std::string fittingPeaksData() const; + MOCK_CONST_METHOD0(fittingPeaksData, std::string()); + + // virtual bool focusedOutWorkspace() const; + MOCK_CONST_METHOD0(focusedOutWorkspace, bool()); + + // virtual Splits the fitting directory if the ENGINX found + MOCK_METHOD1(splitFittingDirectory, + std::vector<std::string>(std::string &selectedfPath)); + + // adds the number of banks to the combo-box widget on the interface + MOCK_METHOD1(addBankItem, void(std::string bankID)); + + // adds the run number to the list view widget on the interface + MOCK_METHOD1(addRunNoItem, void(std::string runNo)); + + // emits the signal within view when run number / bank changed + MOCK_METHOD0(setBankEmit, void()); + + // sets the bank combo-box according to given index + MOCK_METHOD1(setBankIdComboBox, void(int idx)); + + // deletes all items from the fitting combo-box widget + MOCK_CONST_METHOD0(clearFittingComboBox, void()); + + // enables or disables the fitting combo-box + MOCK_CONST_METHOD1(enableFittingComboBox, void(bool enable)); + + // gets the index of the bank according to text found + MOCK_CONST_METHOD1(getFittingComboIdx, int(std::string bank)); + + // deletes all items from the fitting list widget + MOCK_CONST_METHOD0(clearFittingListWidget, void()); + + // enables or disables the fitting list widget + MOCK_CONST_METHOD1(enableFittingListWidget, void(bool enable)); + + // return idx of current selected row of list widget + MOCK_CONST_METHOD0(getFittingListWidgetCurrentRow, int()); + + // sets the current row of the fitting list widget + MOCK_CONST_METHOD1(setFittingListWidgetCurrentRow, void(int idx)); + + // sets the peak list according to the QString given + MOCK_CONST_METHOD1(setPeakList, void(const std::string &peakList)); + + // std::vector<std::string> logMsgs() const; + MOCK_CONST_METHOD0(logMsgs, std::vector<std::string>()); + + // gets the global vector in view containing focused file directory + MOCK_METHOD0(getFittingRunNumVec, std::vector<std::string>()); + + // sets the global vector in view containing focused file directory + MOCK_METHOD1(setFittingRunNumVec, void(std::vector<std::string> assignVec)); + + // sets the fitting run number according to path + MOCK_METHOD1(setFittingRunNo, void(const std::string &path)); + + // To determine whether the current loop is multi-run or single to avoid + // regenerating the list - view widget when not required + MOCK_METHOD0(getFittingMultiRunMode, bool()); + + // sets the fitting mode to multi-run or single to avoid + // regenerating the list - view widget when not required + MOCK_METHOD1(setFittingMultiRunMode, void(bool mode)); + + // void saveSettings() const; + MOCK_CONST_METHOD0(saveSettings, void()); + + // virtual void setDataVector + MOCK_METHOD3(setDataVector, + void(std::vector<boost::shared_ptr<QwtData>> &data, bool focused, + bool plotSinglePeaks)); +}; + +GCC_DIAG_ON_SUGGEST_OVERRIDE + +#endif // MANTID_CUSTOMINTERFACES_ENGGDIFFFITTINGVIEWMOCK_H diff --git a/MantidQt/CustomInterfaces/test/EnggDiffractionPresenterTest.h b/MantidQt/CustomInterfaces/test/EnggDiffractionPresenterTest.h index 6028ed566d4..f1dc97e15ea 100644 --- a/MantidQt/CustomInterfaces/test/EnggDiffractionPresenterTest.h +++ b/MantidQt/CustomInterfaces/test/EnggDiffractionPresenterTest.h @@ -57,12 +57,6 @@ private: doRebinningPulses(runNo, nperiods, timeStep, outWSName); rebinningFinished(); } - - void startAsyncFittingWorker(const std::string &focusedRunNo, - const std::string &ExpectedPeaks) override { - doFitting(focusedRunNo, ExpectedPeaks); - fittingFinished(); - } }; class EnggDiffractionPresenterTest : public CxxTest::TestSuite { @@ -324,12 +318,12 @@ public: // only after the error, it should disable actions at the beginning of the // calculations - EXPECT_CALL(mockView, enableCalibrateAndFocusActions(false)).Times(0); + EXPECT_CALL(mockView, enableCalibrateFocusFitUserActions(false)).Times(0); // and only after the error it should enable them again at the // (unsuccessful) end - this happens when a separate thread // finished (here the thread is mocked) - EXPECT_CALL(mockView, enableCalibrateAndFocusActions(true)).Times(0); + EXPECT_CALL(mockView, enableCalibrateFocusFitUserActions(true)).Times(0); // plots peaks and curves // the test doesnt get to here as it finishes at EnggCalibrate algo @@ -537,11 +531,11 @@ public: // with the normal thread should disable actions at the beginning // of the calculations - EXPECT_CALL(mockView, enableCalibrateAndFocusActions(false)).Times(0); + EXPECT_CALL(mockView, enableCalibrateFocusFitUserActions(false)).Times(0); // and should enable them again at the (unsuccessful) end - this happens // when a separate thread finished (here the thread is mocked) - EXPECT_CALL(mockView, enableCalibrateAndFocusActions(true)).Times(0); + EXPECT_CALL(mockView, enableCalibrateFocusFitUserActions(true)).Times(0); // tests whether the plot functions have been called EXPECT_CALL(mockView, plotCalibWorkspace()).Times(0); @@ -614,11 +608,11 @@ public: // it will not get to the next steps: // should disable actions at the beginning of the calculations - EXPECT_CALL(mockView, enableCalibrateAndFocusActions(false)).Times(0); + EXPECT_CALL(mockView, enableCalibrateFocusFitUserActions(false)).Times(0); // and should enable them again at the (unsuccessful) end - this happens // when a separate thread finished (here the thread is mocked) - EXPECT_CALL(mockView, enableCalibrateAndFocusActions(true)).Times(0); + EXPECT_CALL(mockView, enableCalibrateFocusFitUserActions(true)).Times(0); // A warning about the vanadium EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(1); @@ -768,8 +762,8 @@ public: EXPECT_CALL(mockView, plotFocusedSpectrum(testing::_)).Times(0); // it should not get there - EXPECT_CALL(mockView, enableCalibrateAndFocusActions(false)).Times(0); - EXPECT_CALL(mockView, enableCalibrateAndFocusActions(true)).Times(0); + EXPECT_CALL(mockView, enableCalibrateFocusFitUserActions(false)).Times(0); + EXPECT_CALL(mockView, enableCalibrateFocusFitUserActions(true)).Times(0); // should not get to the point where the status is updated EXPECT_CALL(mockView, showStatus(testing::_)).Times(0); @@ -1307,276 +1301,6 @@ public: testing::Mock::VerifyAndClearExpectations(&mockView)) } - void test_fitting_with_missing_param() { - testing::NiceMock<MockEnggDiffractionView> mockView; - MantidQt::CustomInterfaces::EnggDiffractionPresenter pres(&mockView); - - EXPECT_CALL(mockView, getFittingRunNo()).Times(1).WillOnce(Return("")); - EXPECT_CALL(mockView, fittingPeaksData()).Times(1).WillOnce(Return("")); - - EXPECT_CALL(mockView, setPeakList(testing::_)).Times(0); - - // should not get to the point where the status is updated - EXPECT_CALL(mockView, showStatus(testing::_)).Times(0); - - // No errors/1 warnings. There will be an error log from the algorithms - EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); - EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(1); - - pres.notify(IEnggDiffractionPresenter::FitPeaks); - TSM_ASSERT( - "Mock not used as expected. Some EXPECT_CALL conditions were not " - "satisfied.", - testing::Mock::VerifyAndClearExpectations(&mockView)) - } - - // This would test the fitting tab with no focused workspace - // which should produce a warning - void test_fitting_without_focused_run() { - testing::NiceMock<MockEnggDiffractionView> mockView; - EnggDiffPresenterNoThread pres(&mockView); - - // inputs from user - const std::string mockFname = ""; - EXPECT_CALL(mockView, getFittingRunNo()) - .Times(1) - .WillOnce(Return(mockFname)); - EXPECT_CALL(mockView, fittingPeaksData()) - .Times(1) - .WillOnce(Return("2.57,,4.88,5.78")); - - EXPECT_CALL(mockView, setPeakList(testing::_)).Times(1); - - // should not get to the point where the status is updated - EXPECT_CALL(mockView, showStatus(testing::_)).Times(0); - - // No errors/1 warnings. There will be an error log from the algorithms - EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); - EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(1); - - pres.notify(IEnggDiffractionPresenter::FitPeaks); - TSM_ASSERT( - "Mock not used as expected. Some EXPECT_CALL conditions were not " - "satisfied.", - testing::Mock::VerifyAndClearExpectations(&mockView)) - } - - // This would test the fitting tab with invalid expected peaks but should only - // produce a warning - void test_fitting_with_invalid_expected_peaks() { - testing::NiceMock<MockEnggDiffractionView> mockView; - EnggDiffPresenterNoThread pres(&mockView); - - // inputs from user - EXPECT_CALL(mockView, getFittingRunNo()) - .Times(1) - .WillOnce(Return(g_focusedRun)); - EXPECT_CALL(mockView, fittingPeaksData()) - .Times(1) - .WillOnce(Return(",3.5,7.78,r43d")); - EXPECT_CALL(mockView, setPeakList(testing::_)).Times(1); - - // should not get to the point where the status is updated - EXPECT_CALL(mockView, showStatus(testing::_)).Times(0); - - // No errors/1 warnings. There will be an error log from the algorithms - EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); - EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(1); - - pres.notify(IEnggDiffractionPresenter::FitPeaks); - TSM_ASSERT( - "Mock not used as expected. Some EXPECT_CALL conditions were not " - "satisfied.", - testing::Mock::VerifyAndClearExpectations(&mockView)) - } - - // Fitting test begin here - void test_fitting_runno_valid_single_run() { - testing::NiceMock<MockEnggDiffractionView> mockView; - EnggDiffPresenterNoThread pres(&mockView); - - // inputs from user - EXPECT_CALL(mockView, getFittingRunNo()) - .Times(2) - .WillRepeatedly(Return(std::string(g_focusedBankFile))); - - EXPECT_CALL(mockView, getFittingRunNumVec()) - .Times(1) - .WillOnce(Return(m_ex_run_number)); - - EXPECT_CALL(mockView, splitFittingDirectory(testing::_)) - .Times(1) - .WillOnce(Return(m_ex_run_number)); - - // should not get to the point where the status is updated - EXPECT_CALL(mockView, showStatus(testing::_)).Times(0); - - // No errors/0 warnings. There will be no errors or warnings - EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); - EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(1); - - pres.notify(IEnggDiffractionPresenter::FittingRunNo); - } - - void test_fitting_runno_invalid_run() { - testing::NiceMock<MockEnggDiffractionView> mockView; - EnggDiffPresenterNoThread pres(&mockView); - - // inputs from user - empty run number given - EXPECT_CALL(mockView, getFittingRunNo()) - .Times(2) - .WillRepeatedly(Return(std::string(""))); - - EXPECT_CALL(mockView, getFittingRunNumVec()) - .Times(1) - .WillOnce(Return(m_ex_run_number)); - - EXPECT_CALL(mockView, splitFittingDirectory(testing::_)) - .Times(1) - .WillOnce(Return(m_ex_run_number)); - - // should not get to the point where the status is updated - EXPECT_CALL(mockView, showStatus(testing::_)).Times(0); - - // No errors/1 warnings. There will be an warning for invalid run number - EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); - EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(1); - - pres.notify(IEnggDiffractionPresenter::FittingRunNo); - } - - void test_fitting_runno_multiple_run() { - testing::NiceMock<MockEnggDiffractionView> mockView; - EnggDiffPresenterNoThread pres(&mockView); - // 23931-23934 - std::vector<std::string> RunNumDir; - RunNumDir.emplace_back("241391"); - RunNumDir.emplace_back("241392"); - RunNumDir.emplace_back("241393"); - RunNumDir.emplace_back("241394"); - - // empty vector - std::vector<std::string> splittedFileVec; - - // inputs from user - given multiple run - EXPECT_CALL(mockView, getFittingRunNo()) - .Times(2) - .WillRepeatedly(Return(g_focusedFittingRunNo)); - - EXPECT_CALL(mockView, getFittingRunNumVec()) - .Times(1) - .WillOnce(Return(RunNumDir)); - - EXPECT_CALL(mockView, splitFittingDirectory(testing::_)) - .Times(1) - .WillOnce(Return(splittedFileVec)); - - // could possibly feature to create unique path - EXPECT_CALL(mockView, getFocusDir()).Times(1); - - // should not get to the point where the status is updated - EXPECT_CALL(mockView, showStatus(testing::_)).Times(0); - - // No errors/1 warnings. The warning will be produced because there - // is no focus output directory within the settings tab - EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); - EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(1); - - pres.notify(IEnggDiffractionPresenter::FittingRunNo); - } - - void diable_test_fitting_runno_single_run() { - testing::NiceMock<MockEnggDiffractionView> mockView; - EnggDiffPresenterNoThread pres(&mockView); - - // focus directory need to be set for this in the settings - - // 23931-23934 - std::vector<std::string> RunNumDir; - RunNumDir.emplace_back("241391"); - - // empty vector - std::vector<std::string> splittedFileVec; - - // inputs from user - given multiple run - EXPECT_CALL(mockView, getFittingRunNo()) - .Times(2) - .WillRepeatedly(Return("241391")); - - EXPECT_CALL(mockView, getFittingRunNumVec()) - .Times(1) - .WillOnce(Return(RunNumDir)); - - EXPECT_CALL(mockView, splitFittingDirectory(testing::_)) - .Times(1) - .WillOnce(Return(splittedFileVec)); - - EXPECT_CALL(mockView, getFittingMultiRunMode()) - .Times(1) - .WillOnce(Return(false)); - - EXPECT_CALL(mockView, setFittingRunNumVec(testing::_)).Times(1); - - EXPECT_CALL(mockView, addRunNoItem(testing::_)).Times(1); - - EXPECT_CALL(mockView, addBankItem(testing::_)).Times(1); - - // should not get to the point where the status is updated - EXPECT_CALL(mockView, showStatus(testing::_)).Times(0); - - // No errors/0 warnings. - EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); - EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0); - - pres.notify(IEnggDiffractionPresenter::FittingRunNo); - } - - void test_fitting_runno_browsed_run_add_run_item() { - testing::NiceMock<MockEnggDiffractionView> mockView; - EnggDiffPresenterNoThread pres(&mockView); - // Tests the browse directory file - std::vector<std::string> RunNumDir; - RunNumDir.emplace_back("241395"); - - std::vector<std::string> splittedFileVec; - splittedFileVec.emplace_back("ENGINX"); - splittedFileVec.emplace_back("241395"); - splittedFileVec.emplace_back("focused"); - splittedFileVec.emplace_back("bank"); - splittedFileVec.emplace_back("1"); - - // inputs from user - given multiple run - EXPECT_CALL(mockView, getFittingRunNo()) - .Times(2) - .WillRepeatedly(Return(g_focusedBankFile)); - - EXPECT_CALL(mockView, getFittingRunNumVec()) - .Times(1) - .WillOnce(Return(RunNumDir)); - - EXPECT_CALL(mockView, splitFittingDirectory(testing::_)) - .Times(1) - .WillOnce(Return(splittedFileVec)); - - EXPECT_CALL(mockView, getFittingMultiRunMode()).Times(0); - - EXPECT_CALL(mockView, setFittingRunNumVec(testing::_)).Times(0); - - EXPECT_CALL(mockView, addBankItem(testing::_)).Times(0); - - EXPECT_CALL(mockView, setBankIdComboBox(testing::_)).Times(0); - - EXPECT_CALL(mockView, addRunNoItem(testing::_)).Times(0); - - EXPECT_CALL(mockView, setFittingListWidgetCurrentRow(testing::_)).Times(0); - - // No errors/0 warnings. File entered is not found - EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); - EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(1); - - pres.notify(IEnggDiffractionPresenter::FittingRunNo); - } - void test_logMsg() { testing::NiceMock<MockEnggDiffractionView> mockView; MantidQt::CustomInterfaces::EnggDiffractionPresenter pres(&mockView); @@ -1688,8 +1412,6 @@ private: const static std::string g_eventModeRunNo; const static std::string g_validRunNo; const static std::string g_focusedRun; - const static std::string g_focusedBankFile; - const static std::string g_focusedFittingRunNo; EnggDiffCalibSettings m_basicCalibSettings; std::vector<std::string> m_ex_empty_run_num; @@ -1707,15 +1429,6 @@ private: const std::string EnggDiffractionPresenterTest::g_eventModeRunNo = "ENGINX00228061"; // could also be given as "ENGINX228061" -const std::string EnggDiffractionPresenterTest::g_focusedRun = - "focused_texture_bank_1"; - const std::string EnggDiffractionPresenterTest::g_validRunNo = "228061"; -const std::string EnggDiffractionPresenterTest::g_focusedBankFile = - "ENGINX_241395_focused_texture_bank_1"; - -const std::string EnggDiffractionPresenterTest::g_focusedFittingRunNo = - "241391-241394"; - #endif // MANTID_CUSTOMINTERFACES_ENGGDIFFRACTIONPRESENTERTEST_H diff --git a/MantidQt/CustomInterfaces/test/EnggDiffractionViewMock.h b/MantidQt/CustomInterfaces/test/EnggDiffractionViewMock.h index d0956af59b7..70d8beebac5 100644 --- a/MantidQt/CustomInterfaces/test/EnggDiffractionViewMock.h +++ b/MantidQt/CustomInterfaces/test/EnggDiffractionViewMock.h @@ -6,6 +6,8 @@ #include <gmock/gmock.h> +class QwtData; + GCC_DIAG_OFF_SUGGEST_OVERRIDE // This is a simple mock for the tomo interface view when using SCARF. @@ -90,14 +92,19 @@ public: MOCK_METHOD3(newCalibLoaded, void(const std::string &, const std::string &, const std::string &)); + // virtual std::vector<GSASCalibrationParms> currentCalibration() const + MOCK_CONST_METHOD0( + currentCalibration, + std::vector<MantidQt::CustomInterfaces::GSASCalibrationParms>()); + // virtual std::string enggRunPythonCode(const std::string &pyCode) MOCK_METHOD1(enggRunPythonCode, std::string(const std::string &)); // virtual void enableTabs(bool enable); MOCK_METHOD1(enableTabs, void(bool)); - // virtual void enableCalibrateAndFocusActions(bool enable); - MOCK_METHOD1(enableCalibrateAndFocusActions, void(bool)); + // virtual void enableCalibrateFocusFitUserActions(bool enable); + MOCK_METHOD1(enableCalibrateFocusFitUserActions, void(bool)); // virtual std::string focusingDir() const; MOCK_CONST_METHOD0(focusingDir, std::string()); @@ -135,75 +142,9 @@ public: // virtual double rebinningPulsesPerPeriod() const; MOCK_CONST_METHOD0(rebinningPulsesTime, double()); - // virtual std::string fittingRunNo() const; - MOCK_CONST_METHOD0(getFittingRunNo, std::string()); - - // virtual std::string fittingPeaksData() const; - MOCK_CONST_METHOD0(fittingPeaksData, std::string()); - // virtual bool focusedOutWorkspace() const; MOCK_CONST_METHOD0(focusedOutWorkspace, bool()); - // virtual Splits the fitting directory if the ENGINX found - MOCK_METHOD1(splitFittingDirectory, - std::vector<std::string>(std::string &selectedfPath)); - - // adds the number of banks to the combo-box widget on the interface - MOCK_METHOD1(addBankItem, void(std::string bankID)); - - // adds the run number to the list view widget on the interface - MOCK_METHOD1(addRunNoItem, void(std::string runNo)); - - // emits the signal within view when run number / bank changed - MOCK_METHOD0(setBankEmit, void()); - - // sets the bank combo-box according to given index - MOCK_METHOD1(setBankIdComboBox, void(int idx)); - - // deletes all items from the fitting combo-box widget - MOCK_CONST_METHOD0(clearFittingComboBox, void()); - - // enables or disables the fitting combo-box - MOCK_CONST_METHOD1(enableFittingComboBox, void(bool enable)); - - // gets the index of the bank according to text found - MOCK_CONST_METHOD1(getFittingComboIdx, int(std::string bank)); - - // deletes all items from the fitting list widget - MOCK_CONST_METHOD0(clearFittingListWidget, void()); - - // enables or disables the fitting list widget - MOCK_CONST_METHOD1(enableFittingListWidget, void(bool enable)); - - // return idx of current selected row of list widget - MOCK_CONST_METHOD0(getFittingListWidgetCurrentRow, int()); - - // sets the current row of the fitting list widget - MOCK_CONST_METHOD1(setFittingListWidgetCurrentRow, void(int idx)); - - // sets the peak list according to the QString given - MOCK_CONST_METHOD1(setPeakList, void(std::string peakList)); - - // gets the set focus directory within the setting tab - MOCK_METHOD0(getFocusDir, std::string()); - - // gets the global vector in view containing focused file directory - MOCK_METHOD0(getFittingRunNumVec, std::vector<std::string>()); - - // sets the global vector in view containing focused file directory - MOCK_METHOD1(setFittingRunNumVec, void(std::vector<std::string> assignVec)); - - // sets the fitting run number according to path - MOCK_METHOD1(setFittingRunNo, void(QString path)); - - // To determine whether the current loop is multi-run or single to avoid - // regenerating the list - view widget when not required - MOCK_METHOD0(getFittingMultiRunMode, bool()); - - // sets the fitting mode to multi-run or single to avoid - // regenerating the list - view widget when not required - MOCK_METHOD1(setFittingMultiRunMode, void(bool mode)); - // virtual bool plotCalibWorkspace MOCK_CONST_METHOD0(plotCalibWorkspace, bool()); diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorAppendGroupCommand.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorAppendGroupCommand.h index 92ea727f078..c288990a45b 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorAppendGroupCommand.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorAppendGroupCommand.h @@ -10,7 +10,7 @@ namespace MantidWidgets { DataProcessorAppendGroupCommand defines the action "Insert Group" -Copyright © 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -45,4 +45,4 @@ public: }; } } -#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORAPPENDGROUPCOMMAND_H*/ \ No newline at end of file +#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORAPPENDGROUPCOMMAND_H*/ diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorAppendRowCommand.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorAppendRowCommand.h index fb58d6e6ccc..e113d5c9e7e 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorAppendRowCommand.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorAppendRowCommand.h @@ -10,7 +10,7 @@ namespace MantidWidgets { DataProcessorAppendRowCommand defines the action "Insert Row After" -Copyright © 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -45,4 +45,4 @@ public: }; } } -#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORAPPENDROWCOMMAND_H*/ \ No newline at end of file +#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORAPPENDROWCOMMAND_H*/ diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorClearSelectedCommand.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorClearSelectedCommand.h index 0c87af67fbc..92270dc1234 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorClearSelectedCommand.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorClearSelectedCommand.h @@ -9,7 +9,7 @@ namespace MantidWidgets { DataProcessorClearSelectedCommand defines the action "Clear Selected" -Copyright © 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -44,4 +44,4 @@ public: }; } } -#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORCLEARSELECTEDCOMMAND_H*/ \ No newline at end of file +#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORCLEARSELECTEDCOMMAND_H*/ diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorCommand.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorCommand.h index 3d242f04e31..f862282aa29 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorCommand.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorCommand.h @@ -10,10 +10,9 @@ namespace MantidWidgets { /** @class DataProcessorCommand DataProcessorCommand is an interface which defines the functions any data -processor -action needs to support. +processor action needs to support. -Copyright © 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -60,4 +59,4 @@ protected: typedef std::unique_ptr<DataProcessorCommand> DataProcessorCommand_uptr; } } -#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORCOMMAND_H*/ \ No newline at end of file +#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORCOMMAND_H*/ diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorCopySelectedCommand.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorCopySelectedCommand.h index 0df84f2be90..c650005e6e8 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorCopySelectedCommand.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorCopySelectedCommand.h @@ -9,7 +9,7 @@ namespace MantidWidgets { DataProcessorCopySelectedCommand defines the action "Copy Selected" -Copyright © 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -44,4 +44,4 @@ public: }; } } -#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORCOPYSELECTEDCOMMAND_H*/ \ No newline at end of file +#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORCOPYSELECTEDCOMMAND_H*/ diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorCutSelectedCommand.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorCutSelectedCommand.h index 0e003982725..a928ffd6a59 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorCutSelectedCommand.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorCutSelectedCommand.h @@ -9,7 +9,7 @@ namespace MantidWidgets { DataProcessorCutSelectedCommand defines the action "Cut Selected" -Copyright © 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -44,4 +44,4 @@ public: }; } } -#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORCUTSELECTEDCOMMAND_H*/ \ No newline at end of file +#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORCUTSELECTEDCOMMAND_H*/ diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorDeleteGroupCommand.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorDeleteGroupCommand.h index 8e82fd7fb79..f5439df1ef8 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorDeleteGroupCommand.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorDeleteGroupCommand.h @@ -10,7 +10,7 @@ namespace MantidWidgets { DataProcessorDeleteGroupCommand defines the action "Delete Group" -Copyright © 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -45,4 +45,4 @@ public: }; } } -#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORDELETEGROUPCOMMAND_H*/ \ No newline at end of file +#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORDELETEGROUPCOMMAND_H*/ diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorDeleteRowCommand.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorDeleteRowCommand.h index 082d8bee81a..9563c50d86c 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorDeleteRowCommand.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorDeleteRowCommand.h @@ -10,7 +10,7 @@ namespace MantidWidgets { DataProcessorDeleteRowCommand defines the action "Delete Row" -Copyright © 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -45,4 +45,4 @@ public: }; } } -#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORDELETEROWCOMMAND_H*/ \ No newline at end of file +#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORDELETEROWCOMMAND_H*/ diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorExpandCommand.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorExpandCommand.h index 8e197707e03..f0ccee1d39c 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorExpandCommand.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorExpandCommand.h @@ -9,7 +9,7 @@ namespace MantidWidgets { DataProcessorExpandCommand defines the action "Expand Selection" -Copyright © 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -44,4 +44,4 @@ public: }; } } -#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSOREXPANDCOMMAND_H*/ \ No newline at end of file +#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSOREXPANDCOMMAND_H*/ diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorExportTableCommand.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorExportTableCommand.h index 466392d6cf1..75302adbcdc 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorExportTableCommand.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorExportTableCommand.h @@ -11,7 +11,7 @@ DataProcessorExportTableCommand defines the action "Export .TBL" processor interface presenter needs to support. -Copyright © 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -46,4 +46,4 @@ public: }; } } -#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSOREXPORTTABLECOMMAND_H*/ \ No newline at end of file +#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSOREXPORTTABLECOMMAND_H*/ diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorGroupRowsCommand.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorGroupRowsCommand.h index f2319e69c59..f8a3fb60238 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorGroupRowsCommand.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorGroupRowsCommand.h @@ -9,7 +9,7 @@ namespace MantidWidgets { DataProcessorGroupRowsCommand defines the action "Group Selected" -Copyright © 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -44,4 +44,4 @@ public: }; } } -#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORGROUPROWSCOMMAND_H*/ \ No newline at end of file +#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORGROUPROWSCOMMAND_H*/ diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorImportTableCommand.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorImportTableCommand.h index 01386c8e5f6..09c8f260645 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorImportTableCommand.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorImportTableCommand.h @@ -9,7 +9,7 @@ namespace MantidWidgets { DataProcessorImportTableCommand defines the action "Import .TBL" -Copyright © 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -44,4 +44,4 @@ public: }; } } -#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORIMPORTTABLECOMMAND_H*/ \ No newline at end of file +#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORIMPORTTABLECOMMAND_H*/ diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorNewTableCommand.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorNewTableCommand.h index fde681d0742..91e74b6e596 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorNewTableCommand.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorNewTableCommand.h @@ -9,7 +9,7 @@ namespace MantidWidgets { DataProcessorNewTableCommand defines the action "New Table" -Copyright © 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -44,4 +44,4 @@ public: }; } } -#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORNEWTABLECOMMAND_H*/ \ No newline at end of file +#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORNEWTABLECOMMAND_H*/ diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorOpenTableCommand.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorOpenTableCommand.h index b960a08fc86..cd09308792b 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorOpenTableCommand.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorOpenTableCommand.h @@ -9,7 +9,7 @@ namespace MantidWidgets { DataProcessorOpenTableCommand defines the action "Open Table" -Copyright © 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -44,4 +44,4 @@ public: }; } } -#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSOROPENTABLECOMMAND_H*/ \ No newline at end of file +#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSOROPENTABLECOMMAND_H*/ diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorOptionsCommand.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorOptionsCommand.h index 5f472133303..be6a3e760c7 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorOptionsCommand.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorOptionsCommand.h @@ -9,7 +9,7 @@ namespace MantidWidgets { DataProcessorOptionsCommand defines the action "Import .TBL" -Copyright © 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -44,4 +44,4 @@ public: }; } } -#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSOROPTIONSTABLECOMMAND_H*/ \ No newline at end of file +#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSOROPTIONSTABLECOMMAND_H*/ diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPasteSelectedCommand.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPasteSelectedCommand.h index 04ce9387f15..bd95252faab 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPasteSelectedCommand.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPasteSelectedCommand.h @@ -9,7 +9,7 @@ namespace MantidWidgets { DataProcessorPasteSelectedCommand defines the action "Paste Selected" -Copyright © 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -44,4 +44,4 @@ public: }; } } -#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORPASTESELECTEDCOMMAND_H*/ \ No newline at end of file +#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORPASTESELECTEDCOMMAND_H*/ diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPlotGroupCommand.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPlotGroupCommand.h index 4df37ca733d..b18566abf28 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPlotGroupCommand.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPlotGroupCommand.h @@ -9,7 +9,7 @@ namespace MantidWidgets { DataProcessorPlotGroupCommand defines the action "Plot Selected Groups" -Copyright © 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -44,4 +44,4 @@ public: }; } } -#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORPLOTGROUPCOMMAND_H*/ \ No newline at end of file +#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORPLOTGROUPCOMMAND_H*/ diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPlotRowCommand.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPlotRowCommand.h index 052766aac29..1a0c6f3c671 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPlotRowCommand.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPlotRowCommand.h @@ -9,7 +9,7 @@ namespace MantidWidgets { DataProcessorPlotRowCommand defines the action "Plot Selected Rows" -Copyright © 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -44,4 +44,4 @@ public: }; } } -#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORPLOTROWCOMMAND_H*/ \ No newline at end of file +#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORPLOTROWCOMMAND_H*/ diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorProcessCommand.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorProcessCommand.h index f0d6e20ac55..03f7ce1c27a 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorProcessCommand.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorProcessCommand.h @@ -9,7 +9,7 @@ namespace MantidWidgets { DataProcessorProcessCommand defines the action "Process" -Copyright © 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -44,4 +44,4 @@ public: }; } } -#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORPROCESSCOMMAND_H*/ \ No newline at end of file +#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORPROCESSCOMMAND_H*/ diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorSaveTableAsCommand.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorSaveTableAsCommand.h index e00c8ca1648..ccb14070295 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorSaveTableAsCommand.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorSaveTableAsCommand.h @@ -9,7 +9,7 @@ namespace MantidWidgets { DataProcessorSaveTableAsCommand defines the action "Save Table As" -Copyright © 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -44,4 +44,4 @@ public: }; } } -#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORSAVETABLEASCOMMAND_H*/ \ No newline at end of file +#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORSAVETABLEASCOMMAND_H*/ diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorSaveTableCommand.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorSaveTableCommand.h index 74bf105a1a3..e96c7808e67 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorSaveTableCommand.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorSaveTableCommand.h @@ -9,7 +9,7 @@ namespace MantidWidgets { DataProcessorSaveTableCommand defines the action "Save Table" -Copyright © 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -44,4 +44,4 @@ public: }; } } -#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORSAVETABLECOMMAND_H*/ \ No newline at end of file +#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORSAVETABLECOMMAND_H*/ diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorSeparatorCommand.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorSeparatorCommand.h index 17fefb19454..4234d01032e 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorSeparatorCommand.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorSeparatorCommand.h @@ -11,7 +11,7 @@ DataProcessorSeparatorCommand defines a separator. It has no name, no icon and empty execute() method -Copyright © 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -44,4 +44,4 @@ public: }; } } -#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORSEPARATORCOMMAND_H*/ \ No newline at end of file +#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORSEPARATORCOMMAND_H*/ diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorWorkspaceCommand.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorWorkspaceCommand.h index e4abca0ec33..84670355d6c 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorWorkspaceCommand.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorWorkspaceCommand.h @@ -9,7 +9,7 @@ namespace MantidWidgets { DataProcessorWorkspaceCommand defines a workspace action -Copyright © 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -51,4 +51,4 @@ private: }; } } -#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORWORKSPACECOMMAND_H*/ \ No newline at end of file +#endif /*MANTIDQTMANTIDWIDGETS_DATAPROCESSORWORKSPACECOMMAND_H*/ diff --git a/MantidQt/MantidWidgets/src/DataProcessorUI/DataProcessorGenerateNotebook.cpp b/MantidQt/MantidWidgets/src/DataProcessorUI/DataProcessorGenerateNotebook.cpp index 3d3fe8f7fc9..4da117847ea 100644 --- a/MantidQt/MantidWidgets/src/DataProcessorUI/DataProcessorGenerateNotebook.cpp +++ b/MantidQt/MantidWidgets/src/DataProcessorUI/DataProcessorGenerateNotebook.cpp @@ -86,10 +86,10 @@ std::string DataProcessorGenerateNotebook::generateNotebook( notebook->markdownCell(tableString(m_model, m_whitelist, rows)); - for (auto gIt = rows.begin(); gIt != rows.end(); ++gIt) { + for (const auto &item : rows) { - const int groupId = gIt->first; - const std::set<int> rowSet = gIt->second; + const int groupId = item.first; + const std::set<int> rowSet = item.second; /** Announce the stitch group in the notebook **/ @@ -106,11 +106,11 @@ std::string DataProcessorGenerateNotebook::generateNotebook( // workspaces std::vector<std::string> output_ws; - for (auto rIt = rowSet.begin(); rIt != rowSet.end(); ++rIt) { + for (const auto &row : rowSet) { code_string << "#Load and reduce\n"; auto reduce_row_string = reduceRowString( - groupId, *rIt, m_instrument, m_model, m_whitelist, m_preprocessMap, + groupId, row, m_instrument, m_model, m_whitelist, m_preprocessMap, m_processor, m_preprocessingOptionsMap, m_processingOptions); // The reduction code code_string << boost::get<0>(reduce_row_string); @@ -211,7 +211,7 @@ std::string plotsString(const std::vector<std::string> &output_ws, std::vector<std::string> wsNames; // Iterate through the elements of output_ws - for (auto &outws : output_ws) { + for (const auto &outws : output_ws) { auto workspaces = splitByCommas(outws); @@ -259,24 +259,24 @@ std::string tableString(QDataProcessorTreeModel_sptr model, table_string << "---" << "\n"; - for (auto groupIt = rows.begin(); groupIt != rows.end(); ++groupIt) { + for (const auto &item : rows) { - auto groupId = groupIt->first; - auto rowSet = groupIt->second; + auto groupId = item.first; + auto rowSet = item.second; - for (auto rowIt = rowSet.begin(); rowIt != rowSet.end(); ++rowIt) { + for (const auto &row : rowSet) { table_string << model->data(model->index(groupId, 0)).toString().toStdString(); table_string << " | "; for (int col = 0; col < ncols - 1; col++) - table_string << model->data(model->index(*rowIt, col, + table_string << model->data(model->index(row, col, model->index(groupId, 0))) .toString() .toStdString() << " | "; - table_string << model->data(model->index(*rowIt, ncols - 1, + table_string << model->data(model->index(row, ncols - 1, model->index(groupId, 0))) .toString() .toStdString() << "\n"; @@ -314,13 +314,13 @@ boost::tuple<std::string, std::string> postprocessGroupString( std::vector<std::string> outputName; // Go through each row and prepare the input and output properties - for (auto groupIt = groups.begin(); groupIt != groups.end(); ++groupIt) { + for (const auto &group : groups) { - int nrows = model->rowCount(model->index(*groupIt, 0)); + int nrows = model->rowCount(model->index(group, 0)); for (int row = 0; row < nrows; row++) { // The reduced ws name without prefix (for example 'TOF_13460_13462') - auto suffix = getReducedWorkspaceName(*groupIt, row, model, whitelist); + auto suffix = getReducedWorkspaceName(group, row, model, whitelist); // The reduced ws name: 'IvsQ_TOF_13460_13462' inputNames.emplace_back(processor.prefix(0) + suffix); @@ -565,8 +565,8 @@ loadWorkspaceString(const std::string &runStr, const std::string &instrument, std::ostringstream load_strings; // Remove leading/trailing whitespace from each run - for (auto runIt = runs.begin(); runIt != runs.end(); ++runIt) - boost::trim(*runIt); + for (auto &run : runs) + boost::trim(run); const std::string prefix = preprocessor.prefix(); const std::string outputName = prefix + boost::algorithm::join(runs, "_"); diff --git a/MantidQt/MantidWidgets/src/DataProcessorUI/GenericDataProcessorPresenter.cpp b/MantidQt/MantidWidgets/src/DataProcessorUI/GenericDataProcessorPresenter.cpp index c8164b7f58a..375911f8fce 100644 --- a/MantidQt/MantidWidgets/src/DataProcessorUI/GenericDataProcessorPresenter.cpp +++ b/MantidQt/MantidWidgets/src/DataProcessorUI/GenericDataProcessorPresenter.cpp @@ -253,24 +253,26 @@ void GenericDataProcessorPresenter::process() { } else { // They may have selected a group, in this case we want to process and // post-process the whole group, so populate group with every row - for (auto idxGroup = groups.begin(); idxGroup != groups.end(); ++idxGroup) { - for (int row = 0; row < numRowsInGroup(*idxGroup); row++) - rows[*idxGroup].insert(row); + for (const auto &group : groups) { + for (int row = 0; row < numRowsInGroup(group); row++) + rows[group].insert(row); } } // Check each group and warn if we're only partially processing it - for (auto gIt = rows.begin(); gIt != rows.end(); ++gIt) { + for (const auto &item : rows) { - const int &groupId = gIt->first; - const std::set<int> &rowIds = gIt->second; + const int &groupId = item.first; + const std::set<int> &rowIds = item.second; // Are we only partially processing a group? - if (static_cast<int>(rowIds.size()) < numRowsInGroup(gIt->first) && + if (static_cast<int>(rowIds.size()) < numRowsInGroup(groupId) && m_options["WarnProcessPartialGroup"].toBool()) { + const std::string groupName = + m_model->data(m_model->index(groupId, 0)).toString().toStdString(); std::stringstream err; err << "You have only selected " << rowIds.size() << " of the "; - err << numRowsInGroup(groupId) << " rows in group " << groupId << "."; + err << numRowsInGroup(groupId) << " rows in group '" << groupName << "'."; err << " Are you sure you want to continue?"; if (!m_mainPresenter->askUserYesNo(err.str(), "Continue Processing?")) return; @@ -410,13 +412,13 @@ bool GenericDataProcessorPresenter::processGroups( auto rows = it->second; // Reduce each row - for (auto rIt = rows.begin(); rIt != rows.end(); ++rIt) { + for (const auto &row : rows) { try { - reduceRow(groupId, *rIt); + reduceRow(groupId, row); progressReporter.report(); } catch (std::exception &ex) { const std::string rowNo = - Mantid::Kernel::Strings::toString<int>(*rIt + 1); + Mantid::Kernel::Strings::toString<int>(row + 1); const std::string groupNo = Mantid::Kernel::Strings::toString<int>(groupId); const std::string message = "Error encountered while processing row " + @@ -928,7 +930,7 @@ void GenericDataProcessorPresenter::groupRows() { // If they don't, remove rows from their groups and add them to a // new group - auto selectedRows = m_view->getSelectedRows(); + const auto selectedRows = m_view->getSelectedRows(); if (selectedRows.size() < 2) { // Rows belong to the same group (size == 1) or @@ -942,20 +944,20 @@ void GenericDataProcessorPresenter::groupRows() { appendGroup(); // Append as many rows as the number of selected rows minus one int rowsToAppend = -1; - for (auto it = selectedRows.begin(); it != selectedRows.end(); ++it) - rowsToAppend += static_cast<int>(it->second.size()); + for (const auto &row : selectedRows) + rowsToAppend += static_cast<int>(row.second.size()); for (int i = 0; i < rowsToAppend; i++) insertRow(groupId, i); // Now we just have to set the data int rowIndex = 0; - for (auto it = selectedRows.begin(); it != selectedRows.end(); ++it) { - int oldGroupId = it->first; - auto rows = it->second; - for (auto row = rows.begin(); row != rows.end(); ++row) { + for (const auto &item : selectedRows) { + int oldGroupId = item.first; + auto rows = item.second; + for (const auto &row : rows) { for (int col = 0; col < m_columns; col++) { auto value = m_model->data( - m_model->index(*row, col, m_model->index(oldGroupId, 0))); + m_model->index(row, col, m_model->index(oldGroupId, 0))); m_model->setData( m_model->index(rowIndex, col, m_model->index(groupId, 0)), value); } @@ -1261,16 +1263,15 @@ void GenericDataProcessorPresenter::expandSelection() { /** Clear the currently selected rows */ void GenericDataProcessorPresenter::clearSelected() { - auto selectedRows = m_view->getSelectedRows(); + const auto selectedRows = m_view->getSelectedRows(); - for (auto group = selectedRows.begin(); group != selectedRows.end(); - ++group) { - int groupIndex = group->first; - auto rows = group->second; - for (auto row = rows.begin(); row != rows.end(); ++row) { + for (const auto &item : selectedRows) { + int group = item.first; + auto rows = item.second; + for (const auto &row : rows) { for (auto col = 0; col < m_model->columnCount(); col++) - m_model->setData( - m_model->index(*row, col, m_model->index(groupIndex, 0)), ""); + m_model->setData(m_model->index(row, col, m_model->index(group, 0)), + ""); } } m_tableDirty = true; @@ -1280,18 +1281,18 @@ void GenericDataProcessorPresenter::clearSelected() { void GenericDataProcessorPresenter::copySelected() { std::vector<std::string> lines; - auto selectedRows = m_view->getSelectedRows(); - for (auto it = selectedRows.begin(); it != selectedRows.end(); ++it) { - const int groupId = it->first; - auto rows = it->second; + const auto selectedRows = m_view->getSelectedRows(); + for (const auto &item : selectedRows) { + const int group = item.first; + auto rows = item.second; - for (auto row = rows.begin(); row != rows.end(); ++row) { + for (const auto &row : rows) { std::vector<std::string> line; - line.push_back(std::to_string(groupId)); + line.push_back(std::to_string(group)); for (int col = 0; col < m_columns; ++col) { line.push_back( - m_model->data(m_model->index(*row, col, m_model->index(groupId, 0))) + m_model->data(m_model->index(row, col, m_model->index(group, 0))) .toString() .toStdString()); } @@ -1318,7 +1319,7 @@ void GenericDataProcessorPresenter::pasteSelected() { // If we have rows selected, we'll overwrite them. If not, we'll append new // rows. - auto selectedRows = m_view->getSelectedRows(); + const auto selectedRows = m_view->getSelectedRows(); if (selectedRows.empty()) { // No rows were selected // Use group where rows in clipboard belong and paste new rows to it diff --git a/MantidQt/MantidWidgets/test/DataProcessorUI/DataProcessorGenerateNotebookTest.h b/MantidQt/MantidWidgets/test/DataProcessorUI/DataProcessorGenerateNotebookTest.h index 78deeafcd77..4d6e9b23847 100644 --- a/MantidQt/MantidWidgets/test/DataProcessorUI/DataProcessorGenerateNotebookTest.h +++ b/MantidQt/MantidWidgets/test/DataProcessorUI/DataProcessorGenerateNotebookTest.h @@ -229,9 +229,8 @@ public: "1 | 24682 | 1.5 | | 1.4 | 2.9 | 0.04 | 1 | ", ""}; int i = 0; - for (auto it = notebookLines.begin(); it != notebookLines.end(); - ++it, ++i) { - TS_ASSERT_EQUALS(*it, result[i]) + for (const auto &line : notebookLines) { + TS_ASSERT_EQUALS(line, result[i++]) } } @@ -267,9 +266,8 @@ public: boost::split(notebookLines, output, boost::is_any_of("\n")); int i = 0; - for (auto it = notebookLines.begin(); it != notebookLines.end(); - ++it, ++i) { - TS_ASSERT_EQUALS(*it, result[i]) + for (const auto &line : notebookLines) { + TS_ASSERT_EQUALS(line, result[i++]) } // Test without workspace name @@ -282,9 +280,8 @@ public: boost::split(notebookLinesEmptyStr, outputEmptyStr, boost::is_any_of("\n")); i = 0; - for (auto it = notebookLinesEmptyStr.begin(); - it != notebookLinesEmptyStr.end(); ++it, ++i) { - TS_ASSERT_EQUALS(*it, resultEmptyStr[i]) + for (const auto &line : notebookLinesEmptyStr) { + TS_ASSERT_EQUALS(line, resultEmptyStr[i++]) } } @@ -320,9 +317,8 @@ public: boost::split(notebookLines, boost::get<0>(output), boost::is_any_of("\n")); int i = 0; - for (auto it = notebookLines.begin(); it != notebookLines.end(); - ++it, ++i) { - TS_ASSERT_EQUALS(*it, result[i]) + for (const auto &line : notebookLines) { + TS_ASSERT_EQUALS(line, result[i++]) } } @@ -355,9 +351,8 @@ public: boost::split(notebookLines, output, boost::is_any_of("\n")); int i = 0; - for (auto it = notebookLines.begin(); it != notebookLines.end(); - ++it, ++i) { - TS_ASSERT_EQUALS(*it, result[i]) + for (const auto &line : notebookLines) { + TS_ASSERT_EQUALS(line, result[i++]) } } @@ -383,9 +378,8 @@ public: boost::split(notebookLines, boost::get<0>(output), boost::is_any_of("\n")); int i = 0; - for (auto it = notebookLines.begin(); it != notebookLines.end(); - ++it, ++i) { - TS_ASSERT_EQUALS(*it, result[i]) + for (const auto &line : notebookLines) { + TS_ASSERT_EQUALS(line, result[i++]) } } @@ -415,9 +409,8 @@ public: boost::split(notebookLines, boost::get<0>(output), boost::is_any_of("\n")); int i = 0; - for (auto it = notebookLines.begin(); it != notebookLines.end(); - ++it, ++i) { - TS_ASSERT_EQUALS(*it, result[i]) + for (const auto &line : notebookLines) { + TS_ASSERT_EQUALS(line, result[i++]) } } diff --git a/MantidQt/Python/sip_mantidqt.cpp.in b/MantidQt/Python/sip_mantidqt.cpp.in index 7574d01d9ba..e7a4e84085b 100644 --- a/MantidQt/Python/sip_mantidqt.cpp.in +++ b/MantidQt/Python/sip_mantidqt.cpp.in @@ -10,4 +10,13 @@ // special debugging build of the Python library. #include <boost/python/detail/wrap_python.hpp> + +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC visibility push(default) +#endif + #include "sipmantidqtpythonpart0.cpp" + +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC visibility pop +#endif diff --git a/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PeakPalette.h b/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PeakPalette.h index f6a038683fe..b211476fba5 100644 --- a/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PeakPalette.h +++ b/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PeakPalette.h @@ -130,8 +130,8 @@ bool PeakPalette<C>::operator==(const PeakPalette &other) const { } // Forward declaration for template specialization -template <> PeakPalette<QColor>::PeakPalette(); -template <> PeakPalette<PeakViewColor>::PeakPalette(); +template <> DLLExport PeakPalette<QColor>::PeakPalette(); +template <> DLLExport PeakPalette<PeakViewColor>::PeakPalette(); } // namespace } diff --git a/QtPropertyBrowser/CMakeLists.txt b/QtPropertyBrowser/CMakeLists.txt index 7b55adf7336..b319d08c689 100644 --- a/QtPropertyBrowser/CMakeLists.txt +++ b/QtPropertyBrowser/CMakeLists.txt @@ -133,9 +133,13 @@ endif () target_link_libraries ( ${PROJECT_NAME} LINK_PRIVATE ${TCMALLOC_LIBRARIES_LINKTIME} ${QT_LIBRARIES} ) -if ( WIN32 ) + +if(WIN32) + add_definitions ( -DQT_QTPROPERTYBROWSER_EXPORT ) +elseif(CMAKE_COMPILER_IS_GNUCXX) add_definitions ( -DQT_QTPROPERTYBROWSER_EXPORT ) -endif ( WIN32 ) +endif() + # This is, for the most part, not our code so disable an Intel compiler # warning that crops up a lot in this package diff --git a/QtPropertyBrowser/src/qtpropertybrowser.h b/QtPropertyBrowser/src/qtpropertybrowser.h index a5586d0e21d..d3f01f37957 100644 --- a/QtPropertyBrowser/src/qtpropertybrowser.h +++ b/QtPropertyBrowser/src/qtpropertybrowser.h @@ -95,7 +95,7 @@ QT_BEGIN_NAMESPACE #endif -#if defined(Q_WS_WIN) +#if defined(Q_OS_WIN) # if !defined(QT_QTPROPERTYBROWSER_EXPORT) && !defined(QT_QTPROPERTYBROWSER_IMPORT) # define QT_QTPROPERTYBROWSER_EXPORT # elif defined(QT_QTPROPERTYBROWSER_IMPORT) @@ -107,6 +107,18 @@ QT_BEGIN_NAMESPACE # undef QT_QTPROPERTYBROWSER_EXPORT # define QT_QTPROPERTYBROWSER_EXPORT __declspec(dllexport) # endif +#elif defined(Q_OS_LINUX) +# if !defined(QT_QTPROPERTYBROWSER_EXPORT) && !defined(QT_QTPROPERTYBROWSER_IMPORT) +# define QT_QTPROPERTYBROWSER_EXPORT +# elif defined(QT_QTPROPERTYBROWSER_IMPORT) +# if defined(QT_QTPROPERTYBROWSER_EXPORT) +# undef QT_QTPROPERTYBROWSER_EXPORT +# endif +# define QT_QTPROPERTYBROWSER_EXPORT +# elif defined(QT_QTPROPERTYBROWSER_EXPORT) +# undef QT_QTPROPERTYBROWSER_EXPORT +# define QT_QTPROPERTYBROWSER_EXPORT __attribute__ ((visibility ("default"))) +# endif #else # define QT_QTPROPERTYBROWSER_EXPORT #endif diff --git a/Testing/Data/SystemTest/osiris97944_graphite002_red.nxs.md5 b/Testing/Data/SystemTest/osiris97944_graphite002_red.nxs.md5 new file mode 100644 index 00000000000..1fe030df3a9 --- /dev/null +++ b/Testing/Data/SystemTest/osiris97944_graphite002_red.nxs.md5 @@ -0,0 +1 @@ +8c431c304cde7d4af57f0bc4991a5ea4 diff --git a/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py b/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py index 8c6393919f4..3c0297ab7ac 100644 --- a/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py +++ b/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py @@ -1013,37 +1013,33 @@ class ISISIndirectInelasticIqtAndIqtFitMulti(ISISIndirectInelasticBase): class OSIRISIqtAndIqtFitMulti(ISISIndirectInelasticIqtAndIqtFitMulti): def skipTests(self): - operating_sys = platform.system() - # Skip Test on Windows and OSX - if operating_sys == "Darwin" or operating_sys == "Windows": + # Skip Test OSX + if platform.system() == "Darwin": return True def __init__(self): ISISIndirectInelasticIqtAndIqtFitMulti.__init__(self) # TransformToIqt - self.samples = ['osi97935_graphite002_red.nxs'] + self.samples = ['osiris97944_graphite002_red.nxs'] self.resolution = 'osi97935_graphite002_res.nxs' self.e_min = -0.4 self.e_max = 0.4 self.num_bins = 4 # Iqt Fit - self.func = r'name=LinearBackground,A0=0.510595,A1=0,ties=(A1=0);name=UserFunction,Formula=Intensity*exp( -(x/Tau)^Beta),'\ - 'Intensity=0.489405,Tau=0.105559,Beta=1.61112e-14;ties=(f1.Intensity=1-f0.A0)' + self.func = r'name=LinearBackground,A0=0.213439,A1=0,ties=(A1=0);name=UserFunction,'\ + 'Formula=Intensity*exp(-(x/Tau)^Beta),Intensity=0.786561,Tau=0.0247894,'\ + 'Beta=1;ties=(f1.Intensity=1-f0.A0)' self.ftype = '1E_s' self.startx = 0.0 - self.endx = 0.119681 + self.endx = 0.12 self.spec_min = 0 self.spec_max = 41 def get_reference_files(self): - ref_files = ['II.OSIRISFury.nxs'] - if platform.system() == "Windows": - ref_files += ['II.OSIRISFuryFitMulti_win.nxs'] - else: - ref_files += ['II.OSIRISFuryFitMulti_lin.nxs'] - return ref_files + return ['II.OSIRISIqt.nxs', + 'II.OSIRISIqtFitMulti.nxs'] #------------------------- IRIS tests ----------------------------------------- diff --git a/Testing/SystemTests/tests/analysis/reference/II.OSIRISIqt.nxs.md5 b/Testing/SystemTests/tests/analysis/reference/II.OSIRISIqt.nxs.md5 new file mode 100644 index 00000000000..b3e62099f57 --- /dev/null +++ b/Testing/SystemTests/tests/analysis/reference/II.OSIRISIqt.nxs.md5 @@ -0,0 +1 @@ +5cf2d9f68b600408319cbea8cc274351 diff --git a/Testing/SystemTests/tests/analysis/reference/II.OSIRISIqtFitMulti.nxs.md5 b/Testing/SystemTests/tests/analysis/reference/II.OSIRISIqtFitMulti.nxs.md5 new file mode 100644 index 00000000000..028c3607761 --- /dev/null +++ b/Testing/SystemTests/tests/analysis/reference/II.OSIRISIqtFitMulti.nxs.md5 @@ -0,0 +1 @@ +66d56e31c925e9cba84ae18f8115c174 diff --git a/Testing/Tools/CMakeLists.txt b/Testing/Tools/CMakeLists.txt index 27c1f014e67..c26a5adb4ac 100644 --- a/Testing/Tools/CMakeLists.txt +++ b/Testing/Tools/CMakeLists.txt @@ -15,7 +15,7 @@ elseif(CMAKE_COMPILER_IS_GNUCXX) string(REPLACE "-Wsuggest-override" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") endif() -if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") +if (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-missing-field-initializers" ) endif() diff --git a/Testing/Tools/gmock-1.7.0/CMakeLists.txt b/Testing/Tools/gmock-1.7.0/CMakeLists.txt index 572d0444bf1..aa60cba0732 100644 --- a/Testing/Tools/gmock-1.7.0/CMakeLists.txt +++ b/Testing/Tools/gmock-1.7.0/CMakeLists.txt @@ -38,7 +38,7 @@ endif() # ${gmock_BINARY_DIR}. # Language "C" is required for find_package(Threads). project(gmock CXX C) -cmake_minimum_required(VERSION 2.6.2) +cmake_minimum_required(VERSION 3.5) if (COMMAND set_up_hermetic_build) set_up_hermetic_build() diff --git a/Testing/Tools/gmock-1.7.0/gtest/CMakeLists.txt b/Testing/Tools/gmock-1.7.0/gtest/CMakeLists.txt index 57470c84f3a..b49273ae4da 100644 --- a/Testing/Tools/gmock-1.7.0/gtest/CMakeLists.txt +++ b/Testing/Tools/gmock-1.7.0/gtest/CMakeLists.txt @@ -40,7 +40,7 @@ endif() # ${gtest_BINARY_DIR}. # Language "C" is required for find_package(Threads). project(gtest CXX C) -cmake_minimum_required(VERSION 2.6.2) +cmake_minimum_required(VERSION 3.5) if (COMMAND set_up_hermetic_build) set_up_hermetic_build() diff --git a/Vates/VatesAPI/CMakeLists.txt b/Vates/VatesAPI/CMakeLists.txt index 648511653f6..7299847c40c 100644 --- a/Vates/VatesAPI/CMakeLists.txt +++ b/Vates/VatesAPI/CMakeLists.txt @@ -1,5 +1,5 @@ #This is mainly here so you don't get a complaint when running cmake -cmake_minimum_required( VERSION 2.8.12 ) +cmake_minimum_required( VERSION 3.5 ) project( VatesAPI ) diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHWSignalArray.h b/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHWSignalArray.h index c30a70a3aef..6a023df1145 100644 --- a/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHWSignalArray.h +++ b/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHWSignalArray.h @@ -63,9 +63,9 @@ public: void GetTuple(vtkIdType i, double *tuple) override; vtkIdType LookupTypedValue(Scalar value) override; void LookupTypedValue(Scalar value, vtkIdList *ids) override; - Scalar GetValue(vtkIdType idx) override; + Scalar GetValue(vtkIdType idx) const override; Scalar &GetValueReference(vtkIdType idx) override; - void GetTupleValue(vtkIdType idx, Scalar *t) override; + void GetTypedTuple(vtkIdType idx, Scalar *t) const override; // Description: // This container is read only -- this method does nothing but print a @@ -97,9 +97,9 @@ public: void RemoveTuple(vtkIdType id) override; void RemoveFirstTuple() override; void RemoveLastTuple() override; - void SetTupleValue(vtkIdType i, const Scalar *t) override; - void InsertTupleValue(vtkIdType i, const Scalar *t) override; - vtkIdType InsertNextTupleValue(const Scalar *t) override; + void SetTypedTuple(vtkIdType i, const Scalar *t) override; + void InsertTypedTuple(vtkIdType i, const Scalar *t) override; + vtkIdType InsertNextTypedTuple(const Scalar *t) override; void SetValue(vtkIdType idx, Scalar value) override; vtkIdType InsertNextValue(Scalar v) override; void InsertVariantValue(vtkIdType idx, vtkVariant value) override; @@ -290,7 +290,7 @@ vtkIdType vtkMDHWSignalArray<Scalar>::Lookup(const Scalar &val, //------------------------------------------------------------------------------ template <class Scalar> -Scalar vtkMDHWSignalArray<Scalar>::GetValue(vtkIdType idx) { +Scalar vtkMDHWSignalArray<Scalar>::GetValue(vtkIdType idx) const { m_iterator->jumpTo(m_offset + idx); return m_iterator->getNormalizedSignal(); } @@ -304,8 +304,8 @@ Scalar &vtkMDHWSignalArray<Scalar>::GetValueReference(vtkIdType idx) { //------------------------------------------------------------------------------ template <class Scalar> -void vtkMDHWSignalArray<Scalar>::GetTupleValue(vtkIdType tupleId, - Scalar *tuple) { +void vtkMDHWSignalArray<Scalar>::GetTypedTuple(vtkIdType tupleId, + Scalar *tuple) const { m_iterator->jumpTo(m_offset + tupleId); tuple[0] = m_iterator->getNormalizedSignal(); } @@ -451,19 +451,19 @@ template <class Scalar> void vtkMDHWSignalArray<Scalar>::RemoveLastTuple() { //------------------------------------------------------------------------------ template <class Scalar> -void vtkMDHWSignalArray<Scalar>::SetTupleValue(vtkIdType, const Scalar *) { +void vtkMDHWSignalArray<Scalar>::SetTypedTuple(vtkIdType, const Scalar *) { vtkErrorMacro("Read only container.") return; } //------------------------------------------------------------------------------ template <class Scalar> -void vtkMDHWSignalArray<Scalar>::InsertTupleValue(vtkIdType, const Scalar *) { +void vtkMDHWSignalArray<Scalar>::InsertTypedTuple(vtkIdType, const Scalar *) { vtkErrorMacro("Read only container.") return; } //------------------------------------------------------------------------------ template <class Scalar> -vtkIdType vtkMDHWSignalArray<Scalar>::InsertNextTupleValue(const Scalar *) { +vtkIdType vtkMDHWSignalArray<Scalar>::InsertNextTypedTuple(const Scalar *) { vtkErrorMacro("Read only container.") return -1; } diff --git a/Vates/VatesAPI/src/ADSWorkspaceProvider.cpp b/Vates/VatesAPI/src/ADSWorkspaceProvider.cpp index a198f450cb1..126ebd059d4 100644 --- a/Vates/VatesAPI/src/ADSWorkspaceProvider.cpp +++ b/Vates/VatesAPI/src/ADSWorkspaceProvider.cpp @@ -41,9 +41,11 @@ void ADSWorkspaceProvider<Workspace_Type>::disposeWorkspace( AnalysisDataService::Instance().remove(wsName); } +///@cond // Templated assembled types. -template class ADSWorkspaceProvider<Mantid::API::IMDWorkspace>; -template class ADSWorkspaceProvider<Mantid::API::IMDEventWorkspace>; -template class ADSWorkspaceProvider<Mantid::API::IMDHistoWorkspace>; +template class DLLExport ADSWorkspaceProvider<Mantid::API::IMDWorkspace>; +template class DLLExport ADSWorkspaceProvider<Mantid::API::IMDEventWorkspace>; +template class DLLExport ADSWorkspaceProvider<Mantid::API::IMDHistoWorkspace>; +///@endcond } } diff --git a/Vates/VatesAPI/src/vtkPeakMarkerFactory.cpp b/Vates/VatesAPI/src/vtkPeakMarkerFactory.cpp index 9bb5a96592b..3003756dacf 100644 --- a/Vates/VatesAPI/src/vtkPeakMarkerFactory.cpp +++ b/Vates/VatesAPI/src/vtkPeakMarkerFactory.cpp @@ -231,12 +231,12 @@ vtkPeakMarkerFactory::create(ProgressAction &progressUpdating) const { } else if (shape.shapeName() == Mantid::DataObjects::PeakShapeEllipsoid::ellipsoidShapeName()) { vtkNew<vtkFloatArray> transformSignal; - transformSignal->Allocate(1); transformSignal->SetNumberOfComponents(9); + transformSignal->SetNumberOfTuples(1); auto tensor = getTransformTensor( dynamic_cast<const Mantid::DataObjects::PeakShapeEllipsoid &>(shape), peak); - transformSignal->InsertNextTupleValue(tensor.data()); + transformSignal->SetTypedTuple(0, tensor.data()); peakDataSet->GetPointData()->SetTensors(transformSignal.GetPointer()); vtkNew<vtkRegularPolygonSource> polygonSource; diff --git a/Vates/VatesAPI/test/MockObjects.h b/Vates/VatesAPI/test/MockObjects.h index 32a482510b1..90355657d83 100644 --- a/Vates/VatesAPI/test/MockObjects.h +++ b/Vates/VatesAPI/test/MockObjects.h @@ -31,17 +31,6 @@ using Mantid::Geometry::MDHistoDimension; using Mantid::Geometry::MDHistoDimension_sptr; using Mantid::coord_t; -// Allow unused functions. -#if __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" -#endif - -#if defined(GCC_VERSION) && GCC_VERSION >= 50000 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" -#endif - //===================================================================================== // Test Helper Types. These are shared by several tests in VatesAPI //===================================================================================== @@ -195,7 +184,8 @@ Create a field data entry containing (as contents) the argument text. @param testData : Text to enter @return new vtkFieldData object containing text. */ -vtkFieldData *createFieldDataWithCharArray(std::string testData) { +GCC_UNUSED_FUNCTION vtkFieldData * +createFieldDataWithCharArray(std::string testData) { vtkFieldData *fieldData = vtkFieldData::New(); vtkCharArray *charArray = vtkCharArray::New(); charArray->SetName(Mantid::VATES::XMLDefinitions::metaDataId().c_str()); @@ -279,10 +269,11 @@ view. view. @return full xml as string. */ -std::string constructXML(const std::string &xDimensionIdMapping, - const std::string &yDimensionIdMapping, - const std::string &zDimensionIdMapping, - const std::string &tDimensionIdMapping) { +GCC_UNUSED_FUNCTION std::string +constructXML(const std::string &xDimensionIdMapping, + const std::string &yDimensionIdMapping, + const std::string &zDimensionIdMapping, + const std::string &tDimensionIdMapping) { return std::string("<?xml version=\"1.0\" encoding=\"utf-8\"?>") + "<MDInstruction>" + "<MDWorkspaceName>Input</MDWorkspaceName>" + "<MDWorkspaceLocation>test_horace_reader.sqw</MDWorkspaceLocation>" + @@ -376,7 +367,7 @@ view. view. @return full xml as string. */ -std::string +GCC_UNUSED_FUNCTION std::string constructXMLForMDEvHelperData(const std::string &xDimensionIdMapping, const std::string &yDimensionIdMapping, const std::string &zDimensionIdMapping, @@ -407,8 +398,8 @@ Mantid::API::Workspace_sptr createSimple3DWorkspace() { return outWs; } -Mantid::API::Workspace_sptr get3DWorkspace(bool integratedTDimension, - bool sliceMD) { +GCC_UNUSED_FUNCTION Mantid::API::Workspace_sptr +get3DWorkspace(bool integratedTDimension, bool sliceMD) { using namespace Mantid::API; using namespace Mantid::DataObjects; @@ -446,7 +437,8 @@ Mantid::API::Workspace_sptr get3DWorkspace(bool integratedTDimension, * @param fieldName : The requested field data entry * @return The value of the requested field data entry */ -std::string getStringFieldDataValue(vtkDataSet *ds, std::string fieldName) { +GCC_UNUSED_FUNCTION std::string getStringFieldDataValue(vtkDataSet *ds, + std::string fieldName) { vtkAbstractArray *value = ds->GetFieldData()->GetAbstractArray(fieldName.c_str()); vtkStringArray *array = vtkStringArray::SafeDownCast(value); @@ -455,12 +447,4 @@ std::string getStringFieldDataValue(vtkDataSet *ds, std::string fieldName) { } // namespace -#if __clang__ -#pragma clang diagnostic pop -#endif - -#if defined(GCC_VERSION) && GCC_VERSION >= 50000 -#pragma GCC diagnostic pop -#endif - #endif diff --git a/Vates/VatesAPI/test/vtkDataSetToNonOrthogonalDataSetTest.h b/Vates/VatesAPI/test/vtkDataSetToNonOrthogonalDataSetTest.h index 604d50192bc..658ef648a84 100644 --- a/Vates/VatesAPI/test/vtkDataSetToNonOrthogonalDataSetTest.h +++ b/Vates/VatesAPI/test/vtkDataSetToNonOrthogonalDataSetTest.h @@ -15,14 +15,14 @@ #include "MantidGeometry/MDGeometry/HKL.h" #include "MantidKernel/MDUnit.h" +#include "MantidVatesAPI/vtkRectilinearGrid_Silent.h" #include <vtkDataArray.h> #include <vtkFieldData.h> #include <vtkFloatArray.h> -#include <vtkPoints.h> -#include "MantidVatesAPI/vtkRectilinearGrid_Silent.h" -#include <vtkUnstructuredGrid.h> #include <vtkNew.h> +#include <vtkPoints.h> #include <vtkSmartPointer.h> +#include <vtkUnstructuredGrid.h> using namespace Mantid::API; using namespace Mantid::Kernel; @@ -125,12 +125,11 @@ private: return ds; } - template <typename T> - std::vector<T> getRangeComp(vtkDataSet *ds, std::string fieldname, int size) { - vtkDataArray *arr = ds->GetFieldData()->GetArray(fieldname.c_str()); - vtkTypedDataArray<T> *tarr = vtkTypedDataArray<T>::FastDownCast(arr); - std::vector<T> vals(size); - tarr->GetTupleValue(0, &vals[0]); + std::vector<double> getRangeComp(vtkDataSet *ds, const char *fieldname) { + vtkDataArray *arr = ds->GetFieldData()->GetArray(fieldname); + std::vector<double> vals(arr->GetNumberOfComponents()); + TS_ASSERT_EQUALS(vals.size(), 16); + arr->GetTuple(0, vals.data()); return vals; } @@ -146,8 +145,7 @@ private: TS_ASSERT_DELTA(point[2], 0.8660254, eps); // See if the basis vectors are available - std::vector<double> basisMatrix = - getRangeComp<double>(grid, "ChangeOfBasisMatrix", 16); + std::vector<double> basisMatrix = getRangeComp(grid, "ChangeOfBasisMatrix"); // Row by row check @@ -299,8 +297,7 @@ public: TS_ASSERT_DELTA(point[1], 1.0, eps); TS_ASSERT_DELTA(point[2], 1.0, eps); // See if the basis vectors are available - std::vector<double> basisMatrix = - getRangeComp<double>(ds, "ChangeOfBasisMatrix", 16); + std::vector<double> basisMatrix = getRangeComp(ds, "ChangeOfBasisMatrix"); // Row by row check @@ -361,8 +358,7 @@ public: TS_ASSERT_DELTA(point[1], 1.0, eps); TS_ASSERT_DELTA(point[2], 0.75592895, eps); // See if the basis vectors are available - std::vector<double> basisMatrix = - getRangeComp<double>(ds, "ChangeOfBasisMatrix", 16); + std::vector<double> basisMatrix = getRangeComp(ds, "ChangeOfBasisMatrix"); // Row by row check diff --git a/Vates/VatesAPI/test/vtkMDHWSignalArrayTest.h b/Vates/VatesAPI/test/vtkMDHWSignalArrayTest.h index 1af27a92019..014ec76ddf2 100644 --- a/Vates/VatesAPI/test/vtkMDHWSignalArrayTest.h +++ b/Vates/VatesAPI/test/vtkMDHWSignalArrayTest.h @@ -52,7 +52,7 @@ public: // test alternate member function. double output3[1]; - signal->GetTupleValue(index, output3); + signal->GetTypedTuple(index, output3); TS_ASSERT_DELTA(1.0, output3[0], 0.0001); // test alternate member function. @@ -97,8 +97,8 @@ public: for (auto idx = 0; idx < imageSize / 4; ++idx) { double output1[1], output2[1]; - signal->GetTupleValue(idx * 4, output1); - doubleArray->GetTupleValue(idx, output2); + signal->GetTypedTuple(idx * 4, output1); + doubleArray->GetTypedTuple(idx, output2); TS_ASSERT_DELTA(output1[0], output2[0], 0.0001); } } @@ -153,8 +153,8 @@ public: for (auto idx = 0; idx < 100; ++idx) { double output1[1], output2[1]; - signal->GetTupleValue(idx, output1); - doubleArray->GetTupleValue(idx, output2); + signal->GetTypedTuple(idx, output1); + doubleArray->GetTypedTuple(idx, output2); TS_ASSERT_DELTA(output1[0], output2[0], 0.0001); } } @@ -235,7 +235,7 @@ public: for (auto index = 0; index < imageSize; ++index) { // test member function. double output[1]; - m_signal->GetTupleValue(index, output); + m_signal->GetTypedTuple(index, output); TS_ASSERT_DELTA(0.25, output[0], 0.0001); } } diff --git a/Vates/VatesSimpleGui/StandAloneExec/CMakeLists.txt b/Vates/VatesSimpleGui/StandAloneExec/CMakeLists.txt index 2bdfc7277df..70bc8aaa8be 100644 --- a/Vates/VatesSimpleGui/StandAloneExec/CMakeLists.txt +++ b/Vates/VatesSimpleGui/StandAloneExec/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required( VERSION 2.8.12 ) +cmake_minimum_required( VERSION 3.5 ) project( VatesSimpleGui ) set( PROJECT_NAME VatesSimpleGui ) diff --git a/Vates/VatesSimpleGui/ViewWidgets/src/SaveScreenshotReaction.cpp b/Vates/VatesSimpleGui/ViewWidgets/src/SaveScreenshotReaction.cpp index fbb079c5ee3..b857e53c80f 100644 --- a/Vates/VatesSimpleGui/ViewWidgets/src/SaveScreenshotReaction.cpp +++ b/Vates/VatesSimpleGui/ViewWidgets/src/SaveScreenshotReaction.cpp @@ -4,6 +4,7 @@ #pragma warning disable 1170 #endif +#include "MantidVatesAPI/vtkImageData_Silent.h" #include <pqActiveObjects.h> #include <pqCoreUtilities.h> #include <pqFileDialog.h> @@ -12,14 +13,13 @@ #include <pqRenderViewBase.h> #include <pqSaveSnapshotDialog.h> #include <pqSettings.h> +#include <pqStereoModeHelper.h> #include <pqTabbedMultiViewWidget.h> #include <pqView.h> -#include "MantidVatesAPI/vtkImageData_Silent.h" +#include <vtkPVConfig.h> #include <vtkPVXMLElement.h> -#include <vtkSmartPointer.h> #include <vtkSMSessionProxyManager.h> -#include <vtkPVConfig.h> - +#include <vtkSmartPointer.h> #if defined(__INTEL_COMPILER) #pragma warning enable 1170 #endif @@ -113,10 +113,10 @@ void SaveScreenshotReaction::saveScreenshot() { colorPalette->Copy(chosenPalette); } + // temporarily set stereo mode from dialog. int stereo = ssDialog.getStereoMode(); - if (stereo) { - pqRenderViewBase::setStereo(stereo); - } + pqStereoModeHelper setStereo(stereo, + pqActiveObjects::instance().activeServer()); SaveScreenshotReaction::saveScreenshot(file, size, ssDialog.quality()); @@ -125,11 +125,6 @@ void SaveScreenshotReaction::saveScreenshot() { colorPalette->Copy(clone); } - // restore stereo - if (stereo) { - pqRenderViewBase::setStereo(0); - } - // check if need to render to clear the changes we did // while saving the screenshot. if (clone || stereo) { diff --git a/buildconfig/CMake/Bootstrap.cmake b/buildconfig/CMake/Bootstrap.cmake index 47c96300205..567e9fb3c8d 100644 --- a/buildconfig/CMake/Bootstrap.cmake +++ b/buildconfig/CMake/Bootstrap.cmake @@ -10,7 +10,7 @@ if( MSVC ) include ( ExternalProject ) set( EXTERNAL_ROOT ${PROJECT_SOURCE_DIR}/external ) set( THIRD_PARTY_GIT_URL "https://github.com/mantidproject/thirdparty-msvc2015.git" ) - set ( THIRD_PARTY_GIT_SHA1 988f1be53a5dbbac30afb5ed11320862d06627aa ) + set ( THIRD_PARTY_GIT_SHA1 ed449e33b8a40bfc56c8d3a886ce2aeb4660d071 ) set ( THIRD_PARTY_DIR ${EXTERNAL_ROOT}/src/ThirdParty ) # Generates a script to do the clone/update in tmp set ( _project_name ThirdParty ) diff --git a/buildconfig/CMake/CommonSetup.cmake b/buildconfig/CMake/CommonSetup.cmake index 2548b60c993..3a38ccc220f 100644 --- a/buildconfig/CMake/CommonSetup.cmake +++ b/buildconfig/CMake/CommonSetup.cmake @@ -247,7 +247,7 @@ endif () ########################################################################### if ( CMAKE_COMPILER_IS_GNUCXX ) include ( GNUSetup ) -elseif ( ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" ) +elseif ( ${CMAKE_CXX_COMPILER_ID} MATCHES "Clang" ) include ( GNUSetup ) endif () @@ -311,6 +311,13 @@ if ( CXXTEST_FOUND OR PYUNITTEST_FOUND ) include( SetupDataTargets ) endif() +########################################################################### +# Visibility Setting +########################################################################### +if ( CMAKE_COMPILER_IS_GNUCXX ) + set(CMAKE_CXX_VISIBILITY_PRESET hidden CACHE STRING "") +endif() + ########################################################################### # Set a flag to indicate that this script has been called ########################################################################### diff --git a/buildconfig/CMake/Coveralls.cmake b/buildconfig/CMake/Coveralls.cmake index b6a93eb5f59..73b163d0b48 100644 --- a/buildconfig/CMake/Coveralls.cmake +++ b/buildconfig/CMake/Coveralls.cmake @@ -109,7 +109,7 @@ endfunction() macro(coveralls_turn_on_coverage) if(NOT (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) - AND (NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")) + AND (NOT "${CMAKE_C_COMPILER_ID}" MATCHES "Clang")) message(FATAL_ERROR "Coveralls: Compiler ${CMAKE_C_COMPILER_ID} is not GNU gcc! Aborting... You can set this on the command line using CC=/usr/bin/gcc CXX=/usr/bin/g++ cmake <options> ..") endif() diff --git a/buildconfig/CMake/GNUSetup.cmake b/buildconfig/CMake/GNUSetup.cmake index a1d3722f87e..c1cf0e4452e 100644 --- a/buildconfig/CMake/GNUSetup.cmake +++ b/buildconfig/CMake/GNUSetup.cmake @@ -17,7 +17,7 @@ if ( CMAKE_COMPILER_IS_GNUCXX ) add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) endif() endif() -elseif ( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) +elseif ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) message( STATUS "clang version ${CMAKE_CXX_COMPILER_VERSION}" ) endif() @@ -36,7 +36,7 @@ if ( CMAKE_COMPILER_IS_GNUCXX ) if (NOT (GCC_COMPILER_VERSION VERSION_LESS "4.5")) set(GNUFLAGS "${GNUFLAGS} -Wno-unused-result -pedantic") endif () -elseif ( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) +elseif ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) set(GNUFLAGS "${GNUFLAGS} -Wno-sign-conversion") endif() @@ -80,19 +80,8 @@ set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GNUFLAGS}" ) # -Wno-overloaded-virtual is down here because it's not applicable to the C_FLAGS set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GNUFLAGS} -Woverloaded-virtual -fno-operator-names" ) -if(${CMAKE_VERSION} VERSION_GREATER 3.1.0 OR ${CMAKE_VERSION} VERSION_EQUAL 3.1.0) - set(CMAKE_CXX_STANDARD 14) - set(CMAKE_CXX_STANDARD_REQUIRED 11) -else() - include(CheckCXXCompilerFlag) - CHECK_CXX_COMPILER_FLAG("-std=c++14" COMPILER_SUPPORTS_CXX14) - CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) - if(COMPILER_SUPPORTS_CXX14) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") - elseif(COMPILER_SUPPORTS_CXX11) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - endif() -endif() +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED 11) # XCode isn't picking up the standard set above. if(CMAKE_GENERATOR STREQUAL Xcode) diff --git a/buildconfig/CMake/LinuxPackageScripts.cmake b/buildconfig/CMake/LinuxPackageScripts.cmake index 837ce4b3a73..7bfefbfd0f4 100644 --- a/buildconfig/CMake/LinuxPackageScripts.cmake +++ b/buildconfig/CMake/LinuxPackageScripts.cmake @@ -148,7 +148,7 @@ execute_process ( COMMAND "chmod" "+x" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/mantid OUTPUT_QUIET ERROR_QUIET ) # Package version -set ( EXTRA_LDPATH "\${INSTALLDIR}/../lib/paraview-5.0" ) +set ( EXTRA_LDPATH "\${INSTALLDIR}/../lib/paraview-5.1" ) set ( MANTIDPLOT_EXEC MantidPlot_exe ) configure_file ( ${CMAKE_MODULE_PATH}/Packaging/launch_mantidplot.sh.in ${CMAKE_CURRENT_BINARY_DIR}/launch_mantidplot.sh.install @ONLY ) diff --git a/buildconfig/CMake/ParaViewSetup.cmake b/buildconfig/CMake/ParaViewSetup.cmake index f3c05b2df7b..c74702f3298 100644 --- a/buildconfig/CMake/ParaViewSetup.cmake +++ b/buildconfig/CMake/ParaViewSetup.cmake @@ -1,7 +1,7 @@ # This file will setup some common items that later setups depend on # Set the version of ParaView that is compatible with the Mantid code base -set ( COMPATIBLE_PARAVIEW_VERSION "5.0.0" ) +set ( COMPATIBLE_PARAVIEW_VERSION "5.1.0" ) # Set the name of the OSX application as this tends to be different set ( OSX_PARAVIEW_APP "paraview.app" ) diff --git a/buildconfig/CMake/SquishTestScript.cmake b/buildconfig/CMake/SquishTestScript.cmake index 9c84a97cea4..b6258ec2c88 100644 --- a/buildconfig/CMake/SquishTestScript.cmake +++ b/buildconfig/CMake/SquishTestScript.cmake @@ -10,7 +10,7 @@ # # Based on the SQUISH_ADD_TEST macro # -cmake_minimum_required(VERSION 2.6 FATAL_ERROR) +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) message(STATUS "squish_server_executable='${squish_server_executable}'") message(STATUS "squish_aut='${squish_aut}'") diff --git a/buildconfig/Jenkins/buildscript b/buildconfig/Jenkins/buildscript index 8f82a01cfe2..1d11d37cc30 100755 --- a/buildconfig/Jenkins/buildscript +++ b/buildconfig/Jenkins/buildscript @@ -14,9 +14,9 @@ SCRIPT_DIR=$(dirname "$0") BUILDPKG=true ############################################################################### -# All node currently have PARAVIEW_DIR=4.3.b40280 and PARAVIEW_NEXT_DIR=4.3.1 +# All node currently have PARAVIEW_DIR=5.1.0 and PARAVIEW_NEXT_DIR=5.0.0 ############################################################################### -export PARAVIEW_DIR=${PARAVIEW_NEXT_DIR} +#export PARAVIEW_DIR=${PARAVIEW_NEXT_DIR} ############################################################################### # Print out the versions of things we are using diff --git a/buildconfig/Jenkins/buildscript.bat b/buildconfig/Jenkins/buildscript.bat index 2654b589cff..da8a9cbaeeb 100755 --- a/buildconfig/Jenkins/buildscript.bat +++ b/buildconfig/Jenkins/buildscript.bat @@ -8,7 +8,7 @@ setlocal enableextensions enabledelayedexpansion :: BUILD_THREADS & PARAVIEW_DIR should be set in the configuration of each slave. :: CMake, git & git-lfs should be on the PATH :: -:: All nodes currently have PARAVIEW_DIR=4.3.b40280, PARAVIEW_NEXT_DIR=5.0.0 +:: All nodes currently have PARAVIEW_DIR=5.1.0, PARAVIEW_NEXT_DIR=5.0.0 :: and PARAVIEW_MSVC2015_DIR=4.3.b40280-msvc2015 ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: call cmake.exe --version @@ -28,7 +28,7 @@ echo %sha1% set VS_VERSION=14 call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" amd64 set CM_GENERATOR=Visual Studio 14 2015 Win64 -set PARAVIEW_DIR=%PARAVIEW_NEXT_DIR% +:: set PARAVIEW_DIR=%PARAVIEW_NEXT_DIR% ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: Set up the location for local object store outside of the build and source diff --git a/buildconfig/Jenkins/doctests b/buildconfig/Jenkins/doctests index 66635fa927e..8a758fa3f4d 100755 --- a/buildconfig/Jenkins/doctests +++ b/buildconfig/Jenkins/doctests @@ -46,8 +46,9 @@ fi ############################################################################### # Create the build directory if it doesn't exist ############################################################################### -[ -d $WORKSPACE/build ] || mkdir $WORKSPACE/build -cd $WORKSPACE/build +BUILD_DIR=$WORKSPACE/build +[ -d $BUILD_DIR ] || mkdir $BUILD_DIR +cd $BUILD_DIR ############################################################################### # CMake configuration. We only need a minimal configuration as we will actually @@ -79,11 +80,16 @@ fi ##################################################################################### # Run tests ##################################################################################### +# Remove doctrees directory so it forces a full reparse. This will then pick up all +# reference warnings +if [ -d $BUILD_DIR/docs/doctrees ]; then + rm -rf $BUILD_DIR/docs/doctrees/* +fi # Create clean user properties with UsageData search path userprops=~/.mantid/Mantid.user.properties rm -f $userprops -data_binary_root=${WORKSPACE}/build/ExternalData +data_binary_root=$BUILD_DIR/ExternalData testdata_dir=${data_binary_root}/Testing/Data instrument_dir=${WORKSPACE}/instrument echo "datasearch.directories=${testdata_dir}/DocTest;${testdata_dir}/UnitTest;${instrument_dir}" > $userprops @@ -91,7 +97,8 @@ echo "UpdateInstrumentDefinitions.OnStartup = 0" >> $userprops echo "usagereports.enabled = 0" >> $userprops set +e #don't immediately exit on failure so that we can remove the package -${MANTIDPLOT_EXE} -xq docs/runsphinx_doctest.py +$SCL_ON_RHEL6 "bin/MantidPlot -xq docs/runsphinx_html.py" +$SCL_ON_RHEL6 "bin/MantidPlot -xq docs/runsphinx_doctest.py" status=$? set -e #exit on failures from now on diff --git a/buildconfig/Jenkins/pylint-buildscript b/buildconfig/Jenkins/pylint-buildscript index 397eb648693..ab01d46b956 100755 --- a/buildconfig/Jenkins/pylint-buildscript +++ b/buildconfig/Jenkins/pylint-buildscript @@ -8,6 +8,10 @@ if [ -z "$BUILD_DIR" ]; then exit 1 fi PYLINT_OUTPUT_DIR=$BUILD_DIR/pylint +############################################################################### +# Purge old logs +############################################################################### +rm -f $PYLINT_OUTPUT_DIR/PYLINT-* ############################################################################### # Check if python files have changed @@ -29,11 +33,6 @@ then fi echo "running pylint" -############################################################################### -# Purge old logs -############################################################################### -rm -f $BUILD_DIR/pylint/PYLINT-* - ############################################################################### # Print out the versions of things we are using ############################################################################### diff --git a/docs/source/algorithms/BASISReduction311-v1.rst b/docs/source/algorithms/BASISReduction311-v1.rst new file mode 100644 index 00000000000..430fb2017b6 --- /dev/null +++ b/docs/source/algorithms/BASISReduction311-v1.rst @@ -0,0 +1,68 @@ +.. algorithm:: + +.. summary:: + +.. alias:: + +.. properties:: + +For each property, the algorithm will remember the last value used. If user deletes +this value and leaves blank the property field, the default value will be used. Default +values are typical of the silicon311 reflection. + +Description +----------- + +**Run numbers**: +The syntax for the run numbers designation allows runs to be segregated +into sets. The semicolon symbol ";" is used to separate the runs into sets. +Runs within each set are jointly reduced. + +Examples: + +- 2144-2147,2149,2156 is a single set. All runs jointly reduced. + +- 2144-2147,2149;2156 is set 2144-2147,2149 and set 2156. The sets are reduced separately from each other. + +If *DoIndividual* is checked, then each run number is reduced separately +from the rest. The semicolon symbol is ignored. + +**Momentum transfer binning scheme**: Three values are required, the +lower boundary the bin with the minimum momentum, the bin width, and the +upper boundary ofthe bin with the maximum momentum. + +Reflection Selector +=================== + +There are typical values for the properties of the 311 reflection: + ++------------+----------------+------------------------+ +| Reflection | Energy bins | Momentum transfer bins | +| | (micro-eV) | (inverse Angstroms) | ++============+================+========================+ +| silicon311 | -740, 1.6, 740 | 0.5, 0.2, 3.7 | ++------------+----------------+------------------------+ + +Also the following mask files is associated to the 311 reflection: + ++-----------+------------------------------------------------------------------------------------------------+ +|Reflection | Mask file | ++===========+================================================================================================+ +|silicon311 | BASIS_Mask_OneQuarterRemains_SouthBottom.xml | ++-----------+------------------------------------------------------------------------------------------------+ + +This mask files can be found in the SNS filesystem +(**/SNS/BSS/shared/autoreduce/new_masks_08_12_2015/**) + + +Usage +----- + +.. warning:: + + This algorithm is not meant to be run from the command line. + +.. categories:: + +.. sourcelink:: + diff --git a/docs/source/algorithms/CropToComponent-v1.rst b/docs/source/algorithms/CropToComponent-v1.rst new file mode 100644 index 00000000000..dd58e21b903 --- /dev/null +++ b/docs/source/algorithms/CropToComponent-v1.rst @@ -0,0 +1,50 @@ + +.. algorithm:: + +.. summary:: + +.. alias:: + +.. properties:: + +Description +----------- + +This algorithm takes a list of component names and an input workspaces and produces an output workspace which only contains the detectors which are part of the specified components. If no components are specified then the full workspace is returned. + +The workspace allows users to select a specific bank for exclusive investigation in subsequent operations. + +Workflow +######## + +.. diagram:: AccumulateMD-v1_wkflw.dot + +Usage +----- + +**Example - CropToComponent** + +.. testcode:: CropToComponentExample + + # Create sample workspace with four banks where each bank has 3x3 detectors + sample_workspace = CreateSampleWorkspace(NumBanks=4, BankPixelWidth=3) + + # Crop to a component, we select bank2 here + cropped_workspace = CropToComponent(InputWorkspace=sample_workspace, ComponentNames="bank2") + + # Check the number of histograms + sample_number_of_histograms = sample_workspace.getNumberHistograms() + cropped_number_of_histograms = cropped_workspace.getNumberHistograms() + + print("The original workspace has {0} histograms and the cropped workspace has {1} histograms.".format(sample_number_of_histograms, cropped_number_of_histograms)) + +Output: + +.. testoutput:: CropToComponentExample + + The original workspace has 36 histograms and the cropped workspace has 9 histograms. + +.. categories:: + +.. sourcelink:: + diff --git a/docs/source/algorithms/ExportSpectraMask-v1.rst b/docs/source/algorithms/ExportSpectraMask-v1.rst new file mode 100644 index 00000000000..92b65de4497 --- /dev/null +++ b/docs/source/algorithms/ExportSpectraMask-v1.rst @@ -0,0 +1,65 @@ +.. algorithm:: + +.. summary:: + +.. alias:: + +.. properties:: + +Description +----------- + +The algorithm extracts list of the spectra numbers which are masked on the input workspace and, +if requested, saves these spectra as legacy *.msk* file in ISIS ASCII format. + +The format is described on :ref:`LoadMask <algm-LoadMask>` algorithm pages. + +**Note** It is not recommended to use exported *.msk* files for masking workspaces during reduction as +the result of applying such mask will be different depending on the stage of reduction of the source and target files. +You need to make additional efforts (see :ref:`LoadMask <algm-LoadMask>` algorithm description) to avoid this effect. +It is better to use :ref:`SaveMask <algm-SaveMask>` algorithm instead. This algorithm produces *.xml* files, +containing lists of masked detectors, which will produce identical masking regardless of the workspace grouping and +spectra-detector map, defined for data acquisition electronics during experiment. + +Usage +----- + +**Example: Export Spectra Masks** + +.. testcode:: ExExportSpectraMask + + import sys + #prepare the data: + masks = [1,4,8,10,11,12,12,198,199,200] + test_ws = CreateSampleWorkspace() + test_ws.maskDetectors(masks) + + f_name = 'test_ws_mask.msk' + + #extract mask: + r_masks = ExportSpectraMask(test_ws,Filename=f_name) + + # Compare results: + wmsk = '' + final_fname = os.path.join(config.getString('defaultsave.directory'),f_name) + with open(final_fname,'r') as res_file: + for line in res_file: + wmsk = line + os.remove(final_fname) + + sys.stdout.write("Input mask: {0}\n".format(masks)) + sys.stdout.write("Extracted mask: {0}\n".format(r_masks)) + sys.stdout.write("Saved mask: {0}".format(wmsk)) + + +Output: + +.. testoutput:: ExExportSpectraMask + + Input mask: [1, 4, 8, 10, 11, 12, 12, 198, 199, 200] + Extracted mask: [ 1 4 8 10 11 12 198 199 200] + Saved mask: 1 4 8 10-12 198-200 + +.. categories:: + +.. sourcelink:: diff --git a/docs/source/algorithms/IntegratePeaksMDHKL-v1.rst b/docs/source/algorithms/IntegratePeaksMDHKL-v1.rst new file mode 100644 index 00000000000..e92e4980063 --- /dev/null +++ b/docs/source/algorithms/IntegratePeaksMDHKL-v1.rst @@ -0,0 +1,103 @@ + +.. algorithm:: + +.. summary:: + +.. alias:: + +.. properties:: + +Description +----------- + +:ref:`IntegratePeaksMDHKL <algm-IntegratePeaksMDHKL>` provides integration of a +:ref:`MDHistoWorkspace <MDHistoWorkspace>` or :ref:`MDEventWorkspace <MDWorkspace>` in 3-dimensions. +The units of the workspace must be HKL. The main usage will be for data normalized by +:ref:`MDNormSCD <algm-MDNormSCD>`. +A 3D box is created for each peak and the background and peak data are separated. The intensity and sigma of the +intensity is found from the grid inside the peak and the background is subtracted. The boxes are created and integrated +in parallel and less memory is required than binning all HKL at once. + +:math:`I_{corr} = I_{peak} - pts_{peak}/pts_{bg} * I_{bg}` + +with the errors summed in quadrature: + +:math:`\sigma_{I,corr}^2 = \sigma_{I,peak}^2 + pts_{peak}/pts_{bg} * \sigma_{I,bg}^2` + +Using the DeltaHKL parameter, the problem of nearly peaks or regions of diffuse scattering can be avoided. Also for +normalized data, the unmeasured data points are excluded from the background. See white regions in last figure. + +.. figure:: /images/peak3d.png + :alt: peak3d.png + :width: 400px + :align: center + + Peak Integration Input. 3D Box. + +.. figure:: /images/IntegratePeaksMDHKLbox.png + :alt: IntegratePeaksMDHKLbox.png + :width: 400px + :align: center + + Integration slice at center of box. + +.. figure:: /images/IntegratePeaksMDHKLpeak.png + :alt: IntegratePeaksMDHKLpeak.png + :width: 400px + :align: center + + Integration slice of peak grid points. + +.. figure:: /images/IntegratePeaksMDHKLbkg.png + :alt: IntegratePeaksMDHKLbkg.png + :width: 400px + :align: center + + Integration slice of background grid points. + + +Usage +----- + +**Example - IntegratePeaksMDHKL event histo** + +.. testcode:: IntegratePeaksMDHKLExample + + #Create PeaksWorkspace + sampleWs = CreateSampleWorkspace() + pws = CreatePeaksWorkspace(InstrumentWorkspace=sampleWs,NumberOfPeaks=3) + p = pws.getPeak(0) + p.setHKL(5,0,0) + p = pws.getPeak(1) + p.setHKL(0,0,0) + p = pws.getPeak(2) + p.setHKL(-5,0,0) + #Test with MDEventWorkspace + mdws = CreateMDWorkspace(Dimensions=3, Extents=[-10,10,-10,10,-10,10], Names='[H,0,0],[0,K,0],[0,0,L]',Units='A^-1,A^-1,A^-1',Frames='HKL,HKL,HKL') + FakeMDEventData(InputWorkspace=mdws, PeakParams=[100000,-5,0,0,1]) + FakeMDEventData(InputWorkspace=mdws, PeakParams=[100000,0,0,0,1]) + FakeMDEventData(InputWorkspace=mdws, PeakParams=[100000,5,0,0,1]) + pws =IntegratePeaksMDHKL(InputWorkspace=mdws,PeaksWorkspace=pws,DeltaHKL=1.5,GridPoints=21) + for i in range(3): + p = pws.getPeak(i) + print p.getIntensity(),p.getSigmaIntensity() + #Test with MDHistoWorkspace + mdws = BinMD(InputWorkspace=mdws,AlignedDim0="[H,0,0],-10,10,101",AlignedDim1="[0,K,0],-10,10,101",AlignedDim2="[0,0,L],-10,10,101") + pws =IntegratePeaksMDHKL(InputWorkspace=mdws,PeaksWorkspace=pws,DeltaHKL=1.5,GridPoints=21) + for i in range(3): + p = pws.getPeak(i) + print p.getIntensity(),p.getSigmaIntensity() + + +Output: + +.. testoutput:: IntegratePeaksMDHKLExample + + 99913.3212993 316.143446399 + 99913.3212993 316.143446399 + 99913.3212993 316.143446399 + 99945.2374619 316.168987268 + 99951.6716018 316.174385251 + 99926.3456269 316.148488307 + + diff --git a/docs/source/algorithms/LoadPreNexusLive-v1.rst b/docs/source/algorithms/LoadPreNexusLive-v1.rst new file mode 100644 index 00000000000..674c3b5a99d --- /dev/null +++ b/docs/source/algorithms/LoadPreNexusLive-v1.rst @@ -0,0 +1,32 @@ + +.. algorithm:: + +.. summary:: + +.. alias:: + +.. properties:: + +Description +----------- + +This loads a 'live' file that is periodically saved by the legacy DAS +at SNS. If the ``LoadLogs`` option is specified, it will attempt to +load logs from the most recent saved run. Specifying ``LogFilename`` +will turn off the search capability. + +.. warning:: + + This only works at ORNL. + +Usage +----- + +.. code-block:: python + + LoadPreNexusLive(Instrument='SNAP', OutputWorkspace='SNAP_live') + + +.. categories:: + +.. sourcelink:: diff --git a/docs/source/algorithms/ReplicateMD-v1.rst b/docs/source/algorithms/ReplicateMD-v1.rst index 02ce3ab7841..cb2f2b631b4 100644 --- a/docs/source/algorithms/ReplicateMD-v1.rst +++ b/docs/source/algorithms/ReplicateMD-v1.rst @@ -27,8 +27,8 @@ Usage .. testcode:: ReplicateMDExample1D import numpy as np - data = CreateMDHistoWorkspace(1, SignalInput=np.arange(100), ErrorInput=np.arange(100), NumberOfEvents=np.arange(100), Extents=[-10, 10], NumberOfBins=[100], Names='E', Units='MeV') - shape = CreateMDHistoWorkspace(2, SignalInput=np.tile([1], 10000), ErrorInput=np.tile([1], 10000), NumberOfEvents=np.tile([1], 10000), Extents=[-1,1, -10, 10], NumberOfBins=[100,100], Names='Q,E', Units='A^-1, MeV') + data = CreateMDHistoWorkspace(2, SignalInput=np.arange(20*30), ErrorInput=np.arange(20*30), NumberOfEvents=np.arange(20*30), Extents=[-10, 10, -1,1], NumberOfBins=[20, 30], Names='E,Qx', Units='MeV,A^-1') + shape = CreateMDHistoWorkspace(3, SignalInput=np.tile([1], 20*30*10), ErrorInput=np.tile([1], 20*30*10), NumberOfEvents=np.tile([1], 20*30*10), Extents=[-1,1, -10, 10, -10,10], NumberOfBins=[30,20,10], Names='Qx,E,Qy', Units='A^-1, MeV, A^-1') replicated = ReplicateMD(ShapeWorkspace=shape, DataWorkspace=data) @@ -39,8 +39,8 @@ Output: .. testoutput:: ReplicateMDExample1D - Num dims: 2 - Num points: 10000 + Num dims: 3 + Num points: 6000 .. categories:: diff --git a/docs/source/concepts/HistogramData.rst b/docs/source/concepts/HistogramData.rst index 7e1a154c05d..7aa4975ebcd 100644 --- a/docs/source/concepts/HistogramData.rst +++ b/docs/source/concepts/HistogramData.rst @@ -86,7 +86,7 @@ In its final form, we will be able to do things like the following (things not i .. code-block:: c++ :linenos: - BinEdges edges{1.0, 2.0, 4.0}; + BinEdges edges{1.0, 2.0, 4.0, 8.0}; Counts counts1{4, 100, 4}; Counts counts2{0, 100, 0}; Histogram histogram1(edges, counts1); @@ -111,7 +111,7 @@ In its final form, we will be able to do things like the following (things not i errors[1]; // sqrt(200.0) errors[2]; // 2.0 - // Need bin centers (points data) instead of bin edges? + // Need bin centers (point data) instead of bin edges? auto points = histogram.points(); // Need variance instead of standard deviation? auto variances = histogram.countVariances(); @@ -131,7 +131,7 @@ Further planned features: - Arithmetics will all sub-types (``BinEdges``, ``Points``, ``Counts``, and ``Frequencies``, and also their respective ``Variances`` and ``StandardDeviations``). - Generating bin edges (linear, logarithmic, ...). - Extend the ``Histogram`` interface with more common operations. -- Non-member functions for more complex operations on histogram such as rebinning. +- Non-member functions for more complex operations on histograms such as rebinning. - Validation of data, e.g., non-zero bin widths and positivity of uncertainties. **Any feedback on additional capabilities of the new data types is highly appreciated. @@ -386,7 +386,7 @@ Working with bin edges and counts ///////////////////////////////////////////////////// BinEdges edges = {1.0, 2.0, 4.0}; if(edges.cbegin() != edges.cend()) - *(edges.begin()) += 2.0; + *(edges.begin()) += 0.1; // Range-based for works thanks to iterators: for (auto &edge : edges) edge += 0.1; @@ -400,7 +400,7 @@ Working with bin edges and counts edges[2]; // 4.0 // Only const! This is not possible: - edges[0] += 2.0; // DOES NOT COMPILE + edges[0] += 0.1; // DOES NOT COMPILE // REASON: BinEdges contains a copy-on-write pointer to data, dereferencing in // tight loop is expensive, so interface prevents things like this: @@ -509,7 +509,7 @@ Working with the new ``MatrixWorkspace`` interface // Preserve sharing outputWS->setSharedY(i, inputWS->sharedY(i)); outputWS->setCounts(i, inputWS->counts(i)); // also shares, 'Counts' wraps a cow_ptr - outputWS->setBinEdges(i, inputWS->binEdges(i)); + outputWS->setBinEdges(i, inputWS->binEdges(i)); // shares if input storage mode is 'XMode::BinEdges' @@ -571,7 +571,7 @@ There are two issues you might encounter when implementing new algorithms or whe This happens rarely, typically by creating a workspace that contains histogram data (bin edges) and modifying the size via the legacy interface to store point data (or vice versa). These size modifications are only possible via the legacy interface. The best solution is to determine the storage mode at creation time of the workspace, by specifying the correct length of the X data. - If that is not possible, use the new setters such as `setBinEdges()`, they will trigger a conversion of the internal storage mode (not yet available in Python). + If that is not possible, use the new setters such as ``setBinEdges()``, they will trigger a conversion of the internal storage mode (not yet available in Python). diff --git a/docs/source/images/IntegratePeaksMDHKLbkg.png b/docs/source/images/IntegratePeaksMDHKLbkg.png new file mode 100644 index 0000000000000000000000000000000000000000..ccd1b56e3e6e287d79a8da5a49262ca1a0e9c4a9 GIT binary patch literal 18380 zcmch<cT`hdw>}y~1RLOsh#*Y?d8JAhkfJCUdhbo?9Ssoa2qKCg9i#@N_ue}yy+i1s zNN))p>A$t{{l4>!bI!fv-uuUO42L8nd#^p$T(dmSGyS9}FLnJ2)fE^Fb{+oWnKBG^ z0SSZQ%@bV$??eTRm4kmSBA&ukiNGH>BIA$X^=11PS_l~I+A8!HZ+_@mKMY0>gFkzs z`ZjJIgLG3>J3ZUn_X-b&B{36u(^v5O-<!r(W$X}1Q+N=uC92}#kx!Jed5e?cJqf;7 ztMNMZQ{y38?IzKMdx`z37y4EI`Ua1iqU-$887#ElJyFS%zc|Z9!j0&u-JftJ{5^+= z`M&HRL;w~tj(9{}B^la{60>vE1FsDmy5ohJ;J$2mgy5CzGkfq4=~E&sc=42|kp>16 zC%RjK4}%fiy$Bu>cK7`>F<AL~(g{2m>^-TsFbw8J`t(1))XJx>L9bakY=#e`zgc35 zW|^{Ti>fV)>sb^$`!0yu_Z4gf-zEK}U219KNKPtljNLLs8+^P+OnV(RqGn_EfpNJY zxqxX=0g-k`*z58c0pDk<<oE2cZezpC4lBF9pG%xq`30$oF?7S)?ykGx-)CAkb#3bs zc*04afW;&hfnTr7%MPwl4lu!unu9dvM{fTtwT`xNMv6!AwO%#j?YI<u?~7II7@k)b zjnmCCHY+p#dzbX@kJK6Yx$Lhcef=u!|0y$NQp9y>9qIHHvGGv+CV1G#TGTYu!X8fr zhVtSMPMft$9gcs$zG`L6c@e2~dzo&UwaCFMojb2inqn<(7e@a8XWAck+EeRxP;^fw zyw#14k}@;ABT6n;=Wm80V8{gjSj24uvimn~+>n-sD=jOhGQ!*1+E{MfcqyOS1arr- zO=C5rhKMW12&7&XIeDSkun3LXF-IYX-}Vbf5>j6>fB_e%A76uZ!Yi@A#zKW%w@4KZ zPmc(9(7qbQrq;0_$5YP3!jDY(a^a&a4Xoi7+bJ$fZdF|<B0L38;)A|3uwbrENo%3o zkYUdW;!zJ$s^p&seMC*XyE>qAa=6p&RE?az)%{M_i3oeaD*!kI(amqb1*Si}%Pf<$ zUnDeMA;rGZL!jed4YC?491ECQ1w;ZzBf9&NCN@?iTu770$wyZ!T+3LAl-_s^rhu$C zrI|E|s=w2CFh#lbAcqdMzeKgrg$EOVNlP<A7eoSs{q{xnzkeWe!DqVrV&fR~sw9F9 z#t>5(bCc=8-PSXa%R>ta1}iGVj_j_v6}Q49JO1j_VyH;|3pnoEXM|<Vvpn=8JWepf z4~9KMCgj$X!VGL}BX=1|<AK=~&Og9PU*rfQt+935RXOs{iQ;;mlLreh{LARvnZdy( z<!&8`e!tW(^wtdqYfyQe%?e{Mk0c=Vh@;fdhmm?i9t=~smQlb54#13`hgN~6jmE-n z`vMP&PsG-NrdsD0vL=R!dlA?)cL)CaO7GF+UN@dlOt|kIP-xdW#S_yCrGzrcWHqku z?wX?}S;%POXGNzxkgD6a*m_U%iCMUd-n;BCC8@K=5Ecx19aL2w&gER&o7%vGJz-k% zt}a~_$dITeRLi%eA!kv2u{t%9vAM~)oO+qlROj@F&ZC#dsCg;G^Hk-GRzy0A(_m=z zD#Z=3_-WR#Z$754Z5~fDTaOxdzYEDuyo$ZAK#kk1Q#snxE_KrTG9SfekdzlMoVi@P z{~}ac^7*oXg2-|Y%e~J}^49v<ie%Clj0hXJ?>{HJh!`TOn&!wJ98|467}CkoD3||Y zvd4&3n;+41bgoG6@9!V1n2D!)oLK+u9s|Cn3b4*JX-Q+eaKs%Nnp}<h_2EX9D9?lE z@N@+$Y&JNyJd2%ZE5zb*+f2~nTUi(^_;X?)aWGw^SX~aD#?X#UQ>2_U9Nt$Yz;C%# zVi6<sKy>`%GX-bfyCBhT{i!lCp_le?>2>&*Omz73cOEtxH1<(nh28zwS5#)|Y#*i5 zp!V(AWk<^?d8;A2)<W69)$ERC2h%#_f+p}G`W*ty74prn^ratdVbTf;!wO>YXz!mg zs^#4_(c`tnR=F_(!&ck+!#_V$IBx!W-W9{6f#kEiy<~|GdpbeWeGM~1_3YMG9@mEV zyf>DM*LF~G_I~r~k2aiInrsOb#yMRwh&sgR0Bq^%PBhPouwn4&?^zN)+Yv?lLlLS5 zDts8}D{l@V@h2BCvsQ2Rr_giQ`o#*7YSRgQ5~N1HU-eP3HXhI5uFj0ZVNtZH&uW6x zbi##)h7@NX8t!{@K*9PJ>nleB!;6i2!FP?!M7f>B?GgJ%3_Q1<`RnN6-M-;~&jOCZ zv@kak)}+p=(QJN)l0hb<@aoe}gqfA`pU@vIOn;FVVUqY)tJh5;N?};iM=0>Wy(d(_ zM@vVVa;2XxARu1wG}2`ET~K8@kr_BwlBhq~z}ohndX!i663MN%#;Y(2$&N89D3NSD zb1<~x?YIEtjaLXVXiN4~hS8~}oM#`-KK=WMz!Ag)Y<Yn#M<C{R3O;=E93&SaE913e zKf`XSoyzl6^fJD3Tb=?Rb|Gkf+gnjnig1r&D5ytRPqqMLuQiSwA7Pl+Zqr?(Mg6gE zelim>nh`1}uDoUWV-^}1y*2M^lU`9G`%7K?l)~>XLV0XDvjRGuAk9rPgNXG_%h<+S zGLgs0iyX>^Ud-R{b!Ip5yimb~J~q#9j|g;?Xg5gZD1u0Eo-bd7RtfS9cA=%N!3+(~ zA5%e6vZJ5PN)TK;G$n$6mCh9HW<sP_syCJS-7Vb^0VUK1GFH`*Kjsnd$f^Zrvw$ha zNTP=(&$LhPmWWP_(G8aK+xt0yAS40(_@pr_fF@7U-psBOah|L}G!o|+t2lgT!_AdF z7i4t7^bp-pCz;mjbDnBp?}H0ECqNc8awLb1yca71#=Np%mnXZ}G9f^3(8OIKGg9<m zyyx;Es0PG+F}^0i;sqqg=DY}2pYp(K2~#&FM(?=)%PnByc@yrFj8;drz+>V%F6{;K z=ib^NKi^^T;vDD^U~fzqb%uXL>>9Bf(%b)8KJUMl?;+9Loxq_5{IJRVPn-m|+t9jW zCb^(p3G>G90@<+vKiOnGu=7v#0UmN=Gz~`l)qKJ7RL(H?!&Ee%_K<7WUfhtAU*-AL z35#P)E-&Offfh~x-2L>tJRy-BiuBzD9~fz;*Qn3dx*Pn{V!kTU=Dw~B$#7xhrDb=n zZS5J)fXGq-$v<uh4umz+O>QS!Q`16kKBGm+=5GB~@bG^g4p{sp&4hDLJ^pY1(`PU* z!y7}5@%zWZ7hOSwsw}Q9AjZOqgA4IVrN3VJIeDA?D&!fh6TV(00~&{}<e76idrQt5 zo?LJ$iAz`b2ZTHJk$0yIP$jQ1-^KIDK2J;jV?7v&g}Mgp1L=e>%z($q)_B#>%&BvT zKqsv;%7yo}-gm+$Z?3~m&nvaZy=+!?=YAxS1)LYE(MSy&`>9uR>E&{nPV}Pb2Rj`- z|MK2Bz_UI77%=aiBrsF3YC+?T#u)dVbo=%ZF72VouRm@>bzN{JzT0%d?`R8S(ktFJ zmbWy6OtoAYpqN6dsWUVQj7b+<DDn3}&}xsIx_VP{jIq{*Ab9+ZYk&43#$>(A-hO`^ zSHC)|aGHMRz86hQBl-=o*bNVDk7UoTpU~6+!7`;DgVy}%Pu?-SDSC8#HCMk{o{)q_ zxh<3lJ-v76QlelN@##x<*>PqHV^^Gr#t{j1FeApLgB_$0)GMP`0s2&=C135X*0nCX z4$xn#lZw|Ht{Wm5rt%*Z@)maGxjDgZP^!HuU^~cJf9!%TQ-Q;wnrC11w_>Vvgldb^ z`e5y<gflH-{qXuqFZKyKTSv<G3VHt_$R}>cGA<TPpGPB68~w)Ud>xHs6!il*l&kO8 z@M;YhBv{Y&gWzf1rf6So-=+)|qDu93*n<{K)ox_0T9TVHykEhr$8zc&z6;KWB%)$p z2GnJ|2921xPqQMENXsex?4i7l!sGHO8uX9XMr!x&Jq;bql`*q<yIp@N?+THJ@!Irf z`_swa3`P{~!1-d6rm@|^Sj97`!z`E5)x0tFQfYFvT;=Dl*>zS%HfLi_4v#O;iShBN z+12evuAp<njG`rx{JmqlcLp=vg$0>%_0B#}VMY@h7D4FMcnJ3T8Ud25`AeHd<qA5> z;@1ep6^AuY3oyd_`ubc<wqyh&?+n(XJ_Ncc%V^|;Gpc22a<$yo+ULTfA1r;d%QY_9 ze1%9jGAOc(%AU!3bZ!$NE$u&4Tc{M4E;ld;-yFq?S+uKSkP2iXgOy<^tnS!f>9Tz( z6fJsc{HvSWS>RaA_yeyheq7PPKFy-^?Y&T`T{_>Yz?|kn!@K+)l-cQe-(ntOpEhln z4CW0N&@i=4W#w6<y?$snyys%PW(aGHuO%?H8TB^)@rzlZ?^76aL_$Iy%0nod;B!=l zZT$F~$Ld`%d?haHE_%}PL#cDdx!Tq80)sgg+87Y7*M4ku#+Nq-Qdv&?cpLxdpte2y zlX|i+Zg44t;SHOZ<s4D%;TW~!nHe3tpIrcxqQu}wm{kRvE~d@19#^I-vYw14-#70q zm1HG&AzfT`;o%Q^dow4o()-9WJvr>D>zDD`*w^{Fx`I>qAgzc`=GaC$3dOs)&)l<_ ztdb-4lh|)5RiDxqnYVxB#)48gJ5?lihz6e|o#eN}q+vdNiV-oYVzlV|y_rRQC%Gb$ z-JJzTywqeeoia0>*KJdtrLm8tJ^5AR+tIa?-j=rz%e=&R{rxqA7$eNraEjA#%guvw z+(;5=VE(?J7Rs23?4i}Jvy}VNsQ0A9Pv|>7i;E*J?`KC;tP%zAWSalp(+sqO4@Fm3 zIob|{3y~q%$%xm-PbHf<c6OXhj3~COLr5l7P+yY*SHF_$;tn{Px^hI3&ZQIcH|cci z+_XZNq>bx>0s>Uq=i`RE{x&~Ql!D5F>BgMCqPqLYd-v{z$Ay9-O&T5=8WzU0Sj?B~ zmH`3`+tbL41TRgSyKTs(o?OgaLFWx5efL8bG)9#EBB2rdW{J*<Ru>&SF!^g1`0DLv zpy`oIz4JCY$$216yTUj#G*q7T!E(th4y~-nu2@ss{V!ZwEOfR|ZsfmTb(kD@zuNbq zv7=onf3D85s&eS1Ym_eY?z&c`wtY>DTUtI(_Ir{Z(|SQg&P8&+?@1o+F4+dC$x+*V z;?67DqJvOo_I;8kJC*}8>2DqJ{ZL<7CqTFT`09@pau&k?1Mh14&%t;wBBqPTJ;?=P zFZPQpMrLVAc{zO!S68v!Z>9HY{3JsPB_7>752nz;wrGqWSRSk)xQfoVqbnx9eD(cy z)@484VUOhJ!=mkur@tT8>^ElktvXi>d+st_jhZT&T;x`HWV&h?hfX$m8Sr3x!o=8k zDK&FoXCbZ2lo~7@CdwUGd9=Pi#piVV%)JVcE-Av*6d=_2bmnUzqL{^K@m3CH^`f3u zD%TTjG0)BJZ}Snp9SWwL>DS_qYQ=_vuA81x<6%Y}*GgZ$;p|$-FEydGr@Z~ar&{UE zL-L5kEww_O9erGP)S02uP~Z>n4h<gG3Wl%6A7-X)&)(&$mY6H)?3Hex_TN|o2d$ci zdIE&)t})MP)~@(^afT1XT*>k<?-!5wTE4V%+q`%Z+lJ{XtSzSgULEUGeSofZ9*SBR z3CVNUFWcPSTr?z!F$#QHl2c1bt9aw=*CVJ#)+wvaMNYa82MB>1$dC(cc%!eGVg1S3 zv$%RrbvWy}^#)8kOZ4i6VfGyyI>XHocgMqfWEDLwF*%cDY?#1&<3Ve9+!5}Ky+Xl} z!|W%Px7457^@th<E4XPzJrZr9&@*E{@<x#WHg`WiAYLqe8<rzsZ)TPz`znqseIQfM zb<e!>Gug2-6|i>2ZzkS)`^|5Ylc!(!?Ob)zLqm^WUx5)_A!r++j83VDu$r<lCb~fi z^_SNkI@*l>s5P)07|K2T?TKO$5zzy&V0RU*wt9=bQ|LOVkgG#M;=gp880&F*U}odW z{6weBW`IO2A(SzKQ$yaYCw`!xAfGi&ndy7PMHs^bqKDv>b1kjbLL~wb^o6e|=Qb$R z4@@3axMoOk2C-p$_NVfzsRWce%1Hhi0p_~+b!M6a+?MIyy`3Eug_S(X>s=XSq(k?s zxW$s&2ET#_)*HiVV4Xw0EleVC2Wzk+!;+kMN)MM|T|}TVhrtknGeGUc#c{XcWS?vf zTu~E*zH-a9d*^GN^3bW?XSCc;cm}ODG~D5kSFTtbFQjlA1<t{eL%wSqDj?n!Gg>ng zcYVP+em|y6yc-;Z=$Uj1&<BEEb2&+#rj+@0KEDknOF{HRHgqt#hat-#KTn&_F7F6y z@u~t8hxDYKm$5NFOE=%53QWQtv^>Yk>LvZ!JKS|}J#nc5yHRH2DWy|(65R#DiXk5^ zK<~+0vo#mjK>zDMUg##bj@<1fTF9A+s<Db*GIw0<*U}S4_UDOw8Y^+k7Lx~+&hfpb zl`9Rfdj2e7YGS^M+B&KU{V7yB9*pE*ozCn%4Y#8gZV6##=Aox^3pl~M=jPz#)sWJT zXlaUy;QEAN0hh}@MRl2fp_!{n(-Nfah+^t$uG(|ve}N?nE-tu6@>Eh&v^Gu>N4f(Y zlB*rl#9o!&Oh#sdiEIP0puBo(1X-OJdPpUxCYos^96W6#yh%=JAz2Gr5tG)Fk?02s zxM2fN^e>Z+Qm5~CEQiYih05&GL12x3ZBCyd=VW4>K+iz-*PHesllhLDe}k$bH*j_8 zi=3OlG+~;oFSkkmGmL(Hg0ix5$*Wx|DBE=<>{mg!VDk(BW5o50rU|m6w{EUXxMbh2 zeI#!{CzNBts<Au}FI<WZ40J&Zn3md(J_W{8{&|JG^AS0zDhP|B28ScQ$v^Xs20tH# zb2g$1&pT1C%&^;M^UY&a`=~|UMKtAM%hXxg&W^(ga=>(V?I<G}7#Ai^d>ks4t2OH) zvY(&sxHY%0UFT9d>3)Xq8FxuM`1VTsm@LVm^|Qv1!VVNDS}`++b-1FX7@f-Q`mX#% zPHc<O_o?HtNBX6f<bfWqQd~qPFwmyK(!Oa8bzkV;=HkD9pEMoMFyz>D?WwcFYkgL2 zdI!yjLd3RRGjURby?xYxC1?^G@^0^1nmrbQ;f3imb5N_lCYrDNM8x-=(8=_0;AlEI zsKk8qO}tP<%E-v=lkFKls6CH$hoXV;_wf0a3AtiW%Jx@$3Y&8fVuCX(c;vq(n^h}( zMSyXb4U|;yb(22Yk605Ap^y*|e%Ky?_lX(*FYdL3!VU!k;cAn$R$gs}M+@qVz`xSE z5#=rz7q!Yg?b@v^nX!_W@uu>zSyaOs!|iCRuE$Ws$R@())a)AUJ&v`jL#r_OtwzS$ zhB9I_t0N^vMP<(@kG`GTmcJKjsa-F<y!0Wn5i^QdbTG=*rbX!)<i>OxR2VK;1p6u4 zesN3|ytN?~W0ZS?n#?SgjFz-h>-(VTXp`^N)ux}H!N)7!Dy7Oqac}biGvz}F2U^zo ziq=3L<Qre5Be<t<@)OxY<&&1p7Qi0CgepA9(48r{SdmFP%wE}8^Ur9=P}2g&*tJd^ zt7;8+DoKSIfk_$>yu?KQinQD%(wiqKu;Pa+=<X(=AA7{Im-m3bV|*P!%i`Q-^;8Q7 z0?03ePkm_xJWcq*JheS~POTsDV1~>)mBl;>7rY7vzDMZk!~}I}KUt(^&>?KFOv`~9 zv8V7GpaI2iogg6nY>(e~SBz4azJ|OU6mMYTH5SWs(Alm?bS^^Yi%BaMIL*ZmGkD~+ zRmkCA^Br9oGOe-Lzh#GrVTSn6uhkgx{bzafy{Qoj0#8uFvC+#b<pN)?(Fdp3EM(vZ zlYte^E`y740_SNSD5iuu(~!bqeF2R<2d172M7QfNA+@C1`f(tBRDUc0i}8Yb-i@bk z4b4FP0l<@s{q!1S(`+#?pG#eZ;?p-`KzRCdHGBx8#52A7xPa$7tLmIoVkF(2%|Y`> zA@GTp?8Z;G*Dni)hlIRz<O5hN-d!@<_e|dvIB#>C)azHJJeP@jaQd@w1!L!hM&rR6 z7C^%ajtJYT-8KcgdNtu#mSqHsx(0x88<aorARTS1)qpKDFhb??n$4)uS|2~+<)uC& zD*m^M2_`;wJBVQ78_D35T@$O-$5dNwZq3Iin|-6)Z42AaqR8)xPiLm{)Ft*~=yBhU zK?Y5OQ}$`PdlGya6qy}71w06DBb<@D<A&8P7B||Hr=@%6z9J|tUbgKeRU%2H3<+Ug zO6NJWz#TXOtW$jg1Zc0|+w8IATEg@j_l0<P``R9d!AP&2BeR^6F(&b8=nHj#xiB0t zA95gg8W3VS+5x?Fx$+#HwTGHu(4Na$0Vq)@7p{`NGCk}U9vSI`cDf`4fDj4*9;9jw zS*8&n0UFsCb+i}j_z1j@m}C_TS-N~}z`Oc{uud6AOOh>7?Zl#AqgfY;j}N=pO+W0w zS9}}hQ=^N4Es}W)T7A7WAs8=TYPX+w@7~wnq%fF{4CHrBCDVChj>F4?nT+V1*R@)H z7hzvN2GEew%HClgFLW2K<#mjy6LrvBUVeWJgN>+Hy`x|=(_X;(Zjv#=gRawstUHZi ze1?zNIwW`J1zg`3@D3wuiKY<rNXbhzMUTDbzb*o|qJRJOmO)r_F=vq@5ry%Zmzy+S zfnB&osaMdsrQVZDL<{fFy}zu(ug9m9B*5(oyI>NYZKvl(99<Qix9-z6he!0}C1#x~ z-|HsKtH8LQvAN(w(lmz^fA^PYL7WiT8eY=f^nmy~;5?DYTD-FQ2ci4mU7e0{*KhfP zYAv29oMqnGDek!=NDd2=b22r56Ddf1V)2DX0&&5C<7@sW9)@k-har~J1Ra!?ktc4$ z9PWj#<=6}Zh5h4My8qTzpMtjfI|)=I#L1^WAO~LJ0dPkh(DUzNM<rG#M>05_aD5cj z`*WIk#%-Z1gV-kw=@$%(m@kara>U#xtk>}q=nPrG`mlO*%IU=GyPM3Yr7#6C&~8XM zoE|$1GDWcKND2&PrB+k%^<zAbvi-?fO_d`+!(qUc*fexa!B;uQTnU5h5vjr@xXNY# zD;G>Kf#|{jAfFLZ{F^YC;6Iev%i5;|h8outTPM{u_>1}W2_Jp{7&K@P{y;5P>G$6k zzKip|KqT3s=Sh(jeT;k;Kx6pVe<7y!W>#ROpy9cqD*CeHK0|u32)9!MxvANjSKMP< z`(Hsb!hR2*Lf3m+Wep(T_n^S5AFc2<J%GU;`Uk`ZnMaoL{R3`EL|1$7BwgJ<b%ISR zbm_Wx{MD-3c+D7V9VmJZM26iSk9p9DS>`b-vFy@@D70u)w{$3r`rrBEtHT=Q9Pw&} zPYHPB@x!=c#Ylxf^sxu^z55YHDeyL*HsG#kQD+;o4^F_}+Wk|)m_y~7ynKDkQl{*8 zsH=JtV)<u*wv*ljRe93nyUS=5KC3}RRn-)*l^l9iDRy;7@>g$h_Qf4s<$b+&)pT(9 zrr_?`)$+uk06lx{wf2m?Uk9*)EACip05X-IW&6a4xkj?6<t%MFFZZW9N}U{5mAx?$ z;kGa68vrqxp6*yQv1!Ks_Yv5V2H9IA8TS8M8;%Hgu*HHJ-pgS}COxe7o0-Of9NPbR zGi<P2gA-j*SM}}NH;~JBS5svUu}ezqnkCQ5C*KrbRwHQgL3b5y>vc7`Tim+T6!o*K zD7M^o0Q=)vR|1z_D6i@9TeUBNO1d49q7gk-)xwEaBd}Vam-29TwfY^F%=>0%VAK}0 z%7XwjkyHS2yXnUsjqqT#8OhHds-cXKKX+*4wsBQ-WV<~HGDCu|#_(C1cXv_(f+pSx z2Om^0!>A;w_O9=)W?C)E`)8`Q*+0j-cnNd?>Sow4G-642tcJVYJVCA(@;I*OnZN4t zxSA)mN6%U|-~)+sXMhAqPTA4C<kI?Gae}*c)&GsGL_C()KmU%A?-f|t!xl6}fmrnO zuZB6RM~v{Et@y1w287Jdo;~|pkm-4<OhhOn6Ek!6vuE%B+=$iK5hM`tU^veP_mf@A z;pN_$@6ot_diew0y2O@Z;d)c-#PY~kspaxiazcM;gwct!5bQ2s797`t=c$&nW;+gY z3<~rK^UNnpGNImnHA^*u5h6Nma6ugtlc1`RQh%7g<!nR3hi4Hf;x_m35;0}gT_3`% z1NVJ`U*TZmHNeK34^&0SGcj2-1Se@s0`vuRTy7lDp1b2?#KxWLg#8AV9TLPmC-a#F zk=PoinzOpUCfzj<W_2sW2+ELMfp_u3Na;{Oxy~!4ee|*Q2Mku^LZ_%u2kvZtK7oC8 zyRs*+_6;#^jq2ELu{+)pQ{`yLjl`{uB<1M|Wy`b>zk39s*(2PK6JK>z?N-`)T6L(` z)|nUfU12n^1-^Q&1sI?gKV9wY^(@}W$Ai63>bRs|5I56_sqy`+TIFC-YCXA@WrM3b zdzaP|m-^KAcKB78myPDcB5^Zl83DDnyTv-7R%8r6DSe&X*&~LjRN3TI2w?=(@cTY+ zX<EaJlrUJC>7!KsQ{S@;&BAX~0$ln>dvw8!?v-}+`nScDJdZd15~#Rz_c4ed=nQ#@ z!$F5Ve~l0+a5B$Hb##mfO)+b(Ni3g&_wt-kCYO}(2HqBW))mXWdl_8%)h1)}!{+e5 zqTQ9jzU?y??Vcc4B~H2c`*5ng5yMj3=<PUAI?|Uo=d*VV{{8OdnCjnwRFj$MD7UAa z%?kaA9zj_)x>m)+*JH<~sT{}OdAPw0IWrfiKLG0IgO4ySLpM}EUPLOtJ7IQH>!IlM z+6tgpN0M=IxxTw^u1?}HH`0P&Ed0Gu@1f}&DYf|*0$A)T!}qzqj!=j+_A%AcF<K@9 zk45@xxHG<*L}y*QbO)!TusqgYc={M@&_f?MKvn|1jIqRYg5Tard{~J`PF?@848C$B zNAabVN7qCpp-!AIQeSw|)4*!jPI3E4vk>5_4F(su6Tj(J7OnIb`cyfrk$xNiXA5Km zE334N$n>7LzAQegQeiG7GY=tFc$Q{TjcvYx0jA19{k(Ysr99Ea7!4Z;JYPpj@x2-} z2WQFE?eu$4`VRDW@`%oSMP{?A&c!h~9o$cx7VHT`5<9A8Whmq)WN9UT`1bAIyn~SA zazB&%HU_C(@b=R}r$OQ;BZG&@bzp^4pw*6na2gFlKF>Wi0PFV6ZUeS-^~>R|qs@G~ zi}AE!ayp)u*Wu6TyKt7D(yT;MQMrH^-#GHR;`e<92l2M_bG4?zGLe@6;Pd}DOnNok zHS#MkRW4?0jN=2#J~`YQ+F+Klm|IFO#?S&?L}u8pzyy%VFa8tSHHrZ+5iKYIfbs#X z$fv{Q99Nd`D^;}~B97}5aIOdz%DlfpeBUyaMpch|y?vc->no)nFp9d-Uq(7tTd$DU zQGrs}z0%V&&t?yW8%yO|<zH%O^zrxiS56kbv(z_PtCpqO1{(q;4QVKpmY&^Z5Oxjn z=E}}tv{4vI3J3^z+>tw8pcF4$HhdVt%DazVX3?!E06_MG-b!%mr@l$k-3A`D4)D*B z90O$E{pPj!K|yUflKAf4J%3gqA#L!GeUqH~1c{M=@62!jU0Sz&vGo(4HwRpveXmMg z6LYiFGnJ>^$@a16z*4JdeP$5<FFlFLCD21v|3`iOZvSLq+>Xx*TSFZsv@JysR7a$; z0KhkumH)~&Ej>~M|EIpLX<*e^J9&fpWsvY~@pQK&OV`z=%w#Kzvyl#PhF=e!ywf~A zuEEdCC-%slJRyARHpG@Em-lWIs031m7rF*U7EvnecWgIgL;#9O@e^$PwZg|0+Y2;5 zoC%#Kal-)Mzr$ab**4pfZHe~Y?*sXYhzUp;$OqS)^JV(gM(fIl@>QN)tOsnEqGA~d zag%PZm>5o0Umy3f_Dm?hQ{gx4YCgUfJ9#0fei{E>gs5CEJ8w}0;n7_qLfGD|pTGWH z8~r0MiZKCImtPa_zZhiu>z~1o5JL!rNawARVUAXrq1E^AZhuIyml9n?p7QS|pl<ip zEn1>$=fo}rP$<w>;9nb=*0#)*xGgvFc)+pC=lfF3JA0K*#bUP4QCflL?DpT^0H4Y6 zQd?yDj<;}w7eE;*LkjV|rkhnEfBWZ_iXY(tHtc|7#@!tQ?>bRHEFh_kw+M`gy{B3d z8I+W7{_duUjh4>URp_d^xulKpxi=>6rm!JTA}8ag`te>=LAmkjAC?lxNCdpA9|rGr zL|ChbC?}!1?imr%XGa|fG%^#%nAik5V<C?timrZ0N(@rFm$N@${jC0r&MRgE@qp+q zL<T>81QmRM#{Bnc#Zkil@OODhT0=uX#R6$_Ad=sU5U_QBp8IY^F%M*G=q?ag?~6z7 zblxC6?p^Gj{O3C_qbsd$4L7d<?Eq=Xl|Hb9my{EL0197Uyy#xgqz;r@nWf1EKl$)r z0^rI4e^fAkMMewLe+8_l;RoLIXt_+Vmz3vp>U0WN4#XN3a3Oe{hzR~X55)VPZ^dtk z2kIJlmmX>Zi0zz~1cm;Lh^Mvuc4w0=^x2VMF+%0zm&zz%&|~$o{X@0_D1hPJ*TWx; zkC8x~1X<)On(e9;WNAZuS@nS9Kk&PzM<>K(MwLwQFv6ev-zuxP58Gg7<#qzgyOaDc zOEmZf(7<$`{F|1AehIDp$;ZCJ4K+<d<fPRkFxmqsuYkSocI^@dUf_lHzH78k2=<)o z&*I-h*~iO}^x9}u4)<-4MgBahO47*r)oxub3!r(5e{Pgu`QjYlD&V3d^{Yi_H7`8q zvlnl76>c!6Jq2(7vvqzBC$^5{hA?Qifc_4;KCDp2pxR-fvKZ1N!KUv9PIsT1cY~+e zc#V|m4?oKd$O&K-FVqO1QH!~jt5M0h?_6H##C%MbT<thHiU63ZLA%bpXLmp+3isw_ zS;2i6%(K9%xqF?vBWP5+*A!dEyrw8ADLF~t&IUSpQh#smilg0rCU)&AS%qtK3sGC@ z)g4NYwt=G=rX^ZO#@Cw{j*0ZDt7WTh$~Xg9sF-)OT1#+(K+hhz(R-Ih#6|Y|B@*sh zx8e$Z$!tQH_?NZG;qER#tAMsZ-=N|JD5}H0&-9+W&PA7NC;-M4)qV$)z~@1<=W(J; zdJ#D(uvS{Ry)!o(wD=oVOP=DUPx2nZ7*-*=t(uIC&$ZbB-v4!TR!xv!60oL+s*_7j z$YaB(M~z$4-NMs{p!HwDczU&%b^RKfyZx2C<S`7^8jtQO8b_`v;u1t|lBvK$p}HK< z%J*BQIr6t8%f|!f8{-9ViJiiV+a4$l=iduD!w&3xlmODLyb_T%lGAUpzD5T6-(C>i z&Fbn4)!AvpJSG;QugdijfL*2MokIsit8g!D&3E{-Dc#$4H#SaD=2(2ZudhEJXj>ke zNP?}QbJN!nEOJ_)2NAOJ>d%1qSjw&<$y2c}A3rL-k@lC4Vqt<y%gd{O`bdQ8xP!43 zcp}&XJe0@)ovoKH;YVUtC+0BsF-t9b0pXlHzWxE6Ew2kN5NUo6Lmanx?Z#9grJ!=Z z1rt;JP!p33y2yE;bA7U_);U6;3S;YCrv;AR`>6kwGm|VgyM7-dMu-r2_^;}D#pR-J z4ucI6JMjPx2)hWW=zGM!Uc!i^l7e$*&yIS_5R3AqwwRdn(4hDqvQe+QrIzSl3S?)z z{-Q{&UVvOov)?=%t2_YT0!8<7YY0Ocoq#T7CF&es_;6z+x+CBS4qREB|7#D2XQ!p~ zHA!c7)B=g=gu=Q17sqkS)zU7f>j&+yZfxcdWgIsSuhN4U>DAUcLN4nRorX_HlBGEF zltr~7xK8MIDM4uwCl5C=07Pt<Xa~nYiO5SoZGIb;^ptgBr=^A1)6h!x)#>NBo{3Qo zoEkk4wei|DKCRtv^b1XKjXjnK+FQ=O_uT(QC{VtkK?m#bYYq-n4C?!~BoFdTWZ=q@ zk{=@TG&3PwE;RHT7E_gl@Y@Sb!Fm3E0#G-lUr`1u3=9(G!`az05`GyDnaUb^VSpd> zSIaJSJQ4<*JT!&1%xSqqtho8>XFkj7s^gr4*j0Zh4c;?aWW~v<Xluua9{x7stHtT_ zRpa#Ce|w&#mz0#a(R9#UgqZppFb<%LXpxWW%~>AcwL0W=NA7%8&(RO7bZ?rALf2YR z)K)r`rq$id_c5SrpD43j7g`s#7Y}3pGTiUG?YOr#+G)cXfJ!7BpUhX2p|G0&<;!A_ z7q`Hv8)t(VvU5}UbhKx&^?p;kXxcH=%-FoI-y}`n?-|7Z8gk)e2bfVFS%Aq=^xc|= zgc2CV;xy5N9Uh6rk<G~?s)>4o1unWfBL>2gu3`w+nI>Nc?1Zyk&F^9s^^C-j?;lKU z#}k4R@8T0?ys^#!f<z0$dMTdruK0tj6?A6utLL9txVe?xU3Lc-tDQ`A{JO@=ES3`A zL0aBWC8d?K7Y6P-o6KNA#_|gsIk6@ZsRJOisc$Ak*|;_lmzodpZo7X@lPh&^A?B+* z!il10Cl0p#13$I783^*L1M;oI?X0P|$8xkiLc8ddue4;u;56RJV8IjobHzvI8*A&b z7N`SVVAljt#)&#WS{dOis(&BV3`Y-`4I&%p;TkdK@$%`^#D1B>ccXdi3_%VVEj<8= zKidhi{Y8yz^;~Y|XWdjEbpg_Dur`_8BYO6fOg|>>z!{jsapu=^$fNqcJ>MO-tIyOd zd=;9qO~LV&TDaOPQ+Koo61i9o>oLO*HwPa84vquintR96va`6Sb=kpkanZnhYfz)a z^gtP|47Ol*Hd7@_KX**6g+}0YsLOG^tqay5nH<#Pb92U}o*6o2!@7m9p3B`9mINjD z{3`9i8=Ai$8JHJbyWBQDUnA_k+~d8DF)8a7S6ntwi5l<mA?jlUY87x*F?3cKd!M14 zsYD<Og<?wyWxfk_zG|kj(Ce*~7PEcKz%xkX36wG`>BVMzh&^3QY$`3(1a6Ws1Kj#9 z{LRfno&w9!nrPD+eu!Az0r-oH4YsD!CNnb=QjPcn!RLTkw|TomPn9ux@AQ#ew5SBL ze1fWrOVt-z;WR+IAlPsnj&G+F4E{8Lmz0j%mK_$fpomM06Nxn@<E`*K%igo-E6FtN zj!yovK5p?lxY6Yxf>OKEG`IbkR5pNBXx+D}9G7#F7!rC@=jJ+Zl>y+ee}dpDpZU^k zXv+Pw3LQ+fQ`^L1e&C%|vDs!w)LE5hsU~tVM;1K}T0zJJfp0BKlvPxA?aT9`$025> zc(FFGknDbzbu>5BF@j?|Yn@+xf^VbNI@7y7tFH=TGDQ6BVh`-U?6*a&Zq%XbUfGPY zX#&o%N#PLzQt-qRrys^!->3%=n1w>1&eAo_VV6m{03#Bfx!HSg=Usf|5>ykik+)lQ zXupF%zMC*g;q8!09tx;#FwC^?oH#(N@TzBkWJIT_-RZgZwUUSD5sz>$1Hz0O2M+{1 zAhwAM5fw37h=2Z-2O!FTIChI&FYRnNyL`;i<As$#O-LnsHJipz58x~NfQBkdr^hqv z;KT-T+zH(7pk2+S0%=f+>sJd)mshd0%xZZ(IaZ{GIUALFy)I<l`jOdT?f2`TZJ<yL zvl_Bd_@#gSHn%MJRmPFnk$K0sotX~DD%YFpy_%J^bLjNzJtn5-K+N2|J>MlfQ1U;c z)CIH=t`5-DD>rM44|1u+bm}+dn6TsNZDh?>ZQjEX*eh8@hp&b?YN^GZ+)>X}{C){( zz7h}}dfHi1snOHg_P&iX+jW@31+i`^=l(#SuwFFW41=iNJ08@!2P`U{w`3J1maAQ= z3@l$~pyg~9Q^w3_-r9f%^g7uf)=-V$`YxbNHoQDoH1e$TP&SigauS5sRb^$FA_DxC zfs$(_IY?}C#B9XKhg>By6!K&a8sR0t;XP0k0lI_~AedYI^%DgFu7TA2yglyV@xk4> znGr2eEAn2DfmO{pKVxHH6antJy1fZPWbmSynLJ8q3eSg8&jRZp6#wQCHLXc|<b$vS zMB%HSJ3y32kwMG(_$VhbS2vT1RXxL46@HzzSK;~{-d0D{M4pJ4V`Qh+rq477#iUFS zyffq?Ok92P-HZQ>6(*l=v1d(r9LWLoUKnG1z5PrU_b9>RNt9ZSrV<d9Daocvi=qXq z5pS~{CFBB~_b37Pv3`7fRW9Mse~8T>W>vIO&(&j979}j!&QSnbz=WEkj{w<{<<XDL z1wy?;P)XMEBPUTNb`?*6K3fqu4AAyijRk193z>}{&GMQYUW<R^th~IuEabBGwOKBp zXa5w)`uc$k48gwr>X?y6?DbPhO3F}1siYeGCh%PKj;6j>#JEGhU4qf;zBP;a-wx#m z63Uz?gXp9PtD!7ehmtBMYzj~y<TNZ=pNZ>`zj?HCTtNX%R;cCGs@J-T#^Fw?|0^g^ z6RI7TzBW2Bn|K>9ijW*u%gq9q*1ewD1*i3c++xb;bA0iyR!~|PeC?CE=E?m=3=~P3 zL%BL(m8^ezatK}k4A;AaU{pi5F3_WTiJkWI0>N(V?1ycx6Gz=@>H&k6(hl(BguQ55 z{THh!qr>frch45ObwRyzNflfd1xljNeUNrmd8V!`XH+u@03w<zpm2)DyX;AI7S>nP z8liXiW+XKs)P2P=%0+q*O}D13&?f3wDkE}Zaw6HJ4eC3fnI6qAQy;ooM0QEA*#{Nr zUI$R`09wO85@0Zz0=*)I`W12hwW_(lp`RY=<x3rA4l|rwsX^)CXBnQ?cCwDs(@)4* zbYJ*hq3G8jtS_q)dbvmin3C-P5D)7n>cys1uHGzhd(_?|atLUjT&?magv7L}s;c2Y zuqYn1hs{+^mA+Jvw%4*>X!!p{DSAO`JyE^al?DEPIaASS0VRLyF;#gusP=oi1WuR` zI!<IytHlsz>l2<;9jU3Q7L(q-keHJRzR!Q)N4q|t^W6Vt2;(|@B3p2q0-6&5gB!V6 z46QQ2`a@F!0<N*^6)KODIsFX+6{gxzZIO7L2|jhU;j_T0{p|;5y();Iw)q+w-~EW8 z$)CKc`#@Plo~>@Rx`zypi_3xJu|e0V6My~u9Q$^$^T`6oGwX9$>RNpSiPS-@)GEKV z>f)F6Qjhs7UG9!mkd*271C<Mk-+LSP3#W(jrV@$QX$Qy1J4(zased;AFbA?$!9S8# zz%@p)YbSz(ymYvN=AB7x!^?TS!MY@Ja_UF7)A^Ol5<u<h99k)qD*8j%A3tD2j~)RV zEQ5%pK5&FpD?Y-a{m%A1rDbF~hU>6~9DtV!g4rKrp@p1&y*HIZrD+YMFIOkG09i>) z=Q`Q_`W&oY^-@=9Hs5aQTbkoT#f368t6>Wukd1l#x+an%F2C5U$JEyK<?%(4kv)%G z?J7-H3QpC7H}kxnGrz1?%RFXdr6<Z2!k7bwLxKEBgh2v;Zmhkvmv4GklWu^rK)b{t zI^nixC+GZkr6*XW<IhHDP?bG@c2mQ_q2zFPJ-OBZdsUoW0)I+sN;ct<zUSGhp1*&9 zDrlO(6o|fodpu%$7}DcP#0x)Q;Z{}(30WCREv`Gkn!~K9kFU5W{KqT|h??P0LFy^8 zYYcuH2P#+<be6LZOE_o#mHCd<4>5eZZRsdVp@lE|lf%=eC)_~?BMqlxpu~+HzxqF8 zJ7RqA{l)8)kHjO4jMTVUr16hLVk&L0of>NS@-*bE+NvR7H3Qk{qEn@;<3iT|YbxP# z&^vuvY)$m_KU?hsd*eA;CM+f!kU(1!xlhTaq-LQSWI@L+Qy(KF7-`{PhM%if|0I5_ zJWQp3Y}YQMFaG)k4R~x@j|e8LLIW%aJwKBGHd<x&1JZKC>l7I6nxULe&)$0)%f1|o zg`-<?v6e?)Xe_~)io57S<@TaT6{+f%Kr~R8a8K25tQBjQy-AJC(M$?eV&Z!%F2-kV zKYw)cCu_y7za{}7yYtms%dvL#==>-Sc<2@Kc2S(;!Vcvw&BGV{5%;yz2Oa?Ed7JNm ztTDce=CQ*IsUX^cf<~WXWl?I%N~tNgqg+#<F90C-hD6s>67Yx<?qT1OlXu(a;$le& zcX8=28Bl}$<g83^plBG}iL!|7lJ~$Z_tYPMOBqP#1Hf)*N;G0&<s3oSXu(%j;8~xj zEEb>FDYZ;pyCq%$1Z8z2wNfbeQ(viK&;Q#poZ<h6GThOXP0HSkN6YUcnA~!hrweVN z>)E#>Az-H?4wzIa2cE8S+@Z2FQJ<h5VU^EU9doxa$Cc(w4Nh+er2@2GK)Mz4*d``T z-oMA`46c&4Qs)}8l++#12+tnQQ#lTQ5VP~^(V6<=kCe6PV8Us*L5fZZkgH5^pQHVb z&b1Mx)uG&NH4Y{wrWPB}s2RxNYNZqcZ(}zP<}C7;F#D4lEqm*#s~_%^n4Vm6#P;e_ zaGvI9Ar@W2+10Yb<>MY_u4bus9j}4gnlHpvM!(zc97Q<Vh24)HHwZwb_*FZiOCwli zLaBXEj|EaqwoPL;$E-y*e?NTw{JF)be?+ug@qerTvB$oG`a1tq1|s~4^(-yTD|7o( zRv;v~nC@iM*lINt9)Inc=cQAWXCS_+ElPdxCTQ|(gQ1q+E}>cUEY5Pu-lsn6)|=m= zG0Y%h>(OE}<?albRG*wW(UdsNzlr$xv6XGA(v`%<!^oXJ+k({@Gth!^lRi7xufMrY zCFcqnGZAjX;Gul&8?BZxO|{k$1IwMoYx5mZ<Tq}F*ev8tO}Btn!xIRMVp|psu;cl_ z<;=UYd7#R-_PG5TV9}9K4uLd~5z)omXOsD^M#+)6nwc_fZPBQc(<59=wPBLz?+pgH za+v2tE+kJj@B0>dKGYx+ncoX&dj~yq7S)D1fPN6Ea1o&Mgx(hxo>T)R6fJg0jb^+& z%)#XS4#4YIfdU#-hRIOX2@WfFPpqSHJ^&kH?QHsEV+9~3HQ*0&UH08HJ#8i`8urHx zCVE1qIexq);p(w%b+(;<U0Q=(h6eDyHw%!9+2&-ar%rvn;YPR3>9KXw(KVwO+Jz?H z&)T)N@$&JaxfEyHH7VJ+`Q8wP3=fRU%EV^-O;W3&+~G<0BXC&Zk%MBl$#)WL$4|fP ztzojkB;UPd>0;|b(CfaJi#6H4g0;0f)>uE?3Dflv*6cW;wumIS79)alge&7t@gIwN zTAc_ze|B-|Sc>R+;2plficg!M)pU(`K$a_soXqTFkebu<7;L@avRf*+a@r#rnxbP{ z1y7bF?kRM8#Iht}gZ@@2kE-l%I}H*$Rh<2BosYibMW^B$*V%e)J%XF(NNbbsP-ncb z#9}000Rw_!0$2os=Di4!;)^sRjkHji)S%|gRM25D9ijKdjsOCpg4=|H8H~)tu4TZs zrcZR@<0TQdO0a;}hu}8HMH-}e(+C%BOTmDnUvXcLXga6Ux;lUyp#c?j4MP6XqXC7y z6<5L|z+Y^&30JhSFSXf;?_m0jfIqz3qx&r#>afZ#knK4o3b?`D$E#r|_u_7Jc+`}~ znI4#c0proo<j8{7q=sw#L^@FYuXeZ}iL96p)m7?c?}zhOwkgy?YGaYX<f#4uz>Dw= zoA37jj3yg%IoFY|O!b%pWjAya*3+M_Sr%fFS?jkDC-}6>*-}Vc-(lb#bf(171r)yh zHeZ2^jLZNKwC_$5(n*J6ZMH~6#?s6EZ$7xU+&)$NGU)mcU_l`m1D&HJ!Qgkj&57WX zH|-HLsCxWdCj9q&RC{YHkTa}U{_efYqL&q(!it#eiV;@8xo;%pJ<!#R7cSXfrt+cb zD)M?BDvui4NSAydDENHatf&8YwAcYqpVvL#gm)kBgiY;rwY8v*73z<-vR4461_lZ` zjvs?sMWxv3a}=jWJ{EIQmtQ@pW#DXs;<ot4m<iNE2SP1n$iKqDFv(wFEE~*zj^h}O zbvOVlH+x@p@D$%56P!6n%^n#0Pzkgc2SPzQ9(naHrIujm^^3>ByoUQ$y~0%oxA*1Y z;Wzc_+yr|x^ds}NbB&ng&4+d@V))!+>V#cnS=IA5|K9$Yr{^N*;mx0;o%G>4ws(+{ zhaMUH2?irnhyGuHZMBw~FDFgEFS``1pMYueLUj)PjIH^0i_@l`(c>C9`pM_Wp=oUv zsJAQ@DXO=ek!!xw#09NcrK?a8DRnw319F~fsy{iv%{ie-n07v^lQKK`)BRC109u}H zk_7d{0wHzlo60HAoy`_1p{>h5OIH*3NE`=>jr0|j`<Ea0@GyD&QY#)_j0$nzHaciW zho%sdhz6T!fr_<Dr@U>(erY*90k~Q3g3Wkd%*7$l^0)6$9!{AFlMffAs&ndm0~0K} z^*v6|+Xvb=8rbWHJ?+9+dp5!pE@OlLtB<Z6{euFc{#8j8zB?(Mt=$)CzvgOP@QOuE z8Q`AiR3k$7?Jj|XEHnL<1mSHpbhe7rPybtL06Rb2S;_1{o=`S0)f^>26TrY)CRjRu zz+bTyxhjAyZr(-nh-E9yx(t_zc#I1$1KlbcylQ<&XG_gv6yOw=KkR=tH?IT++F8!@ zn}E6ezVP3lMB}HdNgUR4rUv>|!Hz<;UX{a2VytZqSIZWpd<7!`8P7ibWr+%!wgu?L z$=j81K<+DmIkyZK$5nIi78CYF83_Hm*aRTR_-sasito*P2q_EYeKkUgaav`M*;|o~ z;82qWv@w@Qqt=8|M}*nirHvaZL7#g~7UCQiyHOg}va$<D?S+LxuGl!K=pvJL<5S%n zO|Fx@BU~Ew(MAYEOu1o5-NByDiOVt=`%z31+tviIWwqs*A{Z9DJ-7PM1-Wejx~l~< zCOt9K!Ez2bB%hAx_CeXYn0-7eL95b5#m5Mz87m!VO6_piSd|csAD1o1xO^UKE>#C& zO$Z#6@FTWb3DDqk_(2A;>)#MmI*KiKL$kp9eQdBAs>a3%i=#kF&$#@qqJq_Pk}h53 zlWVEPs(R3Lp23vp=q0<Z*vTl$wdk&sYdy{<epfC&tt>KeWO)Eb=T-OD&bFwetJdjO zdQrPh{D7})o>eVZdIqY4?FHjP=+h+I=<$vy*2PlK&<DF$_%9;8o)D}L;<}a{+Gp&6 zJxC?@YF9J~*bK5wyE;)|Cj9=gw3%79T>MQi+74!?RzA&q=e3>-(=M^rDr>|brGkK< z9hD8B)Rpic;votS{Xu|IrvcAd&T9^2goEs-Io}a6&~kR9O2Mh$sViHTxb|4+PH+ks zNB9O6j__fsY96y5bgf*>#krCHS(|9ApN&m8N3WiB#|RIHyAa$toWQ&F+Dv0Yjxf}r zZ5Q$LN~Kv(z*=lrkx4#p*s%k@XLP+)-oZ9f0_jDWW2x_%+IFZ)T%XEmP%15-u43~` z+w4nLN7wlHlo9|syAy=dBW>tZ0e5COy7wer1St=Ik+I0{4gTV<#l9DrbZBdnyibQ9 zOGmYA%ii7=2)4{pUl(%3jWN-;&>sALSX*ZwGUl|F6Ox>ujv2SDwLAl&3K1du0x%<$ zc4>DtRyp5LVu6^*Yb{N(5{NJ$T5XC(B<s*IpLZ6LnrM`vv(4J;2$YUK+zAI52{b6g zGOWKkz}5L`Z^ETTAugOTsE*$j62p_6;f%;1C_f_s3a`aN!0<tHGhhxzhN319l8~1( zfntHyowhI1#%>jigScOD>8dc@-+AO&Sy(n>gh!wTW{jXJkM>URiJ|XW-E5^huGqF? zbtDjLod^aWH-6_}@NIZJIh0dAeh}f;{7!o(?m#O_o(A!_TrZ>&pRK<X!3-+8Uhn5J z4u_qT(EY&J;NO5d(5rUX8?O_5Ex=iKHsdF{PR9lfLE6=aCGv=!q=0z^n$v|l0A+^e zc4}$sT&P0Gvxfn+o~8DA;h^1NeJm^kAXw16ij*NUq*H<VEC`DSVoKiim@6wMBw|3E zkIo1&afBJta3j4?Kvrgw_!P*H9*YJAe(D>H`o)JleF}9yAg^}`SV$i~gM>O8bp($4 z24`7XOp6x73D3aHUXxLtFpu;81J)Oj9AZa%CuW={$ZgXugPLa`<9&uE8gpa#_#8Iq zF>eOsXpfiy2479*mS~k%DG5e4+BHrv_zwUVld!%w#ICJNsaa?ei+xzx#w<4Mx%T@q zSg<OXJlQR;riyj(fbC5K<)l21pE!O}vpL~DnAJ1~rMQbtvxA;arQvsM;2P^e!SP7D zns$Xlbjy}eK@=qZ1<ISBTSnry$0`x&fH9D>C;Y8b-x!pMXd$-rFlbD#eOSZ^qp$f# z>w&ay@dDx&z-IqZX8!{^ox@E3um200{)kctY%}yEhRbKO0$2-%IQDdERT?#q;*0>V OVDRVi&+?ucdjB7w@wo5+ literal 0 HcmV?d00001 diff --git a/docs/source/images/IntegratePeaksMDHKLbox.png b/docs/source/images/IntegratePeaksMDHKLbox.png new file mode 100644 index 0000000000000000000000000000000000000000..4f7780c213a35afecf436aab79fe9d4bad06d2aa GIT binary patch literal 22669 zcmd43by$?^+BQClfJGR9fQTZYq=0lPpwit8ASvC9G=d5Wh=MdjNO#xJqJY#$cZo3M z&>i!;AC~*w@7{au@A$s|e(N~qZ~^nw9oKbU=XqYwJ0*puL>H+p!eB5W>1UEEFxXiH z40dMeJOTJk-rMRH@XtA?$I@!&!GE6TO#;Es7wn&DJHcR=m!Qv?*#XHO80<DoTJn+F z%lPGSx0h<O!!7HR;{GOglFmxQ-n|#kBmYMCLU-wF<T)j!N1nq};(=c>E6e-K?-if- z^Sc!1yWIMvobJlAvNBs`&cHx%va>p8AE(M(b-s!@_K)G@HYx59;5P5-*qz}S{N3R; zCxB+<<l8L~&|{C11-DZu63~>KD6Qh)P}Fa81_tvzv%kL|mg-Jkfd~G|NLLB|38Xs* z9t)=YdWsm_>wD5M@IA>ZenQ~e_a565!eFFQ=ds`mU(Pquz+mFn@BHtBew%CX-Bxki zF~@`5rZO=x>2v4U=hjJ}+;VweFUTytn9%=JSKo_a-knsK3tUCADmeIZPMq%pIwwuM z9G^SCZhA_>d{GXlwh(nvI|U(>`S!X1V>rbvN$6ha&(GyPs$f06s1rr<{0Ds4A+xLc zv#>7vzKTkQN52$5=B=-*f9<#hgLO1T3t5qlN!{Rbg&F#kcMiEde3(JyCtyV?4es5* zL4yzWgmg?hSdM0DiDg$SEz%Y33G<Z-1ZVf<_=2Z9GgAT^7QFp{%T@f`6#8>sQP*D& z%S&<>oDrt`!bE|G^^FnH7a}kqSI;>O+^)QY2mR%?UZCLroa53NE|)-;@=48Wfi6ds zB|K*BXTd{%ivG}fY`%VjEQ?YIL&8*Y&w;4*%WdJ-p)+-LF6JfSD;w2U>|F2+B~6~( zef~=<sAbuZ1YGj{!hFNY-kuyOIE(~bD)^p@Ig<YVov+-ApJMM^N*DQbphLP(C&UaU zZ2GCQp_N=Fc+^0;Z*v5a?g&;`^qrn+BbK0ab~#xC*?5<zw+@m_FjzyBboUvLb{+qz z{12@IXT*OSU43kFC%S~-6IkeL{XZ888qR~s7w@}mY<{(QY?!LV6rBId`4}M>XU0zv zb`~Tni4xE0h=IjZ7f5U!5=tW8amSc2hpf7!#e5AedH!?_8LSWJPs}=6G=BL$Qpl-E z93W9!!o}mb_dww02j+H7eZ|mOO=w}AuMR{HY2T!=9*WM%!^e;1_K2jn_?jwh`6)6x zSHCu!b@jsh5rzB*^^Qn<80?Cvs(wOo0Fk<-<$D!X)z2c<nfjyg<}M}HcYkpqR%>yu zGzzqHkkzhP$|+A4Jsp_Fh3RxN_$;oj2_*UyX>L-m_c0}6)r^e%iUWw%pP+9&x8^Yv z&G3*@&`ZT#q7~mN;ujp!tTb2|E!(_RVK=Jr=FJ=O@>YF1_DbCn+uHmkL>~L%(4+0e z{$3P?K~HK{??ao76!l2lMoz)j)awgW+lP}&iX>wN#l>7~TBXroQ~4Ucd10sR^QyTe zA|m2G=bc86_~_`&o?<R1Dl$B9-Z)XyF!Van@u5|JY}uK14(+<f{sd!5wwmz!(w3h; zr;1G=?C!+{%EXIRmdFydvd4r3)4-}PxjIUCde+Fu$oBIKXosn(sC;?-GRWL*=-D@X zL<ExG;V}p9comgt9N=pz$~=@#Zec;iZxS7^kiov<_^x>_SXsr$=!Wh^u%nCkKL`rd zmbtD><gp`#WW!unhEuk-oUN!$?_QxEb5p63kA2u3-kX8Xx?68ouil+35xd*>gOW!P zjm$8|bPm=c#wiOGU@#@3pcMaG<0y;nur$l@MONvaFATE%6^O`P&)r;6RyP%*cK>Q| zt6pojZL)~SNXwNV4vT|piZAAjRdYPOo8A(+w0EZTRXP|;_Y85S@Ni)UnA-=oq;Bu! z2%(J6z+Ua);CVLU15Df!ghB5=I~`Vrw`j+-Ef1Gy46YyDY;R1QZG^knc|U&aXFETs z$dRi{Ti8*BiD!#ypA~V%XT1P}S$<EQzdZzNpSFLo6=)rD>k~Z3-B{pbj?A|_Cq9>h z%PV5`;<K}}2M0@cb@q;~x-75BuDaoT@J+Vnlg%+4KZ}f8oR^0<MYs_O>`NmIW1R#b zq}jpA4hCu^mHVtrrU=@#6RI{57K7}u{HEDEw0kNUi4&4=jw(r#F%eP2{on)<=lQkg zAstofVkdhk>?=J|0x5RH#zA0@(LDt-r>S?M3wPMJ!%HY&-WK$1H6)_t;{V)vks4Eh zO_K_vY&RpvXkvFu8CLK6PBD}SU$Lh91;uJo8b74c8RPR<y33S8o1cpC=;F+8QpXgX zH(Gyv@rDEx$34GmkHc;}vM0Q47J=e^a=|2+RjQfz0R<G+*Q7xF@bnbFejAVM<^;!W z7}(%Jl~Tdrwn&AIoNhnvXP|yc&~`H|!j*PPL`p7*FM}%baS_4kvHd^eEum0tZ%*eL z<r~v_^9}8)fbWZj=)ZEvT$iNDGOWRS=uXN-Ny73cb5Lx5PZ|fphXG?}<QpC+3UG#C zhnPuehN#Aip=3m#ZtR5nPId-1-Lm6$<z9LU-eJ%}DB8zC%1;Caqd$F;E4|?A4emuB zi-P)>=|@Ag{h<uDXLQJ^dl%%WZ<lkpUKB+Z`IkZG{}bf#d`TTn?73vG5BlcHr{4D0 zkbT0aRw-wN@ApmcuPoR>1ABd*QfMgh(|m)44htzgG`dsmt=8IpLhV<^&U~a77%w?L zb0hp*gAquwm&n-$-iA~;^50xUMr3_z3ivT?e@?w_!`-8(Q25g6@R+U>lTq`|Sz0}M zHP?~AARYU_B1|VWjX6iNAgRscEJ|zm-TMn<FnVOi(C~dL&Bg4sd~Jg0<RSHBqdL_v zg`Hdi5ALS)8evls>g>M0>uKrf_dJG_YRd)Cr5oKJpl6o+?DgibzYZ?6>Tp<Yqpqd( zLTCTQQz&z;Dch=u@VNLBP~kK*G}6DlKDX*%Wb{R*z3uFP>fq_&zHCJ|Y_|3X#u;L* zyUjfaChv2U_*EM+aeQlO$w@6$3keTrkY-?DkO>Us%kwNv(Itm2SkkL&HHaObn1Orj z+!GNQ|8py(SHftv+1f`MHDg}IQMx-XrAx_1W@pZSeE*&p3JZ(<DRH|sJ_tMcSz{t- zsv816*$%h8dgDW?F={&^8bc|lrIs2$+JY4BYEv^qCp?NO7$ZibyK5$Bz+kG~y&fb~ zV))QVs_@L`rs<#aSB9xX=&Cig2g*E4p-G2{cEl>3vHE6WPr<^XhWCK|`Y;cdtILdb zZY*Wbw1mC69Vg`&z6|>67FgNUK|jFg8PX;M(-@OAVTAC|HYy7kLngI`8>d_9uQZPb zQ)}m*lP`81qox!}ay?y4BpLlgzIOm_^0lP=F~HeNc3$jsnfRwEEr)<}l5&|WFE70Q z^Cf^}v@U+9g1(+qw4>+Dm7^PJ*aiIzYalE!UCB%62dDz(>(&aemmhf-Rx48d0<Bs5 z2=(duQ8okE00LhP<Nz|1{k4~WvRT=I6Ig%W_xD%`A=p9xiWYdw+A~QJDOW_{C*)yV z{s%V^HfYfCaFbo;Zuuy6aQL{nOTTq&_^%U#4Qt0qGq%6#MtCl0y8<?)w#;S~5>1Rf zsy8|30fR+XbkQ`%^B4(M;&nW3CKi8~tUE9f&2|aI1gX|BsWX^3>~;z}3A@K{*8H`T zn+O8RdqY9yUVQgA%!8jW4<z}E{bQKGbB-79Jh7+1_XEf*QL&tu*Q~`Fo@(0WXF<sQ z?NzJPX@H6^M4fqXibEx@N42Nn2a#JfHR}o7B;M|7>ua5E`fbne$86BM-zJ+Z)wIC| zo}bk0QxDBj0Xsa;A=y^$-21fr7db6sHh&K#pkv(>#VOd9#*42*XlMGN{on5_j`<Cj zJTw-X5Bh$#yJT6zElTg-1jAGR9U6e;Y31em^z`nd``L6=`OK5nZA?u~W#pc%-C|;7 z%r0eJOMk%=@#kyj8cWu=+goo_Nsjce7AEw2v^W39E+avC!k0>fn!&|=107x6tyV^A zM?Gq+(6`buG6>;y`P;)ZF+#V`n=F&6yMmDJvDxt@;)}VSekRJ)D(=TpcU~Mhn|Ag< zURM}Bn@+KsmxuX&pKeutY}=r-=*THHqcy`vG`hC${OI`E_=RqEOceXuK_i{ZW9Kr; zQy#-Yn4FNfQZs>Unsuyt9~9)DKXpj!{ZrSjJ_Rx1p;+y@+TES<ltJ1&-r=qHL>&^O zLiPHpWfi3Bh(%fUYVEGr&qW@qGN(ay9?QOGNDgdj+*6aKEk^llR-eMmXNu^U3`N)F zkM!`Djrde?+&UInSuWme5jcjAiHRK2ZLO_q_pf1Y-+H@kWKqi&%@kSBSHzqDb0J$$ zIA>+@PzcS>J#QtZ?8!yEhR(mUwXwMw5ffv<>Qv#`Z<*(@z~FVbg2;#$0&&D&O3M8> z5vStlco#ldkVrs+Dry!S%+)PeI)LW{3A!rPx^I_azehc^SbQiScl07+mPs)#Ux7ww z@s-DFBz>NKiAH#a{9tZN2DO_74EBvRhl2Ah=UcyO5Y*bH?dLU-f(vbv@cc_0dv9WS zY?!4F4qC6+OcqHL;5H4Ihjxm<Jm}<1*&ckB7H#3%S}jnw8X#cB?NfO0nEtvuq0PZZ zbTet21J~J*bC%A4)lA<|kJZP{h{4!Aavn}k&wJw{mVLj!;Gr29MdZZ6XD9PA%d`@m zG8K&i{Si&AOo2-YIZnq+3h_VNeQ?zPm)<dq$&Yd#h;><Vk-&L7O6!zhrCe%Losb0p zI(LvQ11Mm8uQKka^|elfkdO#m^_E+uf{RBT>Hi=+#8PxOY6k03=KNhoT194a?o72w ziYb~OmMP5|THx=Xp_u8*8Hpy&ylJm~a`kVK+=(%_+2SHg!Osvp+mFtU9pinJ+*?B_ z*A(yT_C^Iyfzk$Ly3(~Vm5=gexpU_c7?%u+fjkl|vz8Bv+k=F--`sPy4O7YK71v;N z?{LeC=pyq@!RF{QMJ%jBYJCiMdH)uuwfnl1Svchb^q(=qz#yov@&yd`Vhyj2oD~E^ zkXrvoTz0s6s~{r*nbTNLdq)~Ib+qY%8%Mm!se+L{#E@W@b@67jdAVF3T$4>6ikqJ5 zT6VDfCs5m6ZMGTyB9+GkszI1!bznPGL0cgoWZeP?>FxAXeiH{r-&&);SM&FMWAbc= zE+fP)5%mC`a?>*e>v&-y9;i}pBq(uut{IBddsb0Gh5D7Gu?C_6?)a*uq3NjD?&mUP zrh#K2ca15$I&R8^&QrV(S*>l);8&bjhrbT!1vT5pLe@8+*7RL7e2i~+rI<c5NGZ6; zc<k2MWRL!d$5+SP7?pm~T!Q%?7am8~c7qtMZcncH(mV^#7x@#4=$`*bD0jw6f?|?y z(a4N*`(3+Xpv80!u|pm<^`QuQx`EqHgbn1&{MAGIc|xPn*6>jgO2r=utI5hH%YG7b zT@!z0#}c#l;)+}zxl35UL(FmLrFP$a8m-R2O4?q{$S>wlzjG<iZROL)*+#`99}2(y z@yr!-%C^aBtt0r8-?yVn-rko@R#Q`ZG19@bwZTH&kqID<R$#5^N~irC7K%i7!_()- zk37eH&@Z`1&RzPxQNNMbHsn@7n@m}))p_p#$KJP9tsJ*|U+HaE9L?p%lcG<opDEk5 zJUBX^d^EFr>tB6{+e#80Ue7A#a?fh%*Np2<FI=Yu!vHfxfWIobdS(+4Q4KlfB5_(U z2yud(iJay{Q0T8+I$mociQOH0%sqm4`|CG`!O$3XZA=B(gf84|f(b)HHZgkNl&Vit z&;KAJ9)V*1?W}&UOSyhvJg~8xJM85|=*K>I!0uIbix*P_Ih4fMbWuU&DA$EAnob72 zb3R8+!MtGlZ$EomZK`PXQ~cVkgYa8Ej*$t`$E7RH<7a%Is#CV1h&u}885ciaAbVsI zZNw0FF-NQVa(?@4kDpXf*>mIko5TU`=BAdv*Pa7d`Y3|Wy>6qBO^9{Xs4YXY-rH;3 zV-RWCQ&~jW53VGuP5s}~rQKEyQ&LI$kf-WERXBY>)AM#|GMExFw%Hb+%7F0p%eajV zr~rrR@YvWd%g-gYN9Jmh+NnkC_|owa>JC+U2Wu&z52w3-B-dPq!5*l`zlw7>yttd= zRqZ-4vtu)wU0C>Fe&Y#xRQ}mU{^U)e^g&*mfwyCW&V`xxu1A6NrxZ1u@PvHDR9SyW zS$;hFRdd0=*3b<?69Z}!^KR9gE_TCyHnd9-A=KLgLaW&|HF|(?K(a4pb|i>&qQKS9 z3pjoCH)NvyPgqNWs_EWzHQwtzoWz}EjCJa6S=#2;9jrc*R_WzN_kBuvTIM``HZ48% zhAlnp#+5dk{Il>JF0@OCUScrK*PKsjnqvQ1K5zXs4q!D=2N3W6=z)(`SFl%?=D2Uy zMmB&2-KQODJ6`(Yhf0~P3m`loY&<H|?osEVL7SLsC_fvLP(j_)2zPU<y83HoJKzx8 zZwjxD?q<B5E)X=XozC6b7oC<K9J5KY>){<!wd%&t^+ue2lh#S|KVWpOYoI1{zJen` zVX>zh?g(N~5Hqv06Qlfstq%50u=xw)x=}7GU-Z2SLgp#-Bie9RThZt!dQ%gVz0dEQ zw5oSVzR)(p_hKl=)UlBamHz7S`PqnoJdljJ(UrpUR<vy1sy$i5Jg@b=z3aHRxkJpc z8f@CRU?fY|%LYrgQ_k8PXNt?Cg;m4Uoaag5CE_$!`rdpn=NM3RMZB<^s`922NV<d> zl7J0x-W=nx=#hj75Nf+heOfZ>UKVP;#TCS4I6V;!rwlZs!M8-5w<9!f*aC=qp3psO zxuaAO4bt&11&Rge6KCA=x!R&czw`Kh9DrsGmamF!)lFrOxm`}s+lgdW0oKtpBZ1GJ zPnwF8e))L>fQfT&!x^fFQv_an%CGc?D><)6K{1$h=mOaT##A>=K%#b0AXG3xLT@&> zU{iO0?p31XG>SHd1RMCRAV}bx4N4EO*MzPb=tYPfZV=|Aj2$ff#OaHAS6a5e$mKxy zF*cHDT_JPtD|{EN7`f?uL9_qEGmk{y1|u%vKq}7t1$-(z@t=e+-*4919#CQ8TSdok zjqKj2#%Qp%jce5Tmm!wq0*uClx8pApBF0M&G6BJb!j4$=;YO@Je~y0fq#A^O(~cj< zh1cKn$n9^{9b$z<>aD8=a($GK4|ck@j}NmP9E&N{@vejf2fNf5k5Zj%X(d_5VKyC3 zI*;ApGor4m_j4{~`_w7IU*#)z_T2Xrn?f%*`cTk(Iv6*+e_e>%w0t?ZB^?^*tkP07 z7LEEOkT8=4HYxht{f)qLM>l=`S=01}VzKBc(_#s{y3Bf(xi&7bpp2s~HOgQ(sY73c z=S2gN<wR}_Wz<=^i<Fd0FS$%3%rgjn{TN!1sTXA5q~_C9l7iRUN11m2vJ|LyH2<Qr zA=>}sx7o7ruUuQ$<p(av>ck4WjCVfAC3B)Yy7h-Ec53?i`SrEMkD8uLSkIY)`yds6 zX4YOVuzT}(Kh)>vD?9_s{l)%+7HZt(@1`)xz(uq7Z*^?)7buM>0-1~{5X!0Ms&tyH zrpt9Mp;5Bs_YO4{>%1R7E0`>tqYKo!1HU+%TcWe@$^$#FcE?}BjS{2@W`JQ>S(nDr z($e3~aKTtrMuXw^%qTn-bM*?GY7dLB*lV+Om|AomqcP^F1Ku)-#pq-653lVyv2W$% zyrp3y70CrD>ou=&zzakEO5<2=7_9rP2=Q{TB8m8rT2#>`-W*N!{mLaz?w1qB^)4&I zhhN=C*R<1ElgtZ-j3y~dPbjNVg^t#AN_=45nH^;8qWLEKewntrtQmgl=~3A}yd&ZK zeYT$GkP8e*rr-V1P&bqr0y~oSPW4uJ`)n9J4gXpiqe4vfTxZ<E(auVU{>8H2de|=F z%O56|VU!=|RcGo7ykkV{$gzfLg87?yO}L@zYj4a$grU0`MxjdEb@O?vb%&M@+g4+E z=!}mTM?;5WvSO<Htp>By+apn!e4)O%cqg?=oUd6&Y+6Ll;QX|h*o(O|!05Mri&MD- zic2~8w>>f3z8)f^TAm`_r;du(I&)`bWDzU0`qM`gH`dV(?*2ARl^gN&!!32dZg|}i zViJLWpY$}IGgb0`f&H+Z6xW(y+1p8x8SJy0i5qwx_S<t}ymO@cxS?tztKFxatL|z4 z%yH2Z6V{BT*B6Djd7Pju=;gE=jW&jIPIE|jCzPJfXC+crHd>~8UW_1=^DeilP*GK> zY0<q@o&{EPtOF(NN|#$J@`~(*k8VSA?3$g$OmB;&5^yO<>Lf3Gz;H>5fx8Ubs?g-! zyJ^?qCGS;I+))Remy!$NO1?qEoZ#sh+b#P#7<b(UR;JlsZt#lBHG|c7!$vA%)-z!< zeUghIYLISpV9;w-JAMe+cxm>A5Fq<dx?x0;4>`@tS#z)S-YNGnlqm#ZVw)K!!fPx* z_Fw8`g{p*@!7>>+LIliDb49}lYg4~Py^E)aqV;Lv^PgkW)aI^V+B03Qp%g&}53#A2 zuF%zAo*q0Cr;`#({&^ccq~0aNRZg;FYV&gHLT-l)>c7zQ3RPwgA9!`Z)msD4zzmr_ ziOh8Y&VRp6ohnR3<(QDTXDdc={@c52XWH%B+EsT7lV#-Pl>v7TDExk_xXrIU8Y~~H z@RZUP%}Ntg2JAfJN2*p4)vK%d2W}A+gq!)wyU4>=Pp~Z_F@+T4p&pT)W7Bo3`cfX2 zH;gr-R*;LRxf?*X*&3+bD!y25H@Nj9{B!i@%nVFN|F5+6&rX|}%<ZczV+CMIxrL5a z*yMcu`Z$qmkmNuNxp(3LHg7iK2?u<%B6P9;k}PqDbNVs_hQCP1-!JRCe)rrc8R`z7 zCW+Wql8UM#do3?0#Kv7Qd%lfuZS9z=*RIyIynFYKnT<s#jYc6u)nj+1x7P`iGyn6> zIM=~k(ug?^7vlN1?7hP95tC(w>6o;G<iiPWZ}!28=uLbCFMD2(Kh{Uh!)(mG8RM2X zI_Xs}!Lxy**)$;+nc1Z?CWPG%<9V1CsT5)?<T+pXWNwUk!Gt2OeRf0P!$$?=$1Ak7 z1z|lZJPM*!S&yZq-(CHsh`e%>f+EA!W^_?;cQU8DVuHN75guTmpE>PMm}4AZK)@>D z3JS33G`G#U*rV2SiSpN&H%XY$3U+z$YDA7KrYkJ<FGf$q@E8Cn2ZuQmjy%IkZnwRu zMtARhNA8iU+rPq=!pkI_Ei)3EhoyTS?b-w#mN$7Fj(Cl()_Ex}@UH&u+*kPiBNtw! zFhPZ~OAusVt5*NDPvcalJ<U!00K0KerprX)s~i7HcYb>XnMPS+W`%o&$IQVoIN^2p z(4no*ch=+Ysl%fbRodRVua6_5qM$=!c{eY>*Q?u`)>R&VwV%rePiXlh;C_GPyYz+c zFj$i7kq6e2nncYz0fT8nulUFt^gHoyMZF7!C`p|%>nwm-&khX!hoaEyaZ*u#QpPC4 zD^FN=B-0to+pn&9q~K3Du9Z{%gbv7Jav>gwv*c?Z!VklRbmwBa53<0_mUnRnw{Y{? z`J~AxASOL_-fRb#ZT8Jl)?+B0FkK_+U2hLV^EMO7+E+=Gbmv|ZHZmeC-4mLomFley zvL|`Ga@aJhj{b0(ZJYn7Fqg)<o}KbzN2IrgC=(MpKRSp@9!4BalxU3e?jAqdtu@a$ zuNavxm4<O|tHIRmnrvh3C+nx{>NkEP5m7;HR?GXLjhk`cvWj~GaIAHf|L(2xQ6C8q zW~)R%7x<d|2@sWMOaMzR{_LDk^4aFs4=ZOR&Kdce=WrD;U=KfF4}GdvMc@S%f)VCl zzme~HS%GVga-vmO>?#YYh7lXDw|dWAlq5zO8&f;@@<6oNDH>|dAZ&Pm%WJC{4cb>s zU0V~@A1_Qet_yHz8ozdLj8e!Y^9zmlwR<&`QoFbXEy<giY+vz&xN9V&Y+hR(7On4! zG-#NE=$|en|Dw)9Hi4P>h8>=yU*#(->*(ZIeR#k))5HeLo_t!ONPEW1$fp*0*>2>I zU03&4JTrQDjidHW=O*mMylDV!Yx{*!I8genSnadc&t8b5N^%Z(dRD0Dm*s8&4L&di zaX}S;dc4j2coRb|R^UCj)vukWqdk5d7U4$Dva`&fkFCQM9G;BHn2N**qQABz;Dolt z+%Pm^72U^`=9fx>RXLW921LRmIbD6zAhH+We&YHXr6xiWjTYki%UX;UZ)^3SOa^%Y zJ`dLdh0<bm!V6`*oW~Ox@|yK74E6~<QfvA=cv{i!&tB`CfABqcr?1s#Fz7FtZQ_1F zlk$v{)j`;mqcd|GxsNb36c|bm%)S_!BI2S)v3tVy^2rin)h$1xVxA9crB;-7gHos= zGjo0@NE<x-2O4i}V?%SZ-&lje3?VVqog0%5t^i7|LG%!5xHWC;A)&)LSKsaUfHC8V zF>M|+s|IG%dudW#zdgSLWTnIW9I(uTc6<-LYYrzwKA@}WdRX_dSk)hOlufE;-Dfi& z>2*qx7Fp9mOQ3`&x9U8dMjt-HWW{%Fv%_S2Sxvd0pI=%mBxBQLmbt(Qvp>wOJ5VyX zY#>76FzIpiV)fYWxKH+1pIk6$u%dg55UXzZ`I8Gao`>SmGa$b_=<u-{_MK(l9Ig5# znHGMsH0rjK0-yHA+F&vH=Ji^zOa-kSNGKM63GxaI<{kW+(79cwvvevSZ24Pp0;)n{ zqYN3FeI$|Zh+)FN@*NOGbxIbL*U%<G&>|1t9=paCZ+GC@QoPLoQv=6g7pk1L*LM^< zvLPCxxwSr_twyZqFM8vYLI@!4b~!%CdfwD)Sw?ficZi&CE#n7i*MhoS@yArf@m&mR zmBU_amyS`TFJhB$H;jkq<*E{1xVy%Mx!mVE_87;izWT|s_o3#~5&-MuM3axDRoLeF z69)CojX8B>UlnJq`r$P>;#L36YqhJ-qGHmG53OOY!V|<Kag|c2?@<-ly;suN-Z*;U zyrF>T1)xh?`@RMkIo(+T+roH@nCbu~`AGV4*TFqzbnoh|s#ee2be_|7yVgvuLtd-; z9sIU_9&c@0-nXH%dl3WsA3QoJN5jqp8s$1cx?x1W9{p{)OYJc`S3bs+a1^@)o^yyA zbi7ou<cF&ZE5ft<@oYEy!Y8R&2DOer4nX;kv+Cp$Q9I4r^Y;m{sNM}A+0-7M+2q)< zJo)<O;CC-lMovy?=Vx-;{BYA+Szg1AG1wSiATCig{K-F+vNUsZkt~u5+x}+xxEf6T z(ISfo|8qY`Q;Lu!x7rDADJx5AC|wGOOWqr~rfui89id9jy!F(K#P>>9!I<$16|yEs zmN@>6leez24JDdiwRk`rc14u)D*!0pv-?LXElOl$WVYhk+52rOerG;!%8oJ~{T!76 zazaFGES+@QEnc;D&DtbjLZFwHjV$<?bcQc;R9#ahjEaF_A#`_~I&$#pMb2?<eN}NF zqszTtTX{bC|A0eQ*Pr5#_R+D);{{v}?_KCigR^%J#dFHY$X(vIx_~dy2%oi%r{Q)w zv0)s-qYK@1LPX}7u9R5!n{Lwsn@Z*DY)v}}+x%PJ^N;KpZ96hQp;o%q&-hmZ=K%vF z{mam6*RHAS?DXb-!g(F$y(gyWsmU;t4ogT7Qbc#f6?m+oxHEUO+0waz43%_|(WU(@ z^SaaC&r@x>=LfqEAPKkyzWO|V^6xH#y~G`~%}`;oZI#<+Dn46QX(}PJ(h6@OuIppR z)5-NOz?}d)flJx!4jFcE3?FT=arauV9<lGc`0v=@A<AU55hdje`QTgDxPBS9SRPyS z)YN9+g%c0qr_rDku>#-z92=%G>xN6(Sl${KDf6g6Ib&I+N6O4YdwP3oF=!Etb(J3b zYLV=Y*}X~+TocK5<3QeldPb1*?5cOhzmoAdlK_3(VEvYIBX1%fP}y#40Xf8?Id>Sv zW*!Vw*oB5DP#k9WyRW@E%we5O(dC0AlRRA{gS1YmN!Gzm*G2+*zFPv_WssyhHjYAf zAT!!gt{09kUAO{f2mo50!(XxohD%SO&zW{e@!;F49%xO2MYG<d6k092F=J+BvSjp8 z`Wo|5%UFMTT=~W(b3w;+H!ij=8)HAuagA18x%*C;<*>?d)7x{o1&U^GiOI?CV|E;v zLQA+JhD$PbJ%Le0(0R{9b2U`#BvZE9S-ERI&Z>Xl*>C$Qz5HLlekHN&odnQs4UF0? z0ji`of80Y&PmeV!mAi`{zA{=4aYu_AlSeukNY_}mJmODSZLb=Ggrg%*X_Y5W-YUlM z6E<Bx1N+puknR3c&jvS<SalejRNz%Q{=-V`B<}qh;Da>H%+l8{kY(_^NXjXwQPDJT zOS{ksQO;LVlVQ|GSM*_b$fkpCq_|s)0SW|C2+#0JHs@PT;D>69;y-9kO;h?~Q2@tq zgqyWr?Es2Bd+^t)7p$Z|;u9-<DA*tFB3=P=%c(}?BbQmo1BO_h`s`uQ_7*Fp&=h?M zx2yQ=F1vB<UnX@<E|2ZatxiorfpmZ_^&gfw2lKVRZA_8Ml|v1?d*d{A#q_bYtK1uS zaDA+QR^k^PzVFZbF36j@kyE!--?TPPdRv`liMnW|=T_<G5CO!r1KAV<FMw1}?BgXF z)>osg3Lnb~x2572?~LQ&p5b~xnX`}A?H^1dXWB#8TnOlWEEL#|j!808Q@>%>3r;+g z432k`^nGR$V+Cxoy95rcQ=+(t!a*VvFXg&9)@e|wl&4$P6FA)j#rKHMpYMSZZl)!4 zNzA}A`3;(*dkjNv*>;yCu3KOA92Fj^)gxNU>ek=Fzq>MveON($D6L@4ea>Hb2m-0Q zZ5OwU#l#q9y*Y$>3CK}dra|OXF6~+=5P>!QHCjmb(mq`?alqZaD3Duxfp&rQ+e8mS zD7rkfVySwy4p0F-(4vBZgy=}Q{52-U{x=jyUxUlfa^7K2t4o6ycS(><<UfaTwpjpw z3ney^MubZjG44^1^`0V8Pf(PT>+5Jqr>ccYT?zn=V}az+S%tC0_Lh`ccIrUXp8@SU z>zf`q3IysI#O(EbzTQNHPkKx4Hw@;%ZHlZe?Nb|fIkYiT1Bn}kH<WzVm#t9pa>sAh z6AL|yF-p%2h36_2tf#Iukc3~K1H{2&sxddZoj;XMMkHI$V>bbqa&R!xW%=W*qxVwR zGUH&r*QWzPI)V~?8@As|W70iX5fA6~m6_6gTHN`TS#T*Mjc35h<GkFR^1aPthA2<F zLSH1mPVjToIaqWDv3CB5*|L)CGFThWDV-_=I28Q}h<`RL6<mT2_PufrQEpbLyYr@O zDO&`$tI22C_zM%FPw@QLQO)Bn^e_@!pqeYbDz5%T5r~ty`XZ=AM=Y(~k!neT_ml0# zH>NLW0VysK1Lbdk7gN7Uik$prg(66OU1`qlI%0E^XM3G8ER_&TX}867KD?4QSoe%? zw7Elt_3ZX~hnB+k|KhJx&BuKD_%W$I&#Mt6SimpEZLJx&OeWsy`*vTI$K}`EgV{F} z^D`@n^V8C*TQi|zi*@UW1)$kIOwIx^lKkaaRJLEf;eV<5J@YZ^bGmjG81rhms&cZ+ zyHN?a&BUco^+(!azylWmQ~);jwSsHEodtQk$5s}*LxziBupybMSGqSU_1M`As$?XJ zpJwA49>t1oUO@6+d8r#B@8$;O+pMhn5J3RKs=JMoe#1u2V1BR5aXyh$Z`0S$jrJ5S z^GWqb>m&y!hpRj`bJsxW-CJ2y!Ca!L$ej(K%JlDt_Lux!IBIkKRz`WeHt5;3E5&EY z$aHF)wHr46O?fD6E4HgYOz5&5*8$XY@0M#okcDirGjPY9*sqGXJ1-ieT(&wF<033H z`U~#^B8F^6m+J!w%m^qE*^M7EMnA^o1kk!GfqM>1<pgfSa-kL$%$%}%BnJzNs?lS= zU4BkZ<up@uG?jLddl{D6M^kC#{dF+Y*`k#ha~=JvPICvs<nIpKWBQ{=VB%^5whBDS z2ctg!nuL)z?;r*5+!YnoXGlx4jE`rPX1;%4`LXBG{p~rQwO0yuJ(787K^FQI;;2Ga zqnlYr_0EuaL$dB)lWF~`c}B%R{&;nNnv=P7Priu9=Y$0Bw#~>qy);Oko1A*UeRE98 z=n3(sS6D5W_`R*aD)XiCcuru&Ovf|u&YI29SZXB178HB_Q@h~0TLDB2P{z-ynk_xW zcWh0*<g*_1u|llRNDzv^*@ive&f{(sjWE7u7DI13&0==y(+d^_ZXUFMd#bMH{47tW zTy3ZD&Y7j9@R($v*tb=Ajs2L(l{4MhLT*(70(qQ&>OiNAqX(dW$T7xdan*WNUmooQ zELRA5gYD{cySzp4126*VraUzvWaXYIy6<9XOn=G39`mkzw9F<)Y}_YNr~KKa+0#9* zuf^*%UTYp|Tjdqci<_aHuDl7h;jh=Ps97m`I*?3x?prU4HYQ$5SPkT9hUN?xodrUa z+4@BB14dS3Y?tunWulrBLGVG@>w#z_>3ixJQuV8r2q3ZQzhqTfmLwifFG?p3Xzna_ zY@alw^3Qd~#sCTtMoJ7UZwx@={J%>aAis(e0lpvjR@Ig?@*W!PJtz~{)dO~{wpqu8 zz4e&`G=;&7=}p;(yH#&uH(Hy_N-02qq%y`@ciP+U{>Tv89*Z~s+*4D9o(ZAm8z>NT zQE4Y<d$<@`^n?Qs_I#E#^CSIt_%{WXz(*jQk#D3aG28tH6qxT%5V@*>5WYR%*YePD z&mQT~H4NZ#7)TcgkgS4gJ<9CYufkuxI^MOwBh_skx|1Feqe@g_ng?<d_5UG51Xa-b zbAnC4i%H0-QbZ4A1FHy7h`hYMm0XwMhL0`K5mDLu1Mc-Q-*pf{dHy{=<Tk&)sC%iM zn5>b?XA<vVFI+KOeyI*O9pL_a#eHR{N>y4~deL3ld^{eR_xtyg=hpXupYU6%RPb{m zi4xOeLYY`~jWAxDAF5JPQX#Vg`99Kk`KtvkESfJSR7=zVGc1qfOi>sFBOge9$KWEv zjY%4@{O__+3klWO%%bJKr?kpZT}U$8NhQcMG5_gq>B`K?^A`-@DvQt>GOyGv&!?;! zd1<@82`x}$f3`X@QMb@0ZluD>$~_L8mom7jq%4rysRCGJR>rFp5y7=(UFc&pCUGgo zZ4=Mdh5WrZc=p?2zyQ*rRiEzIP&V7IxwTxgkJ{}LTB<4e4wARk;tcl|M(pGf*g(0( za`Gz-dw4K$6RdUDMhDWTVSAwq{aJ*u1ycmDUN%w3#NJ?>yX%Rk$VQY{&bS-qO)AJw z-!8WM<K4LGkeKL0ilH6ar!DYWXUOweFqKbyC~b~Z-{o`%Q_xNS%dZ+0%kA@u9vQZB zc!&bUs@)5zaL`}CQ*z=CN&R%9m76%aKIh9z0`-DbqR;hYdG!flLR>8TQ+B01bdE>> ze_-dBesLoTX(5Nc9c0LV`<EB#9O2HBKQ4cM5HLik+ALhI8Nz_!9O^)T+@gD#b`Eo0 zK2|Cze_LGIy14%rThZGB8+@qmprHk=c5AEiGU!G4-p8}SYu(X5;CHq&Mno3f<*q_& zJDwd9$LoexOyGsvbcsA|C+FxZ{(i}&Yj`16*al@WNWynYM6dwEXS-&8&&TCYi(>X4 z)6t%ff%)dVmiOOz(lH{C(Z^-Rml~*ZnIO53KeYE1#TnW0>&ra*>&drgFCUN-FX_8$ z<BwKY9sHKoDYk#r#=>0sa-rCFc9#sRdFZ-Q(*gjz`t#?>yOm1}$TG8WcYqn^UrN8z zD1a9Lw-51x)p-VB79;rfOT(&50y`LgRj7b6kY}67rQoFWTrqB<_{49;ef<A2TbWMG z=(Yq8&>$vr(pWTP!c=1UfB|Y{luZ^gxjm*+^Ju>%>a2Cw$u`2dIA~zj(T(ZpvkZmS zz|c@lX^Si>CMMZ15GOv9(yp>?4h6@c4%%3p!648}=M3id|FHr|^qeRGyXNJ<v|uD5 zrO@pIq*<m1&sJO%kKKe`IBg6-h@Y9!hlD^G{FAdbf8-DRv6^~#|HCLmv<CrmJOUCT z<t2$wPH3W^ibN24T?(kHEqQ1>VExC>JyLC#2$U|W!hhr~GBO$!P;)`0Uah<HW`bSs zoE~s{DYT3mV>R-$b2djxFSN*BxB#u4+w}iawh4=AdfVavSDVn3TrcOTCM6Znmu)Hw zjJa0}>;BWbI<dJsDWb0^BBbf>BlbAVxp5z}bW**Vt*(3b(;sVHo^1d_Hr4#X{>E<% zMmCI#i_5dCMIbQXuUbsdUt_d>*9$F7wN-}m-jb7M!Zp9O?4ZexOiV23=;#>g8r%0- zu#D};gB4Pk7kRkuQU;Ud1=+h4&^<gYe@LZ35)PQZ7PQoLCX>Kt)~~1G7vLB#8vuYX zm69Oc2rs<GY<Rg5e%ZcmrppXYemu+ywkLCt>>Tcb1|8@MIdz~mzP{*jw=(Dquv+86 zqBCB#S+c(l{BEs%x<R33K`J#5ac-hFL5qwP<ZJyO$15=SHl+?1gN7MH;H-w)hfd3~ z2mkO2h4K$nmGGec>M?;XCVo8`av1MD??56yK@46X9mGug(mD-P`STcYRc;z^Qo~?J zuYuK;jS=({u$W!jYP{HmW}%mMuvyd{y9yJ37zi1AVdpf^skYiXk!9d13^~Dbbxb+O z2q<*L+iC;L)dT1<x8FncUqf>Tu%$lG9q9VYzeG`DY7=7n*W;bWp9fYzd;`vTK!$0J zv+25BAmcV0LjfqORjLIDE8qppL};WxA*N*vXu2Z}na>~vs(ODl2dosU!=3KJMx6N` zO5^m=s2x#l5)Wg(x}QcPQ?>sVjl_iP>e|}d%j~fwIu9_EWLU8z;HZ$R_O3idLbU7x z{&jECyx5~63-r?N4BzednYt~Xxc^!qp8rbW(cc=zJx-9j6TP6h!o@wDQLt9}+PG`` zjaiM0C(Cc40i%957Yw%n9!gU(>&g6ua3+f%U-6j>GJgUs?QG=azqQ4PnhL{9!+w7( zwM$%e6M7C!@7lU?U^(q3h4tXl+c7<nqo4i&&3~c~q2y7i7#GkN;0w(z_WW1rZ1Wak z#q(W444*+oWg@Pl2A?^H@!E|AXd((<*_$ohyi#{OG%XPT+Cem=nW|sF*`pNaI{%KA zdTAG<+cK6rjP6q3nZJ3wY%ZpXvno(-EC;tJa`SX%^B(@U`0`Ioj1`&8RK9z>UguHM z;^SfJ4{Vj3=h#R{K!~;NLNNdK%=o%!2J<ChX&ySx+(@#U{s}r<fWDmv)Xq#`JAza| zP-WpouKqFNe)%H7%q*A+8R0cUZ6`J%OX=X#4^Rl#$6@MA9XqLrj_V&yzr26v(Vx{e zkb{e^9&zo}_<t9!>Qq}kpjPtN1-)w|DNcS-xc^3zEaYnBSpv35(w?yLJ6vOOkr7lI z7hF5w{}n}Rx{0QklbCKTD`Q-rFrRwc@9K@`oF{_*m+oVP)v$K$@r~ej3sd>&+hD)L zmKoFig>a%?z%1w6PxpNHof4bT&1{#|DHia17|fnILq<L;;E(HFi}flXk#DgY0m|T% zD1yOg$^H>Kv|eMiUZ4Fd?g%1)X`B!y9xdhGoFAX2WDS|?|Em8_=QH#o3hY$qcYB8A zxwX)~AZ7d{IzZh0>hzcQ21zvd&JaM^medINr4>#+_fG|`F`u5vm$b;Lxl0<*NZYx# z;2~fg*SZ_W_YQCIo4QzWx9fi2*M75001FgV(5$j4aqaoh0WZWgx?dS(t3H*ZENPGW z%7lTt0yN33u+ecN{ufj{FYT7|{kWzM94}r9`XE~{Z`T4_JI0-Y5;cL`w+N=>u?lEh zJU92yBH$tjQcpnlj}T&|XQKAdxn)RKo&#M^1%oA<U>sZ{imtz})xI^RPFz`DbMQU^ z$!D-T;g)fe_-S5(LDUA%@g+aVRy%~8ZTxrScb34+g$?{I+gt;pjoj=pXt8^nBz;Gr zR?MMO{9*zEoBY_vj9xHtmoI57<y^ql!bWEfwJqM}zY<loiAj8ubD!nuK-W#+a7c3R zjxO3v0$l(A?}5-ft<G-6hrgC+O}TjRcgQSf`*+tfs9!;xM$)O7UFGH32PGOsnOSu} z9026KxRV(=j9xzap)^~MN<@E7)crp|YwB)KwJF%>8o4@o0GQ>Zrb<Ho@^M$$55OOC zL(S`-#zT5(K$-#qm%^HQj58TjYC86)wjU!>fqzc|{M=soH#Y!xtmU6HZ@H*J<SIP= zCvZ*3jYccqbs0s@L;x2-(jv>h)bys0`pGUpOHlmTYfJo~rT}6qldc~&Pr*%tfk6Kb zK>ZyevUAL7YMFMd()<4XyGF%bIyHTmfS8y;*ym55rd1ic9tmFtnimzyWZ#2!{4ZO( zGzbX3i;@yb0YhJ3gO-KA0I@Ig$0C3D|H_V;uY+lpKb$65vW}4x*0IywvG6vODsMXF z$>6@5D^cc=_P!wWYtqr67>kxJWVU8~!eW0xh9bh-%*Dw_K`yi^DAET6aZ+ihIx4Uo z{~cC(pF^>pABUN6ir~Av=F_o>7<O8{j{&@n&oo`_3ED?GEFbj?fpU{92P8DTG-TI< z=u05YL)nF>ZsCdP_9BCHc4p?!9x|3Puxn&wWqJ0}A5q!EeWZJ$47}1X<Q&S4Ewnjb zzC5Nd=u-wppz&%|DN_KoSv2wnfcB#fS{o<zT(fMe8J-eR^9rX~7Zx<Jaw4lnHx^k$ z`GCw74Ahf2yV^8cO@lNn`1l+jPC5!A%iQxZc15_!S-@LZO`aUPn+;rpJ_kmtqIp`! ze!EA%7ecMpl3uyHby{}D^Qr@Ba8{%O;w*uOzc)j!r$-9C(E91_gcFHkY%a*-1KDY4 ztJ%$<zO4@K?XfSI9P3e3l)gse&PuGPTUaEkUed<<i){L+j=sU?k)V+VOjy-~_b$B5 z#wh_b2xObd$3d3#t)1#s%53h{ZN7)D9WU&V72{k_+zRTaMGWe_MQB8Ha*bO~G5}++ zfE8+XL)(lLOI1vUrGO4js2x=I$>g#K-|9k!vvL5jVBRA<21Z89Z)?xpfe?~o-2|3z zNcA>(T6%h>vPxKUFjW@cr2FXU{a^t`^L22Y8!2T_6sbmR-r8LrkOx}{vWXF)x>CM> zmywm<zE$x|wikF_Yg>Tt<s+bnvKUx2z`5>*bW;A+A6h5ssK(aQlbws$O%RE#w=X)` z+{YYX_Z*~EYTeZ_wZyc7xt|0oWCVw$mK>`<(~g`MjTzK7e!F=VgBi^71d;=2D^YYi z0#41X#(~hSi9^~K8>I^qElYz11$G~3dKctlGavaAKs=wzh((5U*!%kZ=8O;7XVbaS z{HN`o6R0x!g?d7g?1dO}cXWkFK?tMpRub5J8<RNkUUShbib#$KdLFA0HJr#xCG(7o zM3vQV_d_k_apS3Cxb-t&)UrWbIkv0GY8xD@adVRQHt_?jgQdHNpZ8z4`|W12OGaBq zN3MERPfw38W<%dcVmu$EvKvz0j#*z&6wdOgIeDAEI;m)b7J~Xs3(gE~4;C5Ydbu~} z_CL!jC=8t75%wMAmehp8y=KYW-Lb-u`8sSN(~cJgyFmeY0a5`{>{Zv)n-;-AOv~@| zN0!51-q8P0Ud?C#cmW%GynJ)q2}1*Fs-9vpmRfiTC^?ltk1OPqgBYg?r=YWS<$nsE z@ks6`U}~JF+BwQVJB-L)!?AiK$(&2{8z>(>6C57b3NJ1$_QmjmmW3kY=J<`5Xxs6v zt+6UposSsc;I#k+ZJp=&JOttu0ari8&A6KW3h$xqkqCgbzmUNXUj7V;t+4-OOM~FL z2ljpxw1FltM+ZH!+k@}Iq3+f)(IwX7=?RY-41vB662Q@9VC6`<#-#9~Ro=e_gRR>n z?u@Ay50y*!!mS_%$1A8;u&dkFh$zUz@p!4Dr+*qSie>}UWZ7Sw27F={_Vmwf3U>U0 zq^@k0oTAK)Eo;U1f_LvWWyr<*zq|okW**>neRVQ{!C+Xpxl0Bb;hvtJ4JbnzGzPS7 zo(4_u76;O8BN5|(p;JQP&ub3)9;MnD$Uv~(=zUD1Ha&rRa8=IhW79LYQ4a=)lgZx| z;Xy2fVeI?UT`h;>6V^Q@7|Y~YGT2JUVQyF7hsYJEgUGqJa5CrVYTX%Hrz$<2I>(5& zCZTG$SN;#Z=B^1k{Cce@;^X6zLV)vrU3>t~7;TwM@p|({bZ{x5KVu|!6zIU9otdU> z5rKrhqVKg*22P%zf*RCUjq3!c4HhV<pedkTEy&Eqrmn569a0gSt5c#eidg=+bw9k+ zx!Xz5@%J<2NRiDUle^{IWt)k$UEk1u2l5C)^$4#uK$Lkdn&cUjJ%$V7WVp@6*cLM6 zMk6&1vUrzx-414`gkL1->zC+oXUO+=p<OB6SIR6(w4uxq=s-zH`93tXU^`DRuH3qN z1*qmyI<Y_vcdIza&MOi~ahZ!TS34Z~`xt}~K#cKfWZl1S3B+S)Wt?m#;`*{^wwDHb zfdC`uy6giPgRynSdLig6Y}sIXr`c&$!P(U@&iE(j_<4J8nsr)wF0UmwQN=jrq=t_p zL8>4QXv*lI%t*u@@0a!}^zMosDP_0{AN`cjDR)eZ%+*SMA|3LO*Sr)c$$BeJ*&ctM zDSNtpJNnxcFy>_U=31y8?@m2JA^|I21-d`x4_E64Ei#ad(#$7wajI=<WNUk31OE&Z zewM~Ie%a-ivhLRbw?4Pes+@ozcF@7J{dFU)Uo-<XXj|Ip@~FZZrjG9l6n1w&Gz>1A zW9AK&Kh+6&>j4dZRb+6dW^?N+Y8zT2phI@y-LN9QOUU1n7dlHACMG7x^wuBg2DAz0 zv3dhCGO{rGr?s(oUl;YOyLkukW2#|8q?F)|8q_b3U7(XTPwx6c8}JSv(MCe`(oT{4 z(T`!B{jXHWiPU!lM3s+#0-}#B_<Jq7?_eLIt{rApyVt|Qe8ZW&y%y3AmcB^?DY{T6 z(IpbnNq7cy$F2BA=1}%P+M##_5WR0Li1J_~hIhc>Qom&SV6c~xzrLW(bNE#YUi{7> z58ee(p2ZirbXmRDHH%wqdnBz(sh_&t<!!cpbsuFLfY;GVfa(8_*Nz0iT&e7yN0pDH zA+OpH;a8Wc7Axwm^eDV5KMTS7(>Itz&KTs+&4>^YO=xbeC!C!-?FkN~TRuG@zOazm zsoeYLl_%<jOOYw36@hcp(~yBR<&>o(;c5c4Pp2)Y(U$)SlDg2jwy+NFlRCn!b*98V zcZ*l3$WW;=x6ldPnnZ1(Ypv_@SXOE(J?ObBvF+;8aCA(0P~La4CpysSvFel5Z#7_v z$%k9^0f&Uam^5E#>i|e}YT74YO(Z06D<&=vf$p<4ze~_k?NL!}8eR_67~EA01GHfQ z=%dP16dlj{_U)W02~9S5lfc)Z#nw^)soY(b7^6~wf_CtIUu-u41QpEZNhh>%LM{?B zq1v_J4171IjgVpVaF_3^&YOYO0Dww|L9d0VLbLUOB;^eF04mSkkhaBs*)TO_<z&G9 zS@uQ>L$7IAllOl(g*pjK<)}Z9L9^+9@e38xkdk`CUYD7Ir9xB#$}e#v7G&PPhwCqX z37HdfA(V~4>D1NKUgvtUX0LdZx*p3?*?alq=~g}7Oo&Z8*j}<)45obk;`!Fpp%wy2 zFM~k$>yIUCFMWBU2aLLwJ$)8u+W(%Rb-$r|bARz5!F#`7)7}2-x$XG@d6p>Ffn~~2 zE2~G3z+Yp)doLzDm)KmY513u*515aaCUKFy3%UJHB8_7p_N`xlMHT4ec^&R9#b_(e zL!Y49!&0N|OHjQomfz@4usF+;!{aofwsK@0wL1o>7G5pH@`+s1vJ@g2cb|TEi53yI zD9&FQ)y;_%Er>vKoHh?R1tk;|+x$JnD_F}n{TTE_L*XDOioI6^F@7a%qbQSowfn!R z45rRghd1IER2dg4>g(jB-@OA}`GerqAxpjJvj`urlkfUKEhAuHU}V0}sSIsibo~%@ zGx^gxR9(jZvM^->Xc)_9l@7gH1R9<HUtrXqOBcydrYQ~oQXz|yQ@Vv-EVofTbhVNA znLYn)x4RM`iTT-j9Gt>snY2)DP*%{Y6Sa*>_7SV1&(q%hg3|91@C+%98L7zt^@wUv z=|iHMTynsl9pzdjY3$T|?>;AIFk6UlT>0-T^IhACnFR3462Rc+R~}V78gwhI95O%u z2pmNt;NItPv?f7fG29lRQ*88xih-wRD875KXaD!^;nLlw{d8=3ZSIKG;gtPL6iZ@> zKKZL3Xrs1pE8}i@pZn_@*3tCEsIz`A*sJ<@D1NH^@CYiE`!0un<v1&bh5jD1?KaC{ zge!hQGN^psQ^)=4Ikxzv*uH|AKAT_v5Ft<SS@POg^V|t%*SEsf%a=#jyz2EgH>TaX z1ki3>m-moP2~M|OE~NP#)^hc5-<TC6{&~4OyWjHqMX92KtcTL}nm>*YkKFS0s$`TJ zDpjNn$Rbih*!5A8k|x*hl+@jS6B|RjFB}=aGm$FjvRG)ZKP?eBbJTqGx^P5Ukpqlh zNZ`r|@^U-*x1YSV2%Ko!mNOki0A8Vq8@=q^lxRT<qnN(l&tc)=Au^LC=86~HVPD5{ zSwA43O}BO%yEmNx(QC$5gWP4Qud$~mtR<Az*whriVHL5u7@@4x@Y~Q%F;+!7ygB4d zWklrL6n}s0%Xae4{eyN6rJR0xT9M|O{Y%=kCFH*DA3lu9$fj6?Gw!z`X}F@E`%rgu zpv?`<&7Zou@*aB;QoQU`P*CWI+2+|sB7-aw9GM#74B;N{_ws2gEKfel#lKjqAT;jP z#AmQk%?r;^xOM=)!7YXhj-uv$=)%+Kmo<W7ZX0#2s&I02d^T3|#_baM10UNLul6x- zJ2OVBZ|xmihTVQHL6`jedB?G<>w-qjSr&^p9bMhch3M|Sd^oi)tiA}9fNaauEYK%N zYya`%{??FU_3oPfAR>m>Eo|ZhoN;3lEAn!86$ndgTJ;XsMD>q<w4t6#nxyKF=#*JH z95)kD@mZ#h4z9pSB3VQG@VjIqrF#0CBoIfVKdUa&2nW6;qJky8Tqvl&FM_H^e@SbP z=Hd*b;;}4b=T+c)csSpE*V@LWsJxs}<gR}!S@#=#-NcE6*KauJeolrGu(OX<x`jvY zovVxHtj%O(aoX4`lF2XJ_PrSA@WT2aJCon0)O^xA@`)7ZQcg_G$QLOK_0Hv1Ot-V6 zqvH+!E#q=q8P>IztKRz7fkBM}%}=5x%v&Fn+e~Oh_UEd-x9okVnz0^Q@1uaklvu2q znR1T!+@zi{ZZD2yO!l&l(8*)xT4@R(DJm+uUx=}_7QcPQ+q<&dDyIV1x4_M+T^Bza zMB%VK!c(VP87LdYp<1CpL$H6@a60V#_^Q{hIkw!OkeNrW<+hXIOp1Yel%1eS;LO@f zj7{^0o3GN+7+}@ASYvrP)&)w+hqis^ahxgkRvDBknptYO@7|eW6vZ~d@Vx#1>NxXw zsM;@pk4h+d)s!XMOEE}fDa8!33u#c6LK0&aCSzA-P%kZvwO)G^Vk}w8G*U6v8O4k+ zjj>P0n4dK=%<rnt=l9?5ue&|Zx%WKFdA|4DbI&1J42l<j&nJ1c{uRf{LA4HdJ?B2% zUCq7e28vG8j-mLUHROh$G7KC`w$CH=ib!cqP8B0VQM&KmTc@taWim*8)A_gD2QpX0 z%fvU2QOX}aZ?5(0{R=}XFe^0=8+Wz>8thK-%14O>mdRdm@kM&Sg1lz>n^h!Xo9JY; z)AX+>G-<sicq1|(`<`=QOFH%?x%Lj77FLm9c02I7(slqu1!A`h461uR&eWc-87f&w z=cZST8gz{KWod(rkBrNi8tg6QPxZ!`1Aq#A5)*T{W?rEbxUQ}uk|ig!!l1teH<%c| zjh|Aw%c2&C6Cd{p7Toat^`jl@f=6C3F_0880%8bqWuX-Vt5?(Of<{-+i!Ttq!S%cq zvSBD^NQiesTeIIv;HUbG8^7niA8*0Ng7TFuG#F}BR<D|NKYx{WHE{GNocj9$MmESO zN4FN7h2Dn(%3-=*mh6j2vc*@b&EyCOEn-BC1>|PqDJCJr+uif^ZCed|q`h@Uj<6 z7F=kw`m7NdJ0&vP_sbQR)`R?hbtFv#5w@@)WF8AmlSjw)w(6B+=!I_FB*bt`XXM-S zMfdke(eTPlO`X5r#m=avpK=PDUAO=meG@O!20sy1<~OLo^0K7U0?r<rS;9gBY4!X` z#`njWaI<oa8erZx=qV*Tyd*OzUmT-6kkwH+Z=w#H%-`kEVX-M97G?IHo}L#!j#A$7 z2dzYNr-cT2JNyVzL8&ckSZF)q+%@trQ!7(`m}3}y)a&w#+R$FH{gG?Bzod<QkLlLN z{909kpDG=BkCFqq!RVfSU56cU?lJ@1MSlMMqHXbeQ4RIJ^w*N@7pD%!CSvNm$GL1> zfR;?=D;%IP>uHCAYiypKDHv_^=X-XRqo7dw4Ui;8shpUiv^ftuf9bA$EjnYGS3r8< zH`q-gd3MwbUQ<hDw4()Vp6TVMjWt`J4)HuB4gI{ml`uf>&nmY)&RXaE3azq=VP7MD zJ`>yZ)Sg^bjaqbq6F<!+gRV6A*rG}4Z^Fe@vkqLBl5$i%rXR7Wdgglrf}9J3V6+ir zPd~rzyoR~mBLulX5-EGyq^1q9!Yyx`rgpXs&qp$A;WMd~ry-D(l)vP}HdQa##O`sz zc|a6m`3_GUYyrBcPKdSkRa!s(Uykuyt%^Z5@RHxoHM173^n!aQtc-^<$6o3#1vr75 z^^RKz2wXG8QDvUkI+Ody<4>sG(gcK98br`OP%CbnYyp@2`#Hq&q`v<1FNMOyk!~Rb z1Y#~CM?x<IPEtdZ8}UgOkkf)7xA7>85Z+dS-27UYUjjXW0Rkt!WQ>qgcL?asWmd=) z)xlJ#owKhcfx;5Gnt@M#@X#9cp^9T+R(`dL5;#_XF)n5__&LCpj|N&_>S-1P{Le~i zv4>M0pPU*g6%b-k8NdcO0*ev4iXeM@C8M|9U^<+M_D@G>LZ4O_M!-^1QfLp2<-tYR zzKus^1*Ip}q-BJ-Lr)5Uq$$?mqY_4O2*m5^YDp%$qa#&Zq!I!5worFTyWSe%?BaS0 zfgpBG$c3+Nc<|9`3Q=H&t{BiXZt>wKcc(oTtWp8ei7BfH_Gs|IK@GF*{i6=9^llym zy$Ko|Em~zwP68{=5p{L-K>G6DF9E~p`B)P`+d5K+zg*PTf2MypNXy9hj^O$C3PgUH zZyY{g%L8gl+gY_!so6XG_n}lOAaAp>%~RHc@szjV;2O5270hbB+u;o=oKlwRD%oEU zx0NRg&0FLEDT%@cB1fD2`V%{>U%6F@d09MC+vK17+SE7;gC<NkVY5&50S^7wz1(fo zjrrl>ZQ6&9B>lX+Xuky(l@fH_#bs%u8;s42n;7<Z=nABn$x&Y-q6I+s)vq4g&L}PI zl^I<NpjF|<9r@-s8G~wgX>zbf|J;~lGbhuP{?V7$G8~T7QQrQ%bYCZgDh$HKZ$EHv zeVo7xBRJ2UD{BgJ9V9l02iMem8yN}R;quRFxb|VX9X4)tBBAsh+@6(=&&0h0KR?lj zY8y^1L$5c72ry3A+4Z-*hgn&{x~c53wZzuCQgbm0{M`iHbM<f9XW22id2@!2@;!;@ z_b|UpinhlCf;oQx#w0Hjrhi-g)6Tivyh8E^66x{6Lg25hLqH$}@=h1l!!INHs?Kk9 zI_X1&Ij+^_#aEb3kKh^j%^oeSxZc_RyJJ-9wR^KZbIa!vf?v_e?9nFAo)>>7Ccdoq z|Nd?dx)q2#2|K^34CL_=KEv40YISjuhQ{s##s@u&BWxs&LP^U=pTEOA1NevDrF2UH z845^Zdx`*rQFD>)9-1S6bE{X&sF9WRwqGx`cv9Qg*fBc#Y&A_-!O3*4w@pXu(ogRA zgDy+#P*q8K%pyh^GD<(j9^m_co*TQo=1z;bmVr;IYaSNH(g<G8<iey5k8zPkJ|8m* z_gMeayRP!%U%e)$;8m1Z=7_a!)uLGhHvpoV^$*bJtIWZipD@E07KH>_cb{pQeY#`U z=YQ%;;{IZ@*}aXjCH}{?x^g-n9oG#0XxeF;Yl&5QB&p?lGcQvHs`-FZ>hy&;mcsZ^ zI03{b6S(SYEbZAr5SJ*h<g>M|RN-WH0){fqyq}nD{$qgtC}<1|Sf2xIx3ixj#Wg&r z(&6FSR_<N^*6?5Q)&p$%)J(ES>eb|m+~}b90mC66=J$ZoyHlOE>)Ydel}@<FxMrtx z?+S{4lOo%w_)2ZW%+DcI1XaeN{H1o_v~Rr4=zR`|bBq6dd5aHw`8;oFv`SIkTF}eI z)%6IIV^NgQjy-nZS6Ul0yl~4I?u}a9P|DXQR5atpE#i=4lqx5P@|k-@A3)y;_xIut z!cg9dyHAh3Xt1}ovCea*^6U%5?IIgH#LWCzVB~807THzIoKA~~3?&odI(j_d`}pm= zi6pn%G{U1xWs@H}QZY#>rB{?C40L!}3V_W8dSI1X)Or!-Ms%<TK*x_WTPgmH5742r zzfq?7>(}$?&;08Hw5Y&b=8LQfp9`x(i<WRL$@!vXYT6Fk@Ci!x>9zINAsm^@6H*K_ z(<$W=`37d!u3?gr84J^nllac)R%>wufAdhNBJfjp4XgSt;!+exMY}wQ^b}ueAW7l{ zk9Gb-31~^+8SJ8n_sXn|po9egA3#2rtRGxFN<&OcOn6!H=9TS6uu60U$DOg{E*D#r z=e*=~BqTSoi};k)7R}a!*gI6XG$`>lvs<mm8kkqoNBtXJgL+g3jB}r7&=~{(b*LSk zbx8Pm5h)2>HsNGcvBVR()Kmyi_dW5+!=9N2jkZbV($w;XrhH}5^z`j$;ByoJ6J<dF zh8ob_ksKdxy|`lcDU4`|e>&qbz%im9(|pnTc~^ivV?j@IVDZ_dn=>bX$-8?h_wXOK zk?(u(hkHbQOcV8g7uHq)B<~iM{GTMtJCOe;=HLJ{)n@m8#*Xm^jNIs1zpILtFYzRU WUp&8%o4@PR0$G_|HmxzfnfPCZ|G?z{ literal 0 HcmV?d00001 diff --git a/docs/source/images/IntegratePeaksMDHKLpeak.png b/docs/source/images/IntegratePeaksMDHKLpeak.png new file mode 100644 index 0000000000000000000000000000000000000000..dac29340d0110d853a7050b1e972c14a2193fc17 GIT binary patch literal 20949 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 literal 0 HcmV?d00001 diff --git a/docs/source/images/peak3d.png b/docs/source/images/peak3d.png new file mode 100644 index 0000000000000000000000000000000000000000..a2a4a1b9c727ae2cb1c4a383ce4e10065231d6e2 GIT binary patch literal 63391 zcmeFZg;$i__dYxfLrD$YEg;<>ATZJm0s?|GNP{$zGfJn(L#H6pCEX(}NOvPhcQ^cQ z{H*t{c)x4Ox>1~U?{m(MYhU|1glnoR;69;z0s?_>l@w*QKp;pl@P&s72L2^&fb$~= zL=RGueW~MZyt}aDMm3dkaFdVnh4JYtLX_DrnA_&!o(^4KRyyOT#a;M?$TU`rtXYrb z&I?ag#y?~QZjCpKk|@=(rWlEPzVIDV-E|>Usq7(OR%z|5eF`4$g1CQus`V5h$wOK{ zt?zG$E2yY>cc-H_>cAQH6!z<G^`xXGoy_De53mIU;-@DQ`S;EHSbCI4^I*E4K`6kJ zo<kA-_=C?RPhpSG-Y10gk55Z9Ea>C&$43a}<MYi+Fa&tOOaAZU|F?Dj=QfWa@qZ!n zf9c}U5B@Jz{$H7R^n?E&l}Lw{lO+7XMW@ba@NgUY3i{*nIa=>;bF1*B{<QpX)|PbO zg$KwyLI!w(*Zna<?CSa?cK;*@mdmb454ooJ2QI?>@2(UWT}^!XG)EAhpJARdtUqFt zY#DZp5VLOj;n0G|ztU$qp$N@4zsMV^+nu(0;dAc!Ntu3F?;mVY{7vBEPu60qnTYze z2=WCLA^8ucz|8M2H#TsC4kBNi4KE&6f^@O|y^ycn045R@g=TzEL)5d#Dc*DzO2i{Y z%SR3;`}cE+By*I*&PoxvZ`;Pi1PQ1dJwx6YP)r2oKWy}k)9YUALkUU8cj2iV461;@ z^$t3z`-S>fT(2*3>c|VcQ5kHZycJZBI4S3;Bg#NV+f&Ag6kVJ-kK*bb-9jHbT^fW2 z-|hYH(D>-@k~tW93z0>%<h{@E!P)2l$bx5TGH8;a8j{V)m|iW1K?<{O3NH2Sn?5*W zru*J`Ay!c%5fM)i#Hc92kC+TjTQr!?Cv7^HoBwV>V{ixm;kp#f-&pD*E^L#Uyp%p| z$7#VgZ<Dx%PB$it0Rm=RX};X%S?va_qt6wyM>&hcL@=)4B8=IgJ~F2IxE1tisO9!z z&@ZTQF5@5o8$#_a=M%1aYI~w1^qSrnNqWeBtG1fIDLC0Q#_B^XU3x3Z{#}iglXbna z8>2SW(8FZS=|Q;=`-dNMaI%^h8EyZ<tUs`RsPl9)$SA;2Htb_udC@3RLjH_#)FDWM z&=3U4j{Enf-OloW;-Qu<<TtMD{`m?FJCS_D*ckkV2@YoKajEazQ@3O&Pv!pSPBG%r zp`q?MZiyQ6+4zQbPKMLki1+GFN>g~$AB3HHBjS6O*f%c16t9B)T`UkDpZ?)j!y=|} z3F5b?yP1Y9D{a$Hg2cFLcWkk3YFxgiFKPR)mRv9*pgWZRya1({E8Do^#~XFyVY)$@ z*<5wNYm%_x?8pX2b<M4z@J#}exDTwsU{glc*tR_NqG)W!oCriI2SmEW`k$k?msO;r zA1q1{OYn=WmVT7w%0_>UgA=eBT_ugzc^wx?^%ySStgJ+b*L<=$1D`pa*-ekNpH`!d zYdXHwJVP!k%wd0mE#*8q1^@P6d*>vK^KJZosfTx$)4#**P;d!#LDaPD-?gr(JVnai zF%>wWoD~Zh-aJWkm0M+qK<JY_1_ympk;;ag>>6^rT<T0xmR>d7_+-qH2c&$X)NJNe z<<7@Ykw!WU6MMog2Gw19u7W8m#RS9~oKx&-cJ8{l(S6Yn$HC|+l;ux=|3CweDUp=L z_^}eQktdNWd(nK^t`^STF{n5#vk24o-D}Y*Q^b=EG^eEpT8m<Ga-nPq=;GX$TKJ%N zom}VLb?S}BoMb?zBPhCggXb>T;S4HEg6hkfgEpS|iUD$s@woA@AZRin6Xg73yxWsO zMTTbTjU*pzn-Wx>J9;O~3gLeN&sEbMB?-oWf*qe?AxcM0mgNtRsPp$WE5k@NO=%b& z?f-qG4#rtk`?Ls4o`I4tfbHJ5wXWNu?0pcnS7L&G9|b=-70~_o=-&hso;mN5KFFBv zoly{o9<B)d>6ohPD3_!YCK=AG{1K_WSjJr(`y%oqddU-_pTFKHi1&yd9^<c~pFy~? zH?98#31L&{YL@He#KvmK(^cK_`UwuFvm(QmBJ~&eZ%V<bI*muMq?+>rkC_baP-%-2 z%oz%MjiWjaX8*I=;(jQ8*;mEry1m&H*P(~XmE8+|j2@UOwoPK*D1n{K8jOn<%3_1E z*ZVaoaMU038yc~H%%ekp{w=WtwtIfNeUh};z%LNk@TQGcM3|51GT2DNfMK^DO^_Ed z3Xbsom-j3&xw2`VU(I>RSx&7x_g&&0oJA%{;!rz}fm8n@z+{bmu%7PSr}4RBl~#DR zZ}jNHpFOJKv&oHTg$2~p7*T{KJYX|xny=OHoQHn_OW13GU0}97na>u2tRNl!CboYS z^<CODhjh4a<X5;J9#9u12_MhY5->b7mq3tU0=%6k{pd7h3=;(GjPd0yWD;7%)EVO& z-(H?FJg&Mo@r)L%LG7<C+c(JVZ?)2UfA~k@tC+NaT%A`@!Ygc4!#j(JXs&LO1oU5s zO^$z7iY`KvZ3s;ts^Pi|Y&2kw9(AhNGHI6i=LV#4;!{N~s4{sI;6|49L?>@49GoD^ z(yyBw4fT(G??tu@j|7>>x24w$g%zRfJ?h0w4shl`?1CKB*gnLp#3b0x*=Z}JX}q9e zYWxqKrl{D~9v<2x^xvY!eQ*#(XgbA>+61DSANxKP3P>-vsMWx`M_&zN1_i-RQU5Kd z40wgta+fuyuXsmD#`EiSc1S7a4j-g!2iUS^+r#nl#c(RTQ__>i90(p=_`4H`Nlj6( zt^TXBmZO-LNP{YIKz_sQ7sXkCzNly8r*hU>v~iVC<a$jlmg~iru*1ZebG;IU$DJ7F zu#?$y4T!z2xNUFk{d3pV8)Syith4e-dKb4?GH6~6mp{aiK09-N5bErUF8kYYH$?No zL-4u$c`1>?(u><Z4OF_+Btyg$;_P2>@hP6I&z3eli>~UHDUQd|p!QXf?Q4*@?(0+u zmnv7wFCYNp7AO9^b*E1cqn$#PugiZD<i7~^S=mhMzDZtb@;scN>%v9xiF|ZcAN5e! zNh2%Kxfrf)8ksw0N%Lf)oH%BXS&mG$`|M|muL^ge;Rdk1vk&KEw<HU8C+5@3v@K|` z*hh*2rcpqu$;AmN!|`6-wF`lj$Do>-8oryzpiCU-R((-ED4p$(ZId<qF#ofj!N2E* zvG~j*=j25NZ6)b50F%A?uvbFhq5G!Bh2b5%Tusnp;@$5l`c~L<O2r-Mzt{R%V?3|! z_J&We(3d)LrrxMUkZPWy+Q9+O{g{cp5i4@eT)sb%>fxc)M}ms+%@|8(sa{W?dARs^ zb|%Io5t)gk<r)|ryYG-0lCnSj=s5#!RDZp|=CV+s;CoF9YJmYYi(UrYq0uApd13gK z<`KH|Yb;d}49aaMwJfp>t>xrt=(L*QyV1NijaP3M4ntuoJ1uDAyt`3hz0KlO!bo&9 z*eO;c3<U^}Y2jX-RJmv+ctm3~o{s%wv;~QnbV8%y3GHHNV<647LJp~BIbes1LIL3s zDozR0qhsv*%d=WKVE(t?J`|qo9MeQ}9Y#gVnLwG{h9;OufEnM47w!Yz(|)sz=MgTc zmxL$r;2>-W%e(Us2BNhU4QB9|b}e7keE3=5b;XP;6=9cmQkL~K*R-;sX8Nr)8{_V4 zgS*<_6^?y+1NR$v+f1I8r*KKjhY&n*CK_T?TNJqm)5oIlM(4e7B+ufdb!XRLa3r)= zAd>*R(?E64Cz02BakhELAytFVZhYP)uOi<qes^A25qD8!X8o<-7J)Q)OzZDss}6#I z5N^Rl7<a8t(gwqBoL{sfk^;#^EW6lGA=}XUCt3ZAKAhKYBD^!^*b#psgTZ$pkM8$z z3uYq~KV<TCn-fCoy@g@+>41V}YE7&R!l?SBJb#tkd9%=@C3gt0)#P6VSsWFo`!9W@ zg0H0*LOJP-U6ACZzFe5g*CgalEi{6wMR!dKqyhNvH^sz%mq-?F%o-Ugrns{2w8I2c zG+YqSkOD{0P2mKoBKG5d^L=yi^4W-Ny=)Zh8DrkMjf9s)OEsL5f%lccrjbz$ELn%$ ztkui;*=I4&PaqIz3$r;|{lCcDlnRT`*xSxPzO$8$)PrGYq@{W8!;%8M+~cYKU_K)r zuLH|uOZ2Z;J9sC1S*!dgeL9yDYUW52u$JF#n6jBfh7^+~147`UWZw{m%No=2dT_5$ zd}@8ca1GIN?Q^xUgcGR6zf}vTl{}6gH-ShcP=jx{CK6rjUg|hwmQZI9#{rrAGV7zz z_#1_1!MY_pk8i$KH#kDNG%n=*Ho+(s=6T+b9;TBtxC7O{JIhaKG6~ZdWsiv0XcJco zMH-Vy<+3iL?MHlFv?;yuqF&Hu;N6Plu84Wg(|X-s&j$jTo~2(-ILmcrk&1<30APxF z&+s*?+RH^qL8L7^3cDEOdje>z6vYlOK4H_h&H*JlZ&8iQ(_VIKGg>}&x+GTy1-gSL z^k`OGo2BJ=<Wp|;g3BrUMP<_qAL0kg59-T*j~=3^l3AGUl@ytWfh;~V2EC-C3j|K0 zCsUJ-wl~kjtHrvaf_-1<-|BQ63@RK*_v*<6EAZAY!7?6O&2u)F3M><mq?(_OXi8n_ zb&B@KD;$K+r3FvLAQ6gt^9t+`b>Xzd9Y{MSM0%d;F<wpya_xwzz+K#2?$qF#%?cgz zX|Xy>r}fNgv}!LjB=3D#lU>U2^hG-zrsLuy_ZD<hj=oyqfpwDYv2OTtbwQH_zkC>I zsLR2CgdjawOSb|E$H7IAR%`^K!qt70;%&ogj<$*+KLb~w3}NFSjN=F19i3Gzay+&( z!sN)t$GkJoq<+6c$0C0buDExecPFL($G9P|b274%4E%`|MJ(n6b2Goq449p<qo1S1 zod`VTEZX&hOe8MB%kSm>`oVuEzOvu0<qZjog?0*c)GTC7@4EaKq57f$-8at=P<=08 zrEp(`wb_~Q5&t|j@%)E*(v<EtGNFy4p(_=6GsN(BLK}X5v!v3TOd!X#xX_GX*HP}A z>SQSQ3VdluYhz-Z=td&}w<tH{h!A;dGn8c9*x0Bj$;$UNp<<9T469&B=g?Oe|Gn6g zq8331!9B9CyZ#HCPk-=H`6Iddb!O|sDmfe3$NMND(rJ<B^fLF6#%}!Ou^iUiyVGrY zvPE<c6Xe3XQIHoi%g?X%ul=0P<7X2UdODl%gW4jV@h?~V2Y+h#lefMw%`;cA>LT!` z1badtE3&s_etyN_%-F=8O63Ri@;}*fRi?TE^>+(YhOQh`eK!M{H$MH6C#*}R)o?rZ z`|#fOUEI~_io7%bfxV{k_vbsvd=3$**2Xo%3k4j|FzX}qn~aVxZz~m{efF@M7H46h z`f!!%O-b3)Hs^WM8bITBrtoD{5^9$gy6r4U5*Ln(AED@R<oDYxkp#WAQ3XpEBifkU z&8VPJdu3+d+4y6=nx{4;ZV99o*L&4LBmoJlnuz4sSXye{(0DcW5@=dAu^`uUK<=sF zF0>qdXR-6}ny28Zz@(~BX8AO9eYXaw>b){;xHeBqkmCJoWhmDD_|ov&Nzz<ePXzIm z>SWNda&E`@xn-J%HT}UIuNZW4-o7UH;QW^kY+}+T-m<;+rdW(*t2RT|vH@-U5h>U; z<h|wFq>#Wu7<<(1-&JfTo1im5Hv@r~LSDZ=KC5HqkN@u=YRm0n@O8e!$mew|1iCZJ z>Gz*@C(@#I`NyfEtVN$x3sl7Hr1h-+6xUn34;G;bhN)pze+8T6v@fSVciB}VU=weO zK2z`HCW>H3M?dTPF5MPe^Ujd)1iifiN<IgkMPY(QD2}iZf)SDmfd7{WB&Kwh8kaiT z_frA>iP{|;3Uj>fpt^_JL~U^rb)TOxe=!G=`x^FQ-aa;*HQ>x}A}GaMlsc=(w{kbx zK1aU{A<CJyk+xL_mlpt=?bTc;H<)WgBFuDHO6Ytqka12+nji`3$5%-urhN03IKV~J z%q2yk{7m8PJq;E4et+Fl|H_fQJR_m|%RR3{aYz_+x(NvdkfP7)q(O{Yp^zH*xxq9# zP7&6aexks8%Mv7XlcaWG$#1{5darPiArRY!u_Y{!De!Fy5vJ)K<D)C(8RW7s=J~0j zrU4j?BjtUAV|n$57Y-GArWCxe09Yu@nUf;vN0{nH(RPPB2cl&~k=<=h>yL(y9Rumz zXTHUM$gl=(SINMuGZ^>onn$;%w0RV01u=<1hyeM=)u7rDW@q&w3>@fj)>CR;Hwo?e zKV^h^LczGJ13x6a(tcWKji|ZWj2U4@B}0-6&~!+a!10-cN1x5xLVYJ%^gj>WpQ*Rw z^sj$t;39;A^%`<~`)q05EoRedTIl8_9{z^ZzXI(OJbFh<2WAkXR$o$1KYSz#W>e7Q zm{qnJ^mphGn#?GKr74ToavSgT9eiyFoAZ`lHURAIM#t%v8DY?rWmjNzl+K2fdht)C z<5G)eoizK1D#(g)paUpuyY;p@EZw!F@fF6>LpA%4i%%_!k@qk~>}T(XD(=>R&Sd9R z>8q2TcD(rpKS`&s@r6{Ek{5}w4++I_`nxLfCk^6xh?{1W5o(|-B3NyjDE8nM*YU`A z$1ZSL2pn17!xJ)qX~(N<oNfR3Z0L83^&sbrZ39$`i?6^6h44;({jotoyMB8c_!$J! zH@qhu<~|6~epOKb{~(jSBh2iybMm9ApQSG7C<N(Z9UG?FMCNmB!0e2nR);n|>Rz^; zVY<bQu4A6dfk4}#=3XS#lo_OOa(YtV+87Zl#dp1BL~vz3^0rPl+}N~Gu-Zu04qLAs z9i-3mn3NrMW+ojGcKbpHq4%(4LCE07zT)LK*#y*<ZF6BkpRQ`S56*_Xtn7Ty%VF!q zhSE>P1NRi?>3-_7dNVHQ19P+qSbK9XNs37|V?R2a3mY}K_<uD5T6swc0#d_#9*u}z z8S%un8Bv0`{^LU0Y<9$7*z)3|<IsnwVcS?g;v8n{>fPOAlUS<;ezjK-BMiJ0fdT57 zSZ8`pyM_8*_87+ZX1(!*VfuEjt=qS$ep*$^hNPvnOJ^sIEs{}EVKRRhxzX)Pud4fC zelaf|sJk(i#M<Lk@^p~~V}R1(Y`kftsr0{)+R$K_0Ss~fzhGB72+0_&t!I$f5H6Yg z`*}_Ec~(>D1w%zvPrWe1u&Jf=R6;MQCi5W&j~Fu(k#17!mze3@IzGONx=~3o?h>@> z&s0ZAC=<<U{m@M-Nc$)<IZTI&OghAn!u#N@Xx&Ep7}Z&VVM64GArKRU(v#Y+mciBk zxNST%?>0G5RTdL6yzw}1wVEdffhJWi;z7BD*+$p}ZRj=vSi}92DD3QV5GQ$nl`KLV zHzfjhjk$_m&H7%Of8-v1dLX?Fd2!?~mR3H`4=Dl;+X0i9z!@_t6JiqtJLr>mY;#$@ za<al~@e$|c=euJ>jQod-qF6o>9CLH6>tWD>O{mRq$}k<c5Cwb}TLbh9o7%5MOz-Zr zTEF2x<gOTg5quxzZNPmnFI5m*@e}<9_C>LV!sL=2{{>X!sSeN`2}fwidP@0_xPIl4 z?%8SGykyO6PCcE_J<|ASJQU8sv?!y79aXW1^a7VpQ3`B-Zm#>Gc#ArT0U(xT<4K?e z16FLI9m-%!WmX*~!44!n|A!2s#h(K=js6X{^TBd1MjoBqHvs<HY;>Av*%VIgHp9_o z82;{=FOwa(6Ei4nTKZ-xbee=KSFSCSNKf81zqQDue7i%6g%bkSZ`%Z;flkGpnQTUV z6jj01n_wfrKe;N%bfnLlRIY0lW+eZ%CEr{(KIG`-c>OfeAK&nq^C1v*;k2B)em6G% zTf#=9E6j5kNvcWUlB8FN<*OvbnpMm-AR9Zfo?2y=CbBrNMBy1P`|~YQPx4@}=vjfe z83e%odJevOzcb-<s03_I96Kk=F~jn6I2v|vWFu0U7X%OR+U(l6twPZ@C3ujvT#ad2 zNJ43P<-ya<l1NMv68WRp+iSbOQ?@o81p1#ApaLa)#l(Ezdzj8bVJ&ppCQCk<4jOli zL``%9-<g|e)s1k9bv4@87!Ur@%hF@b4>*gtXq+AYnY=?zf+@3-#W{qfBYIfXvpz19 z7rSx0dUvG3nTSc*R6+kzw4#)~-q&}ZvFaY~i}G0i@lM$xvs;{yMDznaR)OgL5vCTf zA?)tew@u=^4y|glsZRt96#|Q3Q%(Vh4;MzetS@Wh-keTn2#lZ-9}#hcoB4uP^KZJB zQyM{|ts$eZu3)Ku@v^_Wjs0P>W>+$SfjbyI)<_?d13e;4>YhTK+JEdOQH^?rj*lEk z`L9}ahg&#P)-C_TrTSt|5E#bZvw=sa2jVkVdxvpZL7rS81>6~WX+_bv2ZzR4DH>4B zj;G2jW`LR6=aKo;1Q(lulu3@pzYC!CoUbqiPZ=S00Aa=L)cYfQ)FioY6fN%NZYp;* z%S4|(3J(#2$|Gs<_Ndh=!6Lr}p8yka|2PmRp;#qtcD;?_L-q!R8v8jNM@uPtoj-VI zxvZUvqeQy}utN;gtJA#p!&o6c6bQ`~ezWB-Pu&PL*{g478Hq#mlp_&V$Uy^GhF-uX zJ_5yWq5@Cabowb01~C5tA3FMqfO=H(GShF*aW$IOQ@9viT_%T&_fTWn`+7U$4uwHe z+5qP0jcT^vEO@aWMNYlhIU+I<?!$9?kSYTGf{v(p<hDx?L_Mc><~lU;*3vX+cUCRL z{C{F;1<Hb~+B*~i_&>}u{_=)|z&`Z_37jO28KG7CvYmevE5GG+QmjbzRm=F-veM{* zTefDyJ}kn>X}}t-=e3uMo1;j7#)~cd;>fM$C}mkpobkJIbaS9592seG-4$ej>dQP< zVlhq80G1Mk@!lXYD0(g2;MiJv582P5)Xk4O8w4Yupjv$O=91A#C)IPJPL0GO@otwL za=%iD>=)+B4ggqW`N#e5ehQ<y@6GS?kMCK;rQ{~Ol25{*8{eqOD@X0=JPsfN5?M8x zV5$|$FhF01;Uc8@p!$zI1(LEVC5AbUVYoPLIq5$U+z3`EkOq1Bq0jkFHG3F%T{2jc ziiO^}>N#z9$$jqz`{3mPX_{|K82|YnuGC5FoM-a%#Bo2W?8V3`a*Y~u^xCRF<f@=v z%mg8Ui08>AoOS^+6i~gtZmSpi^S5u;5u+l6{`rQ4k#o55$|ygi4C_FxB7W!wW1N!X zra$4>;vOY}0PJ|qeDKBC%ysH_Sa08=KO?^YUxB&~rmA45n(R9cvS^NYqNZHwY>jD2 zU&L(+uK{~`sU6ChG9RS-hb@NMZ81s~Fw;m4xMAF`3xb)RJ<_MeY8v2E!#hX($siG2 zWlMS-?ayk6$e&O7mzoRJqa4wzD}m*UHN9g&&xmkzN|6wxeP8K%gkKzRGV&7JCJCVR zLo)^luLfCg5oSxWTfb@I#2E=IL`_|7YyJmRH=8g_%uHUIo|PO+wSz!UEiBuwE4_Rx zv1$UjdX9(MDEMoMI^sOYnV_V{h8vV3?dat=Cqc+g585R>h#AAMeaVl@nOv%7J>{%< zTq^4I6eHiYUSl_Q({^BBV25!|yS1CoEw-%?gq$YT>`3?Ja8fJ}s)4f<ErIpbfYSuY z`VII_m;~D4RQwJ?aAjwNJ8G-u5hnLCWf4pIy64U6__}`z!*P7`CfxGxUw7n~pV+hs zpHXFbDMJP7%o4aL2rYmKs(h?$n*6a!lo!HsKLOY1;mQX6BVH=Hzbr=Pt1tB^3@wkQ zXe#`ScfQ@}Jf@6o5|(6S)b^6Z_H#M_8gCEmf_K{J#3q=h-BMV#_ot(gu<j6~PJ|*` zE&SY^(yo+`DTZivrGazT#Tki>jW`E#PKKkQTxUzG)_?my(8dAg-ZX(ZIT{xPyI^EN znI)IFw4DE(d6J01v3Jv4NNp1a3|^{iQO?+VSzL?)EvyR;<7(b5JO_tL94j##`jkin zItYmrQF~wZYA}Yf4v&!zkHU(5wVgFnSWKE#X2C@sCP&z-4s+WMb3Oo19CfLH{j7ra z&BGKJ1i$A!Q^G$uD^>v}3t>T_$i4-<3)jP)Z-S})H8i%E{XsN9H^U71&WFXT%23C= zY<@g7`K!)Yg9aR53lDL75gOK8Ph=8~YoUY2BtP4`lpae3Hoa5YkirLn+`oVFJ#t4Y zTR+GuUn6^kwL2<1Zw#)Df+c&h5Sw7zXq7@Qw@>avwb&R7_c*{ZrWomdW&4vmPA#kn zNYeagUA8Ig_>u*9mG&q#4YUJnG4dNNBaJ#SSxR@l`Dn!Y{=ZRybe73&2$TC3(8A7m zcCogsjbF?$M)#I3(ADs7{Fhfk>2NvmSu)oWVIFU(63&3a4TukOIc9j6D$Z^xS6BXU zXCeR#2(vji@)l=&k7IED%5@sqZAJolJ-^TG$4=|K&IWc)XDyu6)o}e|s})rvnoh=4 z;=64pf5sK8@ap`goF<Ri6vCnZ#$9jlUt9g$_QItZ!m4Jw?gD&ZR2;teNcBzPdc`(q zb^Qvw`xMrTvBY1NpN2&uKqR&fcV|bG8M^H-YW*&S#QF$u<9@FLZLz;c2e;0?^J3sl z#6u|c57xYE`Ok3XKdoS7#m@}1dl+JePz|RBt$lXoHC9|TVg17at<+r`(bPp>!@|UR zSN*H6&p=@NM@3zj>#^6t-t2Yq{rioJrtNESzrXnaa&S})e7{gX8mVgY>~HOFp?Izp z!gpn&h6yvSWkPhn)6f$xRi`a#{DXm=y>rJ@%?ta>W9#`AOHj9y4L2%S4Xmnnx>C)k zMcFI`lt}<&f4%7VwfaEu-1K2d!s+&GUVpY!UH(%Ngm6m?z*PP~sKTNOsW#j(n@{so zk8DO&H*pb4#eAtwD6iSiVp${JQ4DAE|CzsJ@n8FT^fTsQbt7XLm;4E;;YQ*p7J^aB z(Rla~TDLd)4w%H_RIzYne+m?1eQBunc7AcPWcnpDFEFtv7GfO^*h|U&6<_o2Zdhf= z<F=!UF&nMg4rfaeLV3h<sGKZbqg(A}RTV~@kzi1eBm(*VWfA36M=ZV_1$0ph7}!qR z2pD*QNww|)#L_B2>pG&45X33pSyXB!8!I`PsPbH6xG#0-kxv&55k1(p%1K4dgqTI} z8@MVjGVN2?XU|q#8>cqyQ&BbYIO%we>N9NsmQd(@X<cv|pt=qtCvB2+v^~7vL`gK? zIk97)KKM$<zTr9dfG7PGaA=N<+jtBRjBcAA^1Zid`I`uY<z#g1cy!EdpmuMWQzm=P zc#0ov)|m4C{Dw%zP^Ia>A(m?T-899~0ej_5L`v%MSdHCk`}DAX_n(`SoTuEjELcGp z#@7h3qflhbfRM8{YQopaWIj9#m@K9ac9|zrj_!flC$yQjgL`;XSlNNYXiq?x9)Qnm zxjFOL1gQiT&71}|&Z$t9&qq@w=<iKdi?KP<#?rDe)=1s@&VM#lm*jCV3R<ZCL>iOa zkmIwvSK+DYD+bZ++6AknC&?b0ye;fYSP;h}pW<<9CValA5sFkx`g=aeusUM5D&5dx zKTZd>CjD|2$pR$<*Tl@d+@N%nqD7l|k(Gu`O`&ffC~e9n^<6r91i*lG;XDv^>KUFE zzN6#SZuY|bm{zJ6#K_sl2y@7z0v|XmWe;I@$ZfReh5a<{24Iue6T3xK{p8lY3~0d{ z&!abGEL!B#+rqlF5}WdWdfhw-L|aGC3~-9J8V0^w5E%7cVH8D|ugJeCG|uF#3xx%m z9j<h9d<uNB$EYi8WKaRHNeNh7X)3<?s{n0~M#EXtS2=e7j}xK@EY9x>s)mE@pWU|+ zfk4&sDQ@;tEeg}fX)J`s-DQPK*Fx2p?<Jj3nKvs6d+^s+Sb6~8A+hgw{-JaETl+b+ z*YSr{OzO$wm5W?jM?Ek5?yqG{p7!bgo#1!kVhP>c)$(hc9a~N-T3ux9iR0ft_lXK~ zXso7ZyxOYGqE2()&<LmbPjGMRaW=yvVSTmpNz!bIa`wno%?z*gnDYo<-|%sejHN@` zdb+Q;j*n1h%TOb`jpOmSa+aLG6da(okqJhoD4?Guj5b_K)EgQHbQ_`zZbF~ovaP)i z=H0$%UeE!bm{iyJTyr1-01GZ>|AvlO0Q+*-Mp~HwBVgOOn6~W76axm_-3h;@WR^;R z^wB{c-D72~H?4?O2$@Z@AM|;+ZFIXs61dV-NdABPJe>1b9qiCB)~F;@n};WGzeF2B zdw74K5vFMN+&laVW-%d0z}8m5V~aanp-HXFx(Ky#tD~vMm(|DRjS@kzlQA@m&R`;n z>$eR8YL&4QTHbd!OyAKjq1s&d<_?Pqg}oA>am;0wo9Aku#N@O|9}MmWh(TEHVhFKH zP~-v5kIUb<w=O_kmlfq&<lQsT^(6ulFp~kS!wzoOl2h?n^ho&@9~EBnNWnpNBvB%a zFn8%ubQQ`drii+vu$1BFb+h--X@Bte5zproEGFPh)t=LlTp5L``YQDee){0?0}Ge5 zN=n7FO(=N=2=^XVAZ>a;XgYeC?=79(Fc<p64r@3Y{HHVS&J2qeP%AW<JGxiC!VH3C znE_L+lFV(YtWMl53oqS$O%7}mc^uVFDTen6Yi$&5Wl?6+0GRlGb4g}j>pJ4w+yAb^ zj6Slv_q$?MZ8<Nnevi&*{OCaAvmKJvLrF28<t8%?oTxy8W?z+p-1Mcfrpu{H0QVCf zZ5nh*5fnB|+3nY8D=eus%H=nhg^QC2YZX#Qr*J+o6?%mVfls&{Umo;bwRCqKW5=RL z8(9#b!Ad{RX;G33gkE(fqTH#s(1}U#0E0hnkX^Kfl!klV9vABOFQ8m|cmPu%PRqum z5UeYQ@Yx2wGmfv#Uk%4Au3C`IuLknN(5LL65ZAdK2laOUJ|+)cR2{}`2m1sNNeg%6 z14k5~&I0)6No;@!D9McP31npi2-eL|Rq`}Yhq;C+%Pu{Hoi(;@c0+jgK7_MJYU?Ff z2VJUaA+DWbk=LuPCd23gtHSF@V~Za`*{A_O*?3@QT%^I<aZ;nsX9XBQ*@&g<7|HUi zyIv`zyvUIT77l{l3M~ZrS{*)mPZH84RkwwHpNs{xF|7L7#GvaKCsGe|gEWk&hl|dP z2>ZNROLcY*+$gn&As#VIgcv~BFGL2C#H9)_GS;yO<5aT-%O3HxuQ08HzY(NVRD6Bz zRk!GWYlvodaJFfsbDmjmK?Jrigo$grD~~xj3>5`uU$QdRP`xH#bL5ItbXg)=4BbUF zTl-xa-s5QTIvY4LyC7J`kB~GpCP<n3t-xiQbXx`R5uvHuiKxnR)wRv1fURyo?bT;4 z0zCtUAXn4;*=E-!zsq_j27_8jHGSEMVpLWj<Yu;(Hm05oPC8FW>1IUTEB9Mg2A4cS z41H(Fgo&+O*fu}hDXzhIn1~EQU~RI%dCxX4bD^RuzXjp&c@~OR3FNzG>)F~ja6uc( z!p4X0<fI?F=X+pMdTV$BbVe{l<yaP0Fch;y=<)DSfR2h=$erS`pikfhVeLJ<dD7qV zjRYOgKXHk6P_3`;5Pj+wFWRuQyDw*4`Rf*ZJ6T|TZfxqpvf^=K-QL1VSpCUUz6Q=N z%uwN*ckBOy8XO%8=Kqs;v|_O&%smNMV4}(lQC3vgObvpy0Xrr3VRr!;3bqEZXt|Yl zl|P4MCjkUzg|OW~YS@3Sd_+h_>FlY~Hor_K%onGzQkcn4>N#z9a-;i>1Rf2@sl7P? z$jpUQn~5dB?jLCG``cZ*+hsKop-FVK5#;6Mz^44TOu$1lg|xkTbF1Z-){HC8q+Z75 zI)A%}*YGOdlT97GYh3z<Y|9ZWSOA?K12`pK2<5g&el&-i3Cpe|MA^Gfi{ZVR0jwoz zZ=nOs06z-@@SDBT8mxR;mHc}sLj^DzR4Jlec^)J9?SERbN^hm*ZgeHzm(im;F+&3z zvzF2WRN#*Kf$tX`XePHiGE9N#t{1zS8yNUfoQ#15>3VdYZRo1mz%Zl;+f%+0C}&JW zq;*j$$_$!$oPqU}PNcGwUt%97G?H$)vd!G-UmO)Lq2nnsdxG_89{mW{hcKIPCV8Vj zNQF6#e_0}Twtm^9Nz0^x*|DjTCmQFMQMi!TnfW}FK!YVJ?4#Ss&(|+ymJQ!t|8?3M z!M)${@AQ!CY<T}h7O(kM#$zufyroou^}O|A5bNO3NPwwkoy6<HvvSoD<;-;fZbUV@ zb>rc>*ruKLmW>fI`&W|&ll5=hW?W*FUD~GVv<<lhi^;>MlERA1q~4!;fy5#Zm^0A! zW-m>o3gwS@b{O<w9JEh$@SBopr2tND=5A%YG+c8P7H2Mj>ejP?Eqn%hjjqF$ofrj8 zHpjLZRe~4Vbe;9(T&(<-W!=d@4?#j!3}Ao^D5I!;?PjIBj3SW5!6@*EVzm!Y&}for zP&*E=zl}GTPxaFR(Wp#fqJZ@M?d;O^O8Hi$#%1nb%QU%f(hW!q`|x26L#I#J7|FWl zp1>J@m{}NpG$5xD#yct$9=zeX-n;Z;a3IXqvpOoSXZSwKO8UA#;A}ir_t<Y=+34e9 zNo8M-OBhWPH0k61>JlQKh!|Adb|vVf80yaQsHn+RxSpwlgX?=Vf&82)U;y)#4Mn;r zRpHb>(PcsL0fcUzre^N-M_bn2a{bDtNBis7A+_xWrr0(Nbyj5`#(bG;k0)KkZP=ES zn``8qzY~ka^qDoHjUN=!(Fpszv{>Q<6i)=7WIMI7qWp2y)YWA>9n-vL8g25^z?Rk9 zqaUu+<`N8YJ(q*?WkS3jB^DD2$W}S*XT$i9K{iXcG+S09({_0i|8U#3B9FH79jI@5 zFHfD;m4G1W_Uo@e^S))^{VWAJZ(k(xI&FygsBAh>9iJuG#Qzq9K{JJXTKi4JoAatq zp2Ht5ba&F!2(NUtJ+}Nln3msH{KrEP{PTFI)mD;K)S3BkeB@N`;02&pyDx+TXlw@$ zpeOg)ZUT?)>KQVI8Qzl^z)%65O$&a|yK1;+M;j=1y0qV*ms#Tt<Bxf4vAGX0C+)!l zEc=W-{k57ZM*gGGR;0pfV0veTS^cMx@e4gBOJ8I0JlF>qHco^ClQA*qcS1Dgf?s24 zSmI77xHt&VBpHz9PK6$xB8fBn?i?SuYz;)Rjg;LrmY7QQpR=knv|4B<p%D46F|mG+ zKA%bp^$fv{Ni@d<T+uFH5}2N}^M8FD34~<CZGJ3Oqo~OC>^LENS}I_s)pG4NCl`vG zOkVPv&29TclP@XL!|<6@Gg||YFqyt)j=(5J2C8hE)JQMHdX8alUzl_ZTm?S7-{|~l zABz*_OlTT$8xJDt7u{b#vu!+yX~2tSNH8AeV&w_%ogek^w>sMDX%DRfhDF?gqw0Vd z3uumyK1&hVZO8k}d66&?%?2S&U#7gzLvxqVpMxfo(tvGI&?cFH1<#8ETHojv=82TU zVV-+qS@nnSj$r+u3MKf%`AjII7L*`vWGM0PP2h(A>CVLi*QQdT5+B#4Aq=~Lt8781 z5pxl!U7rG9u-fgf94CY^8Uh37oTgIlsi;T<120=3%kB#Z<y(;vs##zLzzDc!aihDj z|3J6pU@hMcE6`;=>I8<}LXGcxCf?vxPmLQDN=?mJOLye;6=o1&L`PmooYi$F%n-5q zied2@-TS<gW!Wvcq%gAFc@7c#^ohBl?bc1e`%-4PdhS=&!P*09wJ!E1yYeaR(^Lrg zKwGvwn@JJ3U*UIcK*Y+yxJD-J>oheFaOYDS0C%q5sR;CMo2)>V+>BUb+06(>8f$>Z zH!7`=HVc;RNT?0DsGp7OU#&BpQ{FaWK<L|53zygAb9S#JaY#q_sm&JoEeL>L=ln?i zdcC8;fxS+9A)J78lH4kyXc|wSndxZL6=pPkmVnh_zg<ARIgynzjOks8fc~SuVH@l{ zLz@o+j{0m`!B*`7t#Y~<wgis0rDmQ3wr<#Gt^pd$1NOye?(eLYgwvqU7{&WB#4!;e z-<%N!c-507S39ya<=|~K`=aOizRkRzPA`r43}6Z0OwOCdIk2)`Q|jBsrjz>sW1k%- zq-&u)&#!ZQIf_!@!6cqNp|UBTcq~*ySnhy`Q$c)K@avYq(rW?SCnQqYZI9{L?e&HE z%uMNEn%BYh4g&Cw{)gvRvvf}-++2OlJ3iGk>5YeGsDZ}~?7bm1c@%n_GN#L14uB#s zR{5nY_wH`<x7yV4#iP8pO5b#Vc?WKtmV;C2h7&oNH7%7EYnu8^W(8>!baU@_deS8> zp~ZlZHEQ`qHJbZu%d`H2!V8}*tsBYXKPkLjq{I5cP4+rV&*$nGps*!iYyb-dd|bc> zE=3gMSRZ)(;G<|naUJ+Td|Mr)OjTPPzqM4mKh={J$m{2Aey{qB(dvOY7La{wu?p8! z^Z|Y)kt8o``N#K_Ni#QU+4@r$4SC<-evC{uKx;HJRGfP=Y*H-z-~lZz@(H${Aiso# z;iT`s|Cn``ukxmfp}}vSK3)n!sl&1>=g2#PZFM3N2F0Xj+vw5@qyTg%P#7!B2t8^o zYf8_4lI%V!|15M-pIjUZ(4a^5c7|LwZwv+9-&f0ud_Rd!>&A7z3RXC4P=_-TdOvLQ zfbewefbX>Thk}xd@^^`{`AB$Y>b7dPb*`~bSdg+t+45i=9ZW&O<?my9(PrVT@00*l zrEkyYu&9F<(96v={0A9MJNS8)`i$pcQ<CI$%Y#o2<#MgF6dU7|)OFPrOp_(ue)0XR zp?t24X}`?sb+zZl4}V<V5;Vcx;8ep#f?9S>Kn^JBgn>33`WTrE&bSq6&`qzc2dBJ3 zR%^HX2hnOBn=BBCGoGN6M*L#ykcgA=Jg$4qQG(dfQX7jhJOF#iw<4gFP{b}64-wv` z=9Q;Cf{6%U$qExBBb`tJ<f_Ky8&2Lt*;4mP$2>QK=RfDy8t<xf!2caWH$B$c?wJl7 z@A8S_R$5udmCk-QE$#rH1!kK7un&2=c;jTJE9IIA1cU4S7s+UwP<1{ON)4<z>>wy6 zlF%p{H0<ShKgRka9rdp2Mu$b`NJEz0tF0ObG1hj+zkohsvv!MmJ@4<H6!tu;)1AEg ze4R}u@ZPmTwCXmFi7_&EH;Q~|M!F<K$LFQoxAj`b`VGZfXNVYY^@W*46_?i^*G@$m zV3Kz|3aBRM?=#u}f=2eJoUB&js3jRX?Eu-o(sWFx^OPU=k^0)2?1YW*_1cCO)b)+$ z<oC*Vwjp;A?dRaHG{o?{%-c{5(EbO2@32jAJr?x{l8|$uT2Cc1d$gY}3WBrv5P3jV zS>ZbMww7=9FI8X^6`>pnNbcM0b2`!Czmkm#56<NMQdR#^5fQY+%`ICeogOWG!Y^W4 z*~%ysvfn266zPg~%*BQmFAtu-Tvc`(!du1k%W2tLx=O2OsO^iDq7r%fA2+C0(r?Ar zj7iRt+wv@R60F#NP$K!;#Y7e3g{b10NLCS(Q+8o)G=rhtK%*Foi7$^6CrB}1DZq`0 z6$C5U?#c3%a;LUdaWdR_u|Xb6PW7>=EWWC7f$FONw{@t>DmKce;*D9YrJN?gspcv^ zx_H%hQf<P=y_>;R>nymaF%3&TLCjuO!D(+U8t=QAo(qUrIqaPF91J#!)Q(%tl`<T- z+{hco^&Jn*Z#tyAZQM@P1r|@liMLv~`}NqYEf5|58cm$9m9xFXP&gF9t!+^*<0uoa zbN8?0E06i<xA~EqpmOP#C{;Q4z`|05W8|C&u92gCoSK2L;e0w-90CzdU@`BQc2+rV z<BMzUY(zmZLwhdkcru9LWFl5BrFwe8#29>|YgcQyza-#W^O~C0UH8eC%6*(Bx05R1 zPw*eE?Y_go<J-06g30%Z;PO!aHMjkA7l-D>&nw5im5#DyJ)B{U%yo{nwobbQ=Ua)X zUR*%dr2&+tE;1lEw<btYsk6u*fsG7OTi=p*JhER^wta6EFCxc7QN-NXbz0@H;4Yc+ z#J3>*VjyQ6t6_#Vb1uP^IrpvGa-Q{V#|v?>63l`V*$DrHea^Q;ab|B)ekD@z_q&)W zTd$uwAcKK?d)?8nc{CCd>X`HkOVHo;2k%?rxRH_YFf+tnw(xrQZ{OJC)gj%X<}`Q0 zY~42FiH#O}$08wnevZ7jHBU_q9-HK2<RX9=@66bNDa)_~fE!Zo=>kiI-km?(7S<!e z%&Od*010#l%L)0T_a5AOuf{6-wvcJupFEt$;#kIGH3{xUU5@E=cCr`i6*jyrKjGOX zPr=$l3kVK3|MQk<y<4L8YV4*Mp(Fh$J)WI6ItkU3)wv~#vu|DVj8X-77eG{5yrBQf zLHX*)nxjU5iiZahb78+9oqA<k7+>x;scpd-{<ic+<o7ARv}v-F0Stv6&`W;yU|qVL z3jc|ra#gwYaHO~T_2^-h3Za1jz`fGe`2auBHM2p|kJ`(#uVh)+h6TKdnGkX=F(QLt zB<~(>b>6(bqpiI3CYmWHb^=h#9PLN$`uJ!LLtuHI!bY|4RiB?CJ6t90@+ef;i56$f zJQ1_j?U*Nn8TAaLo)A`vhmaI`79jf|2=73{;3r7n)&pFJv@M++M_;%j3rm}aq)5Ys zM^5d=fk+=+umB}jG%?^C2=qTKz=Ls8(z$%BDrb_2E;J)W<Bz1|$3<#JipaZG6;!*| z<ZKTw>?q{>q5A%-MEw&sx4^}u47QAvrmJd2GArc7)QcZKzOLOKJa95nl?RbZZFHlD zi0I!L%N$KzyZ&iOYAAP@vflzA8YlklnTZY{NUFF7Qa+((UOO>r+LNpc{i|0Sjnhvu z)i8;d%Fp)<VMG*Ec>0X|!lW!kue@gztkR$bI)Qh#><ks@OZGv?n6?2-v;J<UD~r5M zC!)Bai>30(AhrxF{X>?hyQjdUb+{9+?vB>%vS$fMS^EPEf#QYgPXvBqSK7F#IHp<3 zD&{?CYkkltpKXQL$nPPsIYi&gPOYjHhJrv20450wN<u*e2xHVMfv=}(oPq{0CinS? z8SR@uPkk%Jv}lM2XH@h@8pXqF{ZOR7%F<%-5XQZ$r2E_ShIL#Q+0m4E^4xRppN<-l z7V#)4yjuX%>_ceEE_}PkKmxuiZYxQ3H-L?ONBskc5*nP|W2*l5sz-Qt_`%`)msA4i zdNTDc5+|E3-EY-oHRLqi|8jRIaYQyAgenlLM!_qcqXY+PQhQ$~JFqQLxChB8Z4RPX z!_JE}KIR`)$=eOlPlwj*cRAHHG-6@_O$VZ_q$IrYbZ;^;Ti|OO4*72)aFa92>qKlg zhoRHu0QIx5-sQ>BWoy0hgs|@Z)-MHU<E@!&EkLu90-4SOE+}fTngQyJyDJT5`29$e zRXj?GKth*gQ-oJJ-LdsH;oYq9NB-EK4k$+WJhRiocP=sxCeK<XJRG-n3@pA+Vj7*w z72k`!6WHI{`o%$auTbOi(uCr&KWQ6kTV$~{=UW$e(evqHLrQTsX?7&qmrakeaZYD? z=lAktt!mB__<0;#0_m`Q+UiDy<K>);i;S%76VzN68L=8sJNwSTH+Arc{1vjFYE7Bc z(@H2HX<R5WLX9fJ5v48D>ywlFs3W9?2UU4CORTWZ-nze`WxILy1)Wf}NSV}|`SY(0 z1MVV(2`C(ObIKpgMhbphPIL~VI_m8kOn`DZlN5oOBb(HE8##wLcTN#>@qsMv)``G& zHxMRkcOx98c&`_jYG2Em#XbA-j-g_|sLdtqltkpVt|l_pVaf`*&+Lfe|NhYMc&1(F z>jXpdha_hc1%ji~kMbNiQL{tn)q>>#(jw0P89KIPC$_=$tpLGzPWgKW8RS#rH#>n` zD5qS6^l<XQyLB})Q<mT0i65^AYxqCKe4MRr($d}5VA6Qua@OG$9oe0UAfQ55ckub< zdQ(-Q(83;RqJ~o&jLhUWH`_Z)sr-4vD*WOpBOr_qdZE<m^D^~ztDN$N?pa0)2czqu zxL9?eYW?9uUW1412-`O4FvgSEKp`&{A3xwi0cz8_X93jPemm#k6$v(%Om>pLgtmhL z%%6c5m`uX*rEKmd-`)O7K$aWATEy%zCZrzjO@g6dluICxN|GA`Jf~{?U2+Xl4o7d! zGBlWr$z>IFrh#Kmb?Ny{=%FOVW%95uY=o{VhBYjol-4^WUKh=g(DY8kAm>^>Ne9p2 zO@Ijdj~{}8IZ&Io4p!}~_wptU_aj*oN+N3h_*skD(#v_<g&2Jp(F$$N_V1)gz(jK2 z+e6HgqO%tl{&--X8iohQ?vfw<eu+EoLUD+Uv!3|%m+yp(nxhd55%RPREsf5F<8j8g zM5sYbjHTw=@#BNB(^dK0;e$--HFyxTkMa~o-_)4(O88DnuZUyyVZbfR@#lIK#^L}Z z=B?VqI+_vsZVg-su0fh70b$W9SEJB#;QuB<L>eN$L0YmuqSt_9GnA#sg%$$qsAX+s z{RfaA7LBdjW&7ve7G=)P(1Pja59`BvZ~GDo|EK`IL)S`PwffP_&Ell=R(Vu$7MwZ` zz^*QHie#XB$jQwPOZOW~LVxreFWnO|Xeu7Uv0cV=t{lqP|8WpD-jaT;=l&K*v5&u8 zB`mD>`=mKmq7|%*g380%;KFWEu;A%Hkgz+;+c_%A8>s$&<`GuN9gXfKn1Z3$(n#&@ zO9!W1ZEOS<)#@qjQ6g}$^m<N-c&OdMcg44nykN`O{KNMw;*8;;v%@W1?KRz>eRN>l zrgg7~uz4Qsj?#rug_Tj$`@xTw(xxJeeQ+fbbom7Ygk!@0M)PAJ?vq?A0+(__4b?qh zRDKeIENtUGz_1y+*y4HCBiUu~Fq9QR1*SIytoM<#l1`)6?{y5P`Vs?3(zzZu?RpL| z5%Hc5z%_wlXTO!ZL&G0etE`3>J5y~<jvETm*{s0^^Aao@)~oVe<QY6s%4T9@B71hF z4NhY&4%$H?1M&xoX4>dFV43Wf3NN_;^)+xPyZZ?btx|_sUb5e2n=AexLhqQw@eosG zubb&&V$=b$O!fxGnf@?;Nh0H>acIt(;Zj?3mnN|B8_%T5X-;h#ynV-8OQ`>T_ng?p zh`<G1dm4ohh7P!Y@^^MRat|tN-%aPA8I>c!H^O+C#i{s$soM|v4{L4&6b}a|b(zKG z08<e_^uFbjJ|IbD)N<D<#@D}|#NZGK+h-~b*Pm*=d~WGo9wpMVa|P$!%7Sb<uhp>8 zdKOL=ge$U{9ET$D3}6GQ-bJl@%U&|wp2ZSGc%d=amG%Mo+^CemZMlhZ$qQo_FJh4f zCdMBPl?|1)&ko<58z3s6ekNu!;G(NQMOQNJA!ob&+2iC^SF2}sJP~lx;rD1>va?f` z9-$a($9<L~#9bi(c>yr=pI-@&9SUA3BQrjWkaA1v>avPGq1+2($FNJt8}}iIFXGPN z!QU0)x$mBTImk~`L~V1}(>~Y-&wH!Nk$dt+E*Loy`kP9*UlkCf^8QXdkYr;Nk-DXK z$|gpy9pLidx3A0_6JIsRU9XlBDgE%xggc!}@;vCGua*Za{JxG2HKakptXry|Kbrvj z8by<B<6I}rv43LGGtuIfhGKEL!^HYO>)P>t#*Bm15q^)8bUefyS#43g%0bO~;r{K* z-(Tc{U(Oj}WL$OSVayf9T!}}TeIjDRi7o>ud}bU(B5>IZ_P^|<3Lba(?!2Y{+&i!K z@{-%5^-}-C;oBO1x|;id3*A4N@>bIQ|5k_8`ZGQ3Ns#hp(~c&P28?^J>g{o)3@B04 z+)jjAz`w#T>SzO$*I<tKZHrjmv+USy(RgoNg>BV--0Q!T-QJKq4ngkVJ08Z)pLZ=d zNoSk1EKYi}F?N|Fo9JF)jnC7(lXG&CTuvfp<Hpx6;hyM6y}#(r!aC4x4fED+W*E-S zHRTZ$#*64(A<NoIu&^gQ@x{$W6P&DQ`gNvy<>rb7W&llBWiX*E)4FX22Vw?f?@Wx^ ztCXhg_T{`@)UQ#3vzi1NW&k&+6!6}Dwf{t;0oDPl1or`pTE(QA$-BYOzK=iHWhd7w zyI#pE<0D1??LVZ4i2s%|iakX)`~L1L?y>pY$Fi-WDUN%Y(^+20L=JL~^-1r;@`Q`~ z%CmCiO3Dh!=v8rZfvfQWw-Hp?r<}|N2JESAWMf6qx->OU=c1T)*)m+x%3L}nP(dX? z-hx#9cJ5nFNsvIV-HmnDF+6b4v)>Gh`B?K#jgDY7W9WCIX7W*}c3FmTsw9bsW$+V3 zrO1WE#A|^fjk|dT7nzbMiFy;7kq%*EhbBP}y!q>WorTgZ83{^q@WKSU2#}4bPSR2r z@d2XioGZK19aFFqy}f;SGoydwZi;K`8KBXJJADQrcAo(AN!C|UZ`El2Lm4A6+$rYt zdqYV+)<o$&mMujz8wx9TVnHd({N~a8ZMDgQ3e40GPq4S12#@)A4~z`-!#{e?P2>Yf zf`kUV!BH#mmnI0w%@uHzB8iWUFkYL1q`2w(T>3JD4gtm~Wg`tzFhMEs|A=}EuPEE^ zdw6E3L24w1jsXND1j&a+P#Qr+x}>{12PLFKN)T!3?r!Ps?(S}QZ$IDlTkk(GYwjz~ z*=O&4&UFhV&v5HQ&ZVf$#LV0UZi|}ex0nk*h~?g^cubS#@|gd9&RcW4_uEfQjv2!p z&uIbbcahYzq4v%36T0P~+a--|Tm|;_`q}Px@;QVJ+MjLf&r%)NnLIK)m?a0YE(lw1 zZuZ}>gt)o2*Tp3cxr|ua==SKRyThuq;(F_XtFDi#Zw-wP%S76KkG+A0ngT{bVN^)V zuHFk05Y@^L&;w$)xgfn%RE;KyV+IRQeZB*&PWVd2DeARec-X#Kp1EbmSx@e?a(EGY zXTHsUSx3^)UTHGFnM=-B<>5euSI0aM*KZ}Gx|-dN+on}q$Ew!_6}`R%{43H`jcLM^ zkbFBi7spMNjdYPEp;AG|`4G{_sU<9r68nSwj_sxrDWFC;;Ey*y9Gs-y<6d}0{-&J) zEMjYK6brNrQY7^Rb@!`j+L$D4z?G)Xn*X%G{!^Jo(AHN8!Jj{`|6rvxjMeV<awr^7 z=w*P0Ne%076O)v=_hr~E!a=A|!`U?A$CdRXaT}S8n{utkbZ+M*Mp~>b&8U~OC^d3& zgDow2Y$$6yUT*fDU0|oCgOe(rhuCek=?(gpESr78s99CjM&fqomryL<fREntMY0Ev z$iVwj+xwO5KcYUO0MWP-)7DdIlekft7B%_@uh2XxuJ=Zm*D2|3faGkGmkrstivAZv zsPZe;3ajMN(!!&nn2pBGL@+u3W|0nY)Zg&fub(3{#CWPlY){<)LEx|Mt?zgFCiv4) z^gx3M<^AQ8mqp^n&XbdXr)$i8d_1K3+p#sVdM{eDsQ_vKKt#8g17~e7x|zN7{_H8G zQ7|NYPx=V;X+aB#DvcB~)>lA+WR&D`-+sg*&ZVCib^hG5R;tYwJANo~N$OFzRcNyL z%Po0K<WjDAz^*#wkH;UO1+Q7>Tv?TwE@!JM^ADe8GU3*<Oke5a<Uy#Bm{3p@rs1N; z7J`#*O|ql$xl0eKm{;?+Pq8)7NHN+s8=}oeAy9j3-#`$iZ%4D&Aeqw9R99!)X>3Xz zD>l<ks1HrYPFXFO?b9q%M|ODoLC)2{m0RM^KOTz5Jn|9p39rYakVH*r%0DusyR{hE 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 GKll%EMM6{n literal 0 HcmV?d00001 diff --git a/docs/source/release/v3.8.0/diffraction.rst b/docs/source/release/v3.8.0/diffraction.rst index 5df3e8a3f15..111d3f7fda6 100644 --- a/docs/source/release/v3.8.0/diffraction.rst +++ b/docs/source/release/v3.8.0/diffraction.rst @@ -15,6 +15,20 @@ Single Crystal Diffraction has been expanded and improved from previous release. It provides an integrated user-friendly interface for instrument scientists and users to access data, calculate and refine UB matrix, merge multiple data sets for slice-view and peak integration. + +- :ref:`IntegratePeaksMDHKL <algm-IntegratePeaksMDHKL>` has been added to integrate data in HKL space. The + main usage will be to normalize the data using + :ref:`MDNormSCD <algm-MDNormSCD>` and then integrate the resulting MDHistoWorkspace, + but it also integrates MDHistoWorkspaces and MDEventWorkspaces without normalizing. + The MD data must be in units of HKL. A 3D box is created for each peak and the background + and peak data are separated. The intensity and sigma of the intensity is found from the grid inside the peak and + the background is subtracted. The boxes are created and integrated in parallel and less memory is required than + binning all HKL space at once. The figure shows the grid points within an HKL box that are in one peak from Si data. + +.. figure:: ../../images/peak3d.png + :width: 487 + :align: center + Engineering Diffraction diff --git a/docs/source/release/v3.8.0/direct_inelastic.rst b/docs/source/release/v3.8.0/direct_inelastic.rst index 92823b71411..7152e0f2f53 100644 --- a/docs/source/release/v3.8.0/direct_inelastic.rst +++ b/docs/source/release/v3.8.0/direct_inelastic.rst @@ -10,6 +10,11 @@ Improvements - :ref:`MDNormDirectSC <algm-MDNormDirectSC>` has an option to skip safety checks. This improves the speed when acting on workspace groups. +- A qtiGenie method *export_masks* was brought to Mantid as :ref:`ExportSpectraMask <algm-ExportSpectraMask>` Python algorithm and got documentation, unit tests and Python GUI. + The algorithm allows to export list of masked workspace spectra and save these spectra as ISIS *.msk* file. + The export mask procedure is often used by instrument scientists in ISIS, and they had to initialize qtiGenie to do this operation before these changes. + + `Full list of changes on GitHub <http://github.com/mantidproject/mantid/pulls?q=is%3Apr+milestone%3A%22Release+3.8%22+is%3Amerged+label%3A%22Component%3A+Direct+Inelastic%22>`_ Crystal Field @@ -17,3 +22,4 @@ Crystal Field - A fitting function was added (:ref:`CrystalFieldMultiSpectrum <func-CrystalFieldMultiSpectrum>`) that fits crystal field parameters to multiple spectra simultaneously. + diff --git a/docs/source/release/v3.8.0/framework.rst b/docs/source/release/v3.8.0/framework.rst index dafa7b60cd5..4e03492eb4c 100644 --- a/docs/source/release/v3.8.0/framework.rst +++ b/docs/source/release/v3.8.0/framework.rst @@ -22,10 +22,17 @@ Algorithms New ### +- :ref:`LoadPreNexusLive <algm-LoadPreNexusLive>` will load "live" + data from file on legacy SNS DAS instruments. + +- :ref:`CropToComponent <algm-CropToComponent>` allows for cropping a workspace to a list of component names. Improved ######## +- :ref:`FlatPlatePaalmanPingsCorrection <algm-FlatPlatePaalmanPingsCorrection>` & :ref:`CylinderPaalmanPingsCorrection <algm-CylinderPaalmanPingsCorrection>` + now accept 'Direct' as a possible ``EMode`` parameter. + - :ref:`FilterEvents <algm-FilterEvents>` now produces output workspaces with the same workspace numbers as specified by the ``SplittersWorkspace``. @@ -33,6 +40,10 @@ Improved - :ref:`SavePlot1D <algm-SavePlot1D>` has options for writing out plotly html files. +- :ref:`ConvertTableToMatrixWorkspace <algm-ConvertTableToMatrixWorkspace>` The input dialog + had a bug where the table columns were in a reversed order in the dialogue's combo boxes. + This is now fixed and the order is correct. + Deprecated ########## diff --git a/docs/source/release/v3.8.0/indirect_inelastic.rst b/docs/source/release/v3.8.0/indirect_inelastic.rst index f560c071e49..0f6e2b0ee5e 100644 --- a/docs/source/release/v3.8.0/indirect_inelastic.rst +++ b/docs/source/release/v3.8.0/indirect_inelastic.rst @@ -20,6 +20,8 @@ Elwin ~~~~~ - Additional option to ungroup Elwin output +- When using multiple input files, the naming convention for the outputworkspace contains the `first-final` run number. + An example of this would be `osi92764-92767_graphite002_red_elwin_elf` for OSIRIS run between 92764-92767 Jump Fit ~~~~~~~~ @@ -33,6 +35,7 @@ Improvements - Range bars colours in the *ISIS Calibration* interface have been updated to match the convention in the fit wizard. - Vesuvio sigma_theta value updated for single and double differencing in both forward and back scattering. The new value is 0.016 for all. + Bugfixes -------- @@ -43,4 +46,5 @@ Bugfixes * The *ResNorm* interface should no longer crash when using workspaces (rather than files) as input. * Fix bug showing incorrect doublet peaks in :ref:`ISISIndirectDiffractionReduction <algm-ISISIndirectDiffractionReduction>` + `Full list of changes on GitHub <http://github.com/mantidproject/mantid/pulls?q=is%3Apr+milestone%3A%22Release+3.8%22+is%3Amerged+label%3A%22Component%3A+Indirect+Inelastic%22>`_ diff --git a/docs/source/release/v3.8.0/sans.rst b/docs/source/release/v3.8.0/sans.rst index 1c0fc53dea5..83426722712 100644 --- a/docs/source/release/v3.8.0/sans.rst +++ b/docs/source/release/v3.8.0/sans.rst @@ -5,12 +5,18 @@ SANS Changes .. contents:: Table of Contents :local: +Algorithms +---------- + +- :ref:`CropToComponent <algm-CropToComponent>` allows for cropping a workspace to a list of component names. + + Bug Fixes --------- - Fix for beam center finder - Fix loading of multiperiod event files - Fix period selection when loading multiperiod files. - +- Fix the loading of RKH files `Full list of changes on github <http://github.com/mantidproject/mantid/pulls?q=is%3Apr+milestone%3A%22Release+3.8%22+is%3Amerged+label%3A%22Component%3A+SANS%22>`__ diff --git a/docs/source/release/v3.8.0/ui.rst b/docs/source/release/v3.8.0/ui.rst index cd9b65d494b..b8b9db600cf 100644 --- a/docs/source/release/v3.8.0/ui.rst +++ b/docs/source/release/v3.8.0/ui.rst @@ -11,6 +11,8 @@ Installation Windows ####### +* IPython has been upgraded to version 3.2.1 + OS X #### @@ -51,11 +53,16 @@ Documentation Bugs Resolved ------------- + - Floating windows now always stay on top of the main window in OSX SliceViewer Improvements ------------------------ * When opening the sliceviewer, it will default to showing the first two non-integrated dimensions +VSI Improvements +---------------- +* ParaView updated to version 5.1.0 + | Full list of diff --git a/instrument/TOPAZ_Definition_2016-04-06.xml b/instrument/TOPAZ_Definition_2016-04-06.xml index dfcb1b5c1d7..8da0778ce9f 100644 --- a/instrument/TOPAZ_Definition_2016-04-06.xml +++ b/instrument/TOPAZ_Definition_2016-04-06.xml @@ -5,12 +5,11 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mantidproject.org/IDF/1.0 http://schema.mantidproject.org/IDF/1.0/IDFSchema.xsd" name="TOPAZ" valid-from ="2016-04-06 16:24:01" - valid-to ="2100-12-31 23:59:59" - last-modified="2016-04-06 13:45:00"> + valid-to ="2016-07-13 23:59:59" + last-modified="2016-07-16 18:35:00"> <!--Created by Vickie Lynch--> <!--Modified by Vickie Lynch using the TOPAZ.py script from the Translation Service calibration/geometry/ code. --> - <!--Modified valid-to by A.Savici--> <!--DEFAULTS--> <defaults> <length unit="metre"/> diff --git a/instrument/TOPAZ_Definition_2016-07-14.xml b/instrument/TOPAZ_Definition_2016-07-14.xml new file mode 100644 index 00000000000..cbd6aa25426 --- /dev/null +++ b/instrument/TOPAZ_Definition_2016-07-14.xml @@ -0,0 +1,259 @@ +<?xml version='1.0' encoding='UTF-8'?> +<!-- For help on the notation used to specify an Instrument Definition File + see http://www.mantidproject.org/IDF --> +<instrument xmlns="http://www.mantidproject.org/IDF/1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.mantidproject.org/IDF/1.0 http://schema.mantidproject.org/IDF/1.0/IDFSchema.xsd" + name="TOPAZ" valid-from ="2016-07-14 00:00:00" + valid-to ="2100-12-31 23:59:59" + last-modified="2016-07-16 18:35:00"> + + <!--Created by Vickie Lynch--> + <!--Modified by Vickie Lynch using the TOPAZ.py script from the Translation Service calibration/geometry/ code. --> + <!--DEFAULTS--> + <defaults> + <length unit="metre"/> + <angle unit="degree"/> + <reference-frame> + <along-beam axis="z"/> + <pointing-up axis="y"/> + <handedness val="right"/> + </reference-frame> + <default-view view="spherical_y"/> + </defaults> + + <!--SOURCE--> + <component type="moderator"> + <location z="-18.0"/> + </component> + <type name="moderator" is="Source"/> + + <!--SAMPLE--> + <component type="sample-position"> + <location y="0.0" x="0.0" z="0.0"/> + </component> + <type name="sample-position" is="SamplePos"/> + + <!--MONITORS--> + <component type="monitors" idlist="monitors"> + <location/> + </component> + <type name="monitors"> + <component type="monitor"> + <location z="-2.488" name="monitor1"/> + </component> + <component type="monitor"> + <location z="1.049" name="monitor2"/> + </component> + </type> + +<!-- XML Code automatically generated on 2016-07-14 13:35:00.720701 for the Mantid instrument definition file --> +<component type="panel" idstart="851968" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.455000" t="105.192621" p="-33.305992" name="bank13" rot="-99.919712" axis-x="0" axis-y="1" axis-z="0"> + <rot val="53.154399"> + <rot val="41.466968" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<component type="panel" idstart="917504" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.455000" t="133.320872" p="-46.751427" name="bank14" rot="-63.920201" axis-x="0" axis-y="1" axis-z="0"> + <rot val="53.154399"> + <rot val="41.466968" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<component type="panel" idstart="1048576" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.455000" t="133.320872" p="-133.248573" name="bank16" rot="8.080272" axis-x="0" axis-y="1" axis-z="0"> + <rot val="53.154399"> + <rot val="41.466968" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<component type="panel" idstart="1114112" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.455000" t="105.192621" p="-146.694008" name="bank17" rot="44.079783" axis-x="0" axis-y="1" axis-z="0"> + <rot val="53.154399"> + <rot val="41.466968" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<component type="panel" idstart="1179648" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.455000" t="74.807731" p="-146.694071" name="bank18" rot="80.079867" axis-x="0" axis-y="1" axis-z="0"> + <rot val="53.154399"> + <rot val="41.466968" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<component type="panel" idstart="1245184" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.455000" t="46.678985" p="-133.248429" name="bank19" rot="116.080009" axis-x="0" axis-y="1" axis-z="0"> + <rot val="53.154399"> + <rot val="41.466968" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<component type="panel" idstart="1310720" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.425000" t="23.905622" p="-42.859145" name="bank20" rot="-177.410228" axis-x="0" axis-y="1" axis-z="0"> + <rot val="47.178655"> + <rot val="22.073524" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<component type="panel" idstart="1376256" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.425000" t="55.596651" p="-19.516218" name="bank21" rot="-141.410201" axis-x="0" axis-y="1" axis-z="0"> + <rot val="47.178655"> + <rot val="22.073524" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<component type="panel" idstart="1441792" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.425000" t="90.000202" p="-16.000018" name="bank22" rot="-105.410002" axis-x="0" axis-y="1" axis-z="0"> + <rot val="47.178655"> + <rot val="22.073524" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<component type="panel" idstart="1507328" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.425000" t="124.403098" p="-19.516157" name="bank23" rot="-69.410491" axis-x="0" axis-y="1" axis-z="0"> + <rot val="47.178655"> + <rot val="22.073524" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<component type="panel" idstart="1703936" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.425000" t="124.403098" p="-160.483843" name="bank26" rot="38.590066" axis-x="0" axis-y="1" axis-z="0"> + <rot val="47.178655"> + <rot val="22.073524" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<component type="panel" idstart="1769472" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.425000" t="90.000202" p="-163.999982" name="bank27" rot="74.589577" axis-x="0" axis-y="1" axis-z="0"> + <rot val="47.178655"> + <rot val="22.073524" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<component type="panel" idstart="1835008" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.425000" t="55.596651" p="-160.483782" name="bank28" rot="110.589776" axis-x="0" axis-y="1" axis-z="0"> + <rot val="47.178655"> + <rot val="22.073524" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<component type="panel" idstart="1900544" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.425000" t="23.905622" p="-137.140855" name="bank29" rot="146.589803" axis-x="0" axis-y="1" axis-z="0"> + <rot val="47.178655"> + <rot val="22.073524" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<component type="panel" idstart="2162688" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.395000" t="108.000253" p="0.000000" name="bank33" rot="-71.999747" axis-x="0" axis-y="1" axis-z="0"> + <rot val="45.000000"> + <rot val="0.000000" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<component type="panel" idstart="2228224" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.395000" t="143.999764" p="0.000000" name="bank34" rot="-36.000236" axis-x="0" axis-y="1" axis-z="0"> + <rot val="45.000000"> + <rot val="0.000000" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<component type="panel" idstart="2359296" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.395000" t="143.999764" p="180.000000" name="bank36" rot="36.000236" axis-x="0" axis-y="1" axis-z="0"> + <rot val="45.000000"> + <rot val="0.000000" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<component type="panel" idstart="2424832" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.395000" t="108.000253" p="180.000000" name="bank37" rot="71.999747" axis-x="0" axis-y="1" axis-z="0"> + <rot val="45.000000"> + <rot val="0.000000" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<component type="panel" idstart="2490368" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.395000" t="72.000168" p="180.000000" name="bank38" rot="107.999832" axis-x="0" axis-y="1" axis-z="0"> + <rot val="45.000000"> + <rot val="0.000000" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<component type="panel" idstart="2555904" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.395000" t="36.000027" p="180.000000" name="bank39" rot="143.999973" axis-x="0" axis-y="1" axis-z="0"> + <rot val="45.000000"> + <rot val="0.000000" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<component type="panel" idstart="3014656" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.425000" t="124.403098" p="160.483843" name="bank46" rot="69.410491" axis-x="0" axis-y="1" axis-z="0"> + <rot val="47.178655"> + <rot val="-22.073524" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<component type="panel" idstart="3080192" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.425000" t="90.000202" p="163.999982" name="bank47" rot="105.410002" axis-x="0" axis-y="1" axis-z="0"> + <rot val="47.178655"> + <rot val="-22.073524" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<component type="panel" idstart="3145728" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.425000" t="55.596651" p="160.483782" name="bank48" rot="141.410201" axis-x="0" axis-y="1" axis-z="0"> + <rot val="47.178655"> + <rot val="-22.073524" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<component type="panel" idstart="3211264" idfillbyfirst="y" idstepbyrow="256"> +<location r="0.425000" t="23.905622" p="137.140855" name="bank49" rot="177.410228" axis-x="0" axis-y="1" axis-z="0"> + <rot val="47.178655"> + <rot val="-22.073524" axis-x="0" axis-y="1" axis-z="0" /> + </rot> +</location> +</component> +<!-- List of all the bank names: + bank13,bank14,bank16,bank17,bank18,bank19,bank20,bank21,bank22,bank23,bank26,bank27,bank28,bank29,bank33,bank34,bank36,bank37,bank38,bank39,bank46,bank47,bank48,bank49 +--> + +<!-- NOTE: This detector is the same as the SNAP detector --> +<!-- Rectangular Detector Panel --> +<type name="panel" is="rectangular_detector" type="pixel" + xpixels="256" xstart="-0.078795" xstep="+0.000618" + ypixels="256" ystart="-0.078795" ystep="+0.000618" > + <properties/> +</type> + + <!-- Pixel for Detectors--> + <type is="detector" name="pixel"> + <cuboid id="pixel-shape"> + <left-front-bottom-point y="-0.000309" x="-0.000309" z="0.0"/> + <left-front-top-point y="0.000309" x="-0.000309" z="0.0"/> + <left-back-bottom-point y="-0.000309" x="-0.000309" z="-0.0001"/> + <right-front-bottom-point y="-0.000309" x="0.000309" z="0.0"/> + </cuboid> + <algebra val="pixel-shape"/> + </type> + + <!-- Shape for Monitors--> + <!-- TODO: Update to real shape --> + <type is="monitor" name="monitor"> + <cylinder id="some-shape"> + <centre-of-bottom-base p="0.0" r="0.0" t="0.0"/> + <axis y="0.0" x="0.0" z="1.0"/> + <radius val="0.01"/> + <height val="0.03"/> + </cylinder> + <algebra val="some-shape"/> + </type> + + <!--MONITOR IDs--> + <idlist idname="monitors"> + <id val="-1"/> + <id val="-2"/> + </idlist> +</instrument> diff --git a/scripts/HFIR_4Circle_Reduction/MainWindow.ui b/scripts/HFIR_4Circle_Reduction/MainWindow.ui index ecf49a32d81..1edb19a1399 100644 --- a/scripts/HFIR_4Circle_Reduction/MainWindow.ui +++ b/scripts/HFIR_4Circle_Reduction/MainWindow.ui @@ -193,7 +193,7 @@ <bool>true</bool> </property> <property name="currentIndex"> - <number>3</number> + <number>6</number> </property> <widget class="QWidget" name="tab"> <attribute name="title"> @@ -1931,6 +1931,13 @@ p, li { white-space: pre-wrap; } </item> </layout> </item> + <item> + <widget class="QProgressBar" name="progressBar_add_ub_peaks"> + <property name="value"> + <number>24</number> + </property> + </widget> + </item> <item> <layout class="QHBoxLayout" name="horizontalLayout_13"> <item> @@ -2936,6 +2943,13 @@ p, li { white-space: pre-wrap; } </property> </widget> </item> + <item> + <widget class="QPushButton" name="pushButton_sortMergeTable"> + <property name="text"> + <string>Sort</string> + </property> + </widget> + </item> <item> <spacer name="verticalSpacer_10"> <property name="orientation"> @@ -3112,7 +3126,7 @@ p, li { white-space: pre-wrap; } </item> </layout> </item> - <item row="4" column="1"> + <item row="5" column="1"> <layout class="QGridLayout" name="gridLayout_23"> <item row="1" column="0"> <widget class="QPushButton" name="pushButton_exportPeaks"> @@ -3146,32 +3160,8 @@ p, li { white-space: pre-wrap; } </item> </layout> </item> - <item row="4" column="0"> + <item row="5" column="0"> <layout class="QGridLayout" name="gridLayout_22"> - <item row="1" column="6"> - <widget class="QLabel" name="label_48"> - <property name="text"> - <string>Background</string> - </property> - </widget> - </item> - <item row="1" column="10"> - <widget class="QPushButton" name="pushButton_setupPeakIntegration"> - <property name="toolTip"> - <string><html><head/><body><p>Switch to tab 'Peak Integrate' to set up options for peak integration</p></body></html></string> - </property> - <property name="text"> - <string>Single Pt. Set up</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_47"> - <property name="text"> - <string>Peak integration configuration:</string> - </property> - </widget> - </item> <item row="1" column="2"> <widget class="QComboBox" name="comboBox_mergePeakNormType"> <item> @@ -3251,6 +3241,42 @@ p, li { white-space: pre-wrap; } </property> </widget> </item> + <item row="1" column="6"> + <widget class="QLabel" name="label_48"> + <property name="text"> + <string>Background</string> + </property> + </widget> + </item> + <item row="1" column="11"> + <widget class="QPushButton" name="pushButton_setupPeakIntegration"> + <property name="font"> + <font> + <pointsize>11</pointsize> + </font> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Switch to tab 'Peak Integrate' to set up options for peak integration</p></body></html></string> + </property> + <property name="text"> + <string>Single Pt. Set up</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_47"> + <property name="text"> + <string>Peak integration configuration:</string> + </property> + </widget> + </item> + <item row="1" column="10"> + <widget class="QLineEdit" name="lineEdit_scaleFactor"> + <property name="toolTip"> + <string><html><head/><body><p>Peak intensity scale factor</p><p><br/></p></body></html></string> + </property> + </widget> + </item> <item row="1" column="8"> <widget class="QLineEdit" name="lineEdit_numPt4BackgroundRight"> <property name="toolTip"> @@ -3258,7 +3284,7 @@ p, li { white-space: pre-wrap; } </property> </widget> </item> - <item row="1" column="11"> + <item row="1" column="12"> <spacer name="horizontalSpacer_19"> <property name="orientation"> <enum>Qt::Horizontal</enum> @@ -3274,7 +3300,7 @@ p, li { white-space: pre-wrap; } </property> </spacer> </item> - <item row="4" column="11"> + <item row="4" column="12"> <spacer name="horizontalSpacer_22"> <property name="orientation"> <enum>Qt::Horizontal</enum> @@ -3326,7 +3352,7 @@ p, li { white-space: pre-wrap; } </property> </widget> </item> - <item row="4" column="9"> + <item row="4" column="10"> <widget class="QCheckBox" name="checkBox_roundHKL"> <property name="font"> <font> @@ -3365,8 +3391,22 @@ p, li { white-space: pre-wrap; } </property> </spacer> </item> + <item row="1" column="9"> + <widget class="QLabel" name="label_39"> + <property name="text"> + <string>Scale Factor</string> + </property> + </widget> + </item> </layout> </item> + <item row="4" column="0"> + <widget class="QProgressBar" name="progressBar_mergeScans"> + <property name="value"> + <number>24</number> + </property> + </widget> + </item> </layout> </widget> <widget class="QWidget" name="tab_indexPeak"> @@ -3578,20 +3618,6 @@ p, li { white-space: pre-wrap; } </item> <item row="1" column="0"> <layout class="QGridLayout" name="gridLayout_21"> - <item row="0" column="0"> - <widget class="QPushButton" name="pushButton_integratePt"> - <property name="text"> - <string>Integrate Pt</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QCheckBox" name="checkBox_applyMask"> - <property name="text"> - <string>Mask</string> - </property> - </widget> - </item> <item row="1" column="0"> <widget class="QPushButton" name="pushButton_calBkgd"> <property name="font"> @@ -3604,10 +3630,10 @@ p, li { white-space: pre-wrap; } </property> </widget> </item> - <item row="1" column="1"> - <widget class="QCheckBox" name="checkBox_selectPt"> + <item row="0" column="0"> + <widget class="QPushButton" name="pushButton_integratePt"> <property name="text"> - <string>Select</string> + <string>Integrate Pt</string> </property> </widget> </item> diff --git a/scripts/HFIR_4Circle_Reduction/View3DWidget.ui b/scripts/HFIR_4Circle_Reduction/View3DWidget.ui index 87ef8c317a0..e18cc0d3c34 100644 --- a/scripts/HFIR_4Circle_Reduction/View3DWidget.ui +++ b/scripts/HFIR_4Circle_Reduction/View3DWidget.ui @@ -23,9 +23,15 @@ <item> <layout class="QGridLayout" name="gridLayout_2"> <item row="12" column="2"> - <widget class="QPushButton" name="pushButton_6"> + <widget class="QLabel" name="label_5"> + <property name="frameShadow"> + <enum>QFrame::Sunken</enum> + </property> <property name="text"> - <string>Zoom In (X)</string> + <string>X</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> </property> </widget> </item> @@ -39,56 +45,112 @@ </property> </widget> </item> - <item row="12" column="3"> - <widget class="QPushButton" name="pushButton_5"> + <item row="17" column="4"> + <widget class="QPushButton" name="pushButton_2"> <property name="text"> - <string>Zoom Out (X)</string> + <string>Zoom</string> </property> </widget> </item> - <item row="0" column="2"> - <widget class="QComboBox" name="comboBox_scans"> - <property name="toolTip"> - <string><html><head/><body><p>List of available scans</p></body></html></string> + <item row="12" column="4"> + <widget class="QPushButton" name="pushButton_zoomInX"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> </property> - </widget> - </item> - <item row="10" column="2"> - <widget class="QPushButton" name="pushButton_plot3D"> <property name="text"> - <string>Plot</string> + <string>Zoom</string> </property> </widget> </item> - <item row="19" column="3"> - <widget class="QPushButton" name="pushButton_quit"> - <property name="text"> - <string>Close</string> - </property> - </widget> + <item row="7" column="3"> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QLineEdit" name="lineEdit_countsThresholdLower"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>200</width> + <height>16777215</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Data points underthreashold will not be plot on the canvas</p></body></html></string> + </property> + </widget> + </item> + </layout> </item> - <item row="5" column="3"> - <widget class="QLineEdit" name="lineEdit_baseColorGreen"> + <item row="4" column="3"> + <widget class="QLineEdit" name="lineEdit_baseColorRed"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> + <property name="toolTip"> + <string><html><head/><body><p>3 floats from 0 to 1 for RGB</p></body></html></string> + </property> </widget> </item> - <item row="4" column="2"> - <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item row="5" column="2"> + <layout class="QHBoxLayout" name="horizontalLayout_4"> <item> - <widget class="QCheckBox" name="checkBox_changeRed"> + <widget class="QLabel" name="label_2"> <property name="layoutDirection"> <enum>Qt::LeftToRight</enum> </property> <property name="text"> - <string/> + <string>Green</string> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> </property> </widget> </item> + </layout> + </item> + <item row="9" column="2"> + <widget class="QPushButton" name="pushButton_checkCounts"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>700</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>Check</string> + </property> + </widget> + </item> + <item row="9" column="3"> + <widget class="QLabel" name="label_numberDataPoints"> + <property name="font"> + <font> + <pointsize>9</pointsize> + </font> + </property> + <property name="text"> + <string>Number of Counts</string> + </property> + </widget> + </item> + <item row="4" column="2"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> <item> <widget class="QLabel" name="label"> <property name="layoutDirection"> @@ -130,15 +192,8 @@ </property> </spacer> </item> - <item row="17" column="3"> - <widget class="QPushButton" name="pushButton_2"> - <property name="text"> - <string>PushButton</string> - </property> - </widget> - </item> - <item row="14" column="3"> - <widget class="QLineEdit" name="lineEdit_4"> + <item row="5" column="3"> + <widget class="QLineEdit" name="lineEdit_baseColorGreen"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <horstretch>0</horstretch> @@ -149,16 +204,6 @@ </item> <item row="6" column="2"> <layout class="QHBoxLayout" name="horizontalLayout_5"> - <item> - <widget class="QCheckBox" name="checkBox_changeBlue"> - <property name="layoutDirection"> - <enum>Qt::LeftToRight</enum> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> <item> <widget class="QLabel" name="label_4"> <property name="layoutDirection"> @@ -174,14 +219,7 @@ </item> </layout> </item> - <item row="17" column="2"> - <widget class="QPushButton" name="pushButton"> - <property name="text"> - <string>PushButton</string> - </property> - </widget> - </item> - <item row="18" column="3"> + <item row="19" column="3"> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> @@ -194,64 +232,22 @@ </property> </spacer> </item> - <item row="0" column="3"> + <item row="0" column="4"> <widget class="QComboBox" name="comboBox_dataKey"> <property name="toolTip"> <string><html><head/><body><p>List of data keys</p></body></html></string> </property> </widget> </item> - <item row="19" column="2"> - <widget class="QPushButton" name="pushButton_clearPlots"> + <item row="14" column="4"> + <widget class="QPushButton" name="pushButton"> <property name="text"> - <string>Clear</string> + <string>Zoom</string> </property> </widget> </item> - <item row="7" column="3"> - <layout class="QHBoxLayout" name="horizontalLayout_3"> - <item> - <widget class="QLineEdit" name="lineEdit_countsThresholdLower"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="maximumSize"> - <size> - <width>60</width> - <height>16777215</height> - </size> - </property> - <property name="toolTip"> - <string><html><head/><body><p>Data points underthreashold will not be plot on the canvas</p></body></html></string> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="lineEdit_countsThresholdUpper"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="maximumSize"> - <size> - <width>60</width> - <height>16777215</height> - </size> - </property> - <property name="toolTip"> - <string><html><head/><body><p>Data points underthreashold will not be plot on the canvas</p></body></html></string> - </property> - </widget> - </item> - </layout> - </item> - <item row="14" column="2"> - <widget class="QLineEdit" name="lineEdit_3"> + <item row="14" column="3"> + <widget class="QLineEdit" name="lineEdit"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <horstretch>0</horstretch> @@ -260,21 +256,18 @@ </property> </widget> </item> - <item row="4" column="3"> - <widget class="QLineEdit" name="lineEdit_baseColorRed"> + <item row="12" column="3"> + <widget class="QLineEdit" name="lineEdit_xMax"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="toolTip"> - <string><html><head/><body><p>3 floats from 0 to 1 for RGB</p></body></html></string> - </property> </widget> </item> - <item row="16" column="3"> - <widget class="QLineEdit" name="lineEdit_6"> + <item row="17" column="3"> + <widget class="QLineEdit" name="lineEdit_3"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <horstretch>0</horstretch> @@ -283,45 +276,41 @@ </property> </widget> </item> - <item row="5" column="2"> - <layout class="QHBoxLayout" name="horizontalLayout_4"> - <item> - <widget class="QCheckBox" name="checkBox_changeGreen"> - <property name="layoutDirection"> - <enum>Qt::LeftToRight</enum> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="label_2"> - <property name="layoutDirection"> - <enum>Qt::LeftToRight</enum> - </property> - <property name="text"> - <string>Green</string> - </property> - <property name="alignment"> - <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> - </property> - </widget> - </item> - </layout> + <item row="14" column="2"> + <widget class="QLabel" name="label_6"> + <property name="frameShadow"> + <enum>QFrame::Sunken</enum> + </property> + <property name="text"> + <string>Y</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> </item> - <item row="16" column="2"> - <widget class="QLineEdit" name="lineEdit_5"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> + <item row="9" column="4"> + <widget class="QPushButton" name="pushButton_plot3D"> + <property name="text"> + <string>Plot</string> </property> </widget> </item> - <item row="9" column="2"> - <widget class="QPushButton" name="pushButton_checkCounts"> + <item row="17" column="2"> + <widget class="QLabel" name="label_7"> + <property name="frameShadow"> + <enum>QFrame::Sunken</enum> + </property> + <property name="text"> + <string>Z</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item row="7" column="4"> + <widget class="QLineEdit" name="lineEdit_countsThresholdUpper"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <horstretch>0</horstretch> @@ -330,24 +319,63 @@ </property> <property name="maximumSize"> <size> - <width>700</width> + <width>200</width> <height>16777215</height> </size> </property> + <property name="toolTip"> + <string><html><head/><body><p>Data points underthreashold will not be plot on the canvas</p></body></html></string> + </property> + </widget> + </item> + <item row="4" column="4"> + <widget class="QCheckBox" name="checkBox_changeRed"> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> <property name="text"> - <string>Check</string> + <string/> </property> </widget> </item> - <item row="9" column="3"> - <widget class="QLabel" name="label_numberDataPoints"> - <property name="font"> - <font> - <pointsize>9</pointsize> - </font> + <item row="5" column="4"> + <widget class="QCheckBox" name="checkBox_changeGreen"> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> </property> <property name="text"> - <string>Number of Counts</string> + <string/> + </property> + </widget> + </item> + <item row="6" column="4"> + <widget class="QCheckBox" name="checkBox_changeBlue"> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QComboBox" name="comboBox_scans"> + <property name="toolTip"> + <string><html><head/><body><p>List of available scans</p></body></html></string> + </property> + </widget> + </item> + <item row="20" column="3"> + <widget class="QPushButton" name="pushButton_clearPlots"> + <property name="text"> + <string>Clear</string> + </property> + </widget> + </item> + <item row="20" column="4"> + <widget class="QPushButton" name="pushButton_quit"> + <property name="text"> + <string>Close</string> </property> </widget> </item> diff --git a/scripts/HFIR_4Circle_Reduction/__init__.py b/scripts/HFIR_4Circle_Reduction/__init__.py index 04a95e83157..ce584152d8f 100644 --- a/scripts/HFIR_4Circle_Reduction/__init__.py +++ b/scripts/HFIR_4Circle_Reduction/__init__.py @@ -1,2 +1 @@ -#pylint: disable=invalid-name -#pylint: disable=invalid-name +#pylint: disable=invalid-name,C0103 diff --git a/scripts/HFIR_4Circle_Reduction/detector2dview.py b/scripts/HFIR_4Circle_Reduction/detector2dview.py index 0d7c93e30ba..c728c604488 100644 --- a/scripts/HFIR_4Circle_Reduction/detector2dview.py +++ b/scripts/HFIR_4Circle_Reduction/detector2dview.py @@ -98,8 +98,6 @@ class Detector2DView(mpl2dgraphicsview.Mpl2dGraphicsView): assert self._roiStart is not None assert self._roiEnd is not None - print '[DB] Polygon corner = [%s, %s]' % (str(self._roiStart), str(self._roiEnd)) - # create a vertex list of a rectangular vertex_array = np.ndarray(shape=(4, 2)) # upper left corner @@ -130,8 +128,6 @@ class Detector2DView(mpl2dgraphicsview.Mpl2dGraphicsView): """ if self._myPolygon is not None: # polygon is of type matplotlib.patches.Polygon - # print 'My polygon is of type %s.' % str(type(self._myPolygon)) - # print dir(self._myPolygon) self._myPolygon.remove() self._myPolygon = None @@ -200,7 +196,6 @@ class Detector2DView(mpl2dgraphicsview.Mpl2dGraphicsView): if self._roiSelectMode is True and self._mousePressed == Detector2DView.MousePress.LEFT: # start to select a region self._roiStart = (self._currX, self._currY) - print '[DB] Set RIO start to ', self._roiStart return diff --git a/scripts/HFIR_4Circle_Reduction/fourcircle_utility.py b/scripts/HFIR_4Circle_Reduction/fourcircle_utility.py index 9dedf54a792..d83878d4381 100644 --- a/scripts/HFIR_4Circle_Reduction/fourcircle_utility.py +++ b/scripts/HFIR_4Circle_Reduction/fourcircle_utility.py @@ -111,7 +111,6 @@ def generate_mask_file(file_path, ll_corner, ur_corner, rectangular=True): start_det_id = 1 + col_number * NUM_DET_ROW + start_row end_det_id = 1 + col_number * NUM_DET_ROW + end_row det_sub_xml += '%d-%d,' % (start_det_id, end_det_id) - print '[DB] Detector %d - %d' % (start_det_id, end_det_id) # END-FOR # remove last ',' det_sub_xml = det_sub_xml[:-1] diff --git a/scripts/HFIR_4Circle_Reduction/fputility.py b/scripts/HFIR_4Circle_Reduction/fputility.py index c84244f246d..28d79a605e8 100644 --- a/scripts/HFIR_4Circle_Reduction/fputility.py +++ b/scripts/HFIR_4Circle_Reduction/fputility.py @@ -1,3 +1,4 @@ +#pylint: disable=R0914 # Utility methods for Fullprof diff --git a/scripts/HFIR_4Circle_Reduction/guiutility.py b/scripts/HFIR_4Circle_Reduction/guiutility.py index 497feb2d208..adfd6392725 100644 --- a/scripts/HFIR_4Circle_Reduction/guiutility.py +++ b/scripts/HFIR_4Circle_Reduction/guiutility.py @@ -128,13 +128,11 @@ def parse_float_array(array_str): :param array_str: :return: boolean, list of floats/error message """ - print array_str - assert isinstance(array_str, str) + assert isinstance(array_str, str), 'Input array for parsing must be of type string.' array_str = array_str.replace(',', ' ') array_str = array_str.replace('\n', ' ') array_str = array_str.replace('\t ', ' ') array_str = array_str.strip() - print '[DB] After processing: ', array_str float_str_list = array_str.split() float_list = list() diff --git a/scripts/HFIR_4Circle_Reduction/hfctables.py b/scripts/HFIR_4Circle_Reduction/hfctables.py index 0d0591e8cf6..19e5d373770 100644 --- a/scripts/HFIR_4Circle_Reduction/hfctables.py +++ b/scripts/HFIR_4Circle_Reduction/hfctables.py @@ -260,7 +260,6 @@ class UBMatrixTable(tableBase.NTableWidget): Guarantees: return a 3 x 3 ndarray :return: """ - # print '[DB] MatrixTable: _Matrix = ', self._matrix return self._matrix.copy() def get_matrix_str(self): @@ -477,7 +476,7 @@ class ProcessTableWidget(tableBase.NTableWidget): """ TableSetup = [('Scan', 'int'), ('Intensity', 'float'), - ('Corrected Intensity', 'float'), + ('Corrected', 'float'), ('Status', 'str'), ('Peak Centre', 'str'), ('HKL', 'str'), @@ -499,6 +498,7 @@ class ProcessTableWidget(tableBase.NTableWidget): # some commonly used column index self._colIndexKIndex = None self._colIndexHKL = None + self._colIndexStatus = None return @@ -558,11 +558,11 @@ class ProcessTableWidget(tableBase.NTableWidget): assert isinstance(scans, list) if allow_duplicate_scans is False: - scan_list = self.get_scan_list() + scan_list = self.get_scan_list(output_row_number=False) else: scan_list = list() - print '[DB...BAT] <append scans> in-table scans: ' % scan_list + print '[DB...BAT] Existing scan list: ', scan_list # set value as default # Append rows @@ -633,10 +633,11 @@ class ProcessTableWidget(tableBase.NTableWidget): return self.get_cell_value(i_row, j_col_merged) - def get_scan_list(self): + def get_scan_list(self, output_row_number=True): """ Get all scans that are already listed in the table. - :return: + :param output_row_number: + :return: list of 2-tuple or integer according to value of output_row_number """ scan_list = list() num_rows = self.rowCount() @@ -644,7 +645,11 @@ class ProcessTableWidget(tableBase.NTableWidget): for i_row in xrange(num_rows): scan_num = self.get_cell_value(i_row, col_scan_index) - scan_list.append((scan_num, i_row)) + if output_row_number: + scan_list.append((scan_num, i_row)) + else: + scan_list.append(scan_num) + # END-FOR (i_row) return scan_list @@ -685,6 +690,7 @@ class ProcessTableWidget(tableBase.NTableWidget): # set up column index self._colIndexKIndex = self.TableSetup.index(('K-Index', 'int')) self._colIndexHKL = self.TableSetup.index(('HKL', 'str')) + self._colIndexStatus = self.TableSetup.index(('Status', 'str')) return @@ -792,7 +798,7 @@ class ProcessTableWidget(tableBase.NTableWidget): # END-IF if lorentz_corrected: - col_name = ('Corrected Intensity', 'float') + col_name = ('Corrected', 'float') else: col_name = ('Intensity', 'float') intensity_col_index = ProcessTableWidget.TableSetup.index(col_name) @@ -828,7 +834,7 @@ class ProcessTableWidget(tableBase.NTableWidget): for i_row in xrange(num_rows): tmp_scan_no = self.get_cell_value(i_row, 0) if scan_no == tmp_scan_no: - self.update_cell_value(i_row, 2, status) + self.update_cell_value(i_row, self._colIndexStatus, status) set_done = True break # END-FOR @@ -850,8 +856,7 @@ class ProcessTableWidget(tableBase.NTableWidget): assert isinstance(status, str), 'Status (description) must be a string, but not %s.' % str(type(status)) # Set - i_status = self.TableSetup.index(('Status', 'str')) - self.update_cell_value(row_number, i_status, status) + self.update_cell_value(row_number, self._colIndexStatus, status) return diff --git a/scripts/HFIR_4Circle_Reduction/multi_threads_helpers.py b/scripts/HFIR_4Circle_Reduction/multi_threads_helpers.py new file mode 100644 index 00000000000..25701583973 --- /dev/null +++ b/scripts/HFIR_4Circle_Reduction/multi_threads_helpers.py @@ -0,0 +1,252 @@ +#pylint: disable=W0403,R0913 + +from PyQt4 import QtCore +from PyQt4.QtCore import QThread + +import reduce4circleControl as r4c + + +class AddPeaksThread(QThread): + """ + A QThread class to add peaks to Mantid to calculate UB matrix + """ + # signal for a peak is added: int_0 = experiment number, int_1 = scan number + peakAddedSignal = QtCore.pyqtSignal(int, int) + # signal for status: int_0 = experiment number, int_1 = scan number, int_2 = progress (0...) + peakStatusSignal = QtCore.pyqtSignal(int, int, int) + + def __init__(self, main_window, exp_number, scan_number_list): + """ + Initialization + :param main_window: + :param exp_number: + :param scan_number_list: + """ + QThread.__init__(self) + + # check + assert main_window is not None, 'Main window cannot be None' + assert isinstance(exp_number, int), 'Experiment number must be an integer.' + assert isinstance(scan_number_list, list), 'Scan number list must be a list but not %s.' \ + '' % str(type(scan_number_list)) + + # set values + self._mainWindow = main_window + self._expNumber = exp_number + self._scanNumberList = scan_number_list + + # connect to the updateTextEdit slot defined in app1.py + self.peakAddedSignal.connect(self._mainWindow.update_peak_added_info) + self.peakStatusSignal.connect(self._mainWindow.update_adding_peaks_status) + + return + + def __del__(self): + """ + Delete signal + :return: + """ + self.wait() + + return + + def run(self): + """ + method for thread is running + :return: + """ + # declare list of failed + failed_list = list() + + # loop over all scan numbers + for index, scan_number in enumerate(self._scanNumberList): + # update state + self.peakStatusSignal.emit(self._expNumber, scan_number, index) + + # merge peak + status, err_msg = self._mainWindow.controller.merge_pts_in_scan( + self._expNumber, scan_number, [], 'q-sample') + + # continue to the next scan if there is something wrong + if status is False: + failed_list.append((scan_number, err_msg)) + continue + + # find peak + self._mainWindow.controller.find_peak(self._expNumber, scan_number) + + # get PeakInfo + peak_info = self._mainWindow.controller.get_peak_info(self._expNumber, scan_number) + assert isinstance(peak_info, r4c.PeakProcessHelper) + + # send signal to main window for peak being added + self.peakAddedSignal.emit(self._expNumber, scan_number) + # END-FOR + + # send signal with unphysical scan number to flag the end of operation. + self.peakStatusSignal.emit(self._expNumber, -1, len(self._scanNumberList)) + + # pop error if there is any scan that is not reduced right + if len(failed_list) > 0: + failed_scans_str = 'Unable to merge scans: ' + sum_error_str = '' + for fail_tup in failed_list: + failed_scans_str += '%d, ' % fail_tup[0] + sum_error_str += '%s\n' % fail_tup[1] + # END-FOR + + self._mainWindow.pop_one_button_dialog(failed_scans_str) + self._mainWindow.pop_one_button_dialog(sum_error_str) + # END-IF + + return + + +class IntegratePeaksThread(QThread): + """ + A thread to integrate peaks + """ + # signal to emit before a merge/integration status: exp number, scan number, progress, mode + peakMergeSignal = QtCore.pyqtSignal(int, int, float, int) + errorSignal = QtCore.pyqtSignal(int, int, str) + + def __init__(self, main_window, exp_number, scan_tuple_list, mask_det, mask_name, norm_type, num_pt_bg_left, + num_pt_bg_right): + """ + + :param main_window: + :param exp_number: + :param scan_tuple_list: list of tuples for scan as (scan number, pt number list, state as merged) + :param mask_det: + :param mask_name: + :param norm_type: type of normalization + :param num_pt_bg_left: number of Pt in the left + :param num_pt_bg_right: number of Pt for background in the right + """ + # start thread + QThread.__init__(self) + + # check + assert main_window is not None, 'Main window cannot be None' + assert isinstance(exp_number, int), 'Experiment number must be an integer.' + assert isinstance(scan_tuple_list, list), 'Scan (info) tuple list must be a list but not %s.' \ + '' % str(type(scan_tuple_list)) + assert isinstance(mask_det, bool), 'Parameter mask_det must be a boolean but not %s.' \ + '' % str(type(mask_det)) + assert isinstance(mask_name, str), 'Name of mask must be a string but not %s.' % str(type(mask_name)) + assert isinstance(norm_type, str), 'Normalization type must be a string but not %s.' \ + '' % str(type(norm_type)) + assert isinstance(num_pt_bg_left, int) and num_pt_bg_left >= 0 + assert isinstance(num_pt_bg_right, int) and num_pt_bg_right >= 0 + + # set values + self._mainWindow = main_window + self._expNumber = exp_number + self._scanTupleList = scan_tuple_list[:] + self._maskDetector = mask_det + self._normalizeType = norm_type + self._selectedMaskName = mask_name + self._numBgPtLeft = num_pt_bg_left + self._numBgPtRight = num_pt_bg_right + + # link signals + self.peakMergeSignal.connect(self._mainWindow.update_merge_status) + self.errorSignal.connect(self._mainWindow.update_merge_error) + + return + + def __del__(self): + """ + Delete signal + :return: + """ + self.wait() + + return + + def run(self): + """ + Execute the thread! + :return: + """ + for index, scan_tup in enumerate(self._scanTupleList): + # check + assert isinstance(scan_tup, tuple) and len(scan_tup) == 3 + scan_number, pt_number_list, merged = scan_tup + + # emit signal for run start (mode 0) + mode = int(0) + self.peakMergeSignal.emit(self._expNumber, scan_number, float(index), mode) + + # merge if not merged + if merged is False: + self._mainWindow.controller.merge_pts_in_scan(exp_no=self._expNumber, scan_no=scan_number, + pt_num_list=pt_number_list, + target_frame='q-sample') + self._mainWindow.ui.tableWidget_mergeScans.set_status(scan_number, 'Merged') + # END-IF + + # calculate peak center + try: + status, ret_obj = self._mainWindow.controller.calculate_peak_center(self._expNumber, scan_number, + pt_number_list) + except RuntimeError as run_err: + status = False + ret_obj = 'RuntimeError: %s.' % str(run_err) + except AssertionError as ass_err: + status = False + ret_obj = 'AssertionError: %s.' % str(ass_err) + + if status: + center_i = ret_obj + else: + error_msg = 'Unable to find peak for exp %d scan %d: %s.' % (self._expNumber, scan_number, str(ret_obj)) + self._mainWindow.controller.set_peak_intensity(self._expNumber, scan_number, 0.) + self._mainWindow.ui.tableWidget_mergeScans.set_peak_intensity(None, scan_number, 0., False) + self._mainWindow.ui.tableWidget_mergeScans.set_status(scan_number, error_msg) + continue + + # check given mask workspace + if self._maskDetector: + self._mainWindow.controller.check_generate_mask_workspace(self._expNumber, scan_number, + self._selectedMaskName) + + # integrate peak + print '[DB...BAD] Normalization: %s; Use Mask = %s, Mask Workspace = %s.' % ( + self._normalizeType, str(self._maskDetector), self._selectedMaskName + ) + status, ret_obj = self._mainWindow.controller.integrate_scan_peaks(exp=self._expNumber, + scan=scan_number, + peak_radius=1.0, + peak_centre=center_i, + merge_peaks=False, + use_mask=self._maskDetector, + normalization=self._normalizeType, + mask_ws_name=self._selectedMaskName) + # handle integration error + if status: + # get PT dict + pt_dict = ret_obj + else: + # integration failed + error_msg = str(ret_obj) + self.errorSignal.emit(self._expNumber, scan_number, error_msg) + continue + + # calculate background value + background_pt_list = pt_number_list[:self._numBgPtLeft] + pt_number_list[-self._numBgPtRight:] + avg_bg_value = self._mainWindow.controller.estimate_background(pt_dict, background_pt_list) + + # correct intensity by background value + intensity_i = self._mainWindow.controller.simple_integrate_peak(pt_dict, avg_bg_value) + + # emit signal to main app for peak intensity value + mode = 1 + self.peakMergeSignal.emit(self._expNumber, scan_number, float(intensity_i), mode) + # END-FOR + + # terminate the process + self.peakMergeSignal.emit(self._expNumber, -1, len(self._scanTupleList), 2) + self._mainWindow.ui.tableWidget_mergeScans.select_all_rows(False) + + return diff --git a/scripts/HFIR_4Circle_Reduction/peakprocesshelper.py b/scripts/HFIR_4Circle_Reduction/peakprocesshelper.py index 63788445a25..73f5dfd8668 100644 --- a/scripts/HFIR_4Circle_Reduction/peakprocesshelper.py +++ b/scripts/HFIR_4Circle_Reduction/peakprocesshelper.py @@ -44,6 +44,7 @@ class PeakProcessHelper(object): self._myPeakWSKey = (None, None, None) self._myPeakIndex = None + self._ptIntensityDict = None self._myLastPeakUB = None @@ -103,7 +104,6 @@ class PeakProcessHelper(object): # END-FOR (i_peak) self._avgPeakCenter = q_sample_sum/weight_sum - print '[DB] Weighted peak center = %s' % str(self._avgPeakCenter) return @@ -159,10 +159,16 @@ class PeakProcessHelper(object): def get_weighted_peak_centres(self): """ Get the peak centers found in peak workspace. Guarantees: the peak centers and its weight (detector counts) are exported - :return: 2 lists: list of 3-tuple (Qx, Qy, Qz) and list of double (Det_Counts) + :return: 2-tuple: list of 3-tuple (Qx, Qy, Qz) + list of double (Det_Counts) """ + # get PeaksWorkspace + if AnalysisDataService.doesExist(self._myPeakWorkspaceName) is False: + raise RuntimeError('PeaksWorkspace %s does ot exit.' % self._myPeakWorkspaceName) + peak_ws = AnalysisDataService.retrieve(self._myPeakWorkspaceName) + # get peak center, peak intensity and etc. peak_center_list = list() peak_intensity_list = list() num_peaks = peak_ws.getNumberPeaks() @@ -184,7 +190,7 @@ class PeakProcessHelper(object): # get SPICE table spice_table_name = get_spice_table_name(self._myExpNumber, self._myScanNumber) assert AnalysisDataService.doesExist(spice_table_name), 'Spice table for exp %d scan %d cannot be found.' \ - '' % (self._myExpNumber, self._myScanNumber) + '' % (self._myExpNumber, self._myScanNumber) spice_table_ws = AnalysisDataService.retrieve(spice_table_name) @@ -264,6 +270,20 @@ class PeakProcessHelper(object): return + def set_pt_intensity(self, pt_intensity_dict): + """ + Set Pt. intensity + :param pt_intensity_dict: + :return: + """ + assert isinstance(pt_intensity_dict, dict) + + print '[DB...BAT] Pt intensity dict keys: ', pt_intensity_dict.keys() + + self._ptIntensityDict = pt_intensity_dict + + return + def get_sigma(self): """ Get peak intensity's sigma :return: @@ -296,9 +316,6 @@ class PeakProcessHelper(object): self._userHKL[1] = mi_k self._userHKL[2] = mi_l - print '[DB] PeakInfo Set User HKL to (%f, %f, %f) ' % (self._userHKL[0], self._userHKL[1], - self._userHKL[2]) - return def get_experiment_info(self): diff --git a/scripts/HFIR_4Circle_Reduction/reduce4circleControl.py b/scripts/HFIR_4Circle_Reduction/reduce4circleControl.py index d17e9fb06ed..83d34083979 100644 --- a/scripts/HFIR_4Circle_Reduction/reduce4circleControl.py +++ b/scripts/HFIR_4Circle_Reduction/reduce4circleControl.py @@ -209,7 +209,7 @@ class CWSCDReductionControl(object): if self.has_merged_data(exp_number, scan_number, pt_number_list): pass else: - raise RuntimeError('Data must be merged before') + return False, 'Exp %d Scan %d: data must be merged already.' % (exp_number, scan_number) # Find peak in Q-space merged_ws_name = get_merged_md_name(self._instrumentName, exp_number, scan_number, pt_number_list) @@ -579,7 +579,6 @@ class CWSCDReductionControl(object): return False, 'RuntimeError: %s.' % str(error) # get the information whether there is any k-shift vector specified by user - print '[DB...Prototype] Current k-shift vectors are ... ', self._kShiftDict # form k-shift and peak intensity information scan_kindex_dict = dict() @@ -601,7 +600,11 @@ class CWSCDReductionControl(object): no_shift = len(scan_kindex_dict) == 0 for scan_number in scan_number_list: peak_dict = dict() - peak_dict['hkl'] = self._myPeakInfoDict[(exp_number, scan_number)]. get_current_hkl() + try: + peak_dict['hkl'] = self._myPeakInfoDict[(exp_number, scan_number)]. get_current_hkl() + except RuntimeError as run_err: + return False, str('Peak index error: %s.' % run_err) + peak_dict['intensity'] = self._myPeakInfoDict[(exp_number, scan_number)].get_intensity() peak_dict['sigma'] = self._myPeakInfoDict[(exp_number, scan_number)].get_sigma() if no_shift: @@ -619,7 +622,7 @@ class CWSCDReductionControl(object): except AssertionError as error: return False, 'AssertionError: %s.' % str(error) except RuntimeError as error: - return False, 'RuntimeError; %s.' % str(error) + return False, 'RuntimeError: %s.' % str(error) return True, file_content @@ -673,7 +676,6 @@ class CWSCDReductionControl(object): # Find peak in Q-space merged_ws_name = get_merged_md_name(self._instrumentName, exp_number, scan_number, pt_number_list) peak_ws_name = get_peak_ws_name(exp_number, scan_number, pt_number_list) - print '[DB] Found peaks are output workspace %s.' % peak_ws_name api.FindPeaksMD(InputWorkspace=merged_ws_name, MaxPeaks=10, PeakDistanceThreshold=5., @@ -1110,7 +1112,8 @@ class CWSCDReductionControl(object): def integrate_scan_peaks(self, exp, scan, peak_radius, peak_centre, merge_peaks=True, use_mask=False, - normalization='', mask_ws_name=None): + normalization='', mask_ws_name=None, + scale_factor=1): """ :param exp: :param scan: @@ -1121,6 +1124,7 @@ class CWSCDReductionControl(object): :param use_mask: :param normalization: normalization set up (by time or ...) :param mask_ws_name: mask workspace name or None + :param scale_factor: integrated peaks' scaling factor :return: """ # check @@ -1166,10 +1170,7 @@ class CWSCDReductionControl(object): elif normalization == 'monitor': norm_by_mon = True - print '[DB-INFO] Integrate Pt. with mask workspace %s. Norm by time = %d; Norm by monitor = %d.' \ - '' % (mask_ws_name, norm_by_time, norm_by_mon) - - # VZ-FUTURE: Are you sure ScaleFactor is 1 !!! + # integrate peak of a scan api.IntegratePeaksCWSD(InputWorkspace=md_ws_name, OutputWorkspace=integrated_peak_ws_name, PeakRadius=peak_radius, @@ -1178,13 +1179,12 @@ class CWSCDReductionControl(object): NormalizeByMonitor=norm_by_mon, NormalizeByTime=norm_by_time, MaskWorkspace=mask_ws_name, - ScaleFactor=1) + ScaleFactor=scale_factor) # process the output workspace pt_dict = dict() out_peak_ws = AnalysisDataService.retrieve(integrated_peak_ws_name) num_peaks = out_peak_ws.rowCount() - print '[DB....BAT] There are %d peaks to export!' % num_peaks for i_peak in xrange(num_peaks): peak_i = out_peak_ws.getPeak(i_peak) @@ -1193,6 +1193,11 @@ class CWSCDReductionControl(object): pt_dict[run_number_i] = intensity_i # END-FOR + # store the data into peak info + if (exp, scan) not in self._myPeakInfoDict: + raise RuntimeError('Exp %d Scan %d is not recorded in PeakInfo-Dict' % (exp, scan)) + self._myPeakInfoDict[(exp, scan)].set_pt_intensity(pt_dict) + return True, pt_dict def integrate_peaks_q(self, exp_no, scan_no): @@ -1367,6 +1372,7 @@ class CWSCDReductionControl(object): def load_spice_scan_file(self, exp_no, scan_no, spice_file_name=None): """ Load a SPICE scan file to table workspace and run information matrix workspace. + :param exp_no: :param scan_no: :param spice_file_name: :return: status (boolean), error message (string) @@ -1374,6 +1380,7 @@ class CWSCDReductionControl(object): # Default for exp_no if exp_no is None: exp_no = self._expNumber + print '[DB...BAD] Load Spice Scan File Exp Number = %d, Stored Exp. Number = %d' % (exp_no, self._expNumber) # Check whether the workspace has been loaded assert isinstance(exp_no, int) @@ -1495,7 +1502,6 @@ class CWSCDReductionControl(object): continue pt_list_str += ',%d' % pt # END-FOR (pt) - print '[DB] Pt list = %s' % pt_list_str if pt_list_str == '-1': return False, err_msg @@ -1829,8 +1835,6 @@ class CWSCDReductionControl(object): oriented_lattice.errorc(), oriented_lattice.erroralpha(), oriented_lattice.errorbeta(), oriented_lattice.errorgamma()] - print '[DB-BAT] Refined UB = ', refined_ub_matrix, 'of type', type(refined_ub_matrix) - result_tuple = (peak_ws, refined_ub_matrix, lattice, lattice_error) return result_tuple @@ -2078,7 +2082,6 @@ class CWSCDReductionControl(object): try: ws = self._mySpiceTableDict[(exp_no, scan_no)] except KeyError: - print '[DB] Keys to SPICE TABLE: %s' % str(self._mySpiceTableDict.keys()) return None return ws @@ -2236,10 +2239,8 @@ class CWSCDReductionControl(object): wavelength = get_hb3a_wavelength(m1) if wavelength is None: q_range = 0. - print '[DB-BAT] 2theta = %f, lambda = None, Q = %f' % (two_theta, q_range) else: q_range = 4.*math.pi*math.sin(two_theta/180.*math.pi*0.5)/wavelength - print '[DB-BAT] 2theta = %f, lambda = %f, Q = %f' % (two_theta, wavelength, q_range) # appending to list scan_sum_list.append([max_count, scan_number, max_row, max_h, max_k, max_l, diff --git a/scripts/HFIR_4Circle_Reduction/reduce4circleGUI.py b/scripts/HFIR_4Circle_Reduction/reduce4circleGUI.py index 2874c02a89d..c5a16bb452d 100644 --- a/scripts/HFIR_4Circle_Reduction/reduce4circleGUI.py +++ b/scripts/HFIR_4Circle_Reduction/reduce4circleGUI.py @@ -9,12 +9,20 @@ import sys import math import csv import time +import datetime import random import numpy from scipy.optimize import curve_fit from PyQt4 import QtCore, QtGui +from PyQt4.QtCore import QThread +try: + _fromUtf8 = QtCore.QString.fromUtf8 +except AttributeError: + def _fromUtf8(s): + return s + try: from mantidqtpython import MantidQt except ImportError as e: @@ -22,16 +30,13 @@ except ImportError as e: else: NO_SCROLL = False -import reduce4circleControl as r4c +# import reduce4circleControl as r4c import guiutility as gutil import fourcircle_utility as hb3a import plot3dwindow +from multi_threads_helpers import * + -try: - _fromUtf8 = QtCore.QString.fromUtf8 -except AttributeError: - def _fromUtf8(s): - return s # import line for the UI python class from ui_MainWindow import Ui_MainWindow @@ -58,10 +63,14 @@ class MainWindow(QtGui.QMainWindow): # Make UI scrollable if NO_SCROLL is False: self._scrollbars = MantidQt.API.WidgetScrollbarDecorator(self) - self._scrollbars.setEnabled(True) # Must follow after setupUi(self)! + self._scrollbars.setEnabled(True) # Must follow after setupUi(self)! self._init_widgets() + # thread + self._myIntegratePeaksThread = None + self._addUBPeaksThread = None + # Mantid configuration self._instrument = str(self.ui.comboBox_instrument.currentText()) # config = ConfigService.Instance() @@ -261,11 +270,26 @@ class MainWindow(QtGui.QMainWindow): self._my3DWindow = None self._refineConfigWindow = None + # Timing and thread 'global' + self._startMeringScans = time.clock() + self._errorMessageEnsemble = '' + # QSettings self.load_settings() return + @property + def controller(self): + """ Parameter controller + """ + assert self._myControl is not None, 'Controller cannot be None.' + assert isinstance(self._myControl, r4c.CWSCDReductionControl), \ + 'My controller must be of type %s, but not %s.' % ('CWSCDReductionControl', + self._myControl.__class__.__name__) + + return self._myControl + def evt_show_survey(self): """ Show survey result @@ -319,7 +343,6 @@ class MainWindow(QtGui.QMainWindow): self.ui.lineEdit_localSpiceDir.setEnabled(True) self.ui.pushButton_browseLocalDataDir.setEnabled(True) - return def _build_peak_info_list(self): @@ -435,48 +458,17 @@ class MainWindow(QtGui.QMainWindow): # get experiment number status, exp_number = gutil.parse_integers_editors(self.ui.lineEdit_exp) - assert status + if not status: + self.pop_one_button_dialog('Unable to get experiment number\n due to %s.' % str(exp_number)) + return # switch to tab-3 self.ui.tabWidget.setCurrentIndex(MainWindow.TabPage['Calculate UB']) - # find peak and add peak - failed_list = list() - for scan_number in scan_number_list: - # merge peak - status, err_msg = self._myControl.merge_pts_in_scan(exp_number, scan_number, [], 'q-sample') - - # continue to the next scan if there is something wrong - if status is False: - failed_list.append((scan_number, err_msg)) - continue - - # find peak - self._myControl.find_peak(exp_number, scan_number) - - # get PeakInfo - peak_info = self._myControl.get_peak_info(exp_number, scan_number) - assert isinstance(peak_info, r4c.PeakProcessHelper) - - # retrieve and set HKL from spice table - peak_info.retrieve_hkl_from_spice_table() - - # add to table - self.set_ub_peak_table(peak_info) - # END-FOR - - # pop error if there is any scan that is not reduced right - if len(failed_list) > 0: - failed_scans_str = 'Unable to merge scans: ' - sum_error_str = '' - for fail_tup in failed_list: - failed_scans_str += '%d, ' % fail_tup[0] - sum_error_str += '%s\n' % fail_tup[1] - # END-FOR - - self.pop_one_button_dialog(failed_scans_str) - self.pop_one_button_dialog(sum_error_str) - # END-FOR + # prototype for a new thread + self.ui.progressBar_add_ub_peaks.setRange(0, len(scan_number_list)) + self._addUBPeaksThread = AddPeaksThread(self, exp_number, scan_number_list) + self._addUBPeaksThread.start() return @@ -524,8 +516,6 @@ class MainWindow(QtGui.QMainWindow): self.pop_one_button_dialog(int_list) return exp_no, scan_no = int_list - print '[DB] Experiment number = ', exp_no - print '[DB] Scan numbers = ', str(scan_no), 'of type ', type(scan_no) # Get HKL from GUI status, float_list = gutil.parse_float_editors([self.ui.lineEdit_H, @@ -819,7 +809,6 @@ class MainWindow(QtGui.QMainWindow): """ # Find out the lines to get deleted row_num_list = self.ui.tableWidget_peaksCalUB.get_selected_rows() - print '[DB] Row %s are selected' % str(row_num_list) # Delete self.ui.tableWidget_peaksCalUB.delete_rows(row_num_list) @@ -980,10 +969,14 @@ class MainWindow(QtGui.QMainWindow): # write user_header = str(self.ui.lineEdit_fpHeader.text()) try: - status, file_content = self._myControl.export_to_fullprof(exp_number, scan_number_list, user_header, fp_name) + status, file_content = self._myControl.export_to_fullprof(exp_number, scan_number_list, + user_header, fp_name) self.ui.plainTextEdit_fpContent.setPlainText(file_content) if status is False: - self.pop_one_button_dialog(file_content) + error_msg = file_content + if error_msg.startswith('Peak index error'): + error_msg = 'You may forget to index peak\n' + error_msg + self.pop_one_button_dialog(error_msg) except AssertionError as a_err: self.pop_one_button_dialog(str(a_err)) return @@ -1109,9 +1102,6 @@ class MainWindow(QtGui.QMainWindow): else: exp_number, scan_number = ret_obj - # mask workspace? - mask_detectors = self.ui.checkBox_applyMask.isChecked() - normalization = str(self.ui.comboBox_ptCountType.currentText()) if normalization.count('Time') > 0: norm_type = 'time' @@ -1129,14 +1119,28 @@ class MainWindow(QtGui.QMainWindow): else: this_peak_centre = ret_obj + # scale factor + try: + intensity_scale_factor = float(self.ui.lineEdit_scaleFactor.text()) + except ValueError: + intensity_scale_factor = 1. + # get masked workspace + mask_name = str(self.ui.comboBox_maskNames2.currentText()) + if mask_name.startswith('No Mask'): + mask_name = None + # mask workspace? + mask_detectors = mask_name is not None + status, ret_obj = self._myControl.integrate_scan_peaks(exp=exp_number, scan=scan_number, peak_radius=1.0, peak_centre=this_peak_centre, merge_peaks=False, use_mask=mask_detectors, - normalization=norm_type) + mask_ws_name=mask_name, + normalization=norm_type, + scale_factor=intensity_scale_factor) # result due to error if status is False: @@ -1148,8 +1152,6 @@ class MainWindow(QtGui.QMainWindow): pt_dict = ret_obj assert isinstance(pt_dict, dict) - print '[DB-BAT] Returned Pt. dict: ', pt_dict - # clear table if self.ui.tableWidget_peakIntegration.rowCount() > 0: self.ui.tableWidget_peakIntegration.remove_all_rows() @@ -1162,7 +1164,8 @@ class MainWindow(QtGui.QMainWindow): intensity_list.append(pt_intensity) status, msg = self.ui.tableWidget_peakIntegration.append_pt(pt, -1, pt_intensity) if not status: - print '[Error!] Unable to add Pt %d due to %s.' % (pt, msg) + error_msg = '[Error!] Unable to add Pt %d due to %s.' % (pt, msg) + self.pop_one_button_dialog(error_msg) # Set up the experiment information to table self.ui.tableWidget_peakIntegration.set_exp_info(exp_number, scan_number) @@ -1216,10 +1219,12 @@ class MainWindow(QtGui.QMainWindow): # background Pt. status, num_bg_pt = gutil.parse_integers_editors(self.ui.lineEdit_numPt4Background, allow_blank=False) - assert status and num_bg_pt > 0, 'Number of Pt number for background must be larger than 0!' + if not status or num_bg_pt == 0: + self.pop_one_button_dialog('Number of Pt number for background must be larger than 0: %s!' % str(num_bg_pt)) + return - # integrate peak - grand_error_message = '' + # get the merging information: each item should be a tuple as (scan number, pt number list, merged) + scan_number_list = list() for row_number in row_number_list: # get scan number and pt numbers scan_number = self.ui.tableWidget_mergeScans.get_scan_number(row_number) @@ -1227,92 +1232,42 @@ class MainWindow(QtGui.QMainWindow): # set intensity to zero and error message if status is False: - error_msg = 'Unable to get Pt. of experiment %d scan %d due to %s.' % ( - exp_number, scan_number, str(pt_number_list)) - self._myControl.set_peak_intensity(exp_number, scan_number, 0.) + error_msg = 'Unable to get Pt. of experiment %d scan %d due to %s.' % (exp_number, scan_number, + str(pt_number_list)) + self.controller.set_peak_intensity(exp_number, scan_number, 0.) self.ui.tableWidget_mergeScans.set_peak_intensity(row_number, scan_number, 0., False) self.ui.tableWidget_mergeScans.set_status(scan_number, error_msg) continue # merge all Pt. of the scan if they are not merged. merged = self.ui.tableWidget_mergeScans.get_merged_status(row_number) - if merged is False: - self._myControl.merge_pts_in_scan(exp_no=exp_number, scan_no=scan_number, pt_num_list=pt_number_list, - target_frame='q-sample') - self.ui.tableWidget_mergeScans.set_status_by_row(row_number, 'Done') - # END-IF - - # calculate peak center - try: - status, ret_obj = self._myControl.calculate_peak_center(exp_number, scan_number, pt_number_list) - except RuntimeError as run_err: - status = False - ret_obj = 'RuntimeError: %s.' % str(run_err) - except AssertionError as ass_err: - status = False - ret_obj = 'AssertionError: %s.' % str(ass_err) - - if status: - center_i = ret_obj - else: - error_msg = 'Unable to find peak for exp %d scan %d: %s.' % (exp_number, scan_number, str(ret_obj)) - self._myControl.set_peak_intensity(exp_number, scan_number, 0.) - self.ui.tableWidget_mergeScans.set_peak_intensity(row_number, scan_number, 0., False) - self.ui.tableWidget_mergeScans.set_status(scan_number, error_msg) - continue - - # mask workspace - # VZ-FUTURE: consider to modify method generate_mask_workspace() such that it can be generalized outside - # loop - if mask_det: - self._myControl.check_generate_mask_workspace(exp_number, scan_number, selected_mask) - - # integrate peak - status, ret_obj = self._myControl.integrate_scan_peaks(exp=exp_number, - scan=scan_number, - peak_radius=1.0, - peak_centre=center_i, - merge_peaks=False, - use_mask=mask_det, - normalization=norm_type, - mask_ws_name=selected_mask) - # handle integration error - if not status: - error_msg = str(ret_obj) - self._myControl.set_peak_intensity(exp_number, scan_number, 0.) - self.ui.tableWidget_mergeScans.set_peak_intensity(row_number, scan_number, 0., False) - self.ui.tableWidget_mergeScans.set_status(scan_number, error_msg) - continue - - pt_dict = ret_obj - - background_pt_list = pt_number_list[:num_bg_pt] + pt_number_list[-num_bg_pt:] - avg_bg_value = self._myControl.estimate_background(pt_dict, background_pt_list) - intensity_i = self._myControl.simple_integrate_peak(pt_dict, avg_bg_value) - - # check intensity value - if intensity_i < 0: - # set to status - error_msg = 'Negative intensity: %.3f' % intensity_i - self.ui.tableWidget_mergeScans.set_status(scan_no=scan_number, status=error_msg) - # reset intensity to 0. - intensity_i = 0. - # set the calculated peak intensity to _peakInfoDict - status, error_msg = self._myControl.set_peak_intensity(exp_number, scan_number, intensity_i) - if status is False: - grand_error_message += error_msg + '\n' - continue - - # set the value to table - self.ui.tableWidget_mergeScans.set_peak_intensity(row_number, None, intensity_i) + # add to list + scan_number_list.append((scan_number, pt_number_list, merged)) + self.ui.tableWidget_mergeScans.set_status_by_row(row_number, 'Waiting') # END-FOR - # pop error message if there is any - if len(grand_error_message) > 0: - self.pop_one_button_dialog(grand_error_message) + # set the progress bar + self.ui.progressBar_mergeScans.setRange(0, len(scan_number_list)) + self.ui.progressBar_mergeScans.setValue(0) + self.ui.progressBar_mergeScans.setTextVisible(True) + self.ui.progressBar_mergeScans.setStatusTip('Hello') + + # process background setup + status, ret_obj = gutil.parse_integers_editors([self.ui.lineEdit_numPt4Background, + self.ui.lineEdit_numPt4BackgroundRight], + allow_blank=False) + if not status: + error_msg = str(ret_obj) + self.pop_one_button_dialog(error_msg) + return + num_pt_bg_left = ret_obj[0] + num_pt_bg_right = ret_obj[1] - self.ui.tableWidget_mergeScans.select_all_rows(False) + self._myIntegratePeaksThread = IntegratePeaksThread(self, exp_number, scan_number_list, + mask_det, selected_mask, norm_type, + num_pt_bg_left, num_pt_bg_right) + self._myIntegratePeaksThread.start() return @@ -1458,10 +1413,12 @@ class MainWindow(QtGui.QMainWindow): # get experiment number and scan number from the table exp_number, scan_number = self.ui.tableWidget_peakIntegration.get_exp_info() + mask_name = str(self.ui.comboBox_maskNames2.currentText()) + masked = not mask_name.startswith('No Mask') has_integrated = self._myControl.has_integrated_peak(exp_number, scan_number, pt_list=None, normalized_by_monitor=norm_by_monitor, normalized_by_time=norm_by_time, - masked=self.ui.checkBox_applyMask.isChecked()) + masked=masked) # integrate and/or plot if has_integrated: @@ -1675,7 +1632,6 @@ class MainWindow(QtGui.QMainWindow): # Process scan_row_list = self.ui.tableWidget_mergeScans.get_selected_scans() - print '[DB] %d scans have been selected to merge.' % len(scan_row_list) frame = str(self.ui.comboBox_mergeScanFrame.currentText()) for tup2 in scan_row_list: # @@ -1961,10 +1917,9 @@ class MainWindow(QtGui.QMainWindow): :return: """ lower_left_c, upper_right_c = self.ui.graphicsView.get_roi() - print '[DB-BAT] Save RIO as [%s, %s]' % (str(lower_left_c), str(upper_right_c)) status, par_val_list = gutil.parse_integers_editors([self.ui.lineEdit_exp, self.ui.lineEdit_run]) - assert status + assert status, str(par_val_list) exp_number = par_val_list[0] scan_number = par_val_list[1] @@ -2102,8 +2057,14 @@ class MainWindow(QtGui.QMainWindow): # calculate HKL from SPICE ub_matrix = self._myControl.get_ub_matrix(exp_number) index_status, ret_tup = self._myControl.index_peak(ub_matrix, scan_i) - assert index_status - hkl_i = ret_tup[0] + if index_status: + hkl_i = ret_tup[0] + else: + # unable to index peak. use fake hkl and set error message + hkl_i = [0, 0, 0] + error_msg = 'Scan %d: %s' % (scan_i, str(ret_tup)) + self.ui.tableWidget_mergeScans.set_status(scan_i, error_msg) + # END-IF-ELSE(index) # END-IF-ELSE (hkl_from_spice) # round @@ -2416,9 +2377,6 @@ class MainWindow(QtGui.QMainWindow): # peak center weight_peak_centers, weight_peak_intensities = peak_info.get_weighted_peak_centres() qx, qy, qz = peak_info.get_peak_centre() - # get peak intensity - intensity = self._myControl.get_peak_integrated_intensity(exp_number, scan_number) - #intensity = 100000 # convert from list to ndarray num_pt_peaks = len(weight_peak_centers) @@ -2436,7 +2394,8 @@ class MainWindow(QtGui.QMainWindow): avg_peak_centre[0][0] = qx avg_peak_centre[0][1] = qy avg_peak_centre[0][2] = qz - avg_peak_intensity[0] = intensity + # integrated peak intensity + avg_peak_intensity[0] = sum(pt_peak_intensity_array) return md_file_name, pt_peak_centre_array, pt_peak_intensity_array, avg_peak_centre, avg_peak_intensity @@ -2832,3 +2791,136 @@ class MainWindow(QtGui.QMainWindow): self.ui.plainTextEdit_rawDataInformation.setPlainText(info) return + + def update_adding_peaks_status(self, exp_number, scan_number, progress): + """ + Update the status for adding peak to UB matrix calculating + :param exp_number: + :param scan_number: + :param progress: + :return: + """ + # show message to bar + if scan_number < 0: + message = 'Peak processing finished' + else: + message = 'Processing experiment %d scan %d starting from %s.' % (exp_number, scan_number, + str(datetime.datetime.now())) + self.ui.statusbar.showMessage(message) + + # update progress bar + self.ui.progressBar_add_ub_peaks.setValue(progress) + + return + + def update_merge_status(self, exp_number, scan_number, sig_value, mode): + """ + update the status of merging/integrating peaks + :param exp_number: + :param scan_number: + :param sig_value: + :param mode: + :return: + """ + if mode == 0: + # start of processing one peak + progress = int(sig_value - 0.5) + if progress == 0: + # run start + self._startMeringScans = time.clock() + self._errorMessageEnsemble = '' + + self.ui.progressBar_mergeScans.setValue(progress) + + elif mode == 1: + # end of processing one peak + intensity = sig_value + + # check intensity value + is_error = False + if intensity < 0: + # set to status + error_msg = 'Negative intensity: %.3f' % intensity + self.ui.tableWidget_mergeScans.set_status(scan_no=scan_number, status=error_msg) + # reset intensity to 0. + intensity = 0. + is_error = True + + # set the calculated peak intensity to _peakInfoDict + status, error_msg = self._myControl.set_peak_intensity(exp_number, scan_number, intensity) + if status: + # set the value to table + self.ui.tableWidget_mergeScans.set_peak_intensity(None, scan_number, intensity) + if not is_error: + self.ui.tableWidget_mergeScans.set_status(scan_number, 'Done') + else: + self._errorMessageEnsemble += error_msg + '\n' + self.ui.tableWidget_mergeScans.set_status(scan_number, error_msg) + + elif mode == 2: + # end of the whole run + progress = int(sig_value+0.5) + self.ui.progressBar_mergeScans.setValue(progress) + + merge_run_end = time.clock() + + elapsed = merge_run_end - self._startMeringScans + message = 'Peak integration is over. Used %.2f seconds' % elapsed + + self.ui.statusbar.showMessage(message) + + # pop error message if there is any + if len(self._errorMessageEnsemble) > 0: + self.pop_one_button_dialog(self._errorMessageEnsemble) + + del self._myIntegratePeaksThread + + return + + def update_merge_error(self, exp_number, scan_number, error_msg): + """ + Update the merge-scan table for error message + :param exp_number: + :param scan_number: + :param error_msg: + :return: + """ + # check + assert isinstance(exp_number, int) + assert isinstance(scan_number, int) + assert isinstance(error_msg, str) + + # set intensity, state to table + self.ui.tableWidget_mergeScans.set_peak_intensity(row_number=None, scan_number=scan_number, + peak_intensity=0., lorentz_corrected=False) + self.ui.tableWidget_mergeScans.set_status(scan_no=scan_number, status=error_msg) + + # set peak value + status, error_msg = self._myControl.set_peak_intensity(exp_number, scan_number, 0.) + if not status: + self.pop_one_button_dialog(error_msg) + + return + + def update_peak_added_info(self, int_msg, int_msg2): + """ + Update the peak-being-added information + :param int_msg: + :param int_msg2: + :return: + """ + # get parameters passed + exp_number = int_msg + scan_number = int_msg2 + + # get PeakInfo + peak_info = self._myControl.get_peak_info(exp_number, scan_number) + assert isinstance(peak_info, r4c.PeakProcessHelper) + + # retrieve and set HKL from spice table + peak_info.retrieve_hkl_from_spice_table() + + # add to table + self.set_ub_peak_table(peak_info) + + return -- GitLab