musrfit/src/addRun.cpp

852 lines
30 KiB
C++

/***************************************************************************
addRun.cpp
Author: Andreas Suter
e-mail: andreas.suter@psi.ch
***************************************************************************/
/***************************************************************************
* Copyright (C) 2007-2022 by Andreas Suter *
* andreas.suter@psi.ch *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <fstream>
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <TString.h>
#ifdef HAVE_GIT_REV_H
#include "git-revision.h"
#endif
#include "PMusr.h"
#include "PStartupHandler.h"
#include "PRunDataHandler.h"
#include "PFindRun.h"
struct PAddRunInfo {
std::string fPathFileName{""};
PIntVector fT0;
std::string fFileFormat{""};
};
//--------------------------------------------------------------------------
/**
* <p>Sends the usage description to the standard output.
*/
void addRun_syntax()
{
std::cout << std::endl;
std::cout << "usage0: addRun [--help | -h] | [--version | -v]" << std::endl;
std::cout << "usage1: addRun <options1> -rl <runList>" << std::endl;
std::cout << "usage2: addRun <options2> -in <inputFile>" << std::endl;
std::cout << std::endl;
std::cout << " <options1>:" << std::endl;
std::cout << " -t0 <ival>: <ival> is a comma separted list of global t0-bin's, or" << std::endl;
std::cout << " <ival> is a comma separted list of '-1', then it is assumed that there is a prompt peak." << std::endl;
std::cout << " Under this condition the t0-bin will be determined automatically by" << std::endl;
std::cout << " the position of the max-value of the corresponing histograms." << std::endl;
std::cout << " If t0's are not provided, t0-bin will be taken from the file." << std::endl;
std::cout << " -f <format>: <format> is the output file format to be used." << std::endl;
std::cout << " For supported formats see below." << std::endl;
std::cout << " -y <year> : the year at which runs were measured. Format yyyy." << std::endl;
std::cout << " If not provided, the current year is used." << std::endl;
std::cout << " -i <instrument> : <instrument> is one of gps, ltf, flame, gpd, hifi, dolly, lem" << std::endl;
std::cout << " -m <dev> : <dev> is pta or tdc (only needed for bulk). Default: tdc" << std::endl;
std::cout << " -o <fln> : output file name." << std::endl;
std::cout << " -rl <runList> can be:" << std::endl ;
std::cout << " (i) <run0> <run1> <run2> ... <runN> : run numbers, e.g. 123 124" << std::endl;
std::cout << " (ii) <run0>-<runN> : a range, e.g. 123-125 -> 123 124 125" << std::endl;
std::cout << " (iii) <run0>:<runN>:<step> : a sequence, e.g. 123:127:2 -> 123 125 127" << std::endl;
std::cout << " <step> will give the step width and has to be a positive number!" << std::endl;
std::cout << " a <runList> can also combine (i)-(iii), e.g. 123 128-130 133, etc." << std::endl;
std::cout << std::endl;
std::cout << " <options2>:" << std::endl;
std::cout << " -f <format>: <format> is file format of the output-file to be used." << std::endl;
std::cout << " -o <fln> : output file name." << std::endl;
std::cout << " -in <inputFile>: the file name of the file containing the necessary run information" << std::endl;
std::cout << " to add runs with various t0's, fgb's, lgb's, different years, etc." << std::endl;
std::cout << " The structure of the <inputFile> is:" << std::endl;
std::cout << " Lines starting with a '%' and empty lines are ignored." << std::endl;
std::cout << " A single run needs to provide the following information:" << std::endl;
std::cout << " file <path-name>: needs to be a full path name" << std::endl;
std::cout << " t0 <t0-bin> : needs to be the t0 bin or " << std::endl;
std::cout << " 0 to take the t0 bin from the file, or" << std::endl;
std::cout << " -1 for automatic determination via prompt peak (see above)." << std::endl;
std::cout << " Example:" << std::endl;
std::cout << " % file 1. 6 histos present, hence 6 t0-bins" << std::endl;
std::cout << " file /home/test/data/deltat_tdc_gps_4324.bin" << std::endl;
std::cout << " t0 401, 400, 399, 400, 358, 400" << std::endl;
std::cout << " % file 2, take t0-bins from the file" << std::endl;
std::cout << " file /home/test/data/deltat_tdc_gps_4325.bin" << std::endl;
std::cout << " % file 3, deduce to t0-bin's from the prompt peak" << std::endl;
std::cout << " file /home/test/data/deltat_tdc_gps_4325.bin" << std::endl;
std::cout << " t0 -1, -1, -1, -1, -1, -1" << std::endl;
std::cout << std::endl;
std::cout << " Supported uSR file formats:" << std::endl;
std::cout << " MusrRoot, PSI-BIN, PSI-MDU, MUD, NeXus" << std::endl;
std::cout << std::endl;
}
//--------------------------------------------------------------------------
/**
* <p> check if the requested format is supported.
*
* @param format requested format string
*
* @return true if supported, false otherwise
*/
bool addRun_checkFormat(std::string &format) {
bool result = false;
boost::to_lower(format);
if (format == "psi-bin")
format = "psibin";
if (format == "psi-mud")
format = "psimdu";
if (format == "musrroot") {
result = true;
} else if (format == "psibin") {
result = true;
} else if (format == "psimdu") {
result = true;
} else if (format == "mud") {
result = true;
} else if (format == "nexus") {
result = true;
} else if (format == "root") {
result = true;
}
return result;
}
//--------------------------------------------------------------------------
/**
* <p>Reads the inputFile to extract the necessary information.
* @param fileName
* @param infoVec
* @return
*/
bool addRun_readInputFiles(const std::string fileName, std::vector<PAddRunInfo> &infoVec)
{
PAddRunInfo info;
char buf[256], str[256];
std::ifstream fin(fileName.c_str(), std::ifstream::in);
std::string line;
char *tok{nullptr};
int status, ival;
bool lastWasFile{false};
while (fin.good()) {
fin.getline(buf, 256);
line = buf;
boost::trim_left(line);
if (line.empty())
continue;
if (line[0] == '%')
continue;
strcpy(buf, line.c_str());
tok = strtok(buf, " ");
if (!strcmp(tok, "file")) {
if (lastWasFile) {
infoVec.push_back(info);
info.fPathFileName = "";
info.fT0.clear();
}
tok = strtok(NULL, " ");
if (tok == NULL) {
std::cerr << std::endl;
std::cerr << "**ERROR** found label 'file' without argument." << std::endl;
std::cerr << std::endl;
fin.close();
return false;
}
info.fPathFileName = tok;
lastWasFile = true;
} else if (!strcmp(tok, "t0")) {
while ((tok = strtok(NULL, ",")) != NULL) {
status = sscanf(tok, "%d%s", &ival, str);
if (status != 1) {
std::cerr << std::endl;
std::cerr << "**ERROR** found t0 argument '" << tok << "' which is not a number." << std::endl;
std::cerr << std::endl;
fin.close();
return false;
}
info.fT0.push_back(ival);
}
} else {
std::cerr << std::endl;
std::cerr << "**ERROR** found unrecognized token '" << tok << "'." << std::endl;
std::cerr << std::endl;
fin.close();
return false;
}
}
infoVec.push_back(info);
fin.close();
// checks
for (int i=0; i<infoVec.size(); i++) {
if (infoVec[i].fPathFileName.empty()) {
std::cerr << std::endl;
std::cerr << "**ERROR** something is wrong with the inputFile. Found empty pathName." << std::endl;
std::cerr << std::endl;
return false;
}
}
return true;
}
//--------------------------------------------------------------------------
/**
* <p>Automatically determines the t0-bin. This assumes that there is a
* prompt peak in the data!
*
* @param vec histo data
* @return maximum of the histo data
*/
UInt_t addRun_getPromptPeakPos(PDoubleVector *vec)
{
UInt_t pos=0;
Double_t max=vec->at(0);
for (UInt_t i=0; i<vec->size(); i++) {
if (max < vec->at(i)) {
max = vec->at(i);
pos = i;
}
}
return pos;
}
//--------------------------------------------------------------------------
/**
* <p>Filters the t0 arguments. Allowed is a comma separeted list of
* integers > -2.
*
* @param argc argument counter
* @param argv argument list
* @param idx argument index from which to start
* @param t0 vector
*
* @return true on success, false otherwise
*/
bool addRun_filter_t0(int argc, char *argv[], int &idx, PIntVector &t0)
{
int pos{idx}, status, ival;
PIntVector tt0;
// collect run list string from input
for (int i=idx; i<argc; i++) {
pos = i;
if ((argv[i][0] == '-') && isalpha(argv[i][1])) { // next command
pos = i-1;
break;
} else {
status = sscanf(argv[i], "%d", &ival);
if (status != 1) {
std::cerr << std::endl;
std::cerr << "**ERROR** found t0 value '" << argv[i] << "' which is not an integer." << std::endl;
std::cerr << std::endl;
return false;
}
tt0.push_back(ival);
}
}
// make sure that t0's > -2
for (int i=0; i<tt0.size(); i++) {
if (tt0[i] <= -2) {
std::cerr << std::endl;
std::cerr << "**ERROR** found t0 value '" << tt0[i] << "' which is out-of-range." << std::endl;
std::cerr << std::endl;
return false;
}
}
idx = pos;
t0 = tt0;
return true;
}
//--------------------------------------------------------------------------
/**
* <p>Filters the runList arguments. Allowed are: (i) run1 run2 ... runN
* (ii) runStart-runEnd, and (iii) runStart:runEnd:step
*
* @param argc argument counter
* @param argv argument list
* @param idx argument index from which to start
* @param runList vector
*
* @return true on success, false otherwise
*/
bool addRun_filter_runList(int argc, char *argv[], int &idx, PUIntVector &runList)
{
int pos{idx};
std::string runStr{""};
// collect run list string from input
for (int i=idx; i<argc; i++) {
pos = i;
if ((argv[i][0] == '-') && isalpha(argv[i][1])) { // next command
pos = i-1;
break;
} else {
runStr += argv[i];
runStr += " ";
}
}
// extract run list from string
PStringNumberList rl(runStr);
std::string errMsg{""};
if (!rl.Parse(errMsg)) {
std::cerr << "**ERROR** in run list: -rl " << runStr << std::endl;
std::cerr << errMsg << std::endl;
return false;
}
runList = rl.GetList();
idx = pos;
return true;
}
//--------------------------------------------------------------------------
/**
* <p>addRun is used to add various runs.
*
* @param argc number of input arguments
* @param argv list of input arguments
*
* @return PMUSR_SUCCESS if everthing went smooth, otherwise and error number
*/
int main(int argc, char *argv[])
{
// check for --help or --version
if (argc == 2) {
if (!strncmp(argv[1], "--help", 128) || !strncmp(argv[1], "-h", 128)) {
addRun_syntax();
return PMUSR_SUCCESS;
} else if (!strncmp(argv[1], "--version", 128) || !strncmp(argv[1], "-v", 128)) {
#ifdef HAVE_CONFIG_H
#ifdef HAVE_GIT_REV_H
std::cout << std::endl << "addRun version: " << PACKAGE_VERSION << ", git-branch: " << GIT_BRANCH << ", git-rev: " << GIT_CURRENT_SHA1 << " (" << BUILD_TYPE << "), ROOT version: " << ROOT_VERSION_USED << std::endl << std::endl;
#else
std::cout << std::endl << "addRun version: " << PACKAGE_VERSION << " (" << BUILD_TYPE << "), ROOT version: " << ROOT_VERSION_USED << std::endl << std::endl;
#endif
#else
#ifdef HAVE_GIT_REV_H
std::cout << std::endl << "addRun git-branch: " << GIT_BRANCH << ", git-rev: " << GIT_CURRENT_SHA1 << std::endl << std::endl;
#else
std::cout << std::endl << "addRun version: unkown." << std::endl << std::endl;
#endif
#endif
return PMUSR_SUCCESS;
} else {
std::cerr << std::endl;
std::cerr << "**ERROR** missing required input." << std::endl;
std::cerr << std::endl;
addRun_syntax();
return -1;
}
}
// filter arguments
PIntVector t0;
Int_t ival;
UInt_t yearNum{0};
std::string flnOut{""};
std::string format{""}, year{""}, instrument{""}, dev{"tdc"};
PUIntVector runList;
std::string inputFln{""};
int status;
std::vector<PAddRunInfo> addRunInfo;
for (int i=1; i<argc; i++) {
if (!strcmp(argv[i], "-t0")) {
if (i+1 >= argc) {
std::cerr << std::endl;
std::cerr << "**ERROR** found -t0 without value." << std::endl;
std::cerr << std::endl;
return -1;
}
// deal with run-list here
int idx=i+1;
if (!addRun_filter_t0(argc, argv, idx, t0)) {
return -2;
}
i=idx;
} else if (!strcmp(argv[i], "-f")) {
if (i+1 >= argc) {
std::cerr << std::endl;
std::cerr << "**ERROR** found -f without argument." << std::endl;
std::cerr << std::endl;
return -1;
}
format = argv[i+1];
if (!addRun_checkFormat(format)) {
format = "";
std::cerr << std::endl;
std::cerr << "**ERROR** found -f with unsupported format: '" << format << "'" << std::endl;
std::cerr << std::endl;
return -2;
}
i++;
} else if (!strcmp(argv[i], "-y")) {
if (i+1 >= argc) {
std::cerr << std::endl;
std::cerr << "**ERROR** found -y without value." << std::endl;
std::cerr << std::endl;
return -1;
}
status = sscanf(argv[i+1], "%d", &ival);
if (status != 1) {
std::cerr << std::endl;
std::cerr << "**ERROR** found invalid -y value: " << argv[i+1] << "." << std::endl;
std::cerr << std::endl;
return -2;
}
if (1900 - ival > 0) {
std::cerr << std::endl;
std::cerr << "**ERROR** found invalid -y value: " << argv[i+1] << "." << std::endl;
std::cerr << " Format has to be YYYY." << std::endl;
std::cerr << std::endl;
return -2;
}
yearNum = ival;
year = argv[i+1];
i++;
} else if (!strcmp(argv[i], "-i")) {
if (i+1 >= argc) {
std::cerr << std::endl;
std::cerr << "**ERROR** found -i without argument." << std::endl;
std::cerr << std::endl;
return -1;
}
instrument = argv[i+1];
boost::to_lower(instrument);
i++;
} else if (!strcmp(argv[i], "-m")) {
if (i+1 >= argc) {
std::cerr << std::endl;
std::cerr << "**ERROR** found -m without argument." << std::endl;
std::cerr << std::endl;
return -1;
}
std::string str(argv[i+1]);
boost::to_lower(str);
if ((str != "pta") && (str != "tdc")) {
std::cerr << std::endl;
std::cerr << "**ERROR** found -m with unsupported argument '" << argv[i+1] << "'. Possible arguments are 'pta' or 'tdc'." << std::endl;
std::cerr << std::endl;
return -2;
}
dev = str;
i++;
} else if (!strcmp(argv[i], "-o")) {
if (i+1 >= argc) {
std::cerr << std::endl;
std::cerr << "**ERROR** found -o without argument." << std::endl;
std::cerr << std::endl;
return -1;
}
flnOut = argv[i+1];
i++;
} else if (!strcmp(argv[i], "-rl")) {
if (i+1 >= argc) {
std::cerr << std::endl;
std::cerr << "**ERROR** found -rl without argument." << std::endl;
std::cerr << std::endl;
return -1;
}
// deal with run-list here
int idx=i+1;
if (!addRun_filter_runList(argc, argv, idx, runList)) {
return -2;
}
i=idx;
} else if (!strcmp(argv[i], "-in")) {
if (i+1 >= argc) {
std::cerr << std::endl;
std::cerr << "**ERROR** found -in without argument." << std::endl;
std::cerr << std::endl;
return -1;
}
inputFln = argv[i+1];
i++;
} else { // error
std::cerr << std::endl;
std::cerr << "**ERROR** found unexpected command line element '" << argv[i] << "'" << std::endl;
std::cerr << std::endl;
addRun_syntax();
return -1;
}
}
// test for usage1 or usage2
if (inputFln.empty() && (runList.size() == 0)) {
std::cerr << std::endl;
std::cerr << "**ERROR** essential input for usage1 and usage2 is missing." << std::endl;
std::cerr << std::endl;
addRun_syntax();
return -3;
}
if (!inputFln.empty() && (runList.size() > 0)) {
std::cerr << std::endl;
std::cerr << "**ERROR** cannot decide if usage1 or usage2." << std::endl;
std::cerr << std::endl;
addRun_syntax();
return -3;
}
// read startup file
char startup_path_name[128];
TSAXParser *saxParser = new TSAXParser();
PStartupHandler *startupHandler = new PStartupHandler();
if (!startupHandler->StartupFileFound()) {
std::cerr << std::endl << ">> addRun **WARNING** couldn't find " << startupHandler->GetStartupFilePath().Data();
std::cerr << std::endl;
// clean up
if (saxParser) {
delete saxParser;
saxParser = nullptr;
}
if (startupHandler) {
delete startupHandler;
startupHandler = nullptr;
}
} else {
strcpy(startup_path_name, startupHandler->GetStartupFilePath().Data());
saxParser->ConnectToHandler("PStartupHandler", startupHandler);
//status = saxParser->ParseFile(startup_path_name);
// parsing the file as above seems to lead to problems in certain environments;
// use the parseXmlFile function instead (see PStartupHandler.cpp for the definition)
status = parseXmlFile(saxParser, startup_path_name);
// check for parse errors
if (status) { // error
std::cerr << std::endl << ">> addRun **WARNING** Reading/parsing musrfit_startup.xml failed.";
std::cerr << std::endl;
// clean up
if (saxParser) {
delete saxParser;
saxParser = nullptr;
}
if (startupHandler) {
delete startupHandler;
startupHandler = nullptr;
}
} else {
startupHandler->CheckLists();
}
}
// additional tests needed for usage1 (currently for PSI use only)
if (runList.size() > 0) {
if (t0.empty()) {
std::cout << ">> t0 not provided.";
} else {
std::cout << ">> t0: ";
for (int i=0; i<t0.size(); i++)
std::cout << t0[i] << ", ";
}
std::cout << std::endl;
std::cout << ">> format: " << format << std::endl;
std::cout << ">> year: " << year << std::endl;
std::cout << ">> instrument: " << instrument << std::endl;
std::cout << ">> fln out: " << flnOut << std::endl;
std::cout << ">> runList: ";
for (int i=0; i<runList.size(); i++)
std::cout << runList[i] << ", ";
std::cout << std::endl;
PAddRunInfo addRun;
addRun.fT0 = t0;
addRun.fFileFormat = format;
// construct file names
for (int i=0; i<runList.size(); i++) {
PFindRun findRun(startupHandler->GetDataPathList(), startupHandler->GetRunNameTemplateList(), instrument, yearNum, runList[i]);
if (findRun.FoundPathName()) {
std::cout << ">> found path name: " << findRun.GetPathName() << std::endl;
addRun.fPathFileName = findRun.GetPathName();
addRunInfo.push_back(addRun);
} else {
std::cout << "**WARNING** run: " << runList[i] << " for instrument '" << instrument << "' and year '" << year << "' not found" << std::endl;
}
}
}
// additional tests needed for usage2
if (!inputFln.empty()) {
// check if file exists
if (!boost::filesystem::exists(inputFln)) {
std::cerr << std::endl;
std::cerr << "**ERROR** file '" << inputFln << "' seems not to exist." << std::endl;
std::cerr << std::endl;
return -1;
}
// read input-file and data sets
if (!addRun_readInputFiles(inputFln, addRunInfo)) {
return -2;
}
}
for (int i=0; i<addRunInfo.size(); i++) {
std::cout << ">> run " << i+1 << ": " << std::endl;
std::cout << ">> fln : " << addRunInfo[i].fPathFileName << std::endl;
if (addRunInfo[i].fT0.empty()) {
std::cout << ">> t0 not provided.";
} else {
std::cout << ">> t0: ";
for (int j=0; j<addRunInfo[i].fT0.size(); j++) {
std::cout << addRunInfo[i].fT0[j] << ", ";
}
}
std::cout << std::endl;
}
// load the files
std::vector<PRunDataHandler*> runDataHandler;
runDataHandler.resize(addRunInfo.size());
Bool_t isGood{true};
for (UInt_t i=0; i<runDataHandler.size(); i++) {
if (startupHandler != nullptr) {
runDataHandler[i] = new PRunDataHandler(addRunInfo[i].fPathFileName, addRunInfo[i].fFileFormat, startupHandler->GetDataPathList());
if (runDataHandler[i] == nullptr) {
isGood = false;
std::cerr << std::endl;
std::cerr << "**ERROR** couldn't invoke PRunDataHandler (i=" << i << ")." << std::endl;
std::cerr << std::endl;
break;
}
runDataHandler[i]->ReadData();
if (!runDataHandler[i]->IsAllDataAvailable()) {
isGood = false;
std::cerr << std::endl;
std::cerr << "**ERROR** couldn't read data for PRunDataHandler (i=" << i << ")." << std::endl;
std::cerr << std::endl;
break;
}
} else {
runDataHandler[i] = new PRunDataHandler(addRunInfo[i].fPathFileName, addRunInfo[i].fFileFormat);
if (runDataHandler[i] == nullptr) {
isGood = false;
std::cerr << std::endl;
std::cerr << "**ERROR** couldn't invoke PRunDataHandler (i=" << i << ")." << std::endl;
std::cerr << std::endl;
break;
}
runDataHandler[i]->ReadData();
if (!runDataHandler[i]->IsAllDataAvailable()) {
isGood = false;
std::cerr << std::endl;
std::cerr << "**ERROR** couldn't read data for PRunDataHandler (i=" << i << ")." << std::endl;
std::cerr << std::endl;
break;
}
}
}
// make sure that the number of provided t0's are matching the number of histos from the run-file
// 1st make sure all the runs have the same number run data (==1 here)
PAny2ManyInfo *info{nullptr};
PRunDataHandler *dataOut{nullptr};
if (isGood) {
for (UInt_t i=1; i<runDataHandler.size(); i++) {
if (runDataHandler[0]->GetNoOfRunData() != runDataHandler[i]->GetNoOfRunData()) {
isGood = false;
std::cerr << std::endl;
std::cerr << "**ERROR** can only handle same number of run data per run handler." << std::endl;
std::cerr << std::endl;
break;
}
}
info = new PAny2ManyInfo();
if (info == nullptr) {
std::cerr << std::endl;
std::cerr << "**ERROR** couldn't invoke PAny2ManyInfo." << std::endl;
std::cerr << std::endl;
isGood = false;
}
}
if (isGood) {
// prepare for the new added run data sets
info->outFormat = format;
info->year = year;
info->outFileName = flnOut;
dataOut = new PRunDataHandler(info);
if (dataOut == nullptr) {
std::cerr << std::endl;
std::cerr << "**ERROR** couldn't invoke PRunDataHandler for the output file." << std::endl;
std::cerr << std::endl;
isGood = false;
}
}
if (isGood) {
// check that all runs have the same number of histograms
for (UInt_t i=1; i<runDataHandler.size(); i++) {
if (runDataHandler[0]->GetRunData()->GetNoOfHistos() != runDataHandler[0]->GetRunData()->GetNoOfHistos()) {
std::cerr << std::endl;
std::cerr << "**ERROR** can only add runs with the same number of histograms." << std::endl;
std::cerr << std::endl;
isGood = false;
}
}
}
if (isGood) {
// add all the runs
// take first run as the reference for the data
std::vector<PDoubleVector*> addedHistos;
addedHistos.resize(runDataHandler[0]->GetRunData()->GetNoOfHistos());
for (UInt_t i=0; i<runDataHandler[0]->GetRunData()->GetNoOfHistos(); i++) {
addedHistos[i] = runDataHandler[0]->GetRunData()->GetDataSet(i, false)->GetData();
}
// get the t0's for all the reference histos
PIntVector t0Vec;
t0Vec.resize(runDataHandler[0]->GetRunData()->GetNoOfHistos());
if (addRunInfo[0].fT0.empty()) { // i.e. take t0's from data file
for (UInt_t i=0; i<runDataHandler[0]->GetRunData()->GetNoOfHistos(); i++) {
t0Vec[i] = runDataHandler[0]->GetRunData()->GetT0Bin(i+1);
}
addRunInfo[0].fT0 = t0Vec;
} else { // t0 vector present
// make sure that the number of t0's fit the number of histos
if (addRunInfo[0].fT0.size() < runDataHandler[0]->GetRunData()->GetNoOfHistos()) {
UInt_t counts=runDataHandler[0]->GetRunData()->GetNoOfHistos()-addRunInfo[0].fT0.size();
for (UInt_t i=0; i<counts; i++)
addRunInfo[0].fT0.push_back(0);
}
// check t0 data
for (UInt_t i=0; i<addRunInfo[0].fT0.size(); i++) {
if (addRunInfo[0].fT0[i] == 0) { // get t0 from file
addRunInfo[0].fT0[i] = runDataHandler[0]->GetRunData()->GetT0Bin(i+1);
} else if (addRunInfo[0].fT0[i] == -1) { // get t0 from prompt peak
addRunInfo[0].fT0[i] = addRun_getPromptPeakPos(runDataHandler[0]->GetRunData()->GetDataSet(i, false)->GetData());
}
}
}
// loop over the remaining runs, determine t0's if needed and add the data
for (int i=1; i<runDataHandler.size(); i++) {
// get the t0's for all the histos of a run to be added
PIntVector t0Vec;
t0Vec.resize(runDataHandler[i]->GetRunData()->GetNoOfHistos());
if (addRunInfo[i].fT0.empty()) { // i.e. take t0's from data file
for (UInt_t j=0; j<runDataHandler[i]->GetRunData()->GetNoOfHistos(); j++) {
t0Vec[j] = runDataHandler[i]->GetRunData()->GetT0Bin(j+1);
}
addRunInfo[i].fT0 = t0Vec;
} else { // t0 vector present
// make sure that the number of t0's fit the number of histos
if (addRunInfo[i].fT0.size() < runDataHandler[i]->GetRunData()->GetNoOfHistos()) {
UInt_t counts=runDataHandler[i]->GetRunData()->GetNoOfHistos()-addRunInfo[i].fT0.size();
for (UInt_t j=0; j<counts; j++)
addRunInfo[i].fT0.push_back(0);
}
// check t0 data
for (UInt_t j=0; j<addRunInfo[i].fT0.size(); j++) {
if (addRunInfo[i].fT0[j] == 0) { // get t0 from file
addRunInfo[i].fT0[j] = runDataHandler[i]->GetRunData()->GetT0Bin(j+1);
} else if (addRunInfo[i].fT0[j] == -1) { // get t0 from prompt peak
addRunInfo[i].fT0[j] = addRun_getPromptPeakPos(runDataHandler[i]->GetRunData()->GetDataSet(j, false)->GetData());
}
}
}
// calculate the offset due to potential differences in t0's between runs
PIntVector diff;
diff.resize(addRunInfo[i].fT0.size());
for (UInt_t j=0; j<diff.size(); j++) {
diff[j] = addRunInfo[i].fT0[j] - addRunInfo[0].fT0[j];
}
// add all the to be added histos of all remaining runs
PDoubleVector *addData{nullptr};
Int_t idx;
for (int j=0; j<runDataHandler[i]->GetRunData()->GetNoOfHistos(); j++) { // loop over all histos
addData = runDataHandler[i]->GetRunData()->GetDataSet(j, false)->GetData();
for (int k=0; k<addedHistos[j]->size(); k++) { // loop over all elements of a histo
idx = k + diff[j];
if ((idx >= 0) && (idx < addData->size())) {
addedHistos[j]->at(k) += addData->at(idx);
}
}
}
}
// feed all the necessary information for the data file
PRawRunData *rawRunData = new PRawRunData();
rawRunData = runDataHandler[0]->GetRunData(); // copy all
rawRunData->SetGenerator("addRun");
// overwrite the t0 values with the new ones
for (UInt_t i=0; i<rawRunData->GetNoOfHistos(); i++) {
rawRunData->GetDataSet(i, false)->SetTimeZeroBin(addRunInfo[0].fT0[i]);
}
// write histos
for (UInt_t i=0; i<rawRunData->GetNoOfHistos(); i++) {
rawRunData->GetDataSet(i, false)->SetData(*addedHistos[i]);
}
// feed run data handler with new data
if (dataOut->SetRunData(rawRunData)) {
// write output file
dataOut->WriteData();
}
}
// clean up
if (startupHandler) {
delete startupHandler;
}
if (info) {
delete info;
}
if (dataOut) {
delete dataOut;
}
for (int i=0; i<runDataHandler.size(); i++) {
if (runDataHandler[i])
delete runDataHandler[i];
}
runDataHandler.clear();
return PMUSR_SUCCESS;
}