"docs/source/git@code.ornl.gov:mantidproject/mantid.git" did not exist on "0c5e28a42e0055858fae05fd86a4a810b994de40"
Newer
Older
Peterson, Peter
committed
#include "MantidAPI/AlgorithmManager.h"
#include "MantidAPI/AnalysisDataService.h"
#include "MantidAPI/FrameworkManager.h"
Peterson, Peter
committed
#include "MantidAPI/InstrumentDataService.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 "MantidKernel/PropertyManagerDataService.h"
#include "MantidKernel/UsageService.h"
#include <boost/algorithm/string/split.hpp>
#include <nexus/NeXusFile.hpp>
#include <Poco/ActiveResult.h>
#include <tbb/task_scheduler_init.h>
Janik Zikovsky
committed
#include <cstdarg>
Peterson, Peter
committed
#ifdef _WIN32
#include <winsock2.h>
#endif
#ifdef __linux__
#include <execinfo.h>
#endif
#ifdef MPI_BUILD
#include <boost/mpi.hpp>
#endif
using Kernel::ConfigService;
using Kernel::LibraryManager;
using Kernel::LibraryManagerImpl;
using Kernel::UsageService;
namespace API {
namespace {
/// static logger
Kernel::Logger g_log("FrameworkManager");
/// Key to define the location of the framework plugins
const char *PLUGINS_DIR_KEY = "framework.plugins.directory";
/// Key to define the location of the plugins to exclude from loading
const char *PLUGINS_EXCLUDE_KEY = "framework.plugins.exclude";
/** 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.
}
#ifdef __linux__
/**
* Print current backtrace to the given stream
* @param os A reference to an output stream
void *trace_elems[32];
int trace_elem_count(backtrace(trace_elems, 32));
char **stack_syms(backtrace_symbols(trace_elems, trace_elem_count));
for (int i = 0; i < trace_elem_count; ++i) {
os << ' ' << stack_syms[i] << '\n';
}
free(stack_syms);
}
/**
* Designed as a handler function for std::set_terminate. It prints
* a header message and then a backtrace to std::cerr. It calls exit
* with code 1
*/
void terminateHandler() {
std::cerr << "\n********* UNHANDLED EXCEPTION *********\n";
try {
std::rethrow_exception(std::current_exception());
} catch (const std::exception &exc) {
std::cerr << " what(): " << exc.what() << "\n\n";
} catch (...) {
std::cerr << " what(): Unknown exception type. No more information "
"available\n\n";
}
std::cerr << "Backtrace:\n";
backtraceToStream(std::cerr);
exit(1);
}
/**
* Designed as a SIGSEGV handler for detecting segfaults
* and printing a backtrace to std::cerr. It exits with
* code -1
*/
void sigsegvHandler(int) {
std::cerr << "\n********* SEGMENTATION FAULT *********\n";
backtraceToStream(std::cerr);
exit(-1);
}
#endif
Peterson, Peter
committed
/// Default constructor
FrameworkManagerImpl::FrameworkManagerImpl()
Russell Taylor
committed
#ifdef MPI_BUILD
Russell Taylor
committed
#endif
Peterson, Peter
committed
{
#ifdef __linux__
std::set_terminate(terminateHandler);
std::signal(SIGSEGV, sigsegvHandler);
setGlobalNumericLocaleToC();
Gigg, Martyn Anthony
committed
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() << '\n';
disableNexusOutput();
setNumOMPThreadsToConfigValue();
g_log.notice() << "This MPI process is rank: "
<< boost::mpi::communicator().rank() << '\n';
g_log.debug() << "FrameworkManager created.\n";
asynchronousStartupTasks();
}
* Load all plugins from the framework
void FrameworkManagerImpl::loadPlugins() {
loadPluginsUsingKey(PLUGINS_DIR_KEY, PLUGINS_EXCLUDE_KEY);
}
/**
* 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);
static tbb::task_scheduler_init m_init{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
*/
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() {
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();
}
/**
* Clear memory associated with the IDS
*/
void FrameworkManagerImpl::clearInstruments() {
Peterson, Peter
committed
InstrumentDataService::Instance().clear();
}
* Clear memory associated with the PropertyManagers
void FrameworkManagerImpl::clearPropertyManagers() {
using Kernel::PropertyManagerDataService;
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->setPropertiesWithString(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) {
// 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) {
g_log.error() << ex.what() << '\n';
Gigg, Martyn Anthony
committed
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.\n";
Gigg, Martyn Anthony
committed
retVal = false;
}
return retVal;
Peterson, Peter
committed
}
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
/**
* Load a set of plugins from the path pointed to by the given config key
* @param locationKey A string containing a key to lookup in the
* ConfigService
* @param excludeKey A string
*/
void FrameworkManagerImpl::loadPluginsUsingKey(const std::string &locationKey,
const std::string &excludeKey) {
const auto &cfgSvc = Kernel::ConfigService::Instance();
const auto pluginDir = cfgSvc.getString(locationKey);
if (pluginDir.length() > 0) {
std::vector<std::string> excludes;
const auto excludeStr = cfgSvc.getString(excludeKey);
boost::split(excludes, excludeStr, boost::is_any_of(";"));
g_log.debug("Loading libraries from '" + pluginDir + "', excluding '" +
excludeStr + "'");
LibraryManager::Instance().openLibraries(
pluginDir, LibraryManagerImpl::NonRecursive, excludes);
} else {
g_log.debug("No library directory found in key \"" + locationKey + "\"");
}
}
/**
* Set the numeric formatting category of the C locale to classic C.
*/
void FrameworkManagerImpl::setGlobalNumericLocaleToC() {
// Some languages, for example German, using different decimal separators.
// By default C/C++ operations attempting to extract numbers from a stream
// will use the system locale. For those locales where numbers are formatted
// differently we see issues, particularly with opencascade, where Mantid
// will hang or throw an exception while trying to parse text.
//
// The following tells all numerical extraction operations to use classic
// C as the locale.
setlocale(LC_NUMERIC, "C");
}
/// Silence NeXus output
void FrameworkManagerImpl::disableNexusOutput() {
NXMSetError(nullptr, NexusErrorFunction);
}
/// Starts asynchronous tasks that are done as part of Start-up.
void FrameworkManagerImpl::asynchronousStartupTasks() {
int instrumentUpdates(0);
int retVal = Kernel::ConfigService::Instance().getValue(
"UpdateInstrumentDefinitions.OnStartup", instrumentUpdates);
if ((retVal == 1) && (instrumentUpdates == 1)) {
updateInstrumentDefinitions();
} else {
g_log.information() << "Instrument updates disabled - cannot update "
"instrument definitions.\n";
}
int newVersionCheck(0);
int retValVersionCheck = Kernel::ConfigService::Instance().getValue(
"CheckMantidVersion.OnStartup", newVersionCheck);
if ((retValVersionCheck == 1) && (newVersionCheck == 1)) {
checkIfNewerVersionIsAvailable();
} else {
g_log.information() << "Version check disabled.\n";
}
setupUsageReporting();
}
void FrameworkManagerImpl::setupUsageReporting() {
int enabled = 0;
int interval = 0;
auto &configSvc = ConfigService::Instance();
int retVal = configSvc.getValue("Usage.BufferCheckInterval", interval);
auto &usageSvc = UsageService::Instance();
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
usageSvc.setInterval(interval);
}
retVal = configSvc.getValue("usagereports.enabled", enabled);
usageSvc.setEnabled((retVal == 1) && (enabled > 0));
usageSvc.registerStartup();
}
/// Update instrument definitions from github
void FrameworkManagerImpl::updateInstrumentDefinitions() {
try {
IAlgorithm *algDownloadInstrument =
this->createAlgorithm("DownloadInstrument");
algDownloadInstrument->setAlgStartupLogging(false);
algDownloadInstrument->executeAsync();
} catch (Kernel::Exception::NotFoundError &) {
g_log.debug() << "DowndloadInstrument algorithm is not available - cannot "
"update instrument definitions.\n";
}
}
/// Check if a newer release of Mantid is available
void FrameworkManagerImpl::checkIfNewerVersionIsAvailable() {
try {
IAlgorithm *algCheckVersion = this->createAlgorithm("CheckMantidVersion");
algCheckVersion->setAlgStartupLogging(false);
algCheckVersion->executeAsync();
} catch (Kernel::Exception::NotFoundError &) {
g_log.debug() << "CheckMantidVersion algorithm is not available - cannot "
"check if a newer version is available.\n";
Peterson, Peter
committed
} // namespace API
} // Namespace Mantid