Newer
Older
Peterson, Peter
committed
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidAPI/AlgorithmManager.h"
#include "MantidAPI/AnalysisDataService.h"
#include "MantidAPI/FrameworkManager.h"
Peterson, Peter
committed
#include "MantidAPI/InstrumentDataService.h"
#include "MantidAPI/MemoryManager.h"
#include "MantidAPI/PropertyManagerDataService.h"
#include "MantidAPI/WorkspaceGroup.h"
Peterson, Peter
committed
#include "MantidKernel/Exception.h"
#include "MantidKernel/LibraryManager.h"
Gigg, Martyn Anthony
committed
#include "MantidKernel/Memory.h"
#include "MantidKernel/MultiThreaded.h"
#include <Poco/ActiveResult.h>
Janik Zikovsky
committed
#include <cstdarg>
Peterson, Peter
committed
#ifdef _WIN32
#include <winsock2.h>
#endif
#ifdef MPI_BUILD
#include <boost/mpi.hpp>
#endif
namespace Mantid {
namespace API {
namespace {
/// static logger
Kernel::Logger g_log("FrameworkManager");
/// Key that that defines the location of the framework plugins
const char *PLUGINS_DIR_KEY = "plugins.directory";
}
/** This is a function called every time NeXuS raises an error.
* This swallows the errors and outputs nothing.
*
* @param data :: data passed in NXMSetError (will be NULL)
* @param text :: text of the error.
*/
void NexusErrorFunction(void *data, char *text) {
UNUSED_ARG(data);
UNUSED_ARG(text);
// Do nothing.
}
Peterson, Peter
committed
/// Default constructor
FrameworkManagerImpl::FrameworkManagerImpl()
Russell Taylor
committed
#ifdef MPI_BUILD
Russell Taylor
committed
#endif
Peterson, Peter
committed
{
Gigg, Martyn Anthony
committed
// Mantid only understands English...
setGlobalLocaleToAscii();
Gigg, Martyn Anthony
committed
// Setup memory allocation scheme
Kernel::MemoryOptions::initAllocatorOptions();
Gigg, Martyn Anthony
committed
Peterson, Peter
committed
#ifdef _WIN32
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
Peterson, Peter
committed
#endif
#if defined(_MSC_VER) && _MSC_VER < 1900
// This causes the exponent to consist of two digits.
// VC++ >=1900 use standards conforming behaviour and only
// uses the number of digits required
Peterson, Peter
committed
_set_output_format(_TWO_DIGIT_EXPONENT);
#endif
g_log.notice() << Mantid::welcomeMessage() << std::endl;
loadPluginsUsingKey(PLUGINS_DIR_KEY);
disableNexusOutput();
setNumOMPThreadsToConfigValue();
g_log.notice() << "This MPI process is rank: "
<< boost::mpi::communicator().rank() << std::endl;
Peterson, Peter
committed
g_log.debug() << "FrameworkManager created." << std::endl;
AsynchronousStartupTasks();
}
/// Destructor
FrameworkManagerImpl::~FrameworkManagerImpl() {}
/// Starts asynchronous tasks that are done as part of Start-up.
void FrameworkManagerImpl::AsynchronousStartupTasks() {
int updateInstrumentDefinitions = 0;
int retVal = Kernel::ConfigService::Instance().getValue(
"UpdateInstrumentDefinitions.OnStartup", updateInstrumentDefinitions);
if ((retVal == 1) && (updateInstrumentDefinitions == 1)) {
UpdateInstrumentDefinitions();
<< "Instrument updates disabled - cannot update instrument definitions."
<< std::endl;
int checkIfNewerVersionIsAvailable = 0;
int retValVersionCheck = Kernel::ConfigService::Instance().getValue(
"CheckMantidVersion.OnStartup", checkIfNewerVersionIsAvailable);
if ((retValVersionCheck == 1) && (checkIfNewerVersionIsAvailable == 1)) {
CheckIfNewerVersionIsAvailable();
} else {
g_log.information() << "Version check disabled." << std::endl;
Peterson, Peter
committed
}
/// Update instrument definitions from github
void FrameworkManagerImpl::UpdateInstrumentDefinitions() {
try {
IAlgorithm *algDownloadInstrument =
this->createAlgorithm("DownloadInstrument");
algDownloadInstrument->setAlgStartupLogging(false);
Poco::ActiveResult<bool> result = algDownloadInstrument->executeAsync();
} catch (Kernel::Exception::NotFoundError &) {
g_log.debug() << "DowndloadInstrument algorithm is not available - cannot "
"update instrument definitions." << std::endl;
/// Check if a newer release of Mantid is available
void FrameworkManagerImpl::CheckIfNewerVersionIsAvailable() {
try {
IAlgorithm *algCheckVersion = this->createAlgorithm("CheckMantidVersion");
algCheckVersion->setAlgStartupLogging(false);
Poco::ActiveResult<bool> result = algCheckVersion->executeAsync();
} catch (Kernel::Exception::NotFoundError &) {
g_log.debug() << "CheckMantidVersion algorithm is not available - cannot "
"check if a newer version is available." << std::endl;
/**
* Load a set of plugins from the path pointed to by the given config key
* @param key :: A string containing a key to lookup in the ConfigService
*/
void FrameworkManagerImpl::loadPluginsUsingKey(const std::string &key) {
Kernel::ConfigServiceImpl &config = Kernel::ConfigService::Instance();
std::string pluginDir = config.getString(key);
g_log.debug("Loading libraries from \"" + pluginDir + "\"");
Kernel::LibraryManager::Instance().OpenAllLibraries(pluginDir, false);
g_log.debug("No library directory found in key \"" + key + "\"");
}
}
* Set the global locale for all C++ stream operations to use simple ASCII
* characters.
* If the system supports it UTF-8 encoding will be used, otherwise the
* classic C locale is used
*/
void FrameworkManagerImpl::setGlobalLocaleToAscii() {
// This ensures that all subsequent stream operations interpret everything as
// simple
// ASCII. On systems in the UK and US having this as the system default is not
// an issue.
// However, systems that have their encoding set differently can see
// unexpected behavour when
// translating from string->numeral values. One example is floating-point
// interpretation in
// German where a comma is used instead of a period.
std::locale::global(std::locale::classic());
}
/// Silence NeXus output
void FrameworkManagerImpl::disableNexusOutput() {
NXMSetError(NULL, NexusErrorFunction);
}
/**
* Set the number of OpenMP cores to use based on the config value
*/
void FrameworkManagerImpl::setNumOMPThreadsToConfigValue() {
// Set the number of threads to use for this process
int maxCores(0);
int retVal = Kernel::ConfigService::Instance().getValue(
"MultiThreaded.MaxCores", maxCores);
if (retVal > 0 && maxCores > 0) {
setNumOMPThreads(maxCores);
}
}
/**
* Set the number of OpenMP cores to use based on the config value
* @param nthreads :: The maximum number of threads to use
*/
void FrameworkManagerImpl::setNumOMPThreads(const int nthreads) {
g_log.debug() << "Setting maximum number of threads to " << nthreads << "\n";
PARALLEL_SET_NUM_THREADS(nthreads);
}
/**
* Returns the number of OpenMP threads that will be used
* @returns The number of OpenMP threads that will be used in the next parallel
* call
*/
int FrameworkManagerImpl::getNumOMPThreads() const {
return PARALLEL_GET_MAX_THREADS;
}
Peterson, Peter
committed
/** Clears all memory associated with the AlgorithmManager
* and with the Analysis & Instrument data services.
*/
void FrameworkManagerImpl::clear() {
Peterson, Peter
committed
clearAlgorithms();
clearInstruments();
clearData();
Peterson, Peter
committed
}
void FrameworkManagerImpl::shutdown()
{
Kernel::UsageService::Instance().shutdown();
Peterson, Peter
committed
/**
* Clear memory associated with the AlgorithmManager
*/
void FrameworkManagerImpl::clearAlgorithms() {
Peterson, Peter
committed
AlgorithmManager::Instance().clear();
}
/**
* Clear memory associated with the ADS
*/
void FrameworkManagerImpl::clearData() {
Peterson, Peter
committed
AnalysisDataService::Instance().clear();
Mantid::API::MemoryManager::Instance().releaseFreeMemory();
Peterson, Peter
committed
}
/**
* Clear memory associated with the IDS
*/
void FrameworkManagerImpl::clearInstruments() {
Peterson, Peter
committed
InstrumentDataService::Instance().clear();
}
* Clear memory associated with the PropertyManagers
void FrameworkManagerImpl::clearPropertyManagers() {
PropertyManagerDataService::Instance().clear();
}
Peterson, Peter
committed
/** Creates and initialises an instance of an algorithm
Janik Zikovsky
committed
* @param algName :: The name of the algorithm required
* @param version :: The version of the algorithm
* @return A pointer to the created algorithm.
* WARNING! DO NOT DELETE THIS POINTER, because it is owned
* by a shared pointer in the AlgorithmManager.
Peterson, Peter
committed
* @throw NotFoundError Thrown if algorithm requested is not registered
*/
IAlgorithm *FrameworkManagerImpl::createAlgorithm(const std::string &algName,
const int &version) {
IAlgorithm *alg = AlgorithmManager::Instance().create(algName, version).get();
return alg;
Peterson, Peter
committed
}
/** Creates an instance of an algorithm and sets the properties provided
Janik Zikovsky
committed
* @param algName :: The name of the algorithm required
* @param propertiesArray :: A single string containing properties in the
Peterson, Peter
committed
* form "Property1=Value1;Property2=Value2;..."
Janik Zikovsky
committed
* @param version :: The version of the algorithm
Peterson, Peter
committed
* @return A pointer to the created algorithm
* WARNING! DO NOT DELETE THIS POINTER, because it is owned
* by a shared pointer in the AlgorithmManager.
Peterson, Peter
committed
* @throw NotFoundError Thrown if algorithm requested is not registered
* @throw std::invalid_argument Thrown if properties string is ill-formed
*/
IAlgorithm *
FrameworkManagerImpl::createAlgorithm(const std::string &algName,
const std::string &propertiesArray,
const int &version) {
Peterson, Peter
committed
// Use the previous method to create the algorithm
IAlgorithm *alg = AlgorithmManager::Instance()
.create(algName, version)
.get(); // createAlgorithm(algName);
alg->setPropertiesWithSimpleString(propertiesArray);
Peterson, Peter
committed
return alg;
}
/** Creates an instance of an algorithm, sets the properties provided and
* then executes it.
Janik Zikovsky
committed
* @param algName :: The name of the algorithm required
* @param propertiesArray :: A single string containing properties in the
Peterson, Peter
committed
* form "Property1=Value1;Property2=Value2;..."
Janik Zikovsky
committed
* @param version :: The version of the algorithm
Peterson, Peter
committed
* @return A pointer to the executed algorithm
* WARNING! DO NOT DELETE THIS POINTER, because it is owned
* by a shared pointer in the AlgorithmManager.
Peterson, Peter
committed
* @throw NotFoundError Thrown if algorithm requested is not registered
* @throw std::invalid_argument Thrown if properties string is ill-formed
* @throw runtime_error Thrown if algorithm cannot be executed
*/
IAlgorithm *FrameworkManagerImpl::exec(const std::string &algName,
const std::string &propertiesArray,
const int &version) {
Peterson, Peter
committed
// Make use of the previous method for algorithm creation and property setting
IAlgorithm *alg = createAlgorithm(algName, propertiesArray, version);
Peterson, Peter
committed
// Now execute the algorithm
alg->execute();
Peterson, Peter
committed
return alg;
}
Janik Zikovsky
committed
/** Run any algorithm with a variable number of parameters
*
* @param algorithmName
* @param count :: number of arguments given.
* @return the algorithm created
*/
IAlgorithm_sptr FrameworkManagerImpl::exec(const std::string &algorithmName,
int count, ...) {
if (count % 2 == 1) {
throw std::runtime_error(
"Must have an even number of parameter/value string arguments");
// Create the algorithm
IAlgorithm_sptr alg =
AlgorithmManager::Instance().createUnmanaged(algorithmName, -1);
Janik Zikovsky
committed
alg->initialize();
if (!alg->isInitialized())
throw std::runtime_error(algorithmName + " was not initialized.");
va_list Params;
va_start(Params, count);
for (int i = 0; i < count; i += 2) {
Janik Zikovsky
committed
std::string paramName = va_arg(Params, const char *);
std::string paramValue = va_arg(Params, const char *);
alg->setPropertyValue(paramName, paramValue);
}
va_end(Params);
alg->execute();
return alg;
}
Peterson, Peter
committed
/** Returns a shared pointer to the workspace requested
Janik Zikovsky
committed
* @param wsName :: The name of the workspace
Peterson, Peter
committed
* @return A pointer to the workspace
*
* @throw NotFoundError If workspace is not registered with analysis data
*service
Peterson, Peter
committed
*/
Workspace *FrameworkManagerImpl::getWorkspace(const std::string &wsName) {
Peterson, Peter
committed
Workspace *space;
Peterson, Peter
committed
space = AnalysisDataService::Instance().retrieve(wsName).get();
} catch (Kernel::Exception::NotFoundError &) {
throw Kernel::Exception::NotFoundError("Unable to retrieve workspace",
wsName);
Peterson, Peter
committed
}
return space;
}
/** Removes and deletes a workspace from the data service store.
*
* @param wsName :: The user-given name for the workspace
Peterson, Peter
committed
* @return true if the workspace was found and deleted
Peterson, Peter
committed
* @throw NotFoundError Thrown if workspace cannot be found
*/
bool FrameworkManagerImpl::deleteWorkspace(const std::string &wsName) {
Gigg, Martyn Anthony
committed
bool retVal = false;
boost::shared_ptr<Workspace> ws_sptr;
Gigg, Martyn Anthony
committed
ws_sptr = AnalysisDataService::Instance().retrieve(wsName);
} catch (Kernel::Exception::NotFoundError &ex) {
Gigg, Martyn Anthony
committed
g_log.error() << ex.what() << std::endl;
return false;
}
boost::shared_ptr<WorkspaceGroup> ws_grpsptr =
boost::dynamic_pointer_cast<WorkspaceGroup>(ws_sptr);
if (ws_grpsptr) {
Gigg, Martyn Anthony
committed
// selected workspace is a group workspace
AnalysisDataService::Instance().deepRemoveGroup(wsName);
Gigg, Martyn Anthony
committed
}
// Make sure we drop the references so the memory will get freed when we
// expect it to
ws_sptr.reset();
ws_grpsptr.reset();
Gigg, Martyn Anthony
committed
AnalysisDataService::Instance().remove(wsName);
retVal = true;
} catch (Kernel::Exception::NotFoundError &) {
// workspace was not found
g_log.error() << "Workspace " << wsName << " could not be found."
<< std::endl;
Gigg, Martyn Anthony
committed
retVal = false;
}
Mantid::API::MemoryManager::Instance().releaseFreeMemory();
Gigg, Martyn Anthony
committed
return retVal;
Peterson, Peter
committed
}
void FrameworkManagerImpl::setupUsageReporting() {
int enabled = 0;
int interval = 0;
int retVal = Kernel::ConfigService::Instance().getValue("Usage.BufferCheckInterval", interval);
if ((retVal == 1) && (interval > 0)) {
Kernel::UsageService::Instance().setInterval(interval);
}
retVal = Kernel::ConfigService::Instance().getValue("usagereports.enabled", enabled);
Kernel::UsageService::Instance().setEnabled((retVal == 1) && (enabled > 0));
Kernel::UsageService::Instance().registerStartup();
}
Peterson, Peter
committed
} // namespace API
} // Namespace Mantid