Newer
Older
#include "MantidDataHandling/ProcessDasNexusLog.h"
#include "MantidKernel/System.h"
#include "MantidKernel/MandatoryValidator.h"
#include "MantidAPI/MatrixWorkspace.h"
#include "MantidAPI/WorkspaceProperty.h"
#include "MantidKernel/TimeSeriesProperty.h"
#include "MantidKernel/Property.h"
#include "MantidKernel/DateAndTime.h"
#include "MantidAPI/FileProperty.h"
#include <fstream>
using namespace Mantid::Kernel;
using namespace Mantid::API;
namespace Mantid
{
namespace DataHandling
{
DECLARE_ALGORITHM(ProcessDasNexusLog)
//----------------------------------------------------------------------------------------------
/** Constructor
*/
ProcessDasNexusLog::ProcessDasNexusLog()
{
}
//----------------------------------------------------------------------------------------------
/** Destructor
*/
ProcessDasNexusLog::~ProcessDasNexusLog()
{
}
void ProcessDasNexusLog::initDocs(){
this->setWikiSummary("Some sample logs recorded by the SNS data acquisition group (DAS) are not usable. This very specialized algorithm will process sample logs of this type. ");
this->setOptionalMessage("Very specialized algorithm to fix certain SNS DAS logs that cannot be used directly.");
return;
}
void ProcessDasNexusLog::init()
{
this->declareProperty(new API::WorkspaceProperty<API::MatrixWorkspace>("InputWorkspace", "", Direction::InOut),
"Input Workspace containing the log to process.");
this->declareProperty("LogToProcess", "", boost::make_shared<MandatoryValidator<std::string> >(),
"Name of the log to process.");
this->declareProperty("ProcessedLog", "", boost::make_shared<MandatoryValidator<std::string> >(),
"Name of the new log containing processed log.");
this->declareProperty(new API::FileProperty("OutputDirectory", "", API::FileProperty::Directory),
"Directory for output files.");
this->declareProperty("NumberOfOutputs", 4000, "Number of log entries written to file. A negative input disables this option. ");
this->declareProperty(new API::FileProperty("OutputLogFile", "", API::FileProperty::OptionalSave),
"Directory for output files.");
return;
}
void ProcessDasNexusLog::exec()
{
// 1. Get input
API::MatrixWorkspace_sptr inWS = getProperty("InputWorkspace");
std::string inlogname = getProperty("LogToProcess");
std::string outlogname = getProperty("ProcessedLog");
int numentriesoutput = getProperty("NumberOfOutputs");
std::string outputfilename = getProperty("OutputLogFile");
// 2. Check Input
// 1. Get log
Kernel::Property* log(NULL);
try {
log = inWS->run().getProperty(inlogname);
} catch ( Exception::NotFoundError& )
{
// Will trigger non-existent log message below
}
if (!log)
{
g_log.error() << "Log " << inlogname << " does not exist!" << std::endl;
throw std::invalid_argument("Non-existent log name");
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
}
Kernel::TimeSeriesProperty<double>* tslog = dynamic_cast<Kernel::TimeSeriesProperty<double>* >(log);
if (!tslog)
{
g_log.error() << "Log " << inlogname << " is not time series log" << std::endl;
throw std::invalid_argument("Log type error!");
}
// 3. Do some check for log statistic
checkLog(inWS, inlogname);
// 3. Convert Das log to log for absolute time
std::vector<Kernel::DateAndTime> abstimevec;
std::vector<double> orderedtofs;
convertToAbsoluteTime(inWS, inlogname, abstimevec, orderedtofs);
// 4. Add vector to log
addLog(inWS, abstimevec, 1.0, outlogname, tslog->timesAsVector(), orderedtofs, false);
// 5. Optionally write out log to
if (numentriesoutput > 0)
{
this->writeLogtoFile(inWS, inlogname, static_cast<size_t>(numentriesoutput), outputfilename);
}
}
/*
* Add and check log from processed absolute time stamps
*/
void ProcessDasNexusLog::addLog(API::MatrixWorkspace_sptr ws, std::vector<Kernel::DateAndTime> timevec,
double unifylogvalue, std::string logname, std::vector<Kernel::DateAndTime> pulsetimes,
std::vector<double> orderedtofs, bool docheck)
{
// 1. Do some static
g_log.notice() << "Vector size = " << timevec.size() << std::endl;
double sum1dtms = 0.0; // sum(dt^2)
double sum2dtms = 0.0; // sum(dt^2)
size_t numinvert = 0;
size_t numsame = 0;
size_t numnormal = 0;
double maxdtms = 0;
double mindtms = 1.0E20;
size_t numdtabove10p = 0;
size_t numdtbelow10p = 0;
double sampledtms = 0.00832646*1.0E6;
double dtmsA10p = sampledtms*1.1;
double dtmsB10p = sampledtms/1.0;
for (size_t i = 1; i < timevec.size(); i ++)
{
int64_t dtns = timevec[i].totalNanoseconds()-timevec[i-1].totalNanoseconds();
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
double dtms = static_cast<double>(dtns)*1.0E-3;
sum1dtms += dtms;
sum2dtms += dtms*dtms;
if (dtns == 0)
numsame ++;
else if (dtns < 0)
numinvert ++;
else
numnormal ++;
if (dtms > maxdtms)
maxdtms = dtms;
if (dtms < mindtms)
mindtms = dtms;
if (dtms > dtmsA10p)
numdtabove10p ++;
else if (dtms < dtmsB10p)
numdtbelow10p ++;
} // ENDFOR
double dt = sum1dtms/static_cast<double>(timevec.size())*1.0E-6;
double stddt = sqrt(sum2dtms/static_cast<double>(timevec.size())*1.0E-12 - dt*dt);
g_log.notice() << "Normal dt = " << numnormal << std::endl;
g_log.notice() << "Zero dt = " << numsame << std::endl;
g_log.notice() << "Negative dt = " << numinvert << std::endl;
g_log.notice() << "Avg d(T) = " << dt << " seconds +/- " << stddt << ", Frequency = " << 1.0/dt << std::endl;
g_log.notice() << "d(T) (unit ms) is in range [" << mindtms << ", " << maxdtms << "]"<< std::endl;
g_log.notice() << "Number of d(T) 10% larger than average = " << numdtabove10p << std::endl;
g_log.notice() << "Number of d(T) 10% smaller than average = " << numdtbelow10p << std::endl;
g_log.notice() << "Size of timevec, pulsestimes, orderedtofs = " << timevec.size() << ", "
<< pulsetimes.size() << ", " << orderedtofs.size() << std::endl;
if (docheck)
{
exportErrorLog(ws, timevec, pulsetimes, orderedtofs, 1/(0.5*240.1));
calDistributions(timevec, 1/(0.5*240.1));
}
// 2. Add log
Kernel::TimeSeriesProperty<double>* newlog = new Kernel::TimeSeriesProperty<double>(logname);
for (size_t i = 0; i < timevec.size(); i ++)
{
newlog->addValue(timevec[i], unifylogvalue);
}
ws->mutableRun().addProperty(newlog, true);
return;
}
/*
* Export time stamps looking erroreous
*/
void ProcessDasNexusLog::exportErrorLog(API::MatrixWorkspace_sptr ws, std::vector<Kernel::DateAndTime> abstimevec,
std::vector<Kernel::DateAndTime> pulsetimes, std::vector<double>orderedtofs, double dts)
{
std::string outputdir = getProperty("OutputDirectory");
if (outputdir[outputdir.size()-1] != '/')
outputdir += "/";
std::string ofilename = outputdir + "errordeltatime.txt";
g_log.notice() << ofilename << std::endl;
std::ofstream ofs;
ofs.open(ofilename.c_str(), std::ios::out);
size_t numbaddt = 0;
Kernel::DateAndTime t0(ws->run().getProperty("run_start")->value());
for (size_t i = 1; i < abstimevec.size(); i++)
{
double tempdts = static_cast<double>(abstimevec[i].totalNanoseconds()-abstimevec[i-1].totalNanoseconds())*1.0E-9;
double dev = (tempdts-dts)/dts;
bool baddt = false;
if (fabs(dev) > 0.5)
baddt = true;
if (baddt)
{
numbaddt ++;
double deltapulsetimeSec1 = static_cast<double>(pulsetimes[i-1].totalNanoseconds()-t0.totalNanoseconds())*1.0E-9;
double deltapulsetimeSec2 = static_cast<double>(pulsetimes[i].totalNanoseconds()-t0.totalNanoseconds())*1.0E-9;
int index1 = static_cast<int>(deltapulsetimeSec1*60);
int index2 = static_cast<int>(deltapulsetimeSec2*60);
ofs << "Error d(T) = " << tempdts << " vs Correct d(T) = " << dts << std::endl;
ofs << index1 << "\t\t" << pulsetimes[i-1].totalNanoseconds() << "\t\t" << orderedtofs[i-1] << std::endl;
ofs << index2 << "\t\t" << pulsetimes[i].totalNanoseconds() << "\t\t" << orderedtofs[i] << std::endl;
}
}
ofs.close();
}
/*
* Output distributions in order for a better understanding of the log
* @param dts: d(T) in second
*/
void ProcessDasNexusLog::calDistributions(std::vector<Kernel::DateAndTime> timevec, double dts)
{
// 1. Calculate percent deviation vs. number of cases
std::vector<double> x1, y1;
for (int i=-99; i < 100; i++)
{
x1.push_back(static_cast<double>(i));
y1.push_back(0);
}
for (size_t i = 1; i < timevec.size(); i ++)
{
double tempdts = static_cast<double>(timevec[i].totalNanoseconds()-timevec[i-1].totalNanoseconds())*1.0E-9;
int index = static_cast<int>((tempdts-dts)/dts*100)+99;
if (index < 0)
index = 0;
else if (index > 199)
index = 19;
y1[static_cast<size_t>(index)]++;
}
/* Skip output */
for (size_t i = 0; i < x1.size(); i ++)
g_log.notice() << i << "\t\t" << x1[i] << "\t\t" << y1[i] << std::endl;
/**/
// 2. Calculate space distribution on error cases
std::vector<double> x2s;
std::vector<size_t> y2;
size_t numperiods = 100;
int64_t spanns = timevec[timevec.size()-1].totalNanoseconds()-timevec[0].totalNanoseconds();
double timestepsec = static_cast<double>(spanns)*1.0E-9/static_cast<double>(numperiods);
for (size_t i = 0; i < numperiods; i++)
{
x2s.push_back(static_cast<double>(i)*timestepsec);
y2.push_back(0);
}
size_t numbaddt = 0;
for (size_t i = 1; i < timevec.size(); i ++)
{
double tempdts = static_cast<double>(timevec[i].totalNanoseconds()-timevec[i-1].totalNanoseconds())*1.0E-9;
double dev = (tempdts-dts)/dts;
bool baddt = false;
if (fabs(dev) > 0.5)
baddt = true;
if (baddt)
{
numbaddt ++;
int index = static_cast<int>(static_cast<double>(timevec[i].totalNanoseconds()-timevec[0].totalNanoseconds())*1.0E-9/timestepsec);
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
if (index < 0)
throw std::runtime_error("Impossible to have index less than 0");
if (index >= static_cast<int>(numperiods))
{
g_log.error() << "Logic error X" << std::endl;
index = static_cast<int>(numperiods)-1;
}
y2[static_cast<size_t>(index)] ++;
}
} // ENDFOR
/* Skip
for (size_t i = 0; i < x2s.size(); i ++)
g_log.notice() << i << "\t\t" << x2s[i] << "\t\t" << y2[i] << std::endl;
*/
g_log.notice() << "total number of wrong dt = " << numbaddt << std::endl;
return;
}
/*
* Check log in workspace
*/
void ProcessDasNexusLog::checkLog(API::MatrixWorkspace_sptr ws, std::string logname)
{
// 1. Get log
Kernel::Property* log = ws->run().getProperty(logname);
if (!log)
{
g_log.error() << "Log " << logname << " does not exist!" << std::endl;
throw std::invalid_argument("Non-exising log name");
}
Kernel::TimeSeriesProperty<double>* tslog = dynamic_cast<Kernel::TimeSeriesProperty<double>* >(log);
if (!tslog)
{
g_log.error() << "Log " << logname << " is not time series log" << std::endl;
throw std::invalid_argument("Log type error!");
}
// 2. Survey
std::vector<Kernel::DateAndTime> times = tslog->timesAsVector();
g_log.information() << "Entries of times = " << times.size() << std::endl;
size_t countsame = 0;
size_t countinverse = 0;
for (size_t i=1; i<times.size(); i++)
{
Kernel::DateAndTime tprev = times[i-1];
Kernel::DateAndTime tpres = times[i];
if (tprev == tpres)
countsame ++;
else if (tprev > tpres)
countinverse ++;
}
// 3. Output
Kernel::DateAndTime t0(ws->run().getProperty("run_start")->value());
Kernel::time_duration dts = times[0]-t0;
Kernel::time_duration dtf = times[times.size()-1]-t0;
size_t f = times.size()-1;
g_log.information() << "Number of Equal Time Stamps = " << countsame << std::endl;
g_log.information() << "Number of Inverted Time Stamps = " << countinverse << std::endl;
g_log.information() << "Run Start = " << t0.totalNanoseconds() << std::endl;
g_log.information() << "First Log (Absolute Time, Relative Time): " << times[0].totalNanoseconds() << ", "
<< Kernel::DateAndTime::nanosecondsFromDuration(dts) << std::endl;
g_log.information() << "Last Log (Absolute Time, Relative Time): " << times[f].totalNanoseconds() << ", "
<< Kernel::DateAndTime::nanosecondsFromDuration(dtf) << std::endl;
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
return;
}
/*
* Convert DAS log to a vector of absolute time
* @param orderedtofs: tofs with abstimevec
*/
void ProcessDasNexusLog::convertToAbsoluteTime(API::MatrixWorkspace_sptr ws, std::string logname,
std::vector<Kernel::DateAndTime>& abstimevec, std::vector<double>& orderedtofs)
{
// 1. Get log
Kernel::Property* log = ws->run().getProperty(logname);
Kernel::TimeSeriesProperty<double>* tslog = dynamic_cast<Kernel::TimeSeriesProperty<double>* >(log);
std::vector<Kernel::DateAndTime> times = tslog->timesAsVector();
std::vector<double> values = tslog->valuesAsVector();
// 2. Get converted
size_t numsamepulses = 0;
std::vector<double> tofs;
Kernel::DateAndTime prevtime(0);
for (size_t i = 0; i < times.size(); i ++)
{
Kernel::DateAndTime tnow = times[i];
if (tnow > prevtime)
{
// (a) Process previous logs
std::sort(tofs.begin(), tofs.end());
for (size_t j=0; j<tofs.size(); j++)
{
Kernel::DateAndTime temptime = prevtime+static_cast<int64_t>(tofs[j]*100);
abstimevec.push_back(temptime);
orderedtofs.push_back(tofs[j]);
}
// (b) Clear
tofs.clear();
// (c) Update time
prevtime = tnow;
}
else
{
numsamepulses ++;
}
// (d) Push the current value
tofs.push_back(values[i]);
} // ENDFOR
// Clear the last
if (!tofs.empty())
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
{
// (a) Process previous logs: note value is in unit of 100 nano-second
std::sort(tofs.begin(), tofs.end());
for (size_t j=0; j<tofs.size(); j++)
{
Kernel::DateAndTime temptime = prevtime+static_cast<int64_t>(tofs[j]*100);
abstimevec.push_back(temptime);
orderedtofs.push_back(tofs[j]);
}
}
else
{
throw std::runtime_error("Impossible for this to happen!");
}
return;
} // END Function
/*
* Write a certain number of log entries (from beginning) to file
*/
void ProcessDasNexusLog::writeLogtoFile(API::MatrixWorkspace_sptr ws, std::string logname,
size_t numentriesoutput, std::string outputfilename)
{
// 1. Get log
Kernel::Property* log = ws->run().getProperty(logname);
Kernel::TimeSeriesProperty<double>* tslog = dynamic_cast<Kernel::TimeSeriesProperty<double>* >(log);
std::vector<Kernel::DateAndTime> times = tslog->timesAsVector();
std::vector<double> values = tslog->valuesAsVector();
// 2. Write out
std::ofstream ofs;
ofs.open(outputfilename.c_str(), std::ios::out);
ofs << "# Absolute Time (nanosecond)\tPulse Time (nanosecond)\tTOF (ms)" << std::endl;
Kernel::DateAndTime prevtime(0);
std::vector<double> tofs;
for (size_t i = 0; i < numentriesoutput; i ++)
{
Kernel::DateAndTime tnow = times[i];
if (tnow > prevtime)
{
// (a) Process previous logs
std::sort(tofs.begin(), tofs.end());
for (size_t j=0; j<tofs.size(); j++)
{
Kernel::DateAndTime temptime = prevtime+static_cast<int64_t>(tofs[j]*100);
ofs << temptime.totalNanoseconds() << "\t" << tnow.totalNanoseconds() << "\t"
<< tofs[j]*0.1 << std::endl;
}
// (b) Clear
tofs.clear();
// (c) Update time
prevtime = tnow;
}
// (d) Push the current value
tofs.push_back(values[i]);
} // ENDFOR
// Clear the last
if (!tofs.empty())
{
// (a) Process previous logs: note value is in unit of 100 nano-second
std::sort(tofs.begin(), tofs.end());
for (size_t j=0; j<tofs.size(); j++)
{
Kernel::DateAndTime temptime = prevtime+static_cast<int64_t>(tofs[j]*100);
ofs << temptime.totalNanoseconds() << "\t" << prevtime.totalNanoseconds() << "\t"
<< tofs[j]*0.1 << std::endl;
}
}
else
{
throw std::runtime_error("Impossible for this to happen!");
}
ofs.close();
return;
} // END Function
} // namespace Mantid
} // namespace DataHandling