Commit b07180f7 authored by Karl Palmen's avatar Karl Palmen
Browse files

Merge remote-tracking branch 'origin/master' into re #12827

# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
parent 7a245f51
......@@ -112,6 +112,7 @@ set ( SRC_FILES
src/ParamFunction.cpp
src/ParameterReference.cpp
src/ParameterTie.cpp
src/ParallelAlgorithm.cpp
src/PeakFunctionIntegrator.cpp
src/Progress.cpp
src/Projection.cpp
......@@ -307,6 +308,7 @@ set ( INC_FILES
inc/MantidAPI/ParamFunction.h
inc/MantidAPI/ParameterReference.h
inc/MantidAPI/ParameterTie.h
inc/MantidAPI/ParallelAlgorithm.h
inc/MantidAPI/PeakFunctionIntegrator.h
inc/MantidAPI/Progress.h
inc/MantidAPI/Projection.h
......
......@@ -10,13 +10,11 @@
// -- These headers will (most-likely) be used by every inheriting algorithm
#include "MantidAPI/AlgorithmFactory.h" //for the factory macro
#include "MantidAPI/IndexTypeProperty.h"
#include "MantidAPI/Progress.h"
#include "MantidAPI/WorkspaceOpOverloads.h"
#include "MantidAPI/WorkspaceProperty.h"
#include "MantidKernel/EmptyValues.h"
#include "MantidKernel/MultiThreaded.h"
#include <MantidIndexing/SpectrumIndexSet.h>
#include "MantidParallel/ExecutionMode.h"
#include "MantidParallel/StorageMode.h"
......@@ -37,6 +35,9 @@ class Value;
}
namespace Mantid {
namespace Indexing {
class SpectrumIndexSet;
}
namespace Parallel {
class Communicator;
}
......@@ -201,7 +202,7 @@ public:
std::is_convertible<T1 *, MatrixWorkspace *>::value>::type,
typename = typename std::enable_if<
std::is_convertible<T2 *, std::string *>::value ||
std::is_convertible<T2 *, std::vector<int> *>::value>::type>
std::is_convertible<T2 *, std::vector<int64_t> *>::value>::type>
void setWorkspaceInputProperties(const std::string &name,
const boost::shared_ptr<T1> &wksp,
IndexType type, const T2 &list);
......@@ -211,7 +212,7 @@ public:
std::is_convertible<T1 *, MatrixWorkspace *>::value>::type,
typename = typename std::enable_if<
std::is_convertible<T2 *, std::string *>::value ||
std::is_convertible<T2 *, std::vector<int> *>::value>::type>
std::is_convertible<T2 *, std::vector<int64_t> *>::value>::type>
void setWorkspaceInputProperties(const std::string &name,
const std::string &wsName, IndexType type,
const T2 &list);
......@@ -291,6 +292,10 @@ public:
const std::string &name, const double startProgress = -1.,
const double endProgress = -1., const bool enableLogging = true,
const int &version = -1);
void setupAsChildAlgorithm(boost::shared_ptr<Algorithm> algorithm,
const double startProgress = -1.,
const double endProgress = -1.,
const bool enableLogging = true);
/// set whether we wish to track the child algorithm's history and pass it the
/// parent object to fill.
......@@ -403,13 +408,13 @@ protected:
/// versions
bool m_usingBaseProcessGroups = false;
template <typename T, typename = typename std::enable_if<std::is_convertible<
T *, MatrixWorkspace *>::value>::type>
void declareWorkspaceInputProperties(
const std::string &propertyName,
const int allowedIndexTypes = IndexType::WorkspaceIndex,
PropertyMode::Type optional = PropertyMode::Type::Mandatory,
LockMode::Type lock = LockMode::Type::Lock, const std::string &doc = "");
template <typename T, const int AllowedIndexTypes = IndexType::WorkspaceIndex,
typename... WSPropArgs,
typename = typename std::enable_if<
std::is_convertible<T *, MatrixWorkspace *>::value>::type>
void declareWorkspaceInputProperties(const std::string &propertyName,
const std::string &doc,
WSPropArgs &&... wsPropArgs);
private:
template <typename T1, typename T2, typename WsType>
......
#ifndef MANTID_API_ALGORITHM_TCC_
#define MANTID_API_ALGORITHM_TCC_
#include "MantidAPI/Algorithm.h"
#include "MantidAPI/IndexProperty.h"
#include "MantidAPI/WorkspaceProperty.h"
......@@ -25,34 +28,40 @@ namespace API {
@param propertyName Name of property which will be reserved
@param allowedIndexTypes combination of allowed index types. Default
IndexType::WorkspaceIndex
@param optional Determines if workspace property is optional. Default
PropertyMode::Type::Mandatory
@param lock Determines whether or not the workspace is locked. Default
LockMode::Type::Lock
@param wsPropArgs a parameter pack of arguments forwarded to WorkspaceProperty.
Can contain PropertyMode, LockMode, and validators.
@param doc Property documentation string.
*/
template <typename T, typename>
template <typename T, const int AllowedIndexTypes, typename... WSPropArgs,
typename>
void Algorithm::declareWorkspaceInputProperties(const std::string &propertyName,
const int allowedIndexTypes,
PropertyMode::Type optional,
LockMode::Type lock,
const std::string &doc) {
const std::string &doc,
WSPropArgs &&... wsPropArgs) {
auto wsProp = Kernel::make_unique<WorkspaceProperty<T>>(
propertyName, "", Kernel::Direction::Input, optional, lock);
propertyName, "", Kernel::Direction::Input,
std::forward<WSPropArgs>(wsPropArgs)...);
const auto &wsPropRef = *wsProp;
declareProperty(std::move(wsProp), doc);
auto indexTypePropName =
IndexTypeProperty::generatePropertyName(propertyName);
auto indexTypeProp = Kernel::make_unique<IndexTypeProperty>(
indexTypePropName, allowedIndexTypes);
indexTypePropName, AllowedIndexTypes);
const auto &indexTypePropRef = *indexTypeProp;
declareProperty(std::move(indexTypeProp));
declareProperty(std::move(indexTypeProp),
"The type of indices in the optional index set; For optimal "
"performance WorkspaceIndex should be preferred;");
auto indexPropName = IndexProperty::generatePropertyName(propertyName);
declareProperty(Kernel::make_unique<IndexProperty>(indexPropName, wsPropRef,
indexTypePropRef));
indexTypePropRef),
"An optional set of spectra that will be processed by the "
"algorithm; If not set, all spectra will be processed; The "
"indices in this list can be workspace indices or possibly "
"spectrum numbers, depending on the selection made for the "
"index type; Indices are entered as a comma-separated list "
"of values, and/or ranges; For example, '4,6,10-20,1000';");
m_reservedList.push_back(propertyName);
m_reservedList.push_back(indexTypePropName);
......@@ -101,7 +110,7 @@ void Algorithm::setWorkspaceInputProperties(const std::string &name,
/** Mechanism for setting the index property with a workspace shared pointer.
* This method can only be used if T1 is convertible to a MatrixWorkspace and
* T2 is either std::string or std::vector<int>
* T2 is either std::string or std::vector<int64_t>
@param name Property name
@param wsName Workspace name as string
......@@ -146,4 +155,6 @@ Algorithm::getWorkspaceAndIndices(const std::string &name) const {
return std::make_tuple(ws, indexSet);
}
} // namespace API
} // namespace Mantid
\ No newline at end of file
} // namespace Mantid
#endif /*MANTID_API_ALGORITHM_TCC_*/
......@@ -104,6 +104,8 @@ public:
const Run &run() const;
/// Writable version of the run object
Run &mutableRun();
void setSharedRun(Kernel::cow_ptr<Run> run);
/// Access a log for this experiment.
Kernel::Property *getLog(const std::string &log) const;
/// Access a single value from a log for this experiment.
......@@ -187,10 +189,6 @@ protected:
boost::shared_ptr<ModeratorModel> m_moderatorModel;
/// Description of the choppers for this experiment.
std::list<boost::shared_ptr<ChopperModel>> m_choppers;
/// The information on the sample environment
boost::shared_ptr<Sample> m_sample;
/// The run information
boost::shared_ptr<Run> m_run;
/// Parameters modifying the base instrument
boost::shared_ptr<Geometry::ParameterMap> m_parmap;
/// The base (unparametrized) instrument
......@@ -218,15 +216,18 @@ private:
// Loads the xml from an instrument file with some basic error handling
std::string loadInstrumentXML(const std::string &filename);
/// The information on the sample environment
Kernel::cow_ptr<Sample> m_sample;
/// The run information
Kernel::cow_ptr<Run> m_run;
/// Detector grouping information
mutable std::unordered_map<detid_t, size_t> m_det2group;
void cacheDefaultDetectorGrouping() const; // Not thread-safe
void invalidateAllSpectrumDefinitions();
mutable std::once_flag m_defaultDetectorGroupingCached;
/// Mutex to protect against cow_ptr copying
mutable std::recursive_mutex m_mutex;
mutable std::unique_ptr<Beamline::SpectrumInfo> m_spectrumInfo;
mutable std::unique_ptr<SpectrumInfo> m_spectrumInfoWrapper;
mutable std::mutex m_spectrumInfoMutex;
......
......@@ -8,7 +8,12 @@
#include <set>
class SpectrumTester;
namespace Mantid {
namespace DataObjects {
class Histogram1D;
class EventList;
}
namespace API {
class MatrixWorkspace;
......@@ -54,6 +59,9 @@ public:
void copyInfoFrom(const ISpectrum &other);
/// Copy data from another ISpectrum with double-dynamic dispatch.
virtual void copyDataFrom(const ISpectrum &source) = 0;
virtual void setX(const Kernel::cow_ptr<HistogramData::HistogramX> &X) = 0;
virtual MantidVec &dataX() = 0;
virtual const MantidVec &dataX() const = 0;
......@@ -242,6 +250,10 @@ public:
void setMatrixWorkspace(MatrixWorkspace *matrixWorkspace, const size_t index);
virtual void copyDataInto(DataObjects::EventList &) const;
virtual void copyDataInto(DataObjects::Histogram1D &) const;
virtual void copyDataInto(SpectrumTester &) const;
protected:
virtual void checkAndSanitizeHistogram(HistogramData::Histogram &){};
virtual void checkWorksWithPoints() const {}
......
......@@ -8,6 +8,9 @@
#include "MantidKernel/ArrayProperty.h"
namespace Mantid {
namespace Indexing {
class IndexInfo;
}
namespace API {
/** IndexProperty : Implementation of a property type which returns a
......@@ -40,7 +43,7 @@ namespace API {
File change history is stored at: <https://github.com/mantidproject/mantid>
Code Documentation is available at: <http://doxygen.mantidproject.org>
*/
class MANTID_API_DLL IndexProperty : public Kernel::ArrayProperty<int> {
class MANTID_API_DLL IndexProperty : public Kernel::ArrayProperty<int64_t> {
public:
IndexProperty(const std::string &name,
const IWorkspaceProperty &workspaceProp,
......@@ -50,17 +53,20 @@ public:
IndexProperty *clone() const override;
using Kernel::ArrayProperty<int>::operator=;
using Kernel::ArrayProperty<int64_t>::operator=;
bool isDefault() const override;
std::string isValid() const override;
std::string operator=(const std::string &rhs);
operator Indexing::SpectrumIndexSet() const;
Indexing::SpectrumIndexSet getIndices() const;
Indexing::IndexInfo getFilteredIndexInfo() const;
static std::string generatePropertyName(const std::string &name = "");
private:
const Indexing::IndexInfo &getIndexInfoFromWorkspace() const;
const IWorkspaceProperty &m_workspaceProp;
const IndexTypeProperty &m_indexTypeProp;
mutable Indexing::SpectrumIndexSet m_indices;
......@@ -71,4 +77,4 @@ private:
} // namespace API
} // namespace Mantid
#endif /* MANTID_API_INDEXPROPERTY_H_ */
\ No newline at end of file
#endif /* MANTID_API_INDEXPROPERTY_H_ */
......@@ -451,6 +451,7 @@ public:
/// index, weight>
typedef std::map<size_t, double> MaskList;
const MaskList &maskedBins(const size_t &workspaceIndex) const;
void setMaskedBins(const size_t workspaceIndex, const MaskList &maskedBins);
// Methods handling the internal monitor workspace
virtual void
......
#ifndef MANTID_API_PARALLELALGORITHM_H_
#define MANTID_API_PARALLELALGORITHM_H_
#include "MantidAPI/Algorithm.h"
#include "MantidAPI/DllConfig.h"
namespace Mantid {
namespace API {
/** Base class for algorithms that treat all spectra independently, i.e., we can
trivially parallelize over the spectra without changes. The assumption is that
we have one input and one output workspace. The storage mode is just
propagated from input to output. When a specific algorithm is determined to be
trivially parallel (this is a manual process), the only required change to add
MPI support is to inherit from this class instead of Algorithm. Inheriting
from ParallelAlgorithm 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.
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
in a identical manner on all MPI ranks, without requiring changes to the
algorithm, other than setting the correct execution mode via the overloads
provided by ParallelAlgorithm.
@author Simon Heybrock
@date 2017
Copyright &copy; 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_API_DLL ParallelAlgorithm : public Algorithm {
protected:
Parallel::ExecutionMode getParallelExecutionMode(
const std::map<std::string, Parallel::StorageMode> &storageModes)
const override;
};
} // namespace API
} // namespace Mantid
#endif /* MANTID_API_PARALLELALGORITHM_H_ */
......@@ -82,10 +82,6 @@ public:
MatrixWorkspace &child,
const bool differentSize) const;
void initializeFromParentWithoutLogs(const MatrixWorkspace &parent,
MatrixWorkspace &child,
const bool differentSize) const;
/// Create a ITableWorkspace
boost::shared_ptr<ITableWorkspace>
createTable(const std::string &className = "TableWorkspace") const;
......
......@@ -743,6 +743,20 @@ Algorithm_sptr Algorithm::createChildAlgorithm(const std::string &name,
const int &version) {
Algorithm_sptr alg =
AlgorithmManager::Instance().createUnmanaged(name, version);
setupAsChildAlgorithm(alg, startProgress, endProgress, enableLogging);
return alg;
}
/** Setup algorithm as child algorithm.
*
* Used internally by createChildAlgorithm. Arguments are as documented there.
* Can also be used manually for algorithms created otherwise. This allows
* running algorithms that are not declared into the factory as child
* algorithms. */
void Algorithm::setupAsChildAlgorithm(Algorithm_sptr alg,
const double startProgress,
const double endProgress,
const bool enableLogging) {
// set as a child
alg->setChild(true);
alg->setLogging(enableLogging);
......@@ -751,8 +765,8 @@ Algorithm_sptr Algorithm::createChildAlgorithm(const std::string &name,
try {
alg->initialize();
} catch (std::runtime_error &) {
throw std::runtime_error("Unable to initialise Child Algorithm '" + name +
"'");
throw std::runtime_error("Unable to initialise Child Algorithm '" +
alg->name() + "'");
}
// If output workspaces are nameless, give them a temporary name to satisfy
......@@ -783,8 +797,6 @@ Algorithm_sptr Algorithm::createChildAlgorithm(const std::string &name,
PARALLEL_CRITICAL(Algorithm_StoreWeakPtr) {
m_ChildAlgorithms.push_back(weakPtr);
}
return alg;
}
//=============================================================================================
......
......@@ -66,8 +66,7 @@ Kernel::Logger g_log("ExperimentInfo");
/** Constructor
*/
ExperimentInfo::ExperimentInfo()
: m_moderatorModel(), m_choppers(), m_sample(new Sample()),
m_run(new Run()), m_parmap(new ParameterMap()),
: m_moderatorModel(), m_choppers(), m_parmap(new ParameterMap()),
sptr_instrument(new Instrument()) {
m_parmap->setInstrument(sptr_instrument.get());
}
......@@ -91,7 +90,7 @@ ExperimentInfo::~ExperimentInfo() = default;
*/
void ExperimentInfo::copyExperimentInfoFrom(const ExperimentInfo *other) {
m_sample = other->m_sample;
m_run = other->m_run->clone();
m_run = other->m_run;
this->setInstrument(other->getInstrument());
if (other->m_moderatorModel)
m_moderatorModel = other->m_moderatorModel->clone();
......@@ -602,30 +601,17 @@ ChopperModel &ExperimentInfo::chopperModel(const size_t index) const {
*/
const Sample &ExperimentInfo::sample() const {
populateIfNotLoaded();
std::lock_guard<std::recursive_mutex> lock(m_mutex);
return *m_sample;
}
/** Get a reference to the Sample associated with this workspace.
* This non-const method will copy the sample if it is shared between
* more than one workspace, and the reference returned will be to the copy.
* Can ONLY be taken by reference!
* @return reference to sample object
*/
Sample &ExperimentInfo::mutableSample() {
populateIfNotLoaded();
// Use a double-check for sharing so that we only
// enter the critical region if absolutely necessary
if (!m_sample.unique()) {
std::lock_guard<std::recursive_mutex> lock(m_mutex);
// Check again because another thread may have taken copy
// and dropped reference count since previous check
if (!m_sample.unique()) {
boost::shared_ptr<Sample> oldData = m_sample;
m_sample = boost::make_shared<Sample>(*oldData);
}
}
return *m_sample;
return m_sample.access();
}
/** Get a constant reference to the Run object associated with this workspace.
......@@ -633,30 +619,22 @@ Sample &ExperimentInfo::mutableSample() {
*/
const Run &ExperimentInfo::run() const {
populateIfNotLoaded();
std::lock_guard<std::recursive_mutex> lock(m_mutex);
return *m_run;
}
/** Get a reference to the Run object associated with this workspace.
* This non-const method will copy the Run object if it is shared between
* more than one workspace, and the reference returned will be to the copy.
* Can ONLY be taken by reference!
* @return reference to Run object
*/
Run &ExperimentInfo::mutableRun() {
populateIfNotLoaded();
// Use a double-check for sharing so that we only
// enter the critical region if absolutely necessary
if (!m_run.unique()) {
std::lock_guard<std::recursive_mutex> lock(m_mutex);
// Check again because another thread may have taken copy
// and dropped reference count since previous check
if (!m_run.unique()) {
boost::shared_ptr<Run> oldData = m_run;
m_run = boost::make_shared<Run>(*oldData);
}
}
return *m_run;
return m_run.access();
}
/// Set the run object. Use in particular to clear run without copying old run.
void ExperimentInfo::setSharedRun(Kernel::cow_ptr<Run> run) {
m_run = std::move(run);
}
/**
......
......@@ -199,5 +199,19 @@ void ISpectrum::invalidateSpectrumDefinition() const {
m_matrixWorkspace->invalidateSpectrumDefinition(m_index);
}
/// Override in child classes for polymorphic copying of data.
void ISpectrum::copyDataInto(DataObjects::EventList &) const {
throw std::runtime_error("Incompatible types in ISpectrum::copyDataFrom");
}
/// Override in child classes for polymorphic copying of data.
void ISpectrum::copyDataInto(DataObjects::Histogram1D &) const {
throw std::runtime_error("Incompatible types in ISpectrum::copyDataFrom");
}
/// Override in child classes for polymorphic copying of data.
void ISpectrum::copyDataInto(SpectrumTester &) const {
throw std::runtime_error("Incompatible types in ISpectrum::copyDataFrom");
}
} // namespace Mantid
} // namespace API
......@@ -42,25 +42,15 @@ IndexProperty::operator Indexing::SpectrumIndexSet() const {
}
Indexing::SpectrumIndexSet IndexProperty::getIndices() const {
MatrixWorkspace_sptr wksp = boost::dynamic_pointer_cast<MatrixWorkspace>(
m_workspaceProp.getWorkspace());
if (!wksp)
throw std::runtime_error("Invalid workspace type provided to "
"IndexProperty. Must be convertible to "
"MatrixWorkspace.");
const auto &indexInfo = wksp->indexInfo();
const auto &indexInfo = getIndexInfoFromWorkspace();
auto type = m_indexTypeProp.selectedType();
if (m_value.empty()) {
return indexInfo.makeIndexSet();
} else {
auto res = std::minmax_element(m_value.cbegin(), m_value.cend());
auto min = *res.first;
auto max = *res.second;
auto min = m_value.front();
auto max = m_value.back();
auto isRange = (max - min) == static_cast<int>(m_value.size() - 1);
if (isRange) {
switch (type) {
case IndexType::WorkspaceIndex:
......@@ -69,8 +59,8 @@ Indexing::SpectrumIndexSet IndexProperty::getIndices() const {
static_cast<Indexing::GlobalSpectrumIndex>(max));
case IndexType::SpectrumNum:
return indexInfo.makeIndexSet(
static_cast<Indexing::SpectrumNumber>(min),
static_cast<Indexing::SpectrumNumber>(max));
static_cast<Indexing::SpectrumNumber>(static_cast<int32_t>(min)),
static_cast<Indexing::SpectrumNumber>(static_cast<int32_t>(max)));
}
} else {
switch (type) {
......@@ -78,9 +68,13 @@ Indexing::SpectrumIndexSet IndexProperty::getIndices() const {
return indexInfo.makeIndexSet(
std::vector<Indexing::GlobalSpectrumIndex>(m_value.begin(),
m_value.end()));
case IndexType::SpectrumNum:
return indexInfo.makeIndexSet(std::vector<Indexing::SpectrumNumber>(
m_value.begin(), m_value.end()));
case IndexType::SpectrumNum: {
std::vector<Indexing::SpectrumNumber> spectrumNumbers;
for (const auto index : m_value)
spectrumNumbers.push_back(static_cast<Indexing::SpectrumNumber>(
static_cast<int32_t>(index)));
return indexInfo.makeIndexSet(spectrumNumbers);
}
}
}
}
......@@ -89,8 +83,47 @@ Indexing::SpectrumIndexSet IndexProperty::getIndices() const {
return m_indices;
}
/** Return IndexInfo created from workspace but containing selected spectra.
*
* The selected spectra are the same as in the SpectrumIndexSet returned by this
* property and the order is guaranteed to be consistent. That is, if the Nth
* entry in the SpectrumIndexSet is M, the spectrum with index M in the input
* workspace is equal to the spectrum with index N in the returned IndexInfo. */
Indexing::IndexInfo IndexProperty::getFilteredIndexInfo() const {
const auto &indexInfo = getIndexInfoFromWorkspace();
if (m_value.empty())
return indexInfo;
switch (m_indexTypeProp.selectedType()) {
case IndexType::WorkspaceIndex:
return {std::vector<Indexing::GlobalSpectrumIndex>(m_value.begin(),
m_value.end()),
indexInfo};
case IndexType::SpectrumNum: {
std::vector<Indexing::SpectrumNumber> spectrumNumbers;
for (const auto index : m_value)
spectrumNumbers.push_back(
static_cast<Indexing::SpectrumNumber>(static_cast<int32_t>(index)));
return {spectrumNumbers, indexInfo};
}
default:
throw std::runtime_error(
"IndexProperty::getFilteredIndexInfo -- unsupported index type");
}
}
std::string IndexProperty::generatePropertyName(const std::string &name) {
return name + "IndexSet";