21#include <boost/algorithm/string/classification.hpp>
22#include <boost/algorithm/string/split.hpp>
26using namespace Kernel;
28using namespace Geometry;
29using namespace DataObjects;
30using Types::Core::DateAndTime;
38 auto wsValidator = std::make_shared<CompositeValidator>();
44 "An input workspace.");
46 "An output workspace.");
49 "Correlation chopper TDC timing offset in nanoseconds.");
54 std::map<std::string, std::string> errors;
64 if (
inputWS->getInstrument()->getName() !=
"CORELLI")
65 errors[
"InputWorkspace"] =
"This Algorithm will only work for Corelli.";
68 else if (!
inputWS->getInstrument()->getComponentByName(
"correlation-chopper"))
69 errors[
"InputWorkspace"] =
"Correlation chopper not found.";
72 else if (
inputWS->getInstrument()->getComponentByName(
"correlation-chopper")->getStringParameter(
"sequence").empty())
73 errors[
"InputWorkspace"] =
"Found the correlation chopper but no chopper sequence?";
76 else if (!
inputWS->getInstrument()->getSource() || !
inputWS->getInstrument()->getSample())
77 errors[
"InputWorkspace"] =
"Instrument not sufficiently defined: failed to "
78 "get source and/or sample";
81 else if (!
inputWS->run().hasProperty(
"chopper4_TDC"))
82 errors[
"InputWorkspace"] =
"Workspace is missing chopper4 TDCs.";
85 else if (!
inputWS->run().hasProperty(
"BL9:Chop:Skf4:MotorSpeed"))
86 errors[
"InputWorkspace"] =
"Workspace is missing chopper4 Motor Speed.";
90 errors[
"InputWorkspace"] =
"The workspace needs to be a sorted.";
94 errors[
"InputWorkspace"] =
"This workspace has no pulse time information.";
113 std::vector<std::string> chopperSequence = chopper->getStringParameter(
"sequence");
116 std::vector<std::string> chopperSequenceSplit;
117 boost::split(chopperSequenceSplit, chopperSequence[0], boost::is_space());
119 std::vector<double> sequence;
120 sequence.resize(chopperSequenceSplit.size());
121 sequence[0] = boost::lexical_cast<double>(chopperSequenceSplit[0]);
124 double totalOpen = 0;
125 for (
unsigned int i = 1; i < chopperSequenceSplit.size(); i++) {
126 auto seqAngle = boost::lexical_cast<double>(chopperSequenceSplit[i]);
127 sequence[i] = sequence[i - 1] + seqAngle;
129 totalOpen += seqAngle;
133 double dutyCycle = totalOpen / sequence.back();
134 auto weightAbsorbing =
static_cast<float>(-dutyCycle / (1.0 - dutyCycle));
135 g_log.
information() <<
"dutyCycle = " << dutyCycle <<
" weightTransparent = 1.0"
136 <<
" weightAbsorbing = " << weightAbsorbing <<
"\n";
142 throw std::runtime_error(
"chopper4_TDC not found");
144 std::vector<DateAndTime> tdc = chopperTdc->timesAsVector();
147 const auto offset =
static_cast<int64_t
>(offset_int);
149 std::transform(tdc.begin(), tdc.end(), tdc.begin(), [offset](
auto timing) { return timing + offset; });
156 double period = 1e9 /
static_cast<double>(motorSpeed->timeAverageValue());
157 g_log.
information() <<
"Frequency = " << 1e9 / period <<
"Hz Period = " << period <<
"ns\n";
161 const double distanceChopperToSource =
inputWS->getInstrument()->getSource()->getDistance(*chopper);
162 const double distanceSourceToSample =
inputWS->getInstrument()->getSource()->getDistance(*sample);
165 std::vector<std::string> t0_formula =
inputWS->getInstrument()->getStringParameter(
"t0_formula");
166 if (t0_formula.empty())
168 std::string formula = t0_formula[0];
174 auto numHistograms =
static_cast<int64_t
>(
inputWS->getNumberHistograms());
176 const auto &spectrumInfo =
inputWS->spectrumInfo();
178 for (int64_t i = 0; i < numHistograms; ++i) {
181 auto &evlist =
outputWS->getSpectrum(i);
184 if (evlist.getEventType() ==
TOF)
187 std::vector<WeightedEvent> &events = evlist.getWeightedEvents();
194 DateAndTime emptyTime;
195 if (events.back().pulseTime() == emptyTime)
196 throw std::runtime_error(
"Missing pulse times on events. This will not work.");
199 double distanceSourceToDetector = distanceSourceToSample + spectrumInfo.l2(i);
200 double tofScale = distanceChopperToSource / distanceSourceToDetector;
204 parser.DefineVar(
"incidentEnergy",
206 parser.SetExpr(formula);
209 std::vector<WeightedEvent>::iterator it;
210 for (it = events.begin(); it != events.end(); ++it) {
211 double tof = it->tof();
212 E1 = m_convfactor * (distanceSourceToDetector / tof) * (distanceSourceToDetector / tof);
213 double t0 = parser.Eval();
215 DateAndTime tofTime = it->pulseTime() +
static_cast<int64_t
>(((tof - t0) * tofScale + t0) * 1000.);
216 while (tdc_i != tdc.size() && tofTime > tdc[tdc_i])
220 360. *
static_cast<double>(tofTime.totalNanoseconds() - tdc[tdc_i - 1].totalNanoseconds()) / period;
222 std::vector<double>::iterator location;
223 location = std::lower_bound(sequence.begin(), sequence.end(), angle);
225 if ((location - sequence.begin()) % 2 == 0) {
226 it->m_weight *= weightAbsorbing;
227 it->m_errorSquared *= weightAbsorbing * weightAbsorbing;
232 if ((events.back().pulseTime() +
static_cast<int64_t
>(events.back().tof() * 1000.)) >
233 (tdc.back() +
static_cast<int64_t
>(period * 2)))
#define DECLARE_ALGORITHM(classname)
#define PARALLEL_START_INTERRUPT_REGION
Begins a block to skip processing is the algorithm has been interupted Note the end of the block if n...
#define PARALLEL_END_INTERRUPT_REGION
Ends a block to skip processing is the algorithm has been interupted Note the start of the block if n...
#define PARALLEL_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
#define PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
A validator which checks that a workspace has a valid instrument.
Helper class for reporting progress from algorithms.
A property class for workspaces.
A validator which checks that the unit of the workspace referred to by a WorkspaceProperty is the exp...
CorelliCrossCorrelate : TODO: DESCRIPTION.
void exec() override
Execute the algorithm.
DataObjects::EventWorkspace_sptr outputWS
std::map< std::string, std::string > validateInputs() override
Method checking errors on ALL the inputs, before execution.
DataObjects::EventWorkspace_const_sptr inputWS
Input workspace.
Exception for errors associated with the instrument definition.
Exception for when an item is not found in a collection.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
A non-templated interface to a TimeSeriesProperty.
void debug(const std::string &msg)
Logs at debug level.
void warning(const std::string &msg)
Logs at warning level.
void information(const std::string &msg)
Logs at information level.
Validator to check that a property is not left empty.
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
A specialised Property class for holding a series of time-value pairs.
std::complex< double > MANTID_API_DLL E1(std::complex< double > z)
Integral for Gamma.
std::shared_ptr< const IComponent > IComponent_const_sptr
Typdef of a shared pointer to a const IComponent.
std::enable_if< std::is_pointer< Arg >::value, bool >::type threadSafe(Arg workspace)
Thread-safety check Checks the workspace to ensure it is suitable for multithreaded access.
static constexpr double NeutronMass
Mass of the neutron in kg.
static constexpr double meV
1 meV in Joules.
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
@ Input
An input workspace.
@ Output
An output workspace.