diff --git a/Framework/API/inc/MantidAPI/DataProcessorAlgorithm.h b/Framework/API/inc/MantidAPI/DataProcessorAlgorithm.h index 567f75e9289464d928f0527f9f034246fdb01473..47b296679e03914a5995f59be180369bd105bd6b 100644 --- a/Framework/API/inc/MantidAPI/DataProcessorAlgorithm.h +++ b/Framework/API/inc/MantidAPI/DataProcessorAlgorithm.h @@ -4,8 +4,11 @@ #include "MantidKernel/System.h" #include "MantidAPI/Algorithm.h" #include "MantidAPI/AlgorithmManager.h" -#include "MantidAPI/ITableWorkspace_fwd.h" +#include "MantidAPI/DistributedAlgorithm.h" #include "MantidAPI/IEventWorkspace_fwd.h" +#include "MantidAPI/ITableWorkspace_fwd.h" +#include "MantidAPI/ParallelAlgorithm.h" +#include "MantidAPI/SerialAlgorithm.h" #include "MantidKernel/PropertyManager.h" #include <vector> @@ -39,11 +42,13 @@ namespace API { File change history is stored at: <https://github.com/mantidproject/mantid> Code Documentation is available at: <http://doxygen.mantidproject.org> */ -class DLLExport DataProcessorAlgorithm : public Algorithm { +template <class Base> +class DLLExport GenericDataProcessorAlgorithm : public Base { public: - DataProcessorAlgorithm(); + GenericDataProcessorAlgorithm(); std::string getPropertyValue(const std::string &name) const override; - TypedValue getProperty(const std::string &name) const override; + Kernel::PropertyManagerOwner::TypedValue + getProperty(const std::string &name) const override; protected: boost::shared_ptr<Algorithm> createChildAlgorithm( @@ -110,8 +115,8 @@ private: auto alg = createChildAlgorithm(algorithmName); alg->initialize(); - alg->setProperty<LHSType>("LHSWorkspace", lhs); - alg->setProperty<RHSType>("RHSWorkspace", rhs); + alg->template setProperty<LHSType>("LHSWorkspace", lhs); + alg->template setProperty<RHSType>("RHSWorkspace", rhs); alg->execute(); if (alg->isExecuted()) { @@ -137,8 +142,28 @@ private: std::string m_propertyManagerPropertyName; /// Map property names to names in supplied properties manager std::map<std::string, std::string> m_nameToPMName; + + // This method is a workaround for the C4661 compiler warning in visual + // studio. This allows the template declaration and definition to be separated + // in different files. See stack overflow article for a more detailed + // explanation: + // https://stackoverflow.com/questions/44160467/warning-c4661no-suitable-definition-provided-for-explicit-template-instantiatio + // https://stackoverflow.com/questions/33517902/how-to-export-a-class-derived-from-an-explicitly-instantiated-template-in-visual + void visualStudioC4661Workaround(); }; +template <> +MANTID_API_DLL void +GenericDataProcessorAlgorithm<Algorithm>::visualStudioC4661Workaround(); + +using DataProcessorAlgorithm = GenericDataProcessorAlgorithm<Algorithm>; +using SerialDataProcessorAlgorithm = + GenericDataProcessorAlgorithm<SerialAlgorithm>; +using ParallelDataProcessorAlgorithm = + GenericDataProcessorAlgorithm<ParallelAlgorithm>; +using DistributedDataProcessorAlgorithm = + GenericDataProcessorAlgorithm<DistributedAlgorithm>; + } // namespace API } // namespace Mantid diff --git a/Framework/API/inc/MantidAPI/DistributedAlgorithm.h b/Framework/API/inc/MantidAPI/DistributedAlgorithm.h index 0dfebbf6ff55ec8f7468a32e4a507878c47f4f84..0d9351062e8857dea6815f15a953af76bc4a0f0d 100644 --- a/Framework/API/inc/MantidAPI/DistributedAlgorithm.h +++ b/Framework/API/inc/MantidAPI/DistributedAlgorithm.h @@ -16,7 +16,9 @@ namespace API { from DistributedAlgorithm instead of from Algorithm provides the necessary overriden method(s) to allow running an algorithm with MPI. This works under the following conditions: - 1. The algorithm must have a single input and a single output workspace. + 1. The algorithm must input workspaces with compatible storage modes. + StorageMode::Distributed is not compatible with StorageMode::MasterOnly, but + all combinations with StorageMode::Cloned are considered compatible. 2. No output files may be written since filenames would clash. Algorithms that do not modify spectra in a workspace may also use this base class to support MPI. For example, modifications of the instrument are handled diff --git a/Framework/API/inc/MantidAPI/WorkspaceGroup.h b/Framework/API/inc/MantidAPI/WorkspaceGroup.h index a3ab7f468295acfbb1d088c60a5971a547ed5b93..1235c04c8cf11e13f0834be867a981fd8b7cad36 100644 --- a/Framework/API/inc/MantidAPI/WorkspaceGroup.h +++ b/Framework/API/inc/MantidAPI/WorkspaceGroup.h @@ -53,7 +53,8 @@ class Algorithm; class MANTID_API_DLL WorkspaceGroup : public Workspace { public: /// Default constructor. - WorkspaceGroup(); + WorkspaceGroup( + const Parallel::StorageMode storageMode = Parallel::StorageMode::Cloned); /// Destructor ~WorkspaceGroup() override; /// Return a string ID of the class diff --git a/Framework/API/src/Algorithm.cpp b/Framework/API/src/Algorithm.cpp index 3a466777a55a2e32a1fd705294a053bd05b29acb..0e4c36bb38e985db7b7bace28b978784ea5bcd1f 100644 --- a/Framework/API/src/Algorithm.cpp +++ b/Framework/API/src/Algorithm.cpp @@ -502,10 +502,15 @@ bool Algorithm::execute() { return false; } + const auto executionMode = getExecutionMode(); + timingInit += timer.elapsed(resetTimer); // ----- Perform validation of the whole set of properties ------------- - if (!callProcessGroups) // for groups this is called on each workspace - // separately + if ((!callProcessGroups) && + (executionMode != Parallel::ExecutionMode::MasterOnly || + communicator().rank() == + 0)) // for groups this is called on each workspace + // separately { std::map<std::string, std::string> errors = this->validateInputs(); if (!errors.empty()) { @@ -566,7 +571,7 @@ bool Algorithm::execute() { startTime = Mantid::Types::Core::DateAndTime::getCurrentTime(); // Call the concrete algorithm's exec method - this->exec(getExecutionMode()); + this->exec(executionMode); registerFeatureUsage(); // Check for a cancellation request in case the concrete algorithm doesn't interruption_point(); @@ -1773,6 +1778,9 @@ Parallel::ExecutionMode Algorithm::getExecutionMode() const { getLogger().error() << error << "\n"; throw(std::runtime_error(error)); } + getLogger().information() << "MPI Rank " << communicator().rank() + << " running with " + << Parallel::toString(executionMode) << '\n'; return executionMode; } @@ -1792,6 +1800,11 @@ Algorithm::getInputWorkspaceStorageModes() const { else if (!wsProp->isOptional()) map.emplace(prop.name(), Parallel::StorageMode::MasterOnly); } + getLogger().information() + << "Input workspaces for determining execution mode:\n"; + for (const auto &item : map) + getLogger().information() << " " << item.first << " --- " + << Parallel::toString(item.second) << '\n'; return map; } diff --git a/Framework/API/src/DataProcessorAlgorithm.cpp b/Framework/API/src/DataProcessorAlgorithm.cpp index 1e61e78ce112c5048be2eba7f2840447fa7e7f85..053676057f9525dcd205b10d434f08b409cac6c5 100644 --- a/Framework/API/src/DataProcessorAlgorithm.cpp +++ b/Framework/API/src/DataProcessorAlgorithm.cpp @@ -26,11 +26,12 @@ namespace API { //---------------------------------------------------------------------------------------------- /** Constructor */ -DataProcessorAlgorithm::DataProcessorAlgorithm() - : API::Algorithm(), m_useMPI(false), m_loadAlg("Load"), - m_accumulateAlg("Plus"), m_loadAlgFileProp("Filename"), +template <class Base> +GenericDataProcessorAlgorithm<Base>::GenericDataProcessorAlgorithm() + : m_useMPI(false), m_loadAlg("Load"), m_accumulateAlg("Plus"), + m_loadAlgFileProp("Filename"), m_propertyManagerPropertyName("ReductionProperties") { - enableHistoryRecordingForChild(true); + Base::enableHistoryRecordingForChild(true); } //--------------------------------------------------------------------------------------------- @@ -54,7 +55,9 @@ DataProcessorAlgorithm::DataProcessorAlgorithm() *default gives the latest version. * @return shared pointer to the newly created algorithm object */ -boost::shared_ptr<Algorithm> DataProcessorAlgorithm::createChildAlgorithm( +template <class Base> +boost::shared_ptr<Algorithm> +GenericDataProcessorAlgorithm<Base>::createChildAlgorithm( const std::string &name, const double startProgress, const double endProgress, const bool enableLogging, const int &version) { // call parent method to create the child algorithm @@ -63,18 +66,20 @@ boost::shared_ptr<Algorithm> DataProcessorAlgorithm::createChildAlgorithm( alg->enableHistoryRecordingForChild(this->isRecordingHistoryForChild()); if (this->isRecordingHistoryForChild()) { // pass pointer to the history object created in Algorithm to the child - alg->trackAlgorithmHistory(m_history); + alg->trackAlgorithmHistory(Base::m_history); } return alg; } -void DataProcessorAlgorithm::setLoadAlg(const std::string &alg) { +template <class Base> +void GenericDataProcessorAlgorithm<Base>::setLoadAlg(const std::string &alg) { if (alg.empty()) throw std::invalid_argument("Cannot set load algorithm to empty string"); m_loadAlg = alg; } -void DataProcessorAlgorithm::setLoadAlgFileProp( +template <class Base> +void GenericDataProcessorAlgorithm<Base>::setLoadAlgFileProp( const std::string &filePropName) { if (filePropName.empty()) { throw std::invalid_argument( @@ -83,14 +88,16 @@ void DataProcessorAlgorithm::setLoadAlgFileProp( m_loadAlgFileProp = filePropName; } -void DataProcessorAlgorithm::setAccumAlg(const std::string &alg) { +template <class Base> +void GenericDataProcessorAlgorithm<Base>::setAccumAlg(const std::string &alg) { if (alg.empty()) throw std::invalid_argument( "Cannot set accumulate algorithm to empty string"); m_accumulateAlg = alg; } -void DataProcessorAlgorithm::setPropManagerPropName( +template <class Base> +void GenericDataProcessorAlgorithm<Base>::setPropManagerPropName( const std::string &propName) { m_propertyManagerPropertyName = propName; } @@ -103,7 +110,8 @@ void DataProcessorAlgorithm::setPropManagerPropName( * @param nameInProp Name of the property as declared in Algorithm::init(). * @param nameInPropManager Name of the property in the PropertyManager. */ -void DataProcessorAlgorithm::mapPropertyName( +template <class Base> +void GenericDataProcessorAlgorithm<Base>::mapPropertyName( const std::string &nameInProp, const std::string &nameInPropManager) { m_nameToPMName[nameInProp] = nameInPropManager; } @@ -119,8 +127,9 @@ void DataProcessorAlgorithm::mapPropertyName( * * @throws std::runtime_error If you ask to copy a non-existent property */ -void DataProcessorAlgorithm::copyProperty(API::Algorithm_sptr alg, - const std::string &name) { +template <class Base> +void GenericDataProcessorAlgorithm<Base>::copyProperty( + API::Algorithm_sptr alg, const std::string &name) { if (!alg->existsProperty(name)) { std::stringstream msg; msg << "Algorithm \"" << alg->name() << "\" does not have property \"" @@ -129,8 +138,8 @@ void DataProcessorAlgorithm::copyProperty(API::Algorithm_sptr alg, } auto prop = alg->getPointerToProperty(name); - declareProperty(std::unique_ptr<Property>(prop->clone()), - prop->documentation()); + Base::declareProperty(std::unique_ptr<Property>(prop->clone()), + prop->documentation()); } /** @@ -141,10 +150,11 @@ void DataProcessorAlgorithm::copyProperty(API::Algorithm_sptr alg, * @param name * @return */ -std::string -DataProcessorAlgorithm::getPropertyValue(const std::string &name) const { +template <class Base> +std::string GenericDataProcessorAlgorithm<Base>::getPropertyValue( + const std::string &name) const { // explicitly specifying a property wins - if (!isDefault(name)) { + if (!Base::isDefault(name)) { return Algorithm::getPropertyValue(name); } @@ -168,11 +178,13 @@ DataProcessorAlgorithm::getPropertyValue(const std::string &name) const { * @param name * @return */ +template <class Base> PropertyManagerOwner::TypedValue -DataProcessorAlgorithm::getProperty(const std::string &name) const { +GenericDataProcessorAlgorithm<Base>::getProperty( + const std::string &name) const { // explicitely specifying a property wins - if (!isDefault(name)) { - return Algorithm::getProperty(name); + if (!Base::isDefault(name)) { + return Base::getProperty(name); } // return it if it is in the held property manager @@ -188,15 +200,18 @@ DataProcessorAlgorithm::getProperty(const std::string &name) const { return Algorithm::getProperty(name); } -ITableWorkspace_sptr -DataProcessorAlgorithm::determineChunk(const std::string &filename) { +template <class Base> +ITableWorkspace_sptr GenericDataProcessorAlgorithm<Base>::determineChunk( + const std::string &filename) { UNUSED_ARG(filename); throw std::runtime_error( "DataProcessorAlgorithm::determineChunk is not implemented"); } -MatrixWorkspace_sptr DataProcessorAlgorithm::loadChunk(const size_t rowIndex) { +template <class Base> +MatrixWorkspace_sptr +GenericDataProcessorAlgorithm<Base>::loadChunk(const size_t rowIndex) { UNUSED_ARG(rowIndex); throw std::runtime_error( @@ -208,7 +223,9 @@ MatrixWorkspace_sptr DataProcessorAlgorithm::loadChunk(const size_t rowIndex) { * @param partialWS :: workspace to assemble * thread only) */ -Workspace_sptr DataProcessorAlgorithm::assemble(Workspace_sptr partialWS) { +template <class Base> +Workspace_sptr +GenericDataProcessorAlgorithm<Base>::assemble(Workspace_sptr partialWS) { Workspace_sptr outputWS = partialWS; #ifdef MPI_BUILD IAlgorithm_sptr gatherAlg = createChildAlgorithm("GatherWorkspaces"); @@ -233,9 +250,10 @@ Workspace_sptr DataProcessorAlgorithm::assemble(Workspace_sptr partialWS) { * @param outputWSName :: Name of the assembled workspace (available in main * thread only) */ +template <class Base> Workspace_sptr -DataProcessorAlgorithm::assemble(const std::string &partialWSName, - const std::string &outputWSName) { +GenericDataProcessorAlgorithm<Base>::assemble(const std::string &partialWSName, + const std::string &outputWSName) { #ifdef MPI_BUILD std::string threadOutput = partialWSName; Workspace_sptr partialWS = @@ -266,8 +284,9 @@ DataProcessorAlgorithm::assemble(const std::string &partialWSName, * @param outputWSName :: Name of the workspace to save * @param outputFile :: Path to the Nexus file to save */ -void DataProcessorAlgorithm::saveNexus(const std::string &outputWSName, - const std::string &outputFile) { +template <class Base> +void GenericDataProcessorAlgorithm<Base>::saveNexus( + const std::string &outputWSName, const std::string &outputFile) { bool saveOutput = true; #ifdef MPI_BUILD if (boost::mpi::communicator().rank() > 0) @@ -283,7 +302,7 @@ void DataProcessorAlgorithm::saveNexus(const std::string &outputWSName, } /// Return true if we are running on the main thread -bool DataProcessorAlgorithm::isMainThread() { +template <class Base> bool GenericDataProcessorAlgorithm<Base>::isMainThread() { bool mainThread; #ifdef MPI_BUILD mainThread = (boost::mpi::communicator().rank() == 0); @@ -294,7 +313,7 @@ bool DataProcessorAlgorithm::isMainThread() { } /// Return the number of MPI processes running -int DataProcessorAlgorithm::getNThreads() { +template <class Base> int GenericDataProcessorAlgorithm<Base>::getNThreads() { #ifdef MPI_BUILD return boost::mpi::communicator().size(); #else @@ -307,8 +326,10 @@ int DataProcessorAlgorithm::getNThreads() { * @param inputData :: File path or workspace name * @param loadQuiet :: If true then the output is not stored in the ADS */ -Workspace_sptr DataProcessorAlgorithm::load(const std::string &inputData, - const bool loadQuiet) { +template <class Base> +Workspace_sptr +GenericDataProcessorAlgorithm<Base>::load(const std::string &inputData, + const bool loadQuiet) { Workspace_sptr inputWS; // First, check whether we have the name of an existing workspace @@ -370,11 +391,13 @@ Workspace_sptr DataProcessorAlgorithm::load(const std::string &inputData, * * @param propertyManager :: Name of the property manager to retrieve. */ -boost::shared_ptr<PropertyManager> DataProcessorAlgorithm::getProcessProperties( +template <class Base> +boost::shared_ptr<PropertyManager> +GenericDataProcessorAlgorithm<Base>::getProcessProperties( const std::string &propertyManager) const { std::string propertyManagerName(propertyManager); if (propertyManager.empty() && (!m_propertyManagerPropertyName.empty())) { - if (!existsProperty(m_propertyManagerPropertyName)) { + if (!Base::existsProperty(m_propertyManagerPropertyName)) { std::stringstream msg; msg << "Failed to find property \"" << m_propertyManagerPropertyName << "\""; @@ -388,7 +411,7 @@ boost::shared_ptr<PropertyManager> DataProcessorAlgorithm::getProcessProperties( processProperties = PropertyManagerDataService::Instance().retrieve(propertyManagerName); } else { - getLogger().notice() << "Could not find property manager\n"; + Base::getLogger().notice() << "Could not find property manager\n"; processProperties = boost::make_shared<PropertyManager>(); PropertyManagerDataService::Instance().addOrReplace(propertyManagerName, processProperties); @@ -396,14 +419,16 @@ boost::shared_ptr<PropertyManager> DataProcessorAlgorithm::getProcessProperties( return processProperties; } +template <class Base> std::vector<std::string> -DataProcessorAlgorithm::splitInput(const std::string &input) { +GenericDataProcessorAlgorithm<Base>::splitInput(const std::string &input) { UNUSED_ARG(input); throw std::runtime_error( "DataProcessorAlgorithm::splitInput is not implemented"); } -void DataProcessorAlgorithm::forwardProperties() { +template <class Base> +void GenericDataProcessorAlgorithm<Base>::forwardProperties() { throw std::runtime_error( "DataProcessorAlgorithm::forwardProperties is not implemented"); } @@ -418,9 +443,10 @@ void DataProcessorAlgorithm::forwardProperties() { * @param rhs :: the workspace on the right hand side of the divide symbol * @return matrix workspace resulting from the operation */ +template <class Base> MatrixWorkspace_sptr -DataProcessorAlgorithm::divide(const MatrixWorkspace_sptr lhs, - const MatrixWorkspace_sptr rhs) { +GenericDataProcessorAlgorithm<Base>::divide(const MatrixWorkspace_sptr lhs, + const MatrixWorkspace_sptr rhs) { return this->executeBinaryAlgorithm< MatrixWorkspace_sptr, MatrixWorkspace_sptr, MatrixWorkspace_sptr>( "Divide", lhs, rhs); @@ -432,9 +458,10 @@ DataProcessorAlgorithm::divide(const MatrixWorkspace_sptr lhs, * @param rhsValue :: the value on the right hand side of the divide symbol * @return matrix workspace resulting from the operation */ +template <class Base> MatrixWorkspace_sptr -DataProcessorAlgorithm::divide(const MatrixWorkspace_sptr lhs, - const double &rhsValue) { +GenericDataProcessorAlgorithm<Base>::divide(const MatrixWorkspace_sptr lhs, + const double &rhsValue) { return this->executeBinaryAlgorithm< MatrixWorkspace_sptr, MatrixWorkspace_sptr, MatrixWorkspace_sptr>( "Divide", lhs, createWorkspaceSingleValue(rhsValue)); @@ -448,9 +475,10 @@ DataProcessorAlgorithm::divide(const MatrixWorkspace_sptr lhs, * symbol * @return matrix workspace resulting from the operation */ +template <class Base> MatrixWorkspace_sptr -DataProcessorAlgorithm::multiply(const MatrixWorkspace_sptr lhs, - const MatrixWorkspace_sptr rhs) { +GenericDataProcessorAlgorithm<Base>::multiply(const MatrixWorkspace_sptr lhs, + const MatrixWorkspace_sptr rhs) { return this->executeBinaryAlgorithm< MatrixWorkspace_sptr, MatrixWorkspace_sptr, MatrixWorkspace_sptr>( "Divide", lhs, rhs); @@ -464,9 +492,10 @@ DataProcessorAlgorithm::multiply(const MatrixWorkspace_sptr lhs, * symbol * @return matrix workspace resulting from the operation */ +template <class Base> MatrixWorkspace_sptr -DataProcessorAlgorithm::multiply(const MatrixWorkspace_sptr lhs, - const double &rhsValue) { +GenericDataProcessorAlgorithm<Base>::multiply(const MatrixWorkspace_sptr lhs, + const double &rhsValue) { return this->executeBinaryAlgorithm< MatrixWorkspace_sptr, MatrixWorkspace_sptr, MatrixWorkspace_sptr>( "Multiply", lhs, createWorkspaceSingleValue(rhsValue)); @@ -478,9 +507,10 @@ DataProcessorAlgorithm::multiply(const MatrixWorkspace_sptr lhs, * @param rhs :: the workspace on the right hand side of the addition symbol * @return matrix workspace resulting from the operation */ +template <class Base> MatrixWorkspace_sptr -DataProcessorAlgorithm::plus(const MatrixWorkspace_sptr lhs, - const MatrixWorkspace_sptr rhs) { +GenericDataProcessorAlgorithm<Base>::plus(const MatrixWorkspace_sptr lhs, + const MatrixWorkspace_sptr rhs) { return this->executeBinaryAlgorithm< MatrixWorkspace_sptr, MatrixWorkspace_sptr, MatrixWorkspace_sptr>( "Plus", lhs, rhs); @@ -492,9 +522,10 @@ DataProcessorAlgorithm::plus(const MatrixWorkspace_sptr lhs, * @param rhsValue :: the value on the right hand side of the addition symbol * @return matrix workspace resulting from the operation */ +template <class Base> MatrixWorkspace_sptr -DataProcessorAlgorithm::plus(const MatrixWorkspace_sptr lhs, - const double &rhsValue) { +GenericDataProcessorAlgorithm<Base>::plus(const MatrixWorkspace_sptr lhs, + const double &rhsValue) { return this->executeBinaryAlgorithm< MatrixWorkspace_sptr, MatrixWorkspace_sptr, MatrixWorkspace_sptr>( "Plus", lhs, createWorkspaceSingleValue(rhsValue)); @@ -506,9 +537,10 @@ DataProcessorAlgorithm::plus(const MatrixWorkspace_sptr lhs, * @param rhs :: the workspace on the right hand side of the subtraction symbol * @return matrix workspace resulting from the operation */ +template <class Base> MatrixWorkspace_sptr -DataProcessorAlgorithm::minus(const MatrixWorkspace_sptr lhs, - const MatrixWorkspace_sptr rhs) { +GenericDataProcessorAlgorithm<Base>::minus(const MatrixWorkspace_sptr lhs, + const MatrixWorkspace_sptr rhs) { return this->executeBinaryAlgorithm< MatrixWorkspace_sptr, MatrixWorkspace_sptr, MatrixWorkspace_sptr>( "Minus", lhs, rhs); @@ -521,9 +553,10 @@ DataProcessorAlgorithm::minus(const MatrixWorkspace_sptr lhs, * symbol * @return matrix workspace resulting from the operation */ +template <class Base> MatrixWorkspace_sptr -DataProcessorAlgorithm::minus(const MatrixWorkspace_sptr lhs, - const double &rhsValue) { +GenericDataProcessorAlgorithm<Base>::minus(const MatrixWorkspace_sptr lhs, + const double &rhsValue) { return this->executeBinaryAlgorithm< MatrixWorkspace_sptr, MatrixWorkspace_sptr, MatrixWorkspace_sptr>( "Minus", lhs, createWorkspaceSingleValue(rhsValue)); @@ -534,8 +567,10 @@ DataProcessorAlgorithm::minus(const MatrixWorkspace_sptr lhs, * @param rhsValue :: the value to convert to a single value matrix workspace * @return matrix workspace resulting from the operation */ +template <class Base> MatrixWorkspace_sptr -DataProcessorAlgorithm::createWorkspaceSingleValue(const double &rhsValue) { +GenericDataProcessorAlgorithm<Base>::createWorkspaceSingleValue( + const double &rhsValue) { MatrixWorkspace_sptr retVal = WorkspaceFactory::Instance().create("WorkspaceSingleValue", 1, 1, 1); retVal->dataY(0)[0] = rhsValue; @@ -543,5 +578,18 @@ DataProcessorAlgorithm::createWorkspaceSingleValue(const double &rhsValue) { return retVal; } +template <typename T> +void GenericDataProcessorAlgorithm<T>::visualStudioC4661Workaround() {} + +template class GenericDataProcessorAlgorithm<Algorithm>; +template class MANTID_API_DLL GenericDataProcessorAlgorithm<SerialAlgorithm>; +template class MANTID_API_DLL GenericDataProcessorAlgorithm<ParallelAlgorithm>; +template class MANTID_API_DLL + GenericDataProcessorAlgorithm<DistributedAlgorithm>; + +template <> +MANTID_API_DLL void +GenericDataProcessorAlgorithm<Algorithm>::visualStudioC4661Workaround() {} + } // namespace Mantid } // namespace API diff --git a/Framework/API/src/DistributedAlgorithm.cpp b/Framework/API/src/DistributedAlgorithm.cpp index a9c0703e463f1c51675b4eaa9ff69fd724a2bf1c..69688b55ac7d9264b477766bb02b35b2bcf62782 100644 --- a/Framework/API/src/DistributedAlgorithm.cpp +++ b/Framework/API/src/DistributedAlgorithm.cpp @@ -1,11 +1,33 @@ #include "MantidAPI/DistributedAlgorithm.h" +#include <algorithm> + namespace Mantid { namespace API { Parallel::ExecutionMode DistributedAlgorithm::getParallelExecutionMode( const std::map<std::string, Parallel::StorageMode> &storageModes) const { - return Parallel::getCorrespondingExecutionMode(storageModes.begin()->second); + using namespace Parallel; + if (std::any_of( + storageModes.begin(), storageModes.end(), + [](const std::pair<std::string, Parallel::StorageMode> &item) { + return item.second == StorageMode::Distributed; + })) { + if (std::any_of( + storageModes.begin(), storageModes.end(), + [](const std::pair<std::string, Parallel::StorageMode> &item) { + return item.second == StorageMode::MasterOnly; + })) + return ExecutionMode::Invalid; + return ExecutionMode::Distributed; + } + if (std::any_of( + storageModes.begin(), storageModes.end(), + [](const std::pair<std::string, Parallel::StorageMode> &item) { + return item.second == StorageMode::MasterOnly; + })) + return ExecutionMode::MasterOnly; + return ExecutionMode::Identical; } } // namespace API diff --git a/Framework/API/src/WorkspaceGroup.cpp b/Framework/API/src/WorkspaceGroup.cpp index 1fe9323e23858b64485d49e2279951071149dde6..172d62382ad26aa4fa325c8a76ff3561f6141e50 100644 --- a/Framework/API/src/WorkspaceGroup.cpp +++ b/Framework/API/src/WorkspaceGroup.cpp @@ -15,8 +15,8 @@ size_t MAXIMUM_DEPTH = 100; Kernel::Logger g_log("WorkspaceGroup"); } -WorkspaceGroup::WorkspaceGroup() - : Workspace(), +WorkspaceGroup::WorkspaceGroup(const Parallel::StorageMode storageMode) + : Workspace(storageMode), m_deleteObserver(*this, &WorkspaceGroup::workspaceDeleteHandle), m_beforeReplaceObserver(*this, &WorkspaceGroup::workspaceBeforeReplaceHandle), diff --git a/Framework/Algorithms/CMakeLists.txt b/Framework/Algorithms/CMakeLists.txt index 8cffdf1cb499559851ec004d9e8ba9cadf15248b..39fcebb6676aaa9c84544e4d9c50bb80cbac5bc9 100644 --- a/Framework/Algorithms/CMakeLists.txt +++ b/Framework/Algorithms/CMakeLists.txt @@ -42,6 +42,7 @@ set ( SRC_FILES src/ClearCache.cpp src/ClearInstrumentParameters.cpp src/ClearMaskFlag.cpp + src/ClearMaskedSpectra.cpp src/CloneWorkspace.cpp src/Comment.cpp src/CommutativeBinaryOperation.cpp @@ -176,6 +177,7 @@ set ( SRC_FILES src/MaskBins.cpp src/MaskBinsFromTable.cpp src/MaskDetectorsIf.cpp + src/MaskInstrument.cpp src/MatrixWorkspaceAccess.cpp src/Max.cpp src/MaxEnt.cpp @@ -372,6 +374,7 @@ set ( INC_FILES inc/MantidAlgorithms/ClearCache.h inc/MantidAlgorithms/ClearInstrumentParameters.h inc/MantidAlgorithms/ClearMaskFlag.h + inc/MantidAlgorithms/ClearMaskedSpectra.h inc/MantidAlgorithms/CloneWorkspace.h inc/MantidAlgorithms/Comment.h inc/MantidAlgorithms/CommutativeBinaryOperation.h @@ -507,6 +510,7 @@ set ( INC_FILES inc/MantidAlgorithms/MaskBins.h inc/MantidAlgorithms/MaskBinsFromTable.h inc/MantidAlgorithms/MaskDetectorsIf.h + inc/MantidAlgorithms/MaskInstrument.h inc/MantidAlgorithms/MatrixWorkspaceAccess.h inc/MantidAlgorithms/Max.h inc/MantidAlgorithms/MaxEnt.h @@ -718,6 +722,7 @@ set ( TEST_FILES ClearCacheTest.h ClearInstrumentParametersTest.h ClearMaskFlagTest.h + ClearMaskedSpectraTest.h CloneWorkspaceTest.h CommentTest.h CommutativeBinaryOperationTest.h @@ -849,6 +854,7 @@ set ( TEST_FILES MaskBinsFromTableTest.h MaskBinsTest.h MaskDetectorsIfTest.h + MaskInstrumentTest.h MaxEnt/MaxentCalculatorTest.h MaxEnt/MaxentEntropyNegativeValuesTest.h MaxEnt/MaxentEntropyPositiveValuesTest.h diff --git a/Framework/Algorithms/inc/MantidAlgorithms/ClearMaskedSpectra.h b/Framework/Algorithms/inc/MantidAlgorithms/ClearMaskedSpectra.h new file mode 100644 index 0000000000000000000000000000000000000000..fa27e65da2241cd37e2829ac752ddadb2cd43e28 --- /dev/null +++ b/Framework/Algorithms/inc/MantidAlgorithms/ClearMaskedSpectra.h @@ -0,0 +1,54 @@ +#ifndef MANTID_ALGORITHMS_CLEARMASKEDSPECTRA_H_ +#define MANTID_ALGORITHMS_CLEARMASKEDSPECTRA_H_ + +#include "MantidAlgorithms/DllConfig.h" +#include "MantidAPI/DistributedAlgorithm.h" + +namespace Mantid { +namespace Algorithms { + +/** Clear counts (or events, if applicable) on all spectra that are fully + masked. A spectrum is fully masked if all of its associated detectors are + masked, e.g., from a call to `MaskInstrument`. + + @author Simon Heybrock + @date 2017 + + Copyright © 2017 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 ClearMaskedSpectra + : public API::DistributedAlgorithm { +public: + const std::string name() const override; + int version() const override; + const std::string category() const override; + const std::string summary() const override; + +private: + void init() override; + void exec() override; +}; + +} // namespace Algorithms +} // namespace Mantid + +#endif /* MANTID_ALGORITHMS_CLEARMASKEDSPECTRA_H_ */ diff --git a/Framework/Algorithms/inc/MantidAlgorithms/Comment.h b/Framework/Algorithms/inc/MantidAlgorithms/Comment.h index 5d3db76cf3f7cab8e444c7d00d710a9bf4038405..6db408913c375d7497e58e41431b4180075ab000 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/Comment.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/Comment.h @@ -2,7 +2,7 @@ #define MANTID_ALGORITHMS_COMMENT_H_ #include "MantidAlgorithms/DllConfig.h" -#include "MantidAPI/Algorithm.h" +#include "MantidAPI/DistributedAlgorithm.h" namespace Mantid { namespace Algorithms { @@ -29,7 +29,7 @@ namespace Algorithms { File change history is stored at: <https://github.com/mantidproject/mantid> Code Documentation is available at: <http://doxygen.mantidproject.org> */ -class DLLExport Comment : public API::Algorithm { +class DLLExport Comment : public API::DistributedAlgorithm { public: const std::string name() const override; int version() const override; diff --git a/Framework/Algorithms/inc/MantidAlgorithms/CompareWorkspaces.h b/Framework/Algorithms/inc/MantidAlgorithms/CompareWorkspaces.h index daaf7336892038d73107117f7d3af41deb170039..88b4ec69a721b78b49cb1bca33d67ba1e1acd7f8 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/CompareWorkspaces.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/CompareWorkspaces.h @@ -91,6 +91,7 @@ protected: Parallel::ExecutionMode getParallelExecutionMode( const std::map<std::string, Parallel::StorageMode> &storageModes) const override; + void execMasterOnly() override; private: /// Initialise algorithm diff --git a/Framework/Algorithms/inc/MantidAlgorithms/CopyInstrumentParameters.h b/Framework/Algorithms/inc/MantidAlgorithms/CopyInstrumentParameters.h index 474dafe097435597ab160d355d12e344d64b1530..5740e3cae41ea0a185d546a855f46748172558e0 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/CopyInstrumentParameters.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/CopyInstrumentParameters.h @@ -75,6 +75,11 @@ public: /// base target instrument (mainly used in testing) bool isInstrumentDifferent() const { return m_different_instrument_sp; } +protected: + Parallel::ExecutionMode getParallelExecutionMode( + const std::map<std::string, Parallel::StorageMode> &storageModes) + const override; + private: /// Initialisation code void init() override; diff --git a/Framework/Algorithms/inc/MantidAlgorithms/DeleteWorkspace.h b/Framework/Algorithms/inc/MantidAlgorithms/DeleteWorkspace.h index 91890dbf8d5a8ad29a99e245cbc6ef3074a51815..045f2df92cbd500891068a2589dfe8a70fff2797 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/DeleteWorkspace.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/DeleteWorkspace.h @@ -1,10 +1,7 @@ #ifndef MANTID_ALGORITHMS_DELETEWORKSPACE_H_ #define MANTID_ALGORITHMS_DELETEWORKSPACE_H_ -//---------------------------------------------------------------------- -// Includes -//---------------------------------------------------------------------- -#include "MantidAPI/Algorithm.h" +#include "MantidAPI/DistributedAlgorithm.h" namespace Mantid { namespace Algorithms { @@ -37,7 +34,7 @@ namespace Algorithms { File change history is stored at: <https://github.com/mantidproject/mantid> Code Documentation is available at: <http://doxygen.mantidproject.org> */ -class DLLExport DeleteWorkspace : public API::Algorithm { +class DLLExport DeleteWorkspace : public API::DistributedAlgorithm { public: /// Algorithm's name const std::string name() const override { return "DeleteWorkspace"; } diff --git a/Framework/Algorithms/inc/MantidAlgorithms/GroupWorkspaces.h b/Framework/Algorithms/inc/MantidAlgorithms/GroupWorkspaces.h index 1b50e2ba57f8ba0146bbd4bdb543b14a132375c0..97a25bb314f68d4ae5767296cf0052384e957aff 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/GroupWorkspaces.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/GroupWorkspaces.h @@ -1,7 +1,7 @@ #ifndef MANTID_ALGORITHM_GROUP_H_ #define MANTID_ALGORITHM_GROUP_H_ -#include "MantidAPI/DistributedAlgorithm.h" +#include "MantidAPI/Algorithm.h" #include "MantidKernel/ArrayProperty.h" #include "MantidAPI/WorkspaceProperty.h" #include "MantidAPI/WorkspaceGroup_fwd.h" @@ -38,7 +38,7 @@ 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 DLLExport GroupWorkspaces : public API::DistributedAlgorithm { +class DLLExport GroupWorkspaces : public API::Algorithm { public: /// Algorithm's name for identification overriding a virtual method const std::string name() const override { return "GroupWorkspaces"; } @@ -54,6 +54,11 @@ public: return "Transforms\\Grouping;Utility\\Workspaces"; } +protected: + Parallel::ExecutionMode getParallelExecutionMode( + const std::map<std::string, Parallel::StorageMode> &storageModes) + const override; + private: /// Overridden Init method void init() override; diff --git a/Framework/Algorithms/inc/MantidAlgorithms/MaskInstrument.h b/Framework/Algorithms/inc/MantidAlgorithms/MaskInstrument.h new file mode 100644 index 0000000000000000000000000000000000000000..ef6837232280d79e99b2ce84335c6890cc1aecdb --- /dev/null +++ b/Framework/Algorithms/inc/MantidAlgorithms/MaskInstrument.h @@ -0,0 +1,53 @@ +#ifndef MANTID_ALGORITHMS_MASKINSTRUMENT_H_ +#define MANTID_ALGORITHMS_MASKINSTRUMENT_H_ + +#include "MantidAlgorithms/DllConfig.h" +#include "MantidAPI/DistributedAlgorithm.h" + +namespace Mantid { +namespace Algorithms { + +/** Mask specified detectors in an instrument. This is does NOT clear the data + in associated spectra in the workspace. To clear the data manually + `ClearMaskedSpectra` can be called. + + @author Simon Heybrock + @date 2017 + + Copyright © 2017 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 MaskInstrument : public API::DistributedAlgorithm { +public: + const std::string name() const override; + int version() const override; + const std::string category() const override; + const std::string summary() const override; + +private: + void init() override; + void exec() override; +}; + +} // namespace Algorithms +} // namespace Mantid + +#endif /* MANTID_ALGORITHMS_MASKINSTRUMENT_H_ */ diff --git a/Framework/Algorithms/inc/MantidAlgorithms/Q1D2.h b/Framework/Algorithms/inc/MantidAlgorithms/Q1D2.h index 06e40f7c178e16d8bc324137eb5b1e5b589c24fc..e0779024764f9147a15978c86755ba7033597e43 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/Q1D2.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/Q1D2.h @@ -55,6 +55,11 @@ public: /// Algorithm's category for identification const std::string category() const override { return "SANS"; } +protected: + Parallel::ExecutionMode getParallelExecutionMode( + const std::map<std::string, Parallel::StorageMode> &storageModes) + const override; + private: /// the experimental workspace with counts across the detector API::MatrixWorkspace_const_sptr m_dataWS; diff --git a/Framework/Algorithms/inc/MantidAlgorithms/Scale.h b/Framework/Algorithms/inc/MantidAlgorithms/Scale.h index 6ba8290a7106ca0c1bea18fd137f78d879c5639b..5c451b14fcb7b6895775c1e3e2c7f039f50c2ce8 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/Scale.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/Scale.h @@ -1,10 +1,7 @@ #ifndef MANTID_ALGORITHMS_SCALE_H_ #define MANTID_ALGORITHMS_SCALE_H_ -//---------------------------------------------------------------------- -// Includes -//---------------------------------------------------------------------- -#include "MantidAPI/Algorithm.h" +#include "MantidAPI/DistributedAlgorithm.h" namespace Mantid { namespace Algorithms { @@ -46,7 +43,7 @@ namespace Algorithms { File change history is stored at: <https://github.com/mantidproject/mantid> Code Documentation is available at: <http://doxygen.mantidproject.org> */ -class DLLExport Scale : public API::Algorithm { +class DLLExport Scale : public API::DistributedAlgorithm { public: /// Algorithm's name const std::string name() const override { return "Scale"; } diff --git a/Framework/Algorithms/src/ClearMaskedSpectra.cpp b/Framework/Algorithms/src/ClearMaskedSpectra.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0815099a4ff6a863a4156712a75d32e36ad9eb96 --- /dev/null +++ b/Framework/Algorithms/src/ClearMaskedSpectra.cpp @@ -0,0 +1,60 @@ +#include "MantidDataObjects/EventWorkspace.h" +#include "MantidAlgorithms/ClearMaskedSpectra.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidAPI/SpectrumInfo.h" + +using namespace Mantid::Kernel; +using namespace Mantid::API; + +namespace Mantid { +namespace Algorithms { + +// Register the algorithm into the AlgorithmFactory +DECLARE_ALGORITHM(ClearMaskedSpectra) + +/// Algorithms name for identification. @see Algorithm::name +const std::string ClearMaskedSpectra::name() const { + return "ClearMaskedSpectra"; +} + +/// Algorithm's version for identification. @see Algorithm::version +int ClearMaskedSpectra::version() const { return 1; } + +/// Algorithm's category for identification. @see Algorithm::category +const std::string ClearMaskedSpectra::category() const { + return "Transforms\\Masking"; +} + +/// Algorithm's summary for use in the GUI and help. @see Algorithm::summary +const std::string ClearMaskedSpectra::summary() const { + return "Clear counts and/or events in all fully masked spectra."; +} + +void ClearMaskedSpectra::init() { + declareProperty(Kernel::make_unique<WorkspaceProperty<>>( + "InputWorkspace", "The input workspace", Direction::Input)); + declareProperty( + Kernel::make_unique<WorkspaceProperty<>>("OutputWorkspace", "", + Direction::Output), + "Name of the output workspace (can be same as InputWorkspace)"); +} + +void ClearMaskedSpectra::exec() { + MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace"); + MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace"); + if (outputWS != inputWS) { + outputWS = inputWS->clone(); + setProperty("OutputWorkspace", outputWS); + } + + const auto &spectrumInfo = outputWS->spectrumInfo(); + for (size_t i = 0; i < spectrumInfo.size(); ++i) + if (spectrumInfo.hasDetectors(i) && spectrumInfo.isMasked(i)) + outputWS->getSpectrum(i).clearData(); + + if (auto event = dynamic_cast<DataObjects::EventWorkspace *>(outputWS.get())) + event->clearMRU(); +} + +} // namespace Algorithms +} // namespace Mantid diff --git a/Framework/Algorithms/src/CompareWorkspaces.cpp b/Framework/Algorithms/src/CompareWorkspaces.cpp index f2c93adde18bbdcbc656edbe271cb31e0064f776..5724a852f34bbdbd698a9f73e863f23059a8ed7f 100644 --- a/Framework/Algorithms/src/CompareWorkspaces.cpp +++ b/Framework/Algorithms/src/CompareWorkspaces.cpp @@ -15,6 +15,7 @@ #include "MantidDataObjects/TableWorkspace.h" #include "MantidGeometry/Crystal/IPeak.h" #include "MantidKernel/Unit.h" +#include "MantidParallel/Communicator.h" namespace Mantid { namespace Algorithms { @@ -1196,5 +1197,12 @@ Parallel::ExecutionMode CompareWorkspaces::getParallelExecutionMode( return ExecutionMode::Invalid; } +void CompareWorkspaces::execMasterOnly() { + if (communicator().rank() == 0) + exec(); + else + setProperty("Result", true); +} + } // namespace Algorithms } // namespace Mantid diff --git a/Framework/Algorithms/src/CopyInstrumentParameters.cpp b/Framework/Algorithms/src/CopyInstrumentParameters.cpp index 132f59f235eeac250883fd767e48ad467dbd60ce..5ed2d53818cf6a85e35278caf4a2ffad8d5d55c7 100644 --- a/Framework/Algorithms/src/CopyInstrumentParameters.cpp +++ b/Framework/Algorithms/src/CopyInstrumentParameters.cpp @@ -135,5 +135,16 @@ void CopyInstrumentParameters::checkProperties() { } } +Parallel::ExecutionMode CopyInstrumentParameters::getParallelExecutionMode( + const std::map<std::string, Parallel::StorageMode> &storageModes) const { + const auto in = storageModes.at("InputWorkspace"); + const auto out = storageModes.at("InputWorkspace"); + // Source instrument avaible only on master rank, so copying not possible if + // target requires it on non-master ranks. + if (in == Parallel::StorageMode::MasterOnly && in != out) + return Parallel::ExecutionMode::Invalid; + return Parallel::getCorrespondingExecutionMode(out); +} + } // namespace Algorithms } // namespace Mantid diff --git a/Framework/Algorithms/src/GroupWorkspaces.cpp b/Framework/Algorithms/src/GroupWorkspaces.cpp index ed871ee002469922bdba86cbc9aeac3ac3ad8a3d..6d6f839880f4223a57c6e767e1c905a755f39781 100644 --- a/Framework/Algorithms/src/GroupWorkspaces.cpp +++ b/Framework/Algorithms/src/GroupWorkspaces.cpp @@ -3,6 +3,7 @@ #include "MantidAPI/AnalysisDataService.h" #include "MantidAPI/WorkspaceGroup.h" #include "MantidKernel/ArrayProperty.h" +#include "MantidParallel/Communicator.h" namespace Mantid { namespace Algorithms { @@ -31,7 +32,8 @@ void GroupWorkspaces::exec() { const std::vector<std::string> inputWorkspaces = getProperty("InputWorkspaces"); - m_group = boost::make_shared<WorkspaceGroup>(); + // Clear WorkspaceGroup in case algorithm instance is reused. + m_group = nullptr; addToGroup(inputWorkspaces); setProperty("OutputWorkspace", m_group); @@ -63,8 +65,22 @@ void GroupWorkspaces::addToGroup(const API::Workspace_sptr &workspace) { // Remove the group from the ADS AnalysisDataService::Instance().remove(workspace->getName()); } else { + if (!m_group) + m_group = boost::make_shared<WorkspaceGroup>(workspace->storageMode()); + else if (communicator().size() != 1 && + m_group->storageMode() != workspace->storageMode()) + throw std::runtime_error( + "WorkspaceGroup with mixed Parallel::Storage mode is not supported."); m_group->addWorkspace(workspace); } } + +Parallel::ExecutionMode GroupWorkspaces::getParallelExecutionMode( + const std::map<std::string, Parallel::StorageMode> &storageModes) const { + static_cast<void>(storageModes); + const std::vector<std::string> names = getProperty("InputWorkspaces"); + const auto ws = AnalysisDataService::Instance().retrieve(names.front()); + return Parallel::getCorrespondingExecutionMode(ws->storageMode()); +} } } diff --git a/Framework/Algorithms/src/MaskInstrument.cpp b/Framework/Algorithms/src/MaskInstrument.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3cc1f6328eddd0eb65487401ee62f615c19bc347 --- /dev/null +++ b/Framework/Algorithms/src/MaskInstrument.cpp @@ -0,0 +1,58 @@ +#include "MantidAlgorithms/MaskInstrument.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidGeometry/Instrument/DetectorInfo.h" +#include "MantidKernel/ArrayProperty.h" + +using namespace Mantid::Kernel; +using namespace Mantid::API; + +namespace Mantid { +namespace Algorithms { + +// Register the algorithm into the AlgorithmFactory +DECLARE_ALGORITHM(MaskInstrument) + +/// Algorithms name for identification. @see Algorithm::name +const std::string MaskInstrument::name() const { return "MaskInstrument"; } + +/// Algorithm's version for identification. @see Algorithm::version +int MaskInstrument::version() const { return 1; } + +/// Algorithm's category for identification. @see Algorithm::category +const std::string MaskInstrument::category() const { + return "Transforms\\Masking"; +} + +/// Algorithm's summary for use in the GUI and help. @see Algorithm::summary +const std::string MaskInstrument::summary() const { + return "Mask detectors in the instrument WITHOUT clearing data in associated " + "spectra."; +} + +void MaskInstrument::init() { + declareProperty(Kernel::make_unique<WorkspaceProperty<>>( + "InputWorkspace", "The input workspace", Direction::Input)); + declareProperty( + Kernel::make_unique<WorkspaceProperty<>>("OutputWorkspace", "", + Direction::Output), + "Name of the output workspace (can be same as InputWorkspace)"); + declareProperty(make_unique<ArrayProperty<detid_t>>("DetectorIDs"), + "List of detector IDs to mask"); +} + +void MaskInstrument::exec() { + MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace"); + MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace"); + if (outputWS != inputWS) { + outputWS = inputWS->clone(); + setProperty("OutputWorkspace", outputWS); + } + + const std::vector<detid_t> detectorIds = getProperty("DetectorIDs"); + auto &detectorInfo = outputWS->mutableDetectorInfo(); + for (const auto &id : detectorIds) + detectorInfo.setMasked(detectorInfo.indexOf(id), true); +} + +} // namespace Algorithms +} // namespace Mantid diff --git a/Framework/Algorithms/src/Q1D2.cpp b/Framework/Algorithms/src/Q1D2.cpp index 66a569e126fcfedb5d1ed92f9cda483fffb6535d..92c5634276e403003c7ec9e949d78a239c136830 100644 --- a/Framework/Algorithms/src/Q1D2.cpp +++ b/Framework/Algorithms/src/Q1D2.cpp @@ -11,6 +11,8 @@ #include "MantidAPI/WorkspaceFactory.h" #include "MantidAPI/WorkspaceUnitValidator.h" #include "MantidDataObjects/Histogram1D.h" +#include "MantidDataObjects/Workspace2D.h" +#include "MantidDataObjects/WorkspaceCreation.h" #include "MantidGeometry/Instrument.h" #include "MantidKernel/ArrayProperty.h" #include "MantidKernel/BoundedValidator.h" @@ -18,6 +20,9 @@ #include "MantidKernel/RebinParamsValidator.h" #include "MantidKernel/UnitFactory.h" #include "MantidKernel/VectorHelper.h" +#include "MantidIndexing/IndexInfo.h" +#include "MantidParallel/Communicator.h" +#include "MantidTypes/SpectrumDefinition.h" namespace Mantid { namespace Algorithms { @@ -28,6 +33,7 @@ DECLARE_ALGORITHM(Q1D2) using namespace Kernel; using namespace API; using namespace Geometry; +using namespace DataObjects; Q1D2::Q1D2() : API::Algorithm(), m_dataWS(), m_doSolidAngle(false) {} @@ -263,6 +269,40 @@ void Q1D2::exec() { } PARALLEL_CHECK_INTERUPT_REGION + if (communicator().size() > 1) { + int tag = 0; + auto size = static_cast<int>(YOut.size()); + if (communicator().rank() == 0) { + for (int rank = 1; rank < communicator().size(); ++rank) { + HistogramData::HistogramY y(YOut.size()); + HistogramData::HistogramE e2(YOut.size()); + communicator().recv(rank, tag, &y[0], size); + YOut += y; + communicator().recv(rank, tag, &e2[0], size); + EOutTo2 += e2; + communicator().recv(rank, tag, &y[0], size); + normSum += y; + communicator().recv(rank, tag, &e2[0], size); + normError2 += e2; + int detCount; + communicator().recv(rank, tag, detCount); + std::vector<detid_t> detIds(detCount); + communicator().recv(rank, tag, detIds.data(), detCount); + outputWS->getSpectrum(0).addDetectorIDs(detIds); + } + } else { + communicator().send(0, tag, YOut.rawData().data(), size); + communicator().send(0, tag, EOutTo2.rawData().data(), size); + communicator().send(0, tag, normSum.rawData().data(), size); + communicator().send(0, tag, normError2.rawData().data(), size); + const auto detIdSet = outputWS->getSpectrum(0).getDetectorIDs(); + std::vector<detid_t> detIds(detIdSet.begin(), detIdSet.end()); + auto size = static_cast<int>(detIds.size()); + communicator().send(0, tag, size); + communicator().send(0, tag, detIds.data(), size); + } + } + if (useQResolution) { // The number of Q (x)_ values is N, while the number of DeltaQ values is // N-1, @@ -281,7 +321,7 @@ void Q1D2::exec() { } bool doOutputParts = getProperty("OutputParts"); - if (doOutputParts) { + if (doOutputParts && communicator().rank() == 0) { MatrixWorkspace_sptr ws_sumOfCounts = WorkspaceFactory::Instance().create(outputWS); ws_sumOfCounts->setSharedX(0, outputWS->sharedX(0)); @@ -298,13 +338,17 @@ void Q1D2::exec() { ws_sumOfNormFactors->setFrequencyVariances(0, normError2); helper.outputParts(this, ws_sumOfCounts, ws_sumOfNormFactors); + } else if (doOutputParts) { + helper.outputParts(this, nullptr, nullptr); } progress.report("Normalizing I(Q)"); // finally divide the number of counts in each output Q bin by its weighting normalize(normSum, normError2, YOut, EOutTo2); - setProperty("OutputWorkspace", outputWS); + if (communicator().rank() == 0) { + setProperty("OutputWorkspace", outputWS); + } } /** Creates the output workspace, its size, units, etc. @@ -316,24 +360,26 @@ API::MatrixWorkspace_sptr Q1D2::setUpOutputWorkspace(const std::vector<double> &binParams) const { // Calculate the output binning HistogramData::BinEdges XOut(0); - size_t sizeOut = static_cast<size_t>(VectorHelper::createAxisFromRebinParams( + static_cast<void>(VectorHelper::createAxisFromRebinParams( binParams, XOut.mutableRawData())); - // Now create the output workspace - MatrixWorkspace_sptr outputWS = - WorkspaceFactory::Instance().create(m_dataWS, 1, sizeOut, sizeOut - 1); + // Create output workspace. On all but rank 0 this is a temporary workspace. + Indexing::IndexInfo indexInfo(1, communicator().rank() == 0 + ? Parallel::StorageMode::MasterOnly + : Parallel::StorageMode::Cloned, + communicator()); + indexInfo.setSpectrumDefinitions(std::vector<SpectrumDefinition>(1)); + auto outputWS = create<MatrixWorkspace>(*m_dataWS, indexInfo, XOut); outputWS->getAxis(0)->unit() = UnitFactory::Instance().create("MomentumTransfer"); outputWS->setYUnitLabel("1/cm"); - // Set the X vector for the output workspace - outputWS->setBinEdges(0, XOut); outputWS->setDistribution(true); outputWS->getSpectrum(0).clearDetectorIDs(); outputWS->getSpectrum(0).setSpectrumNo(1); - return outputWS; + return std::move(outputWS); } /** Calculate the normalization term for each output bin @@ -664,5 +710,28 @@ void Q1D2::normalize(const HistogramData::HistogramY &normSum, } } +namespace { +void checkStorageMode( + const std::map<std::string, Parallel::StorageMode> &storageModes, + const std::string &name) { + if (storageModes.count(name) && + storageModes.at(name) != Parallel::StorageMode::Cloned) + throw std::runtime_error(name + " must have " + + Parallel::toString(Parallel::StorageMode::Cloned)); +} +} + +Parallel::ExecutionMode Q1D2::getParallelExecutionMode( + const std::map<std::string, Parallel::StorageMode> &storageModes) const { + if (storageModes.count("PixelAdj") || storageModes.count("WavePixelAdj") || + storageModes.count("QResolution")) + throw std::runtime_error( + "Using in PixelAdj, WavePixelAdj, or QResolution in an MPI run of " + + name() + " is currently not supported."); + checkStorageMode(storageModes, "WavelengthAdj"); + return Parallel::getCorrespondingExecutionMode( + storageModes.at("DetBankWorkspace")); +} + } // namespace Algorithms } // namespace Mantid diff --git a/Framework/Algorithms/src/Scale.cpp b/Framework/Algorithms/src/Scale.cpp index 3c0a067f74076dd9e26038f97618118f9a738f1d..d5257ab24d3653e124db075f34034524a5be5ee1 100644 --- a/Framework/Algorithms/src/Scale.cpp +++ b/Framework/Algorithms/src/Scale.cpp @@ -1,6 +1,3 @@ -//---------------------------------------------------------------------- -// Includes -//---------------------------------------------------------------------- #include "MantidAlgorithms/Scale.h" #include "MantidAPI/MatrixWorkspace.h" #include "MantidKernel/ListValidator.h" diff --git a/Framework/Algorithms/test/ClearMaskedSpectraTest.h b/Framework/Algorithms/test/ClearMaskedSpectraTest.h new file mode 100644 index 0000000000000000000000000000000000000000..23c394fb8411b24812dceea253cc514ed3d73eae --- /dev/null +++ b/Framework/Algorithms/test/ClearMaskedSpectraTest.h @@ -0,0 +1,134 @@ +#ifndef MANTID_ALGORITHMS_CLEARMASKEDSPECTRATEST_H_ +#define MANTID_ALGORITHMS_CLEARMASKEDSPECTRATEST_H_ + +#include <cxxtest/TestSuite.h> + +#include "MantidAlgorithms/ClearMaskedSpectra.h" +#include "MantidDataObjects/Workspace2D.h" +#include "MantidDataObjects/WorkspaceCreation.h" +#include "MantidGeometry/Instrument/DetectorInfo.h" + +#include "MantidTestHelpers/InstrumentCreationHelper.h" + +using namespace Mantid; +using namespace Algorithms; +using namespace API; +using namespace DataObjects; +using namespace HistogramData; + +namespace { +MatrixWorkspace_sptr makeWorkspace() { + MatrixWorkspace_sptr ws = + create<Workspace2D>(4, Histogram(Points(1), Counts{1.2})); + InstrumentCreationHelper::addFullInstrumentToWorkspace(*ws, false, false, ""); + return ws; +} + +MatrixWorkspace_sptr run(const MatrixWorkspace_sptr &ws) { + ClearMaskedSpectra alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspace", ws); + alg.setPropertyValue("OutputWorkspace", "dummy"); + alg.execute(); + return alg.getProperty("OutputWorkspace"); +} + +MatrixWorkspace_sptr runInplace(const MatrixWorkspace_sptr &ws) { + ClearMaskedSpectra alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspace", ws); + alg.setPropertyValue("OutputWorkspace", "dummy"); + alg.setProperty("OutputWorkspace", ws); + alg.execute(); + return ws; +} +} + +class ClearMaskedSpectraTest : 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 ClearMaskedSpectraTest *createSuite() { + return new ClearMaskedSpectraTest(); + } + static void destroySuite(ClearMaskedSpectraTest *suite) { delete suite; } + + void test_no_instrument_leaves_data_unchanged() { + MatrixWorkspace_sptr ws = + create<Workspace2D>(4, Histogram(Points(1), Counts{1.2})); + ClearMaskedSpectra alg; + alg.initialize(); + alg.setProperty("InputWorkspace", ws); + TS_ASSERT_THROWS_NOTHING( + alg.setPropertyValue("OutputWorkspace", "_dummy_for_inplace")); + alg.setProperty("OutputWorkspace", ws); + alg.execute(); + TS_ASSERT(alg.isExecuted()); + TS_ASSERT_EQUALS(ws->y(0)[0], 1.2); + TS_ASSERT_EQUALS(ws->y(1)[0], 1.2); + TS_ASSERT_EQUALS(ws->y(2)[0], 1.2); + TS_ASSERT_EQUALS(ws->y(3)[0], 1.2); + } + + void test_no_masking() { + auto in = makeWorkspace(); + auto out = run(in); + TS_ASSERT_DIFFERS(in, out); + TS_ASSERT_EQUALS(out->y(0)[0], 1.2); + TS_ASSERT_EQUALS(out->y(1)[0], 1.2); + TS_ASSERT_EQUALS(out->y(2)[0], 1.2); + TS_ASSERT_EQUALS(out->y(3)[0], 1.2); + } + + void test_no_masking_inplace() { + auto in = makeWorkspace(); + auto out = runInplace(in); + TS_ASSERT_EQUALS(in, out); + TS_ASSERT_EQUALS(out->y(0)[0], 1.2); + TS_ASSERT_EQUALS(out->y(1)[0], 1.2); + TS_ASSERT_EQUALS(out->y(2)[0], 1.2); + TS_ASSERT_EQUALS(out->y(3)[0], 1.2); + } + + void test_masking() { + auto in = makeWorkspace(); + auto &detInfo = in->mutableDetectorInfo(); + detInfo.setMasked(1, true); + auto out = run(in); + TS_ASSERT_DIFFERS(in, out); + TS_ASSERT_EQUALS(out->y(0)[0], 1.2); + TS_ASSERT_EQUALS(out->y(1)[0], 0.0); + TS_ASSERT_EQUALS(out->y(2)[0], 1.2); + TS_ASSERT_EQUALS(out->y(3)[0], 1.2); + } + + void test_masking_inplace() { + auto in = makeWorkspace(); + auto &detInfo = in->mutableDetectorInfo(); + detInfo.setMasked(1, true); + auto out = runInplace(in); + TS_ASSERT_EQUALS(in, out); + TS_ASSERT_EQUALS(out->y(0)[0], 1.2); + TS_ASSERT_EQUALS(out->y(1)[0], 0.0); + TS_ASSERT_EQUALS(out->y(2)[0], 1.2); + TS_ASSERT_EQUALS(out->y(3)[0], 1.2); + } + + void test_does_not_clear_partially_masked() { + auto in = makeWorkspace(); + in->getSpectrum(1).addDetectorID(3); + auto &detInfo = in->mutableDetectorInfo(); + detInfo.setMasked(1, true); + auto out = run(in); + TS_ASSERT_DIFFERS(in, out); + TS_ASSERT_EQUALS(out->y(0)[0], 1.2); + // Only one of the associated detector IDs is masked, data preserved. + TS_ASSERT_EQUALS(out->y(1)[0], 1.2); + TS_ASSERT_EQUALS(out->y(2)[0], 1.2); + TS_ASSERT_EQUALS(out->y(3)[0], 1.2); + } +}; + +#endif /* MANTID_ALGORITHMS_CLEARMASKEDSPECTRATEST_H_ */ diff --git a/Framework/Algorithms/test/MaskInstrumentTest.h b/Framework/Algorithms/test/MaskInstrumentTest.h new file mode 100644 index 0000000000000000000000000000000000000000..8715bcf8dda90560de1db46349fb5e74f07bf018 --- /dev/null +++ b/Framework/Algorithms/test/MaskInstrumentTest.h @@ -0,0 +1,121 @@ +#ifndef MANTID_ALGORITHMS_MASKINSTRUMENTTEST_H_ +#define MANTID_ALGORITHMS_MASKINSTRUMENTTEST_H_ + +#include <cxxtest/TestSuite.h> + +#include "MantidAlgorithms/MaskInstrument.h" +#include "MantidDataObjects/Workspace2D.h" +#include "MantidDataObjects/WorkspaceCreation.h" +#include "MantidAPI/AnalysisDataService.h" +#include "MantidGeometry/Instrument/DetectorInfo.h" + +#include "MantidTestHelpers/InstrumentCreationHelper.h" + +using namespace Mantid; +using namespace Algorithms; +using namespace API; +using namespace DataObjects; + +namespace { +MatrixWorkspace_sptr makeWorkspace() { + MatrixWorkspace_sptr ws = create<Workspace2D>(4, HistogramData::Points(1)); + InstrumentCreationHelper::addFullInstrumentToWorkspace(*ws, false, false, ""); + return ws; +} + +MatrixWorkspace_sptr maskInstrument(const MatrixWorkspace_sptr &ws, + const std::vector<int> &detectorIDs) { + MaskInstrument alg; + alg.setRethrows(true); + alg.initialize(); + alg.setProperty("InputWorkspace", ws); + alg.setPropertyValue("OutputWorkspace", "out"); + alg.setProperty("DetectorIDs", detectorIDs); + alg.execute(); + auto out = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("out"); + AnalysisDataService::Instance().remove("out"); + return out; +} + +MatrixWorkspace_sptr +maskInstrumentInplace(const MatrixWorkspace_sptr &ws, + const std::vector<int> &detectorIDs) { + MaskInstrument alg; + alg.setRethrows(true); + alg.initialize(); + alg.setProperty("InputWorkspace", ws); + TS_ASSERT_THROWS_NOTHING( + alg.setPropertyValue("OutputWorkspace", "_dummy_for_inplace")); + alg.setProperty("OutputWorkspace", ws); + alg.setProperty("DetectorIDs", detectorIDs); + alg.execute(); + return ws; +} +} + +class MaskInstrumentTest : 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 MaskInstrumentTest *createSuite() { return new MaskInstrumentTest(); } + static void destroySuite(MaskInstrumentTest *suite) { delete suite; } + + void test_masking() { + const auto in = makeWorkspace(); + const auto ws = maskInstrument(in, {1, 3}); + TS_ASSERT_DIFFERS(in, ws); + const auto &detInfo = ws->detectorInfo(); + // Note that detector IDs in workspace start at 1, so there is an offset of + // 1 compared to the detector indices checked here. + TS_ASSERT_EQUALS(detInfo.isMasked(0), true); + TS_ASSERT_EQUALS(detInfo.isMasked(1), false); + TS_ASSERT_EQUALS(detInfo.isMasked(2), true); + TS_ASSERT_EQUALS(detInfo.isMasked(3), false); + } + + void test_masking_cummulative() { + const auto in = makeWorkspace(); + const auto ws = maskInstrument(in, {1, 3}); + const auto ws2 = maskInstrument(ws, {1, 2}); + const auto &detInfo = ws->detectorInfo(); + TS_ASSERT_EQUALS(detInfo.isMasked(0), true); + TS_ASSERT_EQUALS(detInfo.isMasked(1), false); + TS_ASSERT_EQUALS(detInfo.isMasked(2), true); + TS_ASSERT_EQUALS(detInfo.isMasked(3), false); + const auto &detInfo2 = ws2->detectorInfo(); + TS_ASSERT_EQUALS(detInfo2.isMasked(0), true); + TS_ASSERT_EQUALS(detInfo2.isMasked(1), true); + TS_ASSERT_EQUALS(detInfo2.isMasked(2), true); + TS_ASSERT_EQUALS(detInfo2.isMasked(3), false); + } + + void test_masking_inplace() { + const auto in = makeWorkspace(); + const auto ws = maskInstrumentInplace(in, {1, 3}); + TS_ASSERT_EQUALS(in, ws); + const auto &detInfo = ws->detectorInfo(); + TS_ASSERT_EQUALS(detInfo.isMasked(0), true); + TS_ASSERT_EQUALS(detInfo.isMasked(1), false); + TS_ASSERT_EQUALS(detInfo.isMasked(2), true); + TS_ASSERT_EQUALS(detInfo.isMasked(3), false); + } + + void test_masking_inplace_cummulative() { + const auto in = makeWorkspace(); + const auto ws = maskInstrumentInplace(in, {1, 3}); + const auto ws2 = maskInstrumentInplace(in, {1, 2}); + const auto &detInfo = ws2->detectorInfo(); + TS_ASSERT_EQUALS(detInfo.isMasked(0), true); + TS_ASSERT_EQUALS(detInfo.isMasked(1), true); + TS_ASSERT_EQUALS(detInfo.isMasked(2), true); + TS_ASSERT_EQUALS(detInfo.isMasked(3), false); + } + + void test_out_of_range() { + const auto in = makeWorkspace(); + TS_ASSERT_THROWS(maskInstrumentInplace(in, {0}), std::out_of_range); + TS_ASSERT_THROWS(maskInstrumentInplace(in, {5}), std::out_of_range); + } +}; + +#endif /* MANTID_ALGORITHMS_MASKINSTRUMENTTEST_H_ */ diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadMask.h b/Framework/DataHandling/inc/MantidDataHandling/LoadMask.h index 5e672678216c7f9342fc5926d903f0a9116813ab..3ea1b44215762d6fbcd497382dc2cc7d7233c6a7 100644 --- a/Framework/DataHandling/inc/MantidDataHandling/LoadMask.h +++ b/Framework/DataHandling/inc/MantidDataHandling/LoadMask.h @@ -2,7 +2,7 @@ #define MANTID_DATAHANDLING_LOADMASK_H_ #include "MantidKernel/System.h" -#include "MantidAPI/Algorithm.h" +#include "MantidAPI/ParallelAlgorithm.h" #include "MantidAPI/MatrixWorkspace_fwd.h" #include "MantidDataObjects/MaskWorkspace.h" #include "MantidGeometry/IDTypes.h" @@ -47,7 +47,7 @@ namespace DataHandling { File change history is stored at: <https://github.com/mantidproject/mantid> Code Documentation is available at: <http://doxygen.mantidproject.org> */ -class DLLExport LoadMask : public API::Algorithm { +class DLLExport LoadMask : public API::ParallelAlgorithm { public: /// Algorithm's name for identification const std::string name() const override { return "LoadMask"; }; diff --git a/Framework/DataHandling/src/LoadEventNexus.cpp b/Framework/DataHandling/src/LoadEventNexus.cpp index a2a1d08e44f69ba32b214287d1a6c40968d3c909..b2449e86b733675e0710832ace447539d887ba8d 100644 --- a/Framework/DataHandling/src/LoadEventNexus.cpp +++ b/Framework/DataHandling/src/LoadEventNexus.cpp @@ -862,6 +862,7 @@ void LoadEventNexus::loadEvents(API::Progress *const prog, m_file->close(); try { ParallelEventLoader::load(*ws, m_filename, m_top_entry_name, bankNames); + g_log.information() << "Used ParallelEventLoader.\n"; loaded = true; shortest_tof = 0.0; longest_tof = 1e10; diff --git a/Framework/PythonInterface/inc/MantidPythonInterface/api/PythonAlgorithm/DataProcessorAdapter.h b/Framework/PythonInterface/inc/MantidPythonInterface/api/PythonAlgorithm/DataProcessorAdapter.h index 9dcb33285dc3621a7d1f50560bdd0cac145e8cb7..38286ac53b0dd23e4b9df1df0e099b22dc701069 100644 --- a/Framework/PythonInterface/inc/MantidPythonInterface/api/PythonAlgorithm/DataProcessorAdapter.h +++ b/Framework/PythonInterface/inc/MantidPythonInterface/api/PythonAlgorithm/DataProcessorAdapter.h @@ -41,10 +41,9 @@ namespace PythonInterface { * It also provides access to the protected methods on DataProcessorAlgorithm * from the type exported to Python */ +template <class Base> class DataProcessorAdapter - : public AlgorithmAdapter<API::DataProcessorAlgorithm> { - typedef AlgorithmAdapter<API::DataProcessorAlgorithm> SuperClass; - + : public AlgorithmAdapter<API::GenericDataProcessorAlgorithm<Base>> { public: /// A constructor that looks like a Python __init__ method DataProcessorAdapter(PyObject *self); diff --git a/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Registry/TypedPropertyValueHandler.h b/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Registry/TypedPropertyValueHandler.h index 17cc262a16b9cecf96245cb465345799aa6639a8..73b19f29ecb61bfc7622531af52e0925c031bead 100644 --- a/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Registry/TypedPropertyValueHandler.h +++ b/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Registry/TypedPropertyValueHandler.h @@ -116,8 +116,11 @@ struct DLLExport TypedPropertyValueHandler< */ void set(Kernel::IPropertyManager *alg, const std::string &name, const boost::python::object &value) const override { - alg->setProperty<HeldType>( - name, boost::dynamic_pointer_cast<T>(ExtractWorkspace(value)())); + if (value == boost::python::object()) + alg->setProperty<HeldType>(name, boost::shared_ptr<T>(nullptr)); + else + alg->setProperty<HeldType>( + name, boost::dynamic_pointer_cast<T>(ExtractWorkspace(value)())); } /** diff --git a/Framework/PythonInterface/mantid/api/src/Exports/Algorithm.cpp b/Framework/PythonInterface/mantid/api/src/Exports/Algorithm.cpp index c638c8db879e262202be14334145548851995a2a..9331a1548ac8c27fc8d9b0c303f3c56535d858d1 100644 --- a/Framework/PythonInterface/mantid/api/src/Exports/Algorithm.cpp +++ b/Framework/PythonInterface/mantid/api/src/Exports/Algorithm.cpp @@ -4,6 +4,9 @@ // design #endif #include "MantidKernel/WarningSuppressions.h" +#include "MantidAPI/SerialAlgorithm.h" +#include "MantidAPI/ParallelAlgorithm.h" +#include "MantidAPI/DistributedAlgorithm.h" #include "MantidPythonInterface/api/PythonAlgorithm/AlgorithmAdapter.h" #ifdef _MSC_VER #pragma warning(default : 4250) @@ -18,14 +21,23 @@ #include <boost/python/scope.hpp> using Mantid::API::Algorithm; +using Mantid::API::SerialAlgorithm; +using Mantid::API::ParallelAlgorithm; +using Mantid::API::DistributedAlgorithm; using Mantid::PythonInterface::AlgorithmAdapter; using Mantid::Kernel::Direction; using namespace boost::python; GET_POINTER_SPECIALIZATION(Algorithm) +GET_POINTER_SPECIALIZATION(SerialAlgorithm) +GET_POINTER_SPECIALIZATION(ParallelAlgorithm) +GET_POINTER_SPECIALIZATION(DistributedAlgorithm) namespace { typedef AlgorithmAdapter<Algorithm> PythonAlgorithm; +typedef AlgorithmAdapter<SerialAlgorithm> PythonSerialAlgorithm; +typedef AlgorithmAdapter<ParallelAlgorithm> PythonParallelAlgorithm; +typedef AlgorithmAdapter<DistributedAlgorithm> PythonDistributedAlgorithm; // declarePyAlgProperty(property*,doc) typedef void (*declarePropertyType1)(boost::python::object &self, @@ -148,3 +160,34 @@ void export_leaf_classes() { // Python so we simply add an alias of the Algorithm name to PythonAlgorithm scope().attr("PythonAlgorithm") = scope().attr("Algorithm"); } + +void export_SerialAlgorithm() { + register_ptr_to_python<boost::shared_ptr<SerialAlgorithm>>(); + register_exception_translator<SerialAlgorithm::CancelException>( + &translateCancel); + class_<SerialAlgorithm, bases<Mantid::API::Algorithm>, + boost::shared_ptr<PythonSerialAlgorithm>, boost::noncopyable>( + "SerialAlgorithm", "Base class for simple serial algorithms"); + scope().attr("PythonSerialAlgorithm") = scope().attr("SerialAlgorithm"); +} + +void export_ParallelAlgorithm() { + register_ptr_to_python<boost::shared_ptr<ParallelAlgorithm>>(); + register_exception_translator<ParallelAlgorithm::CancelException>( + &translateCancel); + class_<ParallelAlgorithm, bases<Mantid::API::Algorithm>, + boost::shared_ptr<PythonParallelAlgorithm>, boost::noncopyable>( + "ParallelAlgorithm", "Base class for simple parallel algorithms"); + scope().attr("PythonParallelAlgorithm") = scope().attr("ParallelAlgorithm"); +} + +void export_DistributedAlgorithm() { + register_ptr_to_python<boost::shared_ptr<DistributedAlgorithm>>(); + register_exception_translator<DistributedAlgorithm::CancelException>( + &translateCancel); + class_<DistributedAlgorithm, bases<Mantid::API::Algorithm>, + boost::shared_ptr<PythonDistributedAlgorithm>, boost::noncopyable>( + "DistributedAlgorithm", "Base class for simple distributed algorithms"); + scope().attr("PythonDistributedAlgorithm") = + scope().attr("DistributedAlgorithm"); +} diff --git a/Framework/PythonInterface/mantid/api/src/Exports/DataProcessorAlgorithm.cpp b/Framework/PythonInterface/mantid/api/src/Exports/DataProcessorAlgorithm.cpp index 6532b0e3de5fdb8d468d1258222436b986435806..fa70073058a6c8f1731dc3b643c3e9985df88d8a 100644 --- a/Framework/PythonInterface/mantid/api/src/Exports/DataProcessorAlgorithm.cpp +++ b/Framework/PythonInterface/mantid/api/src/Exports/DataProcessorAlgorithm.cpp @@ -9,93 +9,104 @@ using Mantid::PythonInterface::DataProcessorAdapter; using namespace boost::python; namespace { -typedef Workspace_sptr (DataProcessorAdapter::*loadOverload1)( - const std::string &); -typedef Workspace_sptr (DataProcessorAdapter::*loadOverload2)( +template <class Base> +using loadOverload1 = + Workspace_sptr (DataProcessorAdapter<Base>::*)(const std::string &); +template <class Base> +using loadOverload2 = Workspace_sptr (DataProcessorAdapter<Base>::*)( const std::string &, const bool); -} -void export_DataProcessorAlgorithm() { +template <class Base> void do_export(const std::string &name) { // for strings will actually create a list using Mantid::PythonInterface::Policies::VectorToNumpy; + using Adapter = DataProcessorAdapter<Base>; - class_<DataProcessorAlgorithm, bases<Algorithm>, - boost::shared_ptr<DataProcessorAdapter>, boost::noncopyable>( - "DataProcessorAlgorithm", "Base class workflow-type algorithms") + class_<GenericDataProcessorAlgorithm<Base>, bases<Base>, + boost::shared_ptr<Adapter>, boost::noncopyable>( + name.c_str(), "Base class workflow-type algorithms") - .def("setLoadAlg", &DataProcessorAdapter::setLoadAlgProxy, - (arg("self"), arg("alg")), + .def("setLoadAlg", &Adapter::setLoadAlgProxy, (arg("self"), arg("alg")), "Set the name of the algorithm called using the load() method " "[Default=Load]") - .def("setLoadAlgFileProp", &DataProcessorAdapter::setLoadAlgFilePropProxy, + .def("setLoadAlgFileProp", &Adapter::setLoadAlgFilePropProxy, (arg("self"), arg("file_prop_name")), "Set the name of the file property for the load algorithm when " "using " "the load() method [Default=Filename]") - .def("setAccumAlg", &DataProcessorAdapter::setAccumAlgProxy, - (arg("self"), arg("alg")), + .def("setAccumAlg", &Adapter::setAccumAlgProxy, (arg("self"), arg("alg")), "Set the name of the algorithm called to accumulate a chunk of " "processed data [Default=Plus]") - .def("copyProperties", &DataProcessorAdapter::copyPropertiesProxy, + .def("copyProperties", &Adapter::copyPropertiesProxy, (arg("self"), arg("alg"), arg("properties") = boost::python::object(), arg("version") = -1), "Copy properties from another algorithm") - .def("determineChunk", &DataProcessorAdapter::determineChunkProxy, + .def("determineChunk", &Adapter::determineChunkProxy, (arg("self"), arg("file_name")), "Return a TableWorkspace containing the information on how to split " "the " "input file when processing in chunks") - .def("loadChunk", &DataProcessorAdapter::loadChunkProxy, + .def("loadChunk", &Adapter::loadChunkProxy, (arg("self"), arg("row_index")), "Load a chunk of data") - .def("load", (loadOverload1)&DataProcessorAdapter::loadProxy, + .def("load", (loadOverload1<Base>)&Adapter::loadProxy, (arg("self"), arg("input_data")), "Loads the given file or workspace data and returns the workspace. " "The output is not stored in the AnalysisDataService.") - .def("load", (loadOverload2)&DataProcessorAdapter::loadProxy, + .def("load", (loadOverload2<Base>)&Adapter::loadProxy, (arg("self"), arg("input_data"), arg("load_quite")), "Loads the given file or workspace data and returns the workspace. " "If loadQuiet=True then output is not stored in the " "AnalysisDataService.") - .def("splitInput", &DataProcessorAdapter::splitInputProxy, - (arg("self"), arg("input")), return_value_policy<VectorToNumpy>()) + .def("splitInput", &Adapter::splitInputProxy, (arg("self"), arg("input")), + return_value_policy<VectorToNumpy>()) - .def("forwardProperties", &DataProcessorAdapter::forwardPropertiesProxy, - arg("self")) + .def("forwardProperties", &Adapter::forwardPropertiesProxy, arg("self")) - .def("getProcessProperties", - &DataProcessorAdapter::getProcessPropertiesProxy, + .def("getProcessProperties", &Adapter::getProcessPropertiesProxy, (arg("self"), arg("property_manager")), "Returns the named property manager from the service or creates " "a new one if it does not exist") - .def("assemble", &DataProcessorAdapter::assembleProxy, + .def("assemble", &Adapter::assembleProxy, (arg("self"), arg("partial_wsname"), arg("output_wsname")), "If an MPI build, assemble the partial workspaces from all MPI " "processes. " "Otherwise, simply returns the input workspace") - .def("saveNexus", &DataProcessorAdapter::saveNexusProxy, + .def("saveNexus", &Adapter::saveNexusProxy, (arg("self"), arg("output_wsname"), arg("output_filename")), "Save a workspace as a nexus file. If this is an MPI build then " "saving only " "happens for the main thread.") - .def("isMainThread", &DataProcessorAdapter::isMainThreadProxy, - arg("self"), + .def("isMainThread", &Adapter::isMainThreadProxy, arg("self"), "Returns true if this algorithm is the main thread for an MPI " "build. For " "non-MPI build it always returns true") - .def("getNThreads", &DataProcessorAdapter::getNThreadsProxy, arg("self"), + .def("getNThreads", &Adapter::getNThreadsProxy, arg("self"), "Returns the number of running MPI processes in an MPI build or 1 " "for " "a non-MPI build"); } +} + +void export_DataProcessorAlgorithm() { + do_export<Algorithm>("DataProcessorAlgorithm"); +} +void export_SerialDataProcessorAlgorithm() { + do_export<SerialAlgorithm>("SerialDataProcessorAlgorithm"); +} +void export_ParallelDataProcessorAlgorithm() { + do_export<ParallelAlgorithm>("ParallelDataProcessorAlgorithm"); +} +void export_DistributedDataProcessorAlgorithm() { + do_export<DistributedAlgorithm>("DistributedDataProcessorAlgorithm"); +} diff --git a/Framework/PythonInterface/mantid/api/src/PythonAlgorithm/AlgorithmAdapter.cpp b/Framework/PythonInterface/mantid/api/src/PythonAlgorithm/AlgorithmAdapter.cpp index 515d5c2052a7a5bfdb6caad6bf8e508e99b6dffd..6d9358d85c22bde259d8e828fe598f2541187999 100644 --- a/Framework/PythonInterface/mantid/api/src/PythonAlgorithm/AlgorithmAdapter.cpp +++ b/Framework/PythonInterface/mantid/api/src/PythonAlgorithm/AlgorithmAdapter.cpp @@ -4,6 +4,9 @@ #include "MantidPythonInterface/kernel/Environment/CallMethod.h" #include "MantidPythonInterface/kernel/Environment/GlobalInterpreterLock.h" #include "MantidAPI/DataProcessorAlgorithm.h" +#include "MantidAPI/SerialAlgorithm.h" +#include "MantidAPI/ParallelAlgorithm.h" +#include "MantidAPI/DistributedAlgorithm.h" #include <boost/python/class.hpp> #include <boost/python/dict.hpp> @@ -310,7 +313,13 @@ template <typename BaseAlgorithm> void AlgorithmAdapter<BaseAlgorithm>::exec() { //----------------------------------------------------------------------------------------------------------------------------- /// API::Algorithm as base template class AlgorithmAdapter<API::Algorithm>; +template class AlgorithmAdapter<API::SerialAlgorithm>; +template class AlgorithmAdapter<API::ParallelAlgorithm>; +template class AlgorithmAdapter<API::DistributedAlgorithm>; /// API::DataProcesstor as base template class AlgorithmAdapter<API::DataProcessorAlgorithm>; +template class AlgorithmAdapter<API::SerialDataProcessorAlgorithm>; +template class AlgorithmAdapter<API::ParallelDataProcessorAlgorithm>; +template class AlgorithmAdapter<API::DistributedDataProcessorAlgorithm>; } } diff --git a/Framework/PythonInterface/mantid/api/src/PythonAlgorithm/DataProcessorAdapter.cpp b/Framework/PythonInterface/mantid/api/src/PythonAlgorithm/DataProcessorAdapter.cpp index bb75454db88695166771bfece58ecc10b171d050..a69ec5a89542dfca5c352bebab3d61266069290d 100644 --- a/Framework/PythonInterface/mantid/api/src/PythonAlgorithm/DataProcessorAdapter.cpp +++ b/Framework/PythonInterface/mantid/api/src/PythonAlgorithm/DataProcessorAdapter.cpp @@ -10,6 +10,13 @@ namespace PythonInterface { * Construct the "wrapper" and stores the reference to the PyObject * @param self A reference to the calling Python object */ -DataProcessorAdapter::DataProcessorAdapter(PyObject *self) : SuperClass(self) {} +template <class Base> +DataProcessorAdapter<Base>::DataProcessorAdapter(PyObject *self) + : AlgorithmAdapter<API::GenericDataProcessorAlgorithm<Base>>(self) {} + +template class DataProcessorAdapter<API::Algorithm>; +template class DataProcessorAdapter<API::SerialAlgorithm>; +template class DataProcessorAdapter<API::ParallelAlgorithm>; +template class DataProcessorAdapter<API::DistributedAlgorithm>; } } diff --git a/Framework/PythonInterface/mantid/dataobjects/src/Exports/MaskWorkspace.cpp b/Framework/PythonInterface/mantid/dataobjects/src/Exports/MaskWorkspace.cpp index 052c61bf3ef9ca530758ce9f61300f32f68bb989..f1c720880cbf865281e9297d70b80e05c7490f32 100644 --- a/Framework/PythonInterface/mantid/dataobjects/src/Exports/MaskWorkspace.cpp +++ b/Framework/PythonInterface/mantid/dataobjects/src/Exports/MaskWorkspace.cpp @@ -13,7 +13,9 @@ GET_POINTER_SPECIALIZATION(MaskWorkspace) void export_MaskWorkspace() { class_<MaskWorkspace, bases<SpecialWorkspace2D, IMaskWorkspace>, - boost::noncopyable>("MaskWorkspace", no_init); + boost::noncopyable>("MaskWorkspace", no_init) + .def("getMaskedDetectors", &MaskWorkspace::getMaskedDetectors, + arg("self"), "Returns all masked detector IDs."); // register pointers RegisterWorkspacePtrToPython<MaskWorkspace>(); diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCalculateTransmission.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCalculateTransmission.py index 85bfaf36bbb484af16b580b68fc1dcbf03fa3859..dd179a4f1766d7ac415e7a290eae783a3cf96b88 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCalculateTransmission.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCalculateTransmission.py @@ -3,7 +3,7 @@ """ SANSCalculateTransmission algorithm calculates the transmission correction of a SANS workspace.""" from __future__ import (absolute_import, division, print_function) from mantid.kernel import (Direction, StringListValidator, PropertyManagerProperty) -from mantid.api import (DataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode) +from mantid.api import (ParallelDataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode) from sans.common.constants import EMPTY_NAME from sans.common.general_functions import create_unmanaged_algorithm from sans.common.enums import (RangeStepType, RebinType, FitType, DataType) @@ -15,7 +15,7 @@ from sans.algorithm_detail.calculate_transmission_helper import (get_detector_id get_region_of_interest) -class SANSCalculateTransmission(DataProcessorAlgorithm): +class SANSCalculateTransmission(ParallelDataProcessorAlgorithm): def category(self): return 'SANS\\Adjust' diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSConvertToQ.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSConvertToQ.py index 2edba033fdd2aaa5c906b28b9dbec550804cd7ac..6d0bb0d4c3ac8fc8e831410391e998938b006a89 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSConvertToQ.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSConvertToQ.py @@ -3,7 +3,7 @@ """ Converts a workspace from wavelengths to momentum transfer.""" from __future__ import (absolute_import, division, print_function) from mantid.kernel import (Direction, PropertyManagerProperty, CompositeValidator) -from mantid.api import (DataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, +from mantid.api import (DistributedDataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, WorkspaceUnitValidator) from sans.common.constants import EMPTY_NAME @@ -13,7 +13,7 @@ from sans.state.state_base import create_deserialized_sans_state_from_property_m from sans.algorithm_detail.q_resolution_calculator import QResolutionCalculatorFactory -class SANSConvertToQ(DataProcessorAlgorithm): +class SANSConvertToQ(DistributedDataProcessorAlgorithm): def category(self): return 'SANS\\ConvertToQ' @@ -81,7 +81,8 @@ class SANSConvertToQ(DataProcessorAlgorithm): # Set the output append_to_sans_file_tag(output_workspace, "_convertq") self.setProperty("OutputWorkspace", output_workspace) - if sum_of_counts_workspace and sum_of_norms_workspace: + output_parts = self.getProperty("OutputParts").value + if output_parts: self._set_partial_workspaces(sum_of_counts_workspace, sum_of_norms_workspace) def _run_q_1d(self, state): diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSConvertToWavelength.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSConvertToWavelength.py index c57fb73620cda10231028b369682c284ced40cca..acbb28a25e876c3e7e8bc7737398382573ad0690 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSConvertToWavelength.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSConvertToWavelength.py @@ -3,7 +3,7 @@ """ SANSConvertToWavelength converts to wavelength units """ from __future__ import (absolute_import, division, print_function) from mantid.kernel import (Direction, PropertyManagerProperty) -from mantid.api import (DataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode) +from mantid.api import (DistributedDataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode) from sans.common.constants import EMPTY_NAME from sans.common.general_functions import (create_unmanaged_algorithm, append_to_sans_file_tag, get_input_workspace_as_copy_if_not_same_as_output_workspace) @@ -11,7 +11,7 @@ from sans.common.enums import (RangeStepType, RebinType) from sans.state.state_base import create_deserialized_sans_state_from_property_manager -class SANSConvertToWavelength(DataProcessorAlgorithm): +class SANSConvertToWavelength(DistributedDataProcessorAlgorithm): def category(self): return 'SANS\\Wavelength' diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSConvertToWavelengthAndRebin.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSConvertToWavelengthAndRebin.py index c9faf23419a2406677835eb67ea38963fa168fb7..905a57eabc0d28379e16334942884ab6e979bc94 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSConvertToWavelengthAndRebin.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSConvertToWavelengthAndRebin.py @@ -5,14 +5,14 @@ from __future__ import (absolute_import, division, print_function) from mantid.kernel import (Direction, StringListValidator, Property) from mantid.dataobjects import EventWorkspace -from mantid.api import (DataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, Progress) +from mantid.api import (DistributedDataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, Progress) from sans.common.constants import EMPTY_NAME from sans.common.general_functions import (create_unmanaged_algorithm, append_to_sans_file_tag, get_input_workspace_as_copy_if_not_same_as_output_workspace) from sans.common.enums import (RebinType, RangeStepType) -class SANSConvertToWavelengthAndRebin(DataProcessorAlgorithm): +class SANSConvertToWavelengthAndRebin(DistributedDataProcessorAlgorithm): def category(self): return 'SANS\\Wavelength' diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCreateAdjustmentWorkspaces.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCreateAdjustmentWorkspaces.py index e5be7ef26cedb0358d63fba0bc12f6027fa44ca7..b183e192a66e6d169a3ccdc220a7114e3d1abcbc 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCreateAdjustmentWorkspaces.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCreateAdjustmentWorkspaces.py @@ -6,7 +6,7 @@ from __future__ import (absolute_import, division, print_function) from mantid.kernel import (Direction, PropertyManagerProperty, StringListValidator, CompositeValidator) -from mantid.api import (DataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, +from mantid.api import (DistributedDataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, WorkspaceUnitValidator) from sans.common.constants import EMPTY_NAME @@ -16,7 +16,7 @@ from sans.state.state_base import create_deserialized_sans_state_from_property_m from mantid import AnalysisDataService -class SANSCreateAdjustmentWorkspaces(DataProcessorAlgorithm): +class SANSCreateAdjustmentWorkspaces(DistributedDataProcessorAlgorithm): def category(self): return 'SANS\\Adjust' diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCreateWavelengthAndPixelAdjustment.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCreateWavelengthAndPixelAdjustment.py index e7cbe1105e5c91e6ded7680a91b19557f88e358a..8fad5ef9475e6177528104a4a9de89061f30ccd1 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCreateWavelengthAndPixelAdjustment.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCreateWavelengthAndPixelAdjustment.py @@ -7,7 +7,7 @@ from __future__ import (absolute_import, division, print_function) from mantid.kernel import (Direction, StringListValidator, PropertyManagerProperty, CompositeValidator) -from mantid.api import (DataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, +from mantid.api import (ParallelDataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, WorkspaceUnitValidator) from sans.state.state_base import create_deserialized_sans_state_from_property_manager @@ -16,7 +16,7 @@ from sans.common.constants import EMPTY_NAME from sans.common.general_functions import create_unmanaged_algorithm -class SANSCreateWavelengthAndPixelAdjustment(DataProcessorAlgorithm): +class SANSCreateWavelengthAndPixelAdjustment(ParallelDataProcessorAlgorithm): def category(self): return 'SANS\\Adjust' diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCrop.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCrop.py index b4313322517434ae871d4b1ade6aade8bef70a4c..431ce38affb2ac5a1ef68e9a1c6ef132d74870c0 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCrop.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCrop.py @@ -4,7 +4,7 @@ from __future__ import (absolute_import, division, print_function) from mantid.kernel import (Direction, StringListValidator) -from mantid.api import (DataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, Progress) +from mantid.api import (DistributedDataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, Progress) from sans.common.constants import EMPTY_NAME from sans.common.enums import DetectorType @@ -12,7 +12,7 @@ from sans.common.general_functions import (create_unmanaged_algorithm, append_to from sans.algorithm_detail.crop_helper import get_component_name -class SANSCrop(DataProcessorAlgorithm): +class SANSCrop(DistributedDataProcessorAlgorithm): def category(self): return 'SANS\\Crop' diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSLoad.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSLoad.py index f159bf65ee4c15445d4d19fc46d79f8f556790be..1afd23f6c1bf36fec90f3808d75241653421cebf 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSLoad.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSLoad.py @@ -5,7 +5,7 @@ from __future__ import (absolute_import, division, print_function) from mantid.kernel import (Direction, PropertyManagerProperty, FloatArrayProperty, EnabledWhenProperty, PropertyCriterion) -from mantid.api import (DataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, Progress, +from mantid.api import (ParallelDataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, Progress, WorkspaceProperty) from sans.state.state_base import create_deserialized_sans_state_from_property_manager @@ -14,7 +14,7 @@ from sans.common.general_functions import create_child_algorithm from sans.algorithm_detail.load_data import SANSLoadDataFactory -class SANSLoad(DataProcessorAlgorithm): +class SANSLoad(ParallelDataProcessorAlgorithm): def category(self): return 'SANS\\Load' diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSMaskWorkspace.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSMaskWorkspace.py index 23025237a9e6cf5bbe52b097fe528bc66f958d62..f99fa02a3a0ee973a7b392e0d0b6bba529b3ff7a 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSMaskWorkspace.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSMaskWorkspace.py @@ -4,7 +4,7 @@ from __future__ import (absolute_import, division, print_function) from mantid.kernel import (Direction, PropertyManagerProperty, StringListValidator) -from mantid.api import (DataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, Progress) +from mantid.api import (DistributedDataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, Progress) from sans.algorithm_detail.mask_workspace import MaskFactory from sans.state.state_base import create_deserialized_sans_state_from_property_manager @@ -12,7 +12,7 @@ from sans.common.enums import DetectorType from sans.common.general_functions import append_to_sans_file_tag -class SANSMaskWorkspace(DataProcessorAlgorithm): +class SANSMaskWorkspace(DistributedDataProcessorAlgorithm): def category(self): return 'SANS\\Mask' diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSMove.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSMove.py index e1975d3a0c7f09709241acce0398ccabeb35475c..210dc5555f508be80b21522f8a0460bd7d54b87f 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSMove.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSMove.py @@ -5,7 +5,7 @@ from __future__ import (absolute_import, division, print_function) from mantid.kernel import (Direction, PropertyManagerProperty, StringListValidator, FloatArrayProperty) -from mantid.api import (DataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, Progress) +from mantid.api import (DistributedDataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, Progress) from sans.algorithm_detail.move_workspaces import SANSMoveFactory from sans.state.state_base import create_deserialized_sans_state_from_property_manager @@ -46,7 +46,7 @@ def get_detector_for_component(move_info, component): return selected_detector -class SANSMove(DataProcessorAlgorithm): +class SANSMove(DistributedDataProcessorAlgorithm): def category(self): return 'SANS\\Move' diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSNormalizeToMonitor.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSNormalizeToMonitor.py index c061576b1c1e1817951296c14efdd03b4021c523..f861d608921ad7e6a4e9df521d0074426ae3d78b 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSNormalizeToMonitor.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSNormalizeToMonitor.py @@ -4,14 +4,14 @@ from __future__ import (absolute_import, division, print_function) from mantid.kernel import (Direction, FloatBoundedValidator, PropertyManagerProperty) -from mantid.api import (DataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode) +from mantid.api import (ParallelDataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode) from sans.common.constants import EMPTY_NAME from sans.common.general_functions import create_unmanaged_algorithm from sans.common.enums import RebinType, RangeStepType from sans.state.state_base import create_deserialized_sans_state_from_property_manager -class SANSNormalizeToMonitor(DataProcessorAlgorithm): +class SANSNormalizeToMonitor(ParallelDataProcessorAlgorithm): def category(self): return 'SANS\\Adjust' diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSReductionCore.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSReductionCore.py index cc17388d70108e4e009abe6a2d2ce18a87a4fe1f..388bd52f3b6eba947ab3eceecb78cdf5143de51d 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSReductionCore.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSReductionCore.py @@ -4,7 +4,7 @@ from __future__ import (absolute_import, division, print_function) from mantid.kernel import (Direction, PropertyManagerProperty, StringListValidator) -from mantid.api import (DataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, +from mantid.api import (DistributedDataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, IEventWorkspace, Progress) from sans.state.state_base import create_deserialized_sans_state_from_property_manager @@ -13,7 +13,7 @@ from sans.common.general_functions import (create_child_algorithm, append_to_san from sans.common.enums import (DetectorType, DataType) -class SANSReductionCore(DataProcessorAlgorithm): +class SANSReductionCore(DistributedDataProcessorAlgorithm): def category(self): return 'SANS\\Reduction' diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSScale.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSScale.py index b1c77dd643f73fb8d11ac6f9ca4a70679b98cf80..7567b4eb06c888a6873d24fe36bf4f1316616527 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSScale.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSScale.py @@ -4,14 +4,14 @@ from __future__ import (absolute_import, division, print_function) from mantid.kernel import (Direction, PropertyManagerProperty) -from mantid.api import (DataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, Progress) +from mantid.api import (DistributedDataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, Progress) from sans.state.state_base import create_deserialized_sans_state_from_property_manager from sans.algorithm_detail.scale_helpers import (DivideByVolumeFactory, MultiplyByAbsoluteScaleFactory) from sans.common.general_functions import (append_to_sans_file_tag) -class SANSScale(DataProcessorAlgorithm): +class SANSScale(DistributedDataProcessorAlgorithm): def category(self): return 'SANS\\Scale' diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSSingleReduction.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSSingleReduction.py index 8b1296ca49ee857e2bd9c7aceb15cb31c2513096..3a57a652d7834573212a1cfe769d615cebbd6578 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSSingleReduction.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSSingleReduction.py @@ -4,7 +4,7 @@ from __future__ import (absolute_import, division, print_function) from mantid.kernel import (Direction, PropertyManagerProperty, Property) -from mantid.api import (DataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, Progress) +from mantid.api import (DistributedDataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, Progress) from sans.state.state_base import create_deserialized_sans_state_from_property_manager from sans.common.enums import (ReductionMode, DataType, ISISReductionMode) @@ -14,7 +14,7 @@ from sans.algorithm_detail.single_execution import (run_core_reduction, get_fina from sans.algorithm_detail.bundles import ReductionSettingBundle -class SANSSingleReduction(DataProcessorAlgorithm): +class SANSSingleReduction(DistributedDataProcessorAlgorithm): def category(self): return 'SANS\\Reduction' @@ -312,6 +312,9 @@ class SANSSingleReduction(DataProcessorAlgorithm): # HAB or LAB anywhere which means that in the future there could be other detectors of relevance. Here we # reference HAB and LAB directly since we currently don't want to rely on dynamic properties. See also in PyInit for reduction_mode, output_workspace in list(reduction_mode_vs_output_workspaces.items()): + # In an MPI reduction output_workspace is produced on the master rank, skip others. + if output_workspace is None: + continue if reduction_mode is ReductionMode.Merged: self.setProperty("OutputWorkspaceMerged", output_workspace) elif reduction_mode is ISISReductionMode.LAB: diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSSliceEvent.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSSliceEvent.py index bdd93f07afe04d08b9b96764c8819ec05fe046b0..e65b923bf0676662f929b0318a90ea5371d3fcee 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSSliceEvent.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSSliceEvent.py @@ -4,7 +4,7 @@ from __future__ import (absolute_import, division, print_function) from mantid.kernel import (Direction, PropertyManagerProperty, StringListValidator) -from mantid.api import (DataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, Progress) +from mantid.api import (DistributedDataProcessorAlgorithm, MatrixWorkspaceProperty, AlgorithmFactory, PropertyMode, Progress) from sans.algorithm_detail.slicer import (SliceEventFactory, get_scaled_workspace) from sans.common.general_functions import append_to_sans_file_tag @@ -12,7 +12,7 @@ from sans.common.enums import DataType from sans.state.state_base import create_deserialized_sans_state_from_property_manager -class SANSSliceEvent(DataProcessorAlgorithm): +class SANSSliceEvent(DistributedDataProcessorAlgorithm): def category(self): return 'SANS\\SliceEvent' diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSFitShiftScale.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSFitShiftScale.py index 288a05f92748fdec45e1fc01e6048d99fd938e7d..d9978e9d5e429643cbd4a858357aab468cb77696 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSFitShiftScale.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSFitShiftScale.py @@ -3,7 +3,7 @@ from __future__ import (absolute_import, division, print_function) from mantid.simpleapi import * -from mantid.api import DataProcessorAlgorithm, MatrixWorkspaceProperty, PropertyMode, AnalysisDataService +from mantid.api import ParallelDataProcessorAlgorithm, MatrixWorkspaceProperty, PropertyMode, AnalysisDataService from mantid.kernel import Direction, Property, StringListValidator, UnitFactory import numpy as np @@ -22,7 +22,7 @@ class Mode(object): pass -class SANSFitShiftScale(DataProcessorAlgorithm): +class SANSFitShiftScale(ParallelDataProcessorAlgorithm): def _make_mode_map(self): return {'ShiftOnly': Mode.ShiftOnly, 'ScaleOnly': Mode.ScaleOnly, 'Both': Mode.BothFit, 'None': Mode.NoneFit} diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSStitch.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSStitch.py index 1ca854a50cb9624f041e4f31fc612e51431d14ca..600c6e8a6ab050588816c8072b6895044c09f007 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSStitch.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSStitch.py @@ -3,7 +3,7 @@ from __future__ import (absolute_import, division, print_function) from mantid.simpleapi import * -from mantid.api import DataProcessorAlgorithm, MatrixWorkspaceProperty, PropertyMode +from mantid.api import ParallelDataProcessorAlgorithm, MatrixWorkspaceProperty, PropertyMode from mantid.kernel import Direction, Property, StringListValidator, UnitFactory, \ EnabledWhenProperty, PropertyCriterion import numpy as np @@ -25,7 +25,7 @@ class Mode(object): pass -class SANSStitch(DataProcessorAlgorithm): +class SANSStitch(ParallelDataProcessorAlgorithm): def _make_mode_map(self): return {'ShiftOnly': Mode.ShiftOnly, 'ScaleOnly': Mode.ScaleOnly, 'Both': Mode.BothFit, 'None': Mode.NoneFit} diff --git a/Testing/SystemTests/tests/analysis/SANS2DSlicingTest_V2.py b/Testing/SystemTests/tests/analysis/SANS2DSlicingTest_V2.py index 9c9a9534fe974bbaeb091c8e85c9d4c7e2647278..3be8ef338c9b3dd611c5181695779efc47ed35a0 100644 --- a/Testing/SystemTests/tests/analysis/SANS2DSlicingTest_V2.py +++ b/Testing/SystemTests/tests/analysis/SANS2DSlicingTest_V2.py @@ -27,7 +27,10 @@ class SANS2DMinimalBatchReductionSlicedTest_V2(stresstesting.MantidStressTest): self.tolerance = 0.02 self.tolerance_is_reller=True self.disableChecking.append('Instrument') - return str(AnalysisDataService['trans_test_rear'][0]), 'SANSReductionGUI.nxs' + try: + return str(AnalysisDataService['trans_test_rear'][0]), 'SANSReductionGUI.nxs' + except KeyError: + return '', 'SANSReductionGUI.nxs' class SANS2DMinimalSingleReductionSlicedTest_V2(stresstesting.MantidStressTest): diff --git a/buildconfig/CMake/Packaging/mantidpython.in b/buildconfig/CMake/Packaging/mantidpython.in index e1a2150fa10a6bb8d1dfd4a4cebdf7dccb3114c4..2eb2ba7c728cbc47f1a26996abcb7896c92b3b04 100755 --- a/buildconfig/CMake/Packaging/mantidpython.in +++ b/buildconfig/CMake/Packaging/mantidpython.in @@ -51,6 +51,11 @@ if [ -n "$1" ] && [ "$1" = "--classic" ]; then set -- @WRAPPER_PREFIX@@PYTHON_EXECUTABLE@ $*@WRAPPER_POSTFIX@ +elif [ -n "$1" ] && [ -n "$2" ] && [ "$1" = "-n" ]; then + ranks=$2 + shift 2 + set -- mpirun -n $ranks @WRAPPER_PREFIX@@PYTHON_EXECUTABLE@ $*@WRAPPER_POSTFIX@ + else IPYTHON_STARTUP="import IPython;IPython.start_ipython()" diff --git a/docs/source/algorithms/ClearMaskedSpectra-v1.rst b/docs/source/algorithms/ClearMaskedSpectra-v1.rst new file mode 100644 index 0000000000000000000000000000000000000000..8574b039493519022bd0ec47722942f4b3c66b02 --- /dev/null +++ b/docs/source/algorithms/ClearMaskedSpectra-v1.rst @@ -0,0 +1,44 @@ + +.. algorithm:: + +.. summary:: + +.. alias:: + +.. properties:: + +Description +----------- + +Clear counts (or events, if applicable) on all spectra that are fully masked. +A spectrum is fully masked if all of its associated detectors are masked, e.g., from a call to `MaskInstrument`. + +Usage +----- + +**Example - ClearMaskedSpectra** + +.. testcode:: ClearMaskedSpectraExample + + ws = CreateSampleWorkspace() + ws = MaskInstrument(InputWorkspace=ws, DetectorIDs='100,102-104') + ws = ClearMaskedSpectra(InputWorkspace=ws) + # Detectors are masked but data is untouched + for i in range(6): + print("Detector {} masked: {:5} data {}".format(i, str(ws.getDetector(i).isMasked()), ws.readY(i)[0])) + +Output: + +.. testoutput:: ClearMaskedSpectraExample + + Detector 0 masked: True data 0.0 + Detector 1 masked: False data 0.3 + Detector 2 masked: True data 0.0 + Detector 3 masked: True data 0.0 + Detector 4 masked: True data 0.0 + Detector 5 masked: False data 0.3 + +.. categories:: + +.. sourcelink:: + diff --git a/docs/source/algorithms/MaskInstrument-v1.rst b/docs/source/algorithms/MaskInstrument-v1.rst new file mode 100644 index 0000000000000000000000000000000000000000..5fbf728786696e7b6c46fb64d96627b8b36ebc92 --- /dev/null +++ b/docs/source/algorithms/MaskInstrument-v1.rst @@ -0,0 +1,44 @@ + +.. algorithm:: + +.. summary:: + +.. alias:: + +.. properties:: + +Description +----------- + +Mask specified detectors in an instrument. +This is does *not* clear the data in associated spectra in the workspace. +To clear the data manually ``ClearMaskedSpectra`` can be called. + +Usage +----- + +**Example - MaskInstrument** + +.. testcode:: MaskInstrumentExample + + ws = CreateSampleWorkspace() + ws = MaskInstrument(InputWorkspace=ws, DetectorIDs='100,102-104') + # Detectors are masked but data is untouched + for i in range(6): + print("Detector {} masked: {:5} data {}".format(i, str(ws.getDetector(i).isMasked()), ws.readY(i)[0])) + +Output: + +.. testoutput:: MaskInstrumentExample + + Detector 0 masked: True data 0.3 + Detector 1 masked: False data 0.3 + Detector 2 masked: True data 0.3 + Detector 3 masked: True data 0.3 + Detector 4 masked: True data 0.3 + Detector 5 masked: False data 0.3 + +.. categories:: + +.. sourcelink:: + diff --git a/docs/source/development/AlgorithmMPISupport.rst b/docs/source/development/AlgorithmMPISupport.rst index ab095259a509d52917faf1a430007c6b70147857..d1537164bcb853f74dfadbaf0a6127028d2684b1 100644 --- a/docs/source/development/AlgorithmMPISupport.rst +++ b/docs/source/development/AlgorithmMPISupport.rst @@ -139,6 +139,19 @@ Build with MPI support To build Mantid with MPI support as described in this document run ``cmake`` with the additional option ``-DMPI_EXPERIMENTAL=ON``. This requires ``boost-mpi`` and a working MPI installation. +Configuration +------------- + +To avoid unintentional DDOSing or potential other issues, there is no MPI support for ``DownloadInstrument`` and ``CheckMantidVersion``. +Error messages can be avoided by disabling these startup checks in the configuration. +Furthermore, to avoid pollution of usage reports, usage reporting should be disabled: + +.. code-block:: sh + + UpdateInstrumentDefinitions.OnStartup = 0 + CheckMantidVersion.OnStartup = 0 + usagereports.enabled = 0 + Writing and running Python scripts ---------------------------------- @@ -165,15 +178,11 @@ For example: print(ws.readY(i)) -Run Python with ``mpirun`` and the desired number of MPI ranks: +Run Python with ``mpirun`` and the desired number of MPI ranks, by using the new ``-n`` flag to ``mantidpython``: .. code-block:: sh - mpirun -n 3 python test.py - -Note that directly using the Mantid Python wrapper ``mantidpython`` is not possible, i.e., ``mpirun -n 3 mantidpython test.py`` does not work. -Instead the correct paths to Mantid and library preloads should be set manually. -Alternatively, a modified version of ``mantidpython`` that internally uses ``mpirun`` to call python could be created. + mantidpython -n 3 test.py Possible output: @@ -276,6 +285,7 @@ The level of thereby enabled MPI support is as follows: In the latter two cases more than one execution mode is supported. Thus this usually works only for algorithms with a single input (and a single output) such that the execution mode can be uniquely derived from the storage mode of the input workpace. +Multiple inputs are also supported to a certain extent. For example, for ``API::DistributedAlgorithm`` the storage modes of the inputs can be mixed if they are compatible, such as ``StorageMode::Distributed`` with ``StorageMode::Cloned`` (resulting in ``ExecutionMode::Distributed``). If none of the other virtual methods listed above is implemented, ``Algorithm`` will run the normal ``exec()`` method on all MPI ranks. The exception are non-master ranks if the execution mode is ``ExecutionMode::MasterOnly`` -- in that case creating a dummy workspace is attempted. @@ -456,116 +466,158 @@ Documentation When adding MPI support for an algorithm, add it to the table at the end of this document. Potential limitations must be described in the comments. +Porting Python reduction scripts in practice +-------------------------------------------- + +The mechanism of execution modes and storage modes allows for "guided" porting of algorithms as follows: + +1. Run Python script such as a system test with two (or more) MPI ranks. +2. At some point an algorithm without any MPI support or inadequate MPI support may be encountered, resulting in an error message similar to this: + + .. code-block:: none + + MyAlg-[Error] Error in execution of algorithm MyAlg: + MyAlg-[Error] Algorithm does not support execution with input workspaces of the following storage types: + MyAlg-[Error] InputWorkspace Parallel::StorageMode::Distributed + MyAlg-[Error] InputWorkspaceMonitor Parallel::StorageMode::Cloned + MyAlg-[Error] . + +3. Add the required MPI support to ``MyAlg`` with one of the mechanisms described above. In rare cases the combination of storage modes of the inputs may be unexpected, indicating an error earlier in the chain which needs to be fixed. +4. Go to 1., until the script finishes successfully. + Supported Algorithms #################### -================================= ======================= ======== -Algorithm Supported modes Comments -================================= ======================= ======== -BinaryOperation all not supported if ``AllowDifferentNumberSpectra`` is enabled -CalculateChiSquared MasterOnly, Identical see ``IFittingAlgorithm`` -CalculateCostFunction MasterOnly, Identical see ``IFittingAlgorithm`` -CalculateFlatBackground MasterOnly, Identical -CalculateTransmission MasterOnly, Identical -CloneWorkspace all -CompareWorkspace MasterOnly, Identical if one input has ``StorageMode::Cloned`` and the other has ``StorageMode::MasterOnly`` then ``ExecutionMode::MasterOnly`` is used -CompressEvents all -ConvertToHistogram all -ConvertToPointData all -ConvertUnits all ``AlignBins`` not supported; for indirect energy mode the number of resulting bins is in general inconsistent across MPI ranks -CreateSingleValuedWorkspace Identical ``OutputWorkspace`` has ``StorageMode::Cloned``, support of ``MasterOnly`` would require adding property for selecting the mode -CreateWorkspace all -CropToComponent all -CropWorkspace all see ``ExtractSpectra`` regarding X cropping -Divide all see ``BinaryOperation`` -EstimateFitParameters MasterOnly, Identical see ``IFittingAlgorithm`` -EvaluateFunction MasterOnly, Identical see ``IFittingAlgorithm`` -ExponentialCorrection all see ``UnaryOperation`` -ExtractSingleSpectrum all in practice ``ExecutionMode::Distributed`` not supported due to current nonzero-spectrum-count limitation -ExtractSpectra2 all currently not available via algorithm factory or Python -ExtractSpectra all not supported with ``DetectorList``, cropping in X may exhibit inconsistent behavior in case spectra have common boundaries within some ranks but not within all ranks or across ranks -FilterBadPulses all -FilterByLogValue all -FilterByTime all -FilterEventsByLogValuePreNexus Identical see ``IFileLoader`` -FindDetectorsInShape all -Fit MasterOnly, Identical see ``IFittingAlgorithm`` -GroupWorkspaces all -IFileLoader Identical implicitly adds support for many load-algorithms inheriting from this -IFittingAlgorithm MasterOnly, Identical implicitly adds support for several fit-algorithms inheriting from this -Load all actual supported mode is dictated by underlying load algorithm, which depends on file type -LoadAscii2 Identical see ``IFileLoader`` -LoadAscii Identical see ``IFileLoader`` -LoadBBY Identical see ``IFileLoader`` -LoadCanSAS1D Identical see ``IFileLoader`` -LoadDaveGrp Identical see ``IFileLoader`` -LoadEmptyInstrument Identical see ``IFileLoader`` -LoadEventNexus Distributed storage mode of output cannot be changed via a parameter currently, min and max bin boundary are not globally the same -LoadEventPreNexus2 Identical see ``IFileLoader`` -LoadFITS Identical see ``IFileLoader`` -LoadGSS Identical see ``IFileLoader`` -LoadILLDiffraction Identical see ``IFileLoader`` -LoadILLIndirect2 Identical see ``IFileLoader`` -LoadILLReflectometry Identical see ``IFileLoader`` -LoadILLSANS Identical see ``IFileLoader`` -LoadILLTOF2 Identical see ``IFileLoader`` -LoadInstrument all -LoadIsawPeaks Identical see ``IFileLoader`` -LoadISISNexus2 Identical see ``IFileLoader`` -LoadLLB Identical see ``IFileLoader`` -LoadMcStas Identical see ``IFileLoader`` -LoadMcStasNexus Identical see ``IFileLoader`` -LoadMD Identical see ``IFileLoader`` -LoadMLZ Identical see ``IFileLoader`` -LoadMuonNexus Identical see ``IFileLoader`` -LoadNexusLogs all -LoadNexusMonitors2 Identical -LoadNexusProcessed Identical see ``IFileLoader`` -LoadNXcanSAS Identical see ``IFileLoader`` -LoadNXSPE Identical see ``IFileLoader`` -LoadParameterFile all segfaults when used in unit tests with MPI threading backend due to `#9365 <https://github.com/mantidproject/mantid/issues/9365>`_, normal use should be ok -LoadPDFgetNFile Identical see ``IFileLoader`` -LoadPreNexus Identical see ``IFileLoader`` -LoadQKK Identical see ``IFileLoader`` -LoadRawHelper Identical see ``IFileLoader`` -LoadRKH Identical see ``IFileLoader`` -LoadSassena Identical see ``IFileLoader`` -LoadSESANS Identical see ``IFileLoader`` -LoadSINQFocus Identical see ``IFileLoader`` -LoadSNSspec Identical see ``IFileLoader`` -LoadSPE Identical see ``IFileLoader`` -LoadSpice2D Identical see ``IFileLoader`` -LoadSQW2 Identical see ``IFileLoader`` -LoadSQW Identical see ``IFileLoader`` -LoadSwans Identical see ``IFileLoader`` -LoadTBL Identical see ``IFileLoader`` -LoadTOFRawNexus Identical see ``IFileLoader`` -Logarithm all see ``UnaryOperation`` -MaskBins all -MaskDetectorsInShape all -MaskSpectra all -Minus all see ``BinaryOperation`` -MoveInstrumentComponent all -Multiply all see ``BinaryOperation`` -OneMinusExponentialCor all see ``UnaryOperation`` -Plus all see ``BinaryOperation`` -PoissonErrors all see ``BinaryOperation`` -PolynomialCorrection all see ``UnaryOperation`` -Power all see ``UnaryOperation`` -PowerLawCorrection all see ``UnaryOperation`` -Rebin all min and max bin boundaries must be given explicitly -RebinToWorkspace all ``WorkspaceToMatch`` must have ``StorageMode::Cloned`` -RemovePromptPulse all -ReplaceSpecialValues all see ``UnaryOperation`` -RotateInstrumentComponent all -SaveNexus MasterOnly -SaveNexusProcessed MasterOnly -SignalOverError all see ``UnaryOperation`` -SortEvents all -SumSpectra MasterOnly, Identical -UnaryOperation all -WeightedMean all see ``BinaryOperation`` -================================= ======================= ======== +====================================== ======================= ======== +Algorithm Supported modes Comments +====================================== ======================= ======== +BinaryOperation all not supported if ``AllowDifferentNumberSpectra`` is enabled +CalculateChiSquared MasterOnly, Identical see ``IFittingAlgorithm`` +CalculateCostFunction MasterOnly, Identical see ``IFittingAlgorithm`` +CalculateFlatBackground MasterOnly, Identical +CalculateTransmission MasterOnly, Identical +CloneWorkspace all +Comment all +CompareWorkspace MasterOnly, Identical if one input has ``StorageMode::Cloned`` and the other has ``StorageMode::MasterOnly`` then ``ExecutionMode::MasterOnly`` is used, with ``ExecutionMode::MasterOnly`` the workspaces always compare equal on non-master ranks +CompressEvents all +ConvertToHistogram all +ConvertToPointData all +ConvertUnits all ``AlignBins`` not supported; for indirect energy mode the number of resulting bins is in general inconsistent across MPI ranks +CopyInstrumentParameters all +CreateSingleValuedWorkspace Identical ``OutputWorkspace`` has ``StorageMode::Cloned``, support of ``MasterOnly`` would require adding property for selecting the mode +CreateWorkspace all +CropToComponent all +CropWorkspace all see ``ExtractSpectra`` regarding X cropping +DeleteWorkspace all +Divide all see ``BinaryOperation`` +EstimateFitParameters MasterOnly, Identical see ``IFittingAlgorithm`` +EvaluateFunction MasterOnly, Identical see ``IFittingAlgorithm`` +ExponentialCorrection all see ``UnaryOperation`` +ExtractSingleSpectrum all in practice ``ExecutionMode::Distributed`` not supported due to current nonzero-spectrum-count limitation +ExtractSpectra2 all currently not available via algorithm factory or Python +ExtractSpectra all not supported with ``DetectorList``, cropping in X may exhibit inconsistent behavior in case spectra have common boundaries within some ranks but not within all ranks or across ranks +FilterBadPulses all +FilterByLogValue all +FilterByTime all +FilterEventsByLogValuePreNexus Identical see ``IFileLoader`` +FindDetectorsInShape all +Fit MasterOnly, Identical see ``IFittingAlgorithm`` +GroupWorkspaces all grouping workspaces with mixed ``StorageMode`` is not supported +IFileLoader Identical implicitly adds support for many load-algorithms inheriting from this +IFittingAlgorithm MasterOnly, Identical implicitly adds support for several fit-algorithms inheriting from this +Load all actual supported mode is dictated by underlying load algorithm, which depends on file type +LoadAscii2 Identical see ``IFileLoader`` +LoadAscii Identical see ``IFileLoader`` +LoadBBY Identical see ``IFileLoader`` +LoadCanSAS1D Identical see ``IFileLoader`` +LoadDaveGrp Identical see ``IFileLoader`` +LoadEmptyInstrument Identical see ``IFileLoader`` +LoadEventNexus Distributed storage mode of output cannot be changed via a parameter currently, min and max bin boundary are not globally the same +LoadEventPreNexus2 Identical see ``IFileLoader`` +LoadFITS Identical see ``IFileLoader`` +LoadGSS Identical see ``IFileLoader`` +LoadILLDiffraction Identical see ``IFileLoader`` +LoadILLIndirect2 Identical see ``IFileLoader`` +LoadILLReflectometry Identical see ``IFileLoader`` +LoadILLSANS Identical see ``IFileLoader`` +LoadILLTOF2 Identical see ``IFileLoader`` +LoadInstrument all +LoadIsawPeaks Identical see ``IFileLoader`` +LoadISISNexus2 Identical see ``IFileLoader`` +LoadLLB Identical see ``IFileLoader`` +LoadMask Identical +LoadMcStas Identical see ``IFileLoader`` +LoadMcStasNexus Identical see ``IFileLoader`` +LoadMD Identical see ``IFileLoader`` +LoadMLZ Identical see ``IFileLoader`` +LoadMuonNexus Identical see ``IFileLoader`` +LoadNexusLogs all +LoadNexusMonitors2 Identical +LoadNexusProcessed Identical see ``IFileLoader`` +LoadNXcanSAS Identical see ``IFileLoader`` +LoadNXSPE Identical see ``IFileLoader`` +LoadParameterFile all segfaults when used in unit tests with MPI threading backend due to `#9365 <https://github.com/mantidproject/mantid/issues/9365>`_, normal use should be ok +LoadPDFgetNFile Identical see ``IFileLoader`` +LoadPreNexus Identical see ``IFileLoader`` +LoadQKK Identical see ``IFileLoader`` +LoadRawHelper Identical see ``IFileLoader`` +LoadRKH Identical see ``IFileLoader`` +LoadSassena Identical see ``IFileLoader`` +LoadSESANS Identical see ``IFileLoader`` +LoadSINQFocus Identical see ``IFileLoader`` +LoadSNSspec Identical see ``IFileLoader`` +LoadSPE Identical see ``IFileLoader`` +LoadSpice2D Identical see ``IFileLoader`` +LoadSQW2 Identical see ``IFileLoader`` +LoadSQW Identical see ``IFileLoader`` +LoadSwans Identical see ``IFileLoader`` +LoadTBL Identical see ``IFileLoader`` +LoadTOFRawNexus Identical see ``IFileLoader`` +Logarithm all see ``UnaryOperation`` +MaskBins all +MaskDetectorsInShape all +MaskSpectra all +Minus all see ``BinaryOperation`` +MoveInstrumentComponent all +Multiply all see ``BinaryOperation`` +OneMinusExponentialCor all see ``UnaryOperation`` +Q1D2 all not all optional normalization inputs are supported +Plus all see ``BinaryOperation`` +PoissonErrors all see ``BinaryOperation`` +PolynomialCorrection all see ``UnaryOperation`` +Power all see ``UnaryOperation`` +PowerLawCorrection all see ``UnaryOperation`` +Rebin all min and max bin boundaries must be given explicitly +RebinToWorkspace all ``WorkspaceToMatch`` must have ``StorageMode::Cloned`` +RemovePromptPulse all +ReplaceSpecialValues all see ``UnaryOperation`` +RotateInstrumentComponent all +SANSCalculateTransmission MasterOnly, Identical +SANSConvertToQ all +SANSConvertToWavelength all +SANSConvertToWavelengthAndRebin all +SANSCreateAdjustmentWorkspaces all +SANSCreateWavelengthAndPixelAdjustment MasterOnly, Identical +SANSCrop all +SANSFitShiftScale MasterOnly, Identical +SANSLoad MasterOnly, Identical child algorithms may actually be run with ``ExecutionMode::Distributed`` if that is their default +SANSMaskWorkspace all +SANSMove all +SANSNormalizeToMonitor MasterOnly, Identical +SANSReductionCore all +SANSScale all +SANSSingleReduction all +SANSSliceEvent all +SANSStitch MasterOnly, Identical +SaveNexus MasterOnly +SaveNexusProcessed MasterOnly +Scale all +SignalOverError all see ``UnaryOperation`` +SortEvents all +SumSpectra MasterOnly, Identical +UnaryOperation all +WeightedMean all see ``BinaryOperation`` +====================================== ======================= ======== Currently none of the above algorithms works with ``StorageMode::Distributed`` in case there are zero spectra on any rank. diff --git a/scripts/SANS/sans/algorithm_detail/mask_workspace.py b/scripts/SANS/sans/algorithm_detail/mask_workspace.py index dd1234632a1cd6037421d67c643bdf96a2c980c7..10caf14904c97a8cd0e277d8087150da9927e1eb 100644 --- a/scripts/SANS/sans/algorithm_detail/mask_workspace.py +++ b/scripts/SANS/sans/algorithm_detail/mask_workspace.py @@ -118,11 +118,11 @@ def mask_with_mask_files(mask_info, workspace): load_options = {"Instrument": idf_path, "OutputWorkspace": EMPTY_NAME} load_alg = create_unmanaged_algorithm(load_name, **load_options) + dummy_params = {"OutputWorkspace": EMPTY_NAME} + mask_alg = create_unmanaged_algorithm("MaskInstrument", **dummy_params) + clear_alg = create_unmanaged_algorithm("ClearMaskedSpectra", **dummy_params) # Masker - mask_name = "MaskDetectors" - mask_options = {"ForceInstrumentMasking": True} - mask_alg = create_unmanaged_algorithm(mask_name, **mask_options) for mask_file in mask_files: mask_file = find_full_file_path(mask_file) @@ -130,11 +130,21 @@ def mask_with_mask_files(mask_info, workspace): load_alg.setProperty("InputFile", mask_file) load_alg.execute() masking_workspace = load_alg.getProperty("OutputWorkspace").value - # Mask the detector ids on the original workspace - mask_alg.setProperty("Workspace", workspace) - mask_alg.setProperty("MaskedWorkspace", masking_workspace) + # Could use MaskDetectors directly with masking_workspace but it does not + # support MPI. Use a three step approach via a, b, and c instead. + # a) Extract detectors to mask from MaskWorkspace + det_ids = masking_workspace.getMaskedDetectors() + # b) Mask the detector ids on the instrument + mask_alg.setProperty("InputWorkspace", workspace) + mask_alg.setProperty("OutputWorkspace", workspace) + mask_alg.setProperty("DetectorIDs", det_ids) mask_alg.execute() - workspace = mask_alg.getProperty("Workspace").value + workspace = mask_alg.getProperty("OutputWorkspace").value + # c) Clear data in all spectra associated with masked detectors + clear_alg.setProperty("InputWorkspace", workspace) + clear_alg.setProperty("OutputWorkspace", workspace) + clear_alg.execute() + workspace = clear_alg.getProperty("OutputWorkspace").value return workspace @@ -243,12 +253,15 @@ def mask_spectra(mask_info, workspace, spectra_block, detector_type): # Perform the masking if total_spectra: - mask_name = "MaskDetectors" - mask_options = {"Workspace": workspace, - "SpectraList": total_spectra} + mask_name = "MaskSpectra" + mask_options = {"InputWorkspace": workspace, + "InputWorkspaceIndexType": "SpectrumNumber", + "OutputWorkspace": "__dummy"} mask_alg = create_unmanaged_algorithm(mask_name, **mask_options) + mask_alg.setProperty("InputWorkspaceIndexSet", list(set(total_spectra))) + mask_alg.setProperty("OutputWorkspace", workspace) mask_alg.execute() - workspace = mask_alg.getProperty("Workspace").value + workspace = mask_alg.getProperty("OutputWorkspace").value return workspace diff --git a/scripts/SANS/sans/algorithm_detail/single_execution.py b/scripts/SANS/sans/algorithm_detail/single_execution.py index 63f78b7ddef7bac25e93768f0ee2df2903dbafaa..dbaa3eaab6dbef022cefab96bb1e1c2a633e42f8 100644 --- a/scripts/SANS/sans/algorithm_detail/single_execution.py +++ b/scripts/SANS/sans/algorithm_detail/single_execution.py @@ -7,6 +7,8 @@ from sans.common.enums import (ISISReductionMode, DetectorType, DataType, Output from sans.algorithm_detail.strip_end_nans_and_infs import strip_end_nans from sans.algorithm_detail.merge_reductions import (MergeFactory, is_sample, is_can) from sans.algorithm_detail.bundles import (OutputBundle, OutputPartsBundle) +from mantid.kernel import mpisetup +import sys def run_core_reduction(reduction_alg, reduction_setting_bundle): @@ -230,7 +232,14 @@ def run_optimized_for_can(reduction_alg, reduction_setting_bundle): output_parts_bundle.output_workspace_norm is None)) partial_output_require_reload = output_parts and is_invalid_partial_workspaces - if output_bundle.output_workspace is None or partial_output_require_reload: + must_reload = output_bundle.output_workspace is None or partial_output_require_reload + if 'boost.mpi' in sys.modules: + # In MPI runs the result is only present on rank 0 (result of Q1D2 integration), + # so the reload flag must be broadcasted from rank 0. + must_reload = mpisetup.boost.mpi.broadcast(mpisetup.boost.mpi.world, must_reload, 0) + + if must_reload: + #if output_bundle.output_workspace is None or partial_output_require_reload: output_bundle, output_parts_bundle = run_core_reduction(reduction_alg, reduction_setting_bundle) # Now we need to tag the workspaces and add it to the ADS diff --git a/scripts/SANS/sans/algorithm_detail/strip_end_nans_and_infs.py b/scripts/SANS/sans/algorithm_detail/strip_end_nans_and_infs.py index 08ffc8bf566c8392ad382f49869f86045556d492..fca6921520c7c5d8305ef2001f35d5515715ffbb 100644 --- a/scripts/SANS/sans/algorithm_detail/strip_end_nans_and_infs.py +++ b/scripts/SANS/sans/algorithm_detail/strip_end_nans_and_infs.py @@ -13,7 +13,7 @@ def strip_end_nans(workspace, parent_alg=None): :return: A trimmed NAN- and INF-trimmed workspace """ # If the workspace is larger than 1D, then there is nothing we can do - if workspace.getNumberHistograms() > 1: + if workspace is None or workspace.getNumberHistograms() != 1: return workspace data = workspace.readY(0) # Find the index at which the first legal value appears diff --git a/scripts/SANS/sans/common/log_tagger.py b/scripts/SANS/sans/common/log_tagger.py index 1c5406b1bb6300a896ff2627ee74c401e9372d00..cec8b7556b0b4726850d7b9372585990209ce352 100644 --- a/scripts/SANS/sans/common/log_tagger.py +++ b/scripts/SANS/sans/common/log_tagger.py @@ -67,6 +67,8 @@ def has_tag(tag, workspace): :param workspace: the workspace to check. :return: true if the tag exists else false. """ + if workspace is None: + return False check_if_valid_tag_and_workspace(tag, workspace) run = workspace.getRun() return tag in run diff --git a/scripts/test/SANS/gui_logic/table_model_test.py b/scripts/test/SANS/gui_logic/table_model_test.py index 739b2aaaa733098e84f66bac0629c0f2b273aea0..8ac1f0d198c9b33e869ab76533d09d5ba17863d6 100644 --- a/scripts/test/SANS/gui_logic/table_model_test.py +++ b/scripts/test/SANS/gui_logic/table_model_test.py @@ -66,7 +66,7 @@ class TableModelTest(unittest.TestCase): self.assertFalse(has_raised) # Test raises for non-existent file path - self.assertRaises(ValueError, func, "/home/test") + self.assertRaises(ValueError, func, "/home/testSDFHSNDFG") # Test that can be set to valid value setattr(table_model, prop, __file__)