"...Diffraction/git@code.ornl.gov:mantidproject/mantid.git" did not exist on "da5f26fafcac6897bfcd3971a861aeeceed90fba"
-
Hahn, Steven authoredHahn, Steven authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
CalculateCountRate.cpp 27.85 KiB
#include "MantidAlgorithms/CalculateCountRate.h"
#include "MantidKernel/PropertyWithValue.h"
#include "MantidKernel/BoundedValidator.h"
#include "MantidKernel/TimeSeriesProperty.h"
#include "MantidKernel/ListValidator.h"
#include "MantidKernel/Unit.h"
#include "MantidKernel/UnitFactory.h"
#include "MantidKernel/MandatoryValidator.h"
#include "MantidKernel/make_unique.h"
#include "MantidAPI/AlgorithmManager.h"
#include "MantidAPI/Axis.h"
#include "MantidAPI/NumericAxis.h"
#include "MantidAPI/Run.h"
#include "MantidAPI/WorkspaceFactory.h"
#include "MantidDataObjects/Workspace2D.h"
#include <numeric>
namespace Mantid {
namespace Algorithms {
// Register the algorithm into the AlgorithmFactory
DECLARE_ALGORITHM(CalculateCountRate)
//----------------------------------------------------------------------------------------------
/// Algorithms name for identification. @see Algorithm::name
const std::string CalculateCountRate::name() const {
return "CalculateCountRate";
}
/// Algorithm's version for identification. @see Algorithm::version
int CalculateCountRate::version() const { return 1; }
/// Algorithm's category for identification. @see Algorithm::category
const std::string CalculateCountRate::category() const {
return "Inelastic\\Utility;Diagnostics;Events\\EventFiltering";
}
/// Algorithm's summary for use in the GUI and help. @see Algorithm::summary
const std::string CalculateCountRate::summary() const {
return "Calculates instrument count rate as the function of the "
"experiment time and adds CountRate log to the source workspace.";
}
//----------------------------------------------------------------------------------------------
/** Declare the algorithm's properties.
*/
void CalculateCountRate::init() {
declareProperty(
Kernel::make_unique<API::WorkspaceProperty<DataObjects::EventWorkspace>>(
"Workspace", "", Kernel::Direction::InOut),
"Name of the event workspace to calculate counting rate for.");
declareProperty(Kernel::make_unique<Kernel::PropertyWithValue<double>>(
"XMin", EMPTY_DBL(), Kernel::Direction::Input),
"Minimal value of X-range for the rate calculations. If left "
"to default, Workspace X-axis minimal value is used.");
declareProperty(Kernel::make_unique<Kernel::PropertyWithValue<double>>(
"XMax", EMPTY_DBL(), Kernel::Direction::Input),
"Maximal value of X-range for the rate calculations. If left "
"to default, Workspace X-axis maximal value is used.");
declareProperty(
Kernel::make_unique<Kernel::PropertyWithValue<std::string>>(
"RangeUnits", "Energy",
boost::make_shared<Kernel::StringListValidator>(
Kernel::UnitFactory::Instance().getKeys()),
Kernel::Direction::Input),
"The units from Mantid Unit factory for calculating the "
"counting rate and XMin-XMax ranges are in. If the "
"X-axis of the input workspace is not expressed"
"in these units, unit conversion will be performed, so the "
"workspace should contain all necessary information for this "
"conversion. E.g. if *RangeUnits* is *EnergyTransfer*, Ei "
"log containing incident energy value should be attached to the "
"input workspace. See ConvertUnits algorithm for the details.");
std::vector<std::string> propOptions{"Elastic", "Direct", "Indirect"};
declareProperty(
"EMode", "Elastic",
boost::make_shared<Kernel::StringListValidator>(propOptions),
"The energy mode for 'RangeUnits' conversion mode (default: elastic)");
// Used logs group
std::string used_logs_mode("Used normalization logs");
declareProperty(
"NormalizeTheRate", true,
"Usually you want to normalize counting rate to some "
"rate related to the source beam intensity. Change this to "
"'false' if appropriate time series log is broken || not attached to "
"the input workspace.");
declareProperty("UseLogDerivative", false,
"If the normalization log contains "
"cumulative counting, derivative "
"of this log is necessary to get "
"correct normalization values.");
declareProperty(
"NormalizationLogName", "proton_charge",
"The name of the log, used in the counting rate normalization. ");
setPropertyGroup("NormalizeTheRate", used_logs_mode);
setPropertyGroup("UseLogDerivative", used_logs_mode);
setPropertyGroup("NormalizationLogName", used_logs_mode);
// Results
declareProperty("CountRateLogName", "block_count_rate",
boost::make_shared<Kernel::MandatoryValidator<std::string>>(),
"The name of the processed time series log with instrument "
"count rate to be added"
" to the source workspace");
declareProperty(
"UseNormLogGranularity", true,
"If true, the count rate log will have the normalization log "
"accuracy; If false, the 'NumTimeSteps' in the visualization "
"workspace below will be used for the target log granularity too.");
// visualization group
std::string spur_vis_mode("Spurion visualization");
declareProperty(
Kernel::make_unique<API::WorkspaceProperty<>>(
"VisualizationWs", "", Kernel::Direction::Output,
API::PropertyMode::Optional),
"Optional name to build 2D matrix workspace for spurion visualization. "
"If name is provided, a 2D workspace with this name will be created "
"containing data to visualize counting rate as function of time in the "
"ranges XMin-XMax");
auto mustBeReasonable = boost::make_shared<Kernel::BoundedValidator<int>>();
mustBeReasonable->setLower(3);
declareProperty(
Kernel::make_unique<Kernel::PropertyWithValue<int>>(
"NumTimeSteps", 200, mustBeReasonable, Kernel::Direction::Input),
"Number of time steps (time accuracy) the visualization workspace has. "
"Also number of steps in 'CountRateLogName' log if "
"'UseNormLogGranularity' is set to false. Should be bigger than 3");
declareProperty(
Kernel::make_unique<Kernel::PropertyWithValue<int>>(
"XResolution", 100, mustBeReasonable, Kernel::Direction::Input),
"Number of steps (accuracy) of the visualization workspace has along "
"X-axis. ");
setPropertyGroup("VisualizationWs", spur_vis_mode);
setPropertyGroup("NumTimeSteps", spur_vis_mode);
setPropertyGroup("XResolution", spur_vis_mode);
}
//----------------------------------------------------------------------------------------------
/** Execute the algorithm.
*/
void CalculateCountRate::exec() {
DataObjects::EventWorkspace_sptr sourceWS = getProperty("Workspace");
API::EventType et = sourceWS->getEventType();
if (et == API::EventType::WEIGHTED_NOTIME) {
throw std::runtime_error("Event workspace " + sourceWS->getName() +
" contains events without necessary frame "
"information. Can not process counting rate");
}
// Identify correct way to treat input logs and general properties of output
// log
this->setOutLogParameters(sourceWS);
//-------------------------------------
// identify ranges for count rate calculations and initiate source workspace
this->setSourceWSandXRanges(sourceWS);
// check if visualization workspace is necessary and if it is, prepare
// visualization workspace to use
this->checkAndInitVisWorkspace();
// create results log and add it to the source workspace
std::string logname = getProperty("CountRateLogName");
auto newlog = new Kernel::TimeSeriesProperty<double>(logname);
sourceWS->mutableRun().addProperty(newlog, true);
// calculate averages requested and modify results log
this->calcRateLog(m_workingWS, newlog);
// clear up log derivative and existing log pointer (if any)
// to avoid incorrect usage
// at subsequent calls to the same algorithm.
m_tmpLogHolder.release();
m_pNormalizationLog = nullptr;
}
/** Process input workspace to calculate instrument counting rate as function of
*experiment time
*@param InputWorkspace :: shared pointer to the input workspace to process
*@param targLog :: pointer to time series property containing count rate
*log.
* Property should exist on input and will be modified
*with
* counting rate log on output.
*/
void CalculateCountRate::calcRateLog(
DataObjects::EventWorkspace_sptr &InputWorkspace,
Kernel::TimeSeriesProperty<double> *const targLog) {
MantidVec countRate(m_numLogSteps);
std::vector<double> countNormalization;
if (this->normalizeCountRate())
countNormalization = m_pNormalizationLog->valuesAsVector();
std::unique_ptr<std::mutex[]> pVisWS_locks;
if (this->buildVisWS()) {
pVisWS_locks.reset(new std::mutex[m_visWs->getNumberHistograms()]);
}
int64_t nHist = static_cast<int64_t>(InputWorkspace->getNumberHistograms());
// Initialize progress reporting.
API::Progress prog(this, 0.0, 1.0, nHist);
double dTRangeMin = static_cast<double>(m_TRangeMin.totalNanoseconds());
double dTRangeMax = static_cast<double>(m_TRangeMax.totalNanoseconds());
std::vector<MantidVec> Buff;
#pragma omp parallel
{
int nThreads = PARALLEL_NUMBER_OF_THREADS;
#pragma omp single
{
// initialize thread's histogram buffer
Buff.resize(nThreads);
}
auto nThread = PARALLEL_THREAD_NUMBER;
Buff[nThread].assign(m_numLogSteps, 0);
#pragma omp for
for (int64_t i = 0; i < nHist; ++i) {
auto nThread = PARALLEL_THREAD_NUMBER;
PARALLEL_START_INTERUPT_REGION
// Get a const event list reference. eventInputWS->dataY() doesn't work.
const DataObjects::EventList &el = InputWorkspace->getSpectrum(i);
el.generateCountsHistogramPulseTime(dTRangeMin, dTRangeMax, Buff[nThread],
m_XRangeMin, m_XRangeMax);
if (this->buildVisWS()) {
this->histogramEvents(el, pVisWS_locks.get());
}
// Report progress
prog.report(name());
PARALLEL_END_INTERUPT_REGION
}
PARALLEL_CHECK_INTERUPT_REGION
// calculate final sums
#pragma omp for
for (int64_t j = 0; j < m_numLogSteps; j++) {
for (int i = 0; i < nThreads; i++) {
countRate[j] += Buff[i][j];
}
// normalize if requested
if (!countNormalization.empty()) {
countRate[j] /= countNormalization[j];
}
}
if (!countNormalization.empty() && this->buildVisWS()) {
#pragma omp for
for (int64_t j = 0; j < int64_t(m_visNorm.size()); j++) {
this->normalizeVisWs(j);
}
}
}
// generate target log timing
std::vector<Kernel::DateAndTime> times(m_numLogSteps);
double dt = (dTRangeMax - dTRangeMin) / static_cast<double>(m_numLogSteps);
auto t0 = m_TRangeMin.totalNanoseconds();
for (auto i = 0; i < m_numLogSteps; i++) {
times[i] =
Kernel::DateAndTime(t0 + static_cast<int64_t>((0.5 + double(i)) * dt));
}
// store calculated values within the target log.
targLog->replaceValues(times, countRate);
}
/** histogram event list into visualization workspace
* @param el :: event list to rebin into visualization workspace
* @param spectraLocks :: pointer to the array of mutexes to lock modifyed
* visualization workspace spectra for a thread
*/
void CalculateCountRate::histogramEvents(const DataObjects::EventList &el,
std::mutex *spectraLocks) {
if (el.empty())
return;
auto events = el.getEvents();
for (const DataObjects::TofEvent &ev : events) {
double pulsetime = static_cast<double>(ev.pulseTime().totalNanoseconds());
double tof = ev.tof();
if (pulsetime < m_visT0 || pulsetime >= m_visTmax)
continue;
if (tof < m_XRangeMin || tof >= m_XRangeMax)
continue;
size_t n_spec = static_cast<size_t>((pulsetime - m_visT0) / m_visDT);
size_t n_bin = static_cast<size_t>((tof - m_XRangeMin) / m_visDX);
(spectraLocks + n_spec)->lock();
auto &Y = m_visWs->mutableY(n_spec);
Y[n_bin]++;
(spectraLocks + n_spec)->unlock();
}
}
/** Normalize single spectrum of the normalization workspace using prepared
* normzlization log
@param wsIndex -- appropriate visualization workspace index to normalize
the spectrum
*/
void CalculateCountRate::normalizeVisWs(int64_t wsIndex) {
auto &Y = m_visWs->mutableY(wsIndex);
for (auto &yv : Y) {
yv /= m_visNorm[wsIndex];
}
}
/** Disable normalization using normalization log.
Helper function to avoid code duplication.
@param NormLogError -- error to print if normalization log is disabled*/
void CalculateCountRate::disableNormalization(const std::string &NormLogError) {
g_log.warning() << NormLogError << std::endl;
m_pNormalizationLog = nullptr;
m_normalizeResult = false;
}
/*Analyse input log parameters and logs, attached to the workspace and identify
* the parameters of the target log, including experiment time.
*
@param InputWorkspace -- input workspace to analyse logs
*/
void CalculateCountRate::setOutLogParameters(
const DataObjects::EventWorkspace_sptr &InputWorkspace) {
std::string NormLogName = getProperty("NormalizationLogName");
std::string TargetLog = getProperty("CountRateLogName");
if (NormLogName == TargetLog) {
throw std::invalid_argument("Target log name: " + TargetLog +
" and normalization log name: " + NormLogName +
" can not be the same");
}
m_normalizeResult = getProperty("NormalizeTheRate");
bool useLogDerivative = getProperty("UseLogDerivative");
bool useLogAccuracy = getProperty("UseNormLogGranularity");
bool logPresent = InputWorkspace->run().hasProperty(NormLogName);
if (!logPresent) {
if (m_normalizeResult) {
this->disableNormalization(
"Normalization log '" + NormLogName +
"' values requested but the log is not attached to the "
"workspace. Normalization disabled");
}
if (useLogDerivative) {
g_log.warning() << "Normalization by log: '" << NormLogName
<< "' -- log derivative requested but the source log is "
"not attached to "
"the workspace. Log derivative will not be used.\n";
useLogDerivative = false;
}
if (useLogAccuracy) {
g_log.warning() << "Using accuracy of the log: '" << NormLogName
<< "' is requested but the log is not attached to the "
"workspace. Will use accuracy defined by "
"'NumTimeSteps' property value.\n";
useLogAccuracy = false;
}
} else {
m_pNormalizationLog =
InputWorkspace->run().getTimeSeriesProperty<double>(NormLogName);
}
// Analyse properties interactions
// if property derivative is specified.
if (useLogDerivative) {
m_tmpLogHolder = m_pNormalizationLog->getDerivative();
m_pNormalizationLog = m_tmpLogHolder.get();
m_useLogDerivative = true;
}
///
if (m_normalizeResult) {
if (!useLogAccuracy) {
g_log.warning() << "Change of the counting log accuracy while "
"normalizing by log values is not implemented. Will "
"use log accuracy.\n";
useLogAccuracy = true;
}
} //---------------------------------------------------------------------
// find target log ranges and identify what normalization should be used
Kernel::DateAndTime runTMin, runTMax;
InputWorkspace->getPulseTimeMinMax(runTMin, runTMax);
//
if (useLogAccuracy) { // extract log times located inside the run time
Kernel::DateAndTime tLogMin, tLogMax;
if (m_useLogDerivative) { // derivative moves events to the bin centre,
// but we need initial range
auto pSource =
InputWorkspace->run().getTimeSeriesProperty<double>(NormLogName);
tLogMin = pSource->firstTime();
tLogMax = pSource->lastTime();
} else {
tLogMin = m_pNormalizationLog->firstTime();
tLogMax = m_pNormalizationLog->lastTime();
}
//
if (tLogMin < runTMin || tLogMax > runTMax) {
if (tLogMin > runTMax ||
tLogMax < runTMin) { // log time is outside of the experiment time.
// Log normalization is impossible
this->disableNormalization(
"Normalization log " + m_pNormalizationLog->name() +
" time lies outside of the the whole experiment time. "
"Log normalization impossible.");
useLogAccuracy = false;
} else {
if (!m_tmpLogHolder) {
m_tmpLogHolder =
Kernel::make_unique<Kernel::TimeSeriesProperty<double>>(
*m_pNormalizationLog->clone());
}
m_tmpLogHolder->filterByTime(runTMin, runTMax);
m_pNormalizationLog = m_tmpLogHolder.get();
m_numLogSteps = m_pNormalizationLog->realSize();
}
} else {
if (tLogMin > runTMin || tLogMax < runTMax) {
this->disableNormalization(
"Normalization log " + m_pNormalizationLog->name() +
" time does not cover the whole experiment time. "
"Log normalization impossible.");
useLogAccuracy = false;
}
}
}
if (useLogAccuracy) {
m_numLogSteps = m_pNormalizationLog->realSize();
if (m_numLogSteps < 2) { // should not ever happen but...
this->disableNormalization(
"Number of points in the Normalization log " +
m_pNormalizationLog->name() +
" smaller then 2. Can not normalize using this log.");
m_numLogSteps = getProperty("NumTimeSteps"); // Always > 2
useLogAccuracy = false;
}
} else {
m_numLogSteps = getProperty("NumTimeSteps");
}
// identify epsilon to use with current time
double t_epsilon = double(runTMax.totalNanoseconds()) *
(1 + std::numeric_limits<double>::epsilon());
int64_t eps_increment =
static_cast<int64_t>(t_epsilon - double(runTMax.totalNanoseconds()));
m_TRangeMin = runTMin - eps_increment;
if (useLogAccuracy) {
// Let's try to establish log step (it should be constant in real
// applications) and define
// binning in such a way, that each historgam bin accomodates
// single log value.
auto iTMax = runTMax.totalNanoseconds();
auto iTMin = m_TRangeMin.totalNanoseconds();
int64_t provDT = (iTMax - iTMin) / (m_numLogSteps - 1);
if (provDT < 1) { // something is fundamentally wrong. This can only happen
// if the log is very short and the distance between log
// boundaries is smaller than dt
this->disableNormalization("Time step of the log " +
m_pNormalizationLog->name() +
" is not consistent with number of log steps. "
"Can not use this log normalization");
useLogAccuracy = false;
} else {
auto iTMax1 = iTMin + provDT * m_numLogSteps;
if (iTMax1 <= iTMax) { // == is possible
m_numLogSteps++;
iTMax1 = iTMin + provDT * m_numLogSteps;
}
m_TRangeMax = Kernel::DateAndTime(iTMax1);
}
}
if (!useLogAccuracy) {
// histogramming excludes rightmost events. Modify max limit to keep them
m_TRangeMax = runTMax + eps_increment; // Should be
// *(1+std::numeric_limits<double>::epsilon())
// but DateTime does not have multiplication
// operator
}
}
/* Retrieve and define data search ranges from input workspace parameters and
* algorithm properties
*
*@param InputWorkspace -- event workspace to process. Also retrieves algorithm
* properties, relevant to the workspace.
*@return -- the input workspace cropped according to XMin-XMax ranges in units,
* requested by the user
*
*/
void CalculateCountRate::setSourceWSandXRanges(
DataObjects::EventWorkspace_sptr &InputWorkspace) {
std::string RangeUnits = getProperty("RangeUnits");
auto axis = InputWorkspace->getAxis(0);
const auto unit = axis->unit();
API::MatrixWorkspace_sptr wst;
if (unit->unitID() != RangeUnits) {
auto conv = createChildAlgorithm("ConvertUnits", 0, 1);
std::string wsName = InputWorkspace->getName();
if (wsName.empty()) {
wsName = "_CountRate_UnitsConverted";
} else {
wsName = "_" + wsName + "_converted";
}
conv->setProperty("InputWorkspace", InputWorkspace);
conv->setPropertyValue("OutputWorkspace", wsName);
std::string Emode = getProperty("Emode");
conv->setProperty("Emode", Emode);
conv->setProperty("Target", RangeUnits);
conv->setRethrows(true);
conv->execute();
wst = conv->getProperty("OutputWorkspace");
} else {
wst = InputWorkspace;
}
m_workingWS = boost::dynamic_pointer_cast<DataObjects::EventWorkspace>(wst);
if (!m_workingWS) {
throw std::runtime_error("SetWSDataRanges:Can not retrieve EventWorkspace "
"after converting units");
}
// data ranges
m_XRangeMin = getProperty("XMin");
m_XRangeMax = getProperty("XMax");
if (m_XRangeMin == EMPTY_DBL() && m_XRangeMax == EMPTY_DBL()) {
m_rangeExplicit = false;
} else {
m_rangeExplicit = true;
}
double realMin, realMax;
m_workingWS->getEventXMinMax(realMin, realMax);
if (!m_rangeExplicit) { // The range is the whole workspace range
m_XRangeMin = realMin;
// include rightmost limit into the histogramming
m_XRangeMax = realMax * (1. + std::numeric_limits<double>::epsilon());
return;
}
if (m_XRangeMin == EMPTY_DBL()) {
m_XRangeMin = realMin;
}
if (m_XRangeMax == EMPTY_DBL()) {
// include rightmost limit into the histogramming
m_XRangeMax = realMax * (1. + std::numeric_limits<double>::epsilon());
}
if (m_XRangeMin < realMin) {
g_log.debug() << "Workspace constrain min range changed from: "
<< m_XRangeMin << " To: " << realMin << std::endl;
m_XRangeMin = realMin;
}
if (m_XRangeMax > realMax) {
g_log.debug() << "Workspace constrain max range changed from: "
<< m_XRangeMax << " To: " << realMax << std::endl;
m_XRangeMax = realMax * (1. + std::numeric_limits<double>::epsilon());
}
// check final ranges valid
if (m_XRangeMax < realMin || m_XRangeMin > realMax) {
throw std::invalid_argument(
" Spurion data search range: [" + std::to_string(m_XRangeMin) + "," +
std::to_string(m_XRangeMin) +
"] lies outside of the workspace's real data range: [" +
std::to_string(realMin) + "," + std::to_string(realMax) + "]");
}
if (m_XRangeMin > m_XRangeMax) {
throw std::invalid_argument(" Minimal spurion search data limit is bigger "
"than the maximal limit. ( Min: " +
std::to_string(m_XRangeMin) + "> Max: " +
std::to_string(m_XRangeMax) + ")");
}
}
/**Check if visualization workspace is necessary and initiate it if requested.
* Sets or clears up internal m_visWS pointer and "do-visualization workspace"
* option.
*/
void CalculateCountRate::checkAndInitVisWorkspace() {
std::string visWSName = getProperty("VisualizationWs");
if (visWSName.empty()) {
m_visWs.reset();
m_doVis = false;
return;
}
m_doVis = true;
int numTBins = getProperty("NumTimeSteps");
if (this->normalizeCountRate()) {
if (numTBins > m_numLogSteps) {
g_log.information() << "Number of time step in normalized visualization "
"workspace exceeds the number of points in the "
"normalization log. This mode is not supported so "
"number of time steps decreased to be equal to "
"the number of normalization log points\n";
numTBins = m_numLogSteps;
}
}
int numXBins = getProperty("XResolution");
std::string RangeUnits = getProperty("RangeUnits");
m_visWs = boost::dynamic_pointer_cast<DataObjects::Workspace2D>(
API::WorkspaceFactory::Instance().create("Workspace2D", numTBins,
numXBins + 1, numXBins));
m_visWs->setTitle(visWSName);
double Xmax = m_XRangeMax;
// a bit dodgy code. It can be generalized
if (std::isinf(Xmax)) {
const auto &Xbin = m_workingWS->x(0);
for (int64_t i = Xbin.size() - 1; i >= 0; --i) {
if (!std::isinf(Xbin[i])) {
Xmax = Xbin[i];
break;
}
}
if (std::isinf(Xmax)) {
g_log.warning() << "All X-range for visualization workspace is infinity. "
"Can not build visualization workspace in the units "
"requested\n";
m_visWs.reset();
m_doVis = false;
return;
}
}
// define X-axis in target units
double dX = (Xmax - m_XRangeMin) / numXBins;
std::vector<double> xx(numXBins);
for (int i = 0; i < numXBins; ++i) {
xx[i] = m_XRangeMin + (0.5 + static_cast<double>(i)) * dX;
}
auto ax0 = Kernel::make_unique<API::NumericAxis>(xx);
ax0->setUnit(RangeUnits);
m_visWs->replaceAxis(0, ax0.release());
// define Y axis (in seconds);
double dt = (static_cast<double>(m_TRangeMax.totalNanoseconds() -
m_TRangeMin.totalNanoseconds()) /
static_cast<double>(numTBins)) *
1.e-9;
xx.resize(numTBins);
for (int i = 0; i < numTBins; i++) {
xx[i] = (0.5 + static_cast<double>(i)) * dt;
}
auto ax1 = Kernel::make_unique<API::NumericAxis>(xx);
auto labelY = boost::dynamic_pointer_cast<Kernel::Units::Label>(
Kernel::UnitFactory::Instance().create("Label"));
labelY->setLabel("sec");
ax1->unit() = labelY;
m_visWs->replaceAxis(1, ax1.release());
setProperty("VisualizationWs", m_visWs);
// define binning parameters used while calculating visualization
m_visX0 = m_XRangeMin;
m_visDX = dX;
m_visT0 = static_cast<double>(m_TRangeMin.totalNanoseconds());
m_visTmax = static_cast<double>(m_TRangeMax.totalNanoseconds());
m_visDT = (m_visTmax - m_visT0) / static_cast<double>(numTBins);
if (this->normalizeCountRate()) {
m_visNorm.resize(numTBins);
this->buildVisWSNormalization(m_visNorm);
}
}
/** Helper function to check if visualization workspace should be used*/
bool CalculateCountRate::buildVisWS() const { return m_doVis; }
/** Helper function, mainly for testing
* @return true if count rate should be normalized and false
* otherwise */
bool CalculateCountRate::normalizeCountRate() const {
return m_normalizeResult;
}
/** Helper function, mainly for testing
* @return true if log derivative is used instead of log itself */
bool CalculateCountRate::useLogDerivative() const { return m_useLogDerivative; }
/** method to prepare normalization vector for the visualisation workspace using
* data from normalization log with, usually, different number of time steps
* Here we assume that the number of time points in the visualization workspace
* is smaller or equal to the number of points in the normalization log.
*
@param normalization -- on output, the vector containing normalization
* coefficients for the visualization workspace spectra
*/
void CalculateCountRate::buildVisWSNormalization(
std::vector<double> &normalization) {
if (!m_pNormalizationLog) {
m_normalizeResult = false;
g_log.warning() << "CalculateCountRate::buildVisWSNormalization: No source "
"normalization log is found. Will not normalize "
"visualization workspace\n";
return;
}
// visualization workspace should be present and initialized at this stage:
auto ax = dynamic_cast<API::NumericAxis *>(m_visWs->getAxis(1));
if (!ax)
throw std::runtime_error(
"Can not retrieve Y-axis from visualization workspace");
normalization.assign(ax->length(), 0.);
// For more accurate logging (in a future, if necessary:)
// auto t_bins = ax->createBinBoundaries();
// double dt = t_bins[2] - t_bins[1]; // equal bins, first bin may be weird.
//
m_pNormalizationLog->histogramData(m_TRangeMin, m_TRangeMax, normalization);
}
} // namespace Algorithms
} // namespace Mantid