Hall A ROOT/C++ Analyzer (podd)
Loading...
Searching...
No Matches
THaOutput.cxx
Go to the documentation of this file.
1//*-- Author : Robert Michaels 05/08/2002
2
4//
5// THaOutput
6//
7// Defines the tree and histogram output for THaAnalyzer.
8// This class reads a file 'output.def' (an example is in /examples)
9// to define which global variables, including arrays, and formulas
10// (THaFormula's), and histograms go to the ROOT output.
11//
12// author: R. Michaels Sept 2002
13//
14//
16
17#include "THaOutput.h"
18#include "TROOT.h"
19#include "THaVform.h"
20#include "THaVhist.h"
21#include "THaVarList.h"
22#include "THaVar.h"
23#include "Textvars.h"
24#include "THaGlobals.h"
25#include "TH1.h"
26#include "TTree.h"
27#include "TFile.h"
28#include "TRegexp.h"
29#include "TError.h"
30#include "TString.h"
31#include "THaEvData.h"
32#include "THaEpicsEvtHandler.h"
33#include "THaString.h"
34#include "FileInclude.h"
35
36#include <algorithm>
37#include <fstream>
38#include <cstring>
39#include <iostream>
40#include <sstream>
41#include <utility>
42#include <vector>
43
44#include "THaBenchmark.h"
45
46using namespace std;
47using namespace THaString;
48using namespace Podd;
49
51//FIXME: these should be member variables
52static Bool_t fgDoBench = false;
54
55static const char comment('#');
56
57//_____________________________________________________________________________
59// Utility class used by THaOutput to store a list of
60// 'keys' to access EPICS data 'string=num' assignments
61public:
62 explicit THaEpicsKey(string nm) : fName(std::move(nm))
63 { fAssign.clear(); }
64 void AddAssign(const string& input) {
65// Add optional assignments. The input must
66// be of the form "epicsvar=number"
67// epicsvar can be a string with spaces if
68// and only if its enclosed in single spaces.
69// E.g. "Yes=1" "No=2", "'RF On'", etc
70 typedef map<string, double>::value_type valType;
71 string sdata = findQuotes(input);
72 auto pos = sdata.find('=');
73 if (pos != string::npos) {
74 string temp1{sdata.substr(0,pos)};
75 string temp2{sdata.substr(pos+1,sdata.length())};
76// In case someone used "==" instead of "="
77 if (temp2.find('=') != string::npos)
78 temp2.assign
79 (sdata.substr(pos+2,sdata.length()));
80 if (strlen(temp2.c_str()) > 0) {
81 double tdat = atof(temp2.c_str());
82 fAssign.insert(valType(temp1,tdat));
83 } else { // In case of "epicsvar="
84 fAssign.insert(valType(temp1,0));
85 }
86 }
87 };
88 static string findQuotes(const string& input) {
89 string result{input};
90 auto pos1 = input.find('\'');
91 if (pos1 != string::npos) {
92 string temp1{input.substr(pos1+1,input.length())};
93 auto pos2 = temp1.find('\'');
94 if (pos2 != string::npos) {
95 result.assign(temp1.substr(0,pos2));
96 result += temp1.substr(pos2+1,temp1.length());
97 }
98 }
99 return result;
100 };
101 Bool_t IsString() { return !fAssign.empty(); };
102 Double_t Eval(const string& input) {
103 if (fAssign.empty()) return 0;
104 for( const auto& pm : fAssign ) {
105 if (input == pm.first) {
106 return pm.second;
107 }
108 }
109 return 0;
110 };
111 Double_t Eval(const TString& input) {
112 return Eval(string(input.Data()));
113 }
114 const string& GetName() { return fName; };
115private:
116 string fName;
117 map<string,Double_t> fAssign;
118};
119
120//_____________________________________________________________________________
122 : tree{other.tree}, name{other.name}, ndata{other.ndata}, nsize{other.nsize},
123 data{new Double_t[nsize]}
124{
125 memcpy(data, other.data, nsize * sizeof(Double_t));
126}
127
128//_____________________________________________________________________________
130{
131 if( this != &rhs ) {
132 tree = rhs.tree; name = rhs.name;
133 if( nsize < rhs.nsize ) {
134 nsize = rhs.nsize; delete [] data; data = new Double_t[nsize];
135 }
136 ndata = rhs.ndata; memcpy( data, rhs.data, nsize*sizeof(Double_t));
137 }
138 return *this;
139}
140
141//_____________________________________________________________________________
142void THaOdata::AddBranches( TTree* _tree, string _name )
143{
144 name = std::move(_name);
145 tree = _tree;
146 string sname = "Ndata." + name;
147 string leaf = sname;
148 tree->Branch(sname.c_str(),&ndata,(leaf+"/I").c_str());
149 // FIXME: defined this way, ROOT always thinks we are variable-size
150 leaf = name + "[" + leaf + "]/D";
151 tree->Branch(name.c_str(),data,leaf.c_str());
152}
153
154//_____________________________________________________________________________
156{
157 constexpr Int_t MAX = 1<<20; // 1,048,576 elements ought to be enough for anyone ;-)
158 if( i > MAX ) return true;
159 Int_t newsize = nsize;
160 while ( i >= newsize ) { newsize *= 2; }
161 if( newsize > MAX ) newsize = MAX;
162 auto* tmp = new Double_t[newsize];
163 memcpy( tmp, data, nsize*sizeof(Double_t) );
164 delete [] data; data = tmp; nsize = newsize;
165 if( tree )
166 tree->SetBranchAddress( name.c_str(), data );
167 return false;
168}
169
170//_____________________________________________________________________________
172 : fNvar(0), fVar(nullptr), fEpicsVar(nullptr), fTree(nullptr),
173 fEpicsTree(nullptr), fInit(false),
174 fExtra(nullptr), fEpicsHandler(nullptr),
175 nx(0), ny(0), iscut(0), xlo(0), xhi(0), ylo(0), yhi(0),
176 fOpenEpics(false), fFirstEpics(false), fIsScalar(false)
177{
178 // Constructor
179}
180
181//_____________________________________________________________________________
183{
184 // Destructor
185
186 delete fExtra; fExtra = nullptr;
187
188 // Delete Trees and histograms only if ROOT system is initialized.
189 // ROOT will report being uninitialized if we're called from the TSystem
190 // destructor, at which point the trees already have been deleted.
191 // FIXME: Trees would also be deleted if deleting the output file, right?
192 // Can we use this here?
193 if( TROOT::Initialized() ) {
194 delete fTree;
195 delete fEpicsTree;
196 }
197 delete [] fVar;
198 delete [] fEpicsVar;
199 for (auto & od : fOdata) delete od;
200 for (auto & form : fFormulas) delete form;
201 for (auto & cut : fCuts) delete cut;
202 for (auto & histo : fHistos) delete histo;
203 for (auto & ek : fEpicsKey) delete ek;
204}
205
206//_____________________________________________________________________________
207Int_t THaOutput::Init( const char* filename )
208{
209 // Initialize output system. Required before anything can happen.
210 //
211 // Only re-attach to variables and re-compile cuts and formulas
212 // upon re-initialization (eg: continuing analysis with another file)
213 if( fInit ) {
214 cout << "\nTHaOutput::Init: Info: THaOutput cannot be completely"
215 << " re-initialized. Keeping existing definitions." << endl;
216 cout << "Global Variables are being re-attached and formula/cuts"
217 << " are being re-compiled." << endl;
218
219 // Assign pointers and recompile stuff reliant on pointers.
220
221 if ( Attach() ) return -4;
222
223 Print();
224
225 return 1;
226 }
227
228 if( !gHaVars ) return -2;
229
230 if( fgDoBench ) fgBench.Begin("Init");
231
232 fTree = new TTree("T","Hall A Analyzer Output DST");
233 fTree->SetAutoSave(200000000);
234 fOpenEpics = false;
235 fFirstEpics = true;
236
237 Int_t err = LoadFile( filename );
238 if( fgDoBench && err != 0 ) fgBench.Stop("Init");
239
240 if( err == -1 ) {
241 return 0; // No error if file not found, but please
242 } // read the instructions.
243 else if( err != 0 ) {
244 delete fTree; fTree = nullptr;
245 return -3;
246 }
247
248 delete fExtra;
249 fExtra = new OutputExtras;
250
251 fNvar = fVarnames.size(); // this gets reassigned below
252 fArrayNames.clear();
253 fVNames.clear();
254
255 for (UInt_t ivar = 0; ivar < fNvar; ivar++) {
256 const auto* pvar = gHaVars->Find(fVarnames[ivar].c_str());
257 if (pvar) {
258 if (pvar->IsArray()) {
259 fArrayNames.push_back(fVarnames[ivar]);
260 fOdata.push_back(new THaOdata());
261 } else {
262 fVNames.push_back(fVarnames[ivar]);
263 }
264 } else {
265 cout << "\nTHaOutput::Init: WARNING: Global variable ";
266 cout << fVarnames[ivar] << " does not exist. "<< endl;
267 cout << "There is probably a typo error... "<<endl;
268 }
269 }
270 UInt_t k = 0;
271 for (auto inam = fFormnames.begin(); inam != fFormnames.end(); ++inam, ++k) {
272 string tinfo = Form("f%d",k);
273 // FIXME: avoid duplicate formulas
274 auto* pform = new THaVform("formula",inam->c_str(),fFormdef[k].c_str());
275 Int_t status = pform->Init();
276 if ( status != 0) {
277 cout << "THaOutput::Init: WARNING: Error in formula ";
278 cout << *inam << endl;
279 cout << "There is probably a typo error... " << endl;
280 pform->ErrPrint(status);
281 delete pform;
282 --k;
283 continue;
284 }
285 pform->SetOutput(fTree);
286 fFormulas.push_back(pform);
287 if( fgVerbose > 2 )
288 pform->LongPrint(); // for debug
289// Add variables (i.e. those var's used by the formula) to tree.
290// Reason is that TTree::Draw() may otherwise fail with ERROR 26
291 vector<string> avar = pform->GetVars();
292 for( const auto& str : avar ) {
293 string svar = StripBracket(str);
294 const auto* pvar = gHaVars->Find(svar.c_str());
295 if (pvar) {
296 if (pvar->IsArray()) {
297 auto found = find(fArrayNames.begin(), fArrayNames.end(), svar);
298 if( found == fArrayNames.end() ) {
299 fArrayNames.push_back(svar);
300 fOdata.push_back(new THaOdata());
301 }
302 } else {
303 auto found = find(fVNames.begin(), fVNames.end(), svar);
304 if( found == fVNames.end() )
305 fVNames.push_back(svar);
306 }
307 }
308 }
309 }
310 k = 0;
311 for( auto iodat = fOdata.begin(); iodat != fOdata.end(); ++iodat, ++k )
312 (*iodat)->AddBranches(fTree, fArrayNames[k]);
313 fNvar = fVNames.size();
314 fVar = new Double_t[fNvar];
315 for (k = 0; k < fNvar; ++k) {
316 string tinfo = fVNames[k] + "/D";
317 fTree->Branch(fVNames[k].c_str(), &fVar[k], tinfo.c_str(), kNbout);
318 }
319 k = 0;
320 for( auto inam = fCutnames.begin(); inam != fCutnames.end(); ++inam, ++k ) {
321 // FIXME: avoid duplicate cuts
322 auto* pcut = new THaVform("cut", inam->c_str(), fCutdef[k].c_str());
323 Int_t status = pcut->Init();
324 if ( status != 0 ) {
325 cout << "THaOutput::Init: WARNING: Error in formula ";
326 cout << *inam << endl;
327 cout << "There is probably a typo error... " << endl;
328 pcut->ErrPrint(status);
329 delete pcut;
330 --k;
331 continue;
332 }
333 pcut->SetOutput(fTree);
334 fCuts.push_back(pcut);
335 if( fgVerbose>2 )
336 pcut->LongPrint(); // for debug
337 }
338 for( auto* pVhist : fHistos ) {
339
340// After initializing formulas and cuts, must sort through
341// histograms and potentially reassign variables.
342// A histogram variable or cut is either a string (which can
343// encode a formula) or an externally defined THaVform.
344 sfvarx = pVhist->GetVarX();
345 sfvary = pVhist->GetVarY();
346 for( auto* pVform : fFormulas ) {
347 string stemp(pVform->GetName());
348 if (CmpNoCase(sfvarx,stemp) == 0) {
349 pVhist->SetX(pVform);
350 }
351 if (CmpNoCase(sfvary,stemp) == 0) {
352 pVhist->SetY(pVform);
353 }
354 }
355 if (pVhist->HasCut()) {
356 scut = pVhist->GetCutStr();
357 for( auto* pcut : fCuts ) {
358 string stemp(pcut->GetName());
359 if (CmpNoCase(scut,stemp) == 0) {
360 pVhist->SetCut(pcut);
361 }
362 }
363 }
364 pVhist->Init();
365 }
366
367 if (!fEpicsKey.empty()) {
368 auto siz = fEpicsKey.size();
369 delete [] fEpicsVar;
370 fEpicsVar = new Double_t[siz];
371 for( size_t i = 0; i < siz; ++i ) {
372 fEpicsVar[i] = -1e32;
373 string epicsbr = CleanEpicsName(fEpicsKey[i]->GetName());
374 string tinfo = epicsbr + "/D";
375 fTree->Branch(epicsbr.c_str(), &fEpicsVar[i],
376 tinfo.c_str(), kNbout);
377 fEpicsTree->Branch(epicsbr.c_str(), &fEpicsVar[i],
378 tinfo.c_str(), kNbout);
379 }
380 auto* extras = static_cast<OutputExtras*>(fExtra);
381 fEpicsTree->Branch("timestamp", &(extras->fEpicsTimestamp), "timestamp/L", kNbout);
382 fEpicsTree->Branch("evnum", &(extras->fEpicsEvtNum), "evnum/L", kNbout);
383 }
384
385 Print();
386
387 fInit = true;
388
389 if( fgDoBench ) fgBench.Stop("Init");
390
391 if( fgDoBench ) fgBench.Begin("Attach");
392 Int_t st = Attach();
393 if( fgDoBench ) fgBench.Stop("Attach");
394 if ( st )
395 return -4;
396
397 return 0;
398}
399
400void THaOutput::BuildList( const vector<string>& vdata)
401{
402 // Build list of EPICS variables and
403 // SCALER variables to add to output.
404
405 if (vdata.empty()) return;
406 if (CmpNoCase(vdata[0],"begin") == 0) {
407 if (vdata.size() < 2) return;
408 if (CmpNoCase(vdata[1],"epics") == 0) fOpenEpics = true;
409 }
410 if (CmpNoCase(vdata[0],"end") == 0) {
411 if (vdata.size() < 2) return;
412 if (CmpNoCase(vdata[1],"epics") == 0) fOpenEpics = false;
413 }
414 if (fOpenEpics) {
415 if (fFirstEpics) {
416 if (!fEpicsTree)
417 fEpicsTree = new TTree("E","Hall A Epics Data");
418 fFirstEpics = false;
419 return;
420 } else {
421 fEpicsKey.push_back(new THaEpicsKey(vdata[0]));
422 if (vdata.size() > 1) {
423 vector<string> esdata = reQuote(vdata);
424 for (int k = 1; k < (int)esdata.size(); k++) {
425 fEpicsKey[fEpicsKey.size()-1]->AddAssign(esdata[k]);
426 }
427 }
428 }
429 } else {
430 fFirstEpics = true;
431 }
432}
433
434
435//_____________________________________________________________________________
437{
438 // Get the pointers for the global variables
439 // Also, sets the size of the fVariables and fArrays vectors
440 // according to the size of the related names array
441
442 if( !gHaVars ) return -2;
443
444 UInt_t NAry = fArrayNames.size();
445 UInt_t NVar = fVNames.size();
446
447 fVariables.resize(NVar);
448 fArrays.resize(NAry);
449
450 // simple variable-type names
451 for (UInt_t ivar = 0; ivar < NVar; ivar++) {
452 auto* pvar = gHaVars->Find(fVNames[ivar].c_str());
453 if (pvar) {
454 if ( !pvar->IsArray() ) {
455 fVariables[ivar] = pvar;
456 } else {
457 cout << "\tTHaOutput::Attach: ERROR: Global variable " << fVNames[ivar]
458 << " changed from simple to array!! Leaving empty space for variable"
459 << endl;
460 fVariables[ivar] = nullptr;
461 }
462 } else {
463 cout << "\nTHaOutput::Attach: WARNING: Global variable ";
464 cout << fVarnames[ivar] << " NO LONGER exists (it did before). "<< endl;
465 cout << "This is not supposed to happen... "<<endl;
466 }
467 }
468
469 // arrays
470 for (UInt_t ivar = 0; ivar < NAry; ivar++) {
471 auto* pvar = gHaVars->Find(fArrayNames[ivar].c_str());
472 if (pvar) {
473 if ( pvar->IsArray() ) {
474 fArrays[ivar] = pvar;
475 } else {
476 cout << "\tTHaOutput::Attach: ERROR: Global variable " << fVNames[ivar]
477 << " changed from ARRAY to Simple!! Leaving empty space for variable"
478 << endl;
479 fArrays[ivar] = nullptr;
480 }
481 } else {
482 cout << "\nTHaOutput::Attach: WARNING: Global variable ";
483 cout << fVarnames[ivar] << " NO LONGER exists (it did before). "<< endl;
484 cout << "This is not supposed to happen... "<<endl;
485 }
486 }
487
488 // Reattach formulas, cuts, histos
489
490 for (auto & form : fFormulas) {
491 form->ReAttach();
492 }
493 for (auto & cut : fCuts) {
494 cut->ReAttach();
495 }
496 for (auto & hist : fHistos) {
497 hist->ReAttach();
498 }
499
500 return 0;
501
502}
503
504//_____________________________________________________________________________
506{
507 // Process the EPICS data, this fills the trees.
508
509 if ( !epicshandle ) return 0;
510 if ( !epicshandle->IsMyEvent(evdata->GetEvType())
511 || fEpicsKey.empty() || !fEpicsTree ) return 0;
512 if( fgDoBench ) fgBench.Begin("EPICS");
513 auto* extras = static_cast<OutputExtras*>(fExtra);
514 extras->fEpicsTimestamp = -1;
515 extras->fEpicsEvtNum = evdata->GetEvNum(); // most recent physics event number
516 auto siz = fEpicsKey.size();
517 for( size_t i = 0; i < siz; ++i ) {
518 if (epicshandle->IsLoaded(fEpicsKey[i]->GetName().c_str())) {
519 // cout << "EPICS name "<<fEpicsKey[i]->GetName()<<" val "
520 // << epicshandle->GetString(fEpicsKey[i]->GetName().c_str())<<endl;
521 if (fEpicsKey[i]->IsString()) {
522 fEpicsVar[i] =
523 fEpicsKey[i]->Eval(
524 epicshandle->GetString(fEpicsKey[i]->GetName().c_str()));
525 } else {
526 fEpicsVar[i] = epicshandle->GetData(fEpicsKey[i]->GetName().c_str());
527 }
528 // fill time stamp (once is ok since this is an EPICS event)
529 //FIXME: check for inconsistent time stamps?
530 extras->fEpicsTimestamp =
531 epicshandle->GetTime(fEpicsKey[i]->GetName().c_str());
532 } else {
533 fEpicsVar[i] = -1e32; // data not yet found
534 }
535 }
536 if (fEpicsTree) fEpicsTree->Fill();
537 if( fgDoBench ) fgBench.Stop("EPICS");
538 return 1;
539}
540
541//_____________________________________________________________________________
543{
544 // Process the variables, formulas, and histograms.
545 // This is called by THaAnalyzer.
546
547 if( fgDoBench ) fgBench.Begin("Formulas");
548 for (auto & form : fFormulas)
549 if (form) form->Process();
550 if( fgDoBench ) fgBench.Stop("Formulas");
551
552 if( fgDoBench ) fgBench.Begin("Cuts");
553 for (auto & cut : fCuts)
554 if (cut) cut->Process();
555 if( fgDoBench ) fgBench.Stop("Cuts");
556
557 if( fgDoBench ) fgBench.Begin("Variables");
558 for (UInt_t ivar = 0; ivar < fNvar; ivar++) {
559 const auto* pvar = fVariables[ivar];
560 if( pvar ) {
561 Double_t x = pvar->GetValue();
562 if( x == kMinInt ) x = kBig;
563 fVar[ivar] = x;
564 }
565 }
566 Int_t k = 0;
567 for (auto it = fOdata.begin(); it != fOdata.end(); ++it, ++k) {
568 THaOdata* pdat(*it);
569 pdat->Clear();
570 const auto* pvar = fArrays[k];
571 if ( pvar == nullptr ) continue;
572 // Fill array in reverse order so that fOdata[k] gets resized just once
573 Int_t i = pvar->GetLen();
574 bool first = true;
575 while( i-- > 0 ) {
576 // FIXME: for better efficiency, should use pointer to data and
577 // Fill(int n,double* data) method in case of a contiguous array
578 Double_t x = pvar->GetValue(i);
579 if( x == kMinInt ) x = kBig;
580 if (pdat->Fill(i,x) != 1) {
581 if( fgVerbose>0 && first ) {
582 cerr << "THaOutput::ERROR: storing too much variable sized data: "
583 << pvar->GetName() <<" "<<pvar->GetLen()<<endl;
584 first = false;
585 }
586 }
587 }
588 }
589 if( fgDoBench ) fgBench.Stop("Variables");
590
591 if( fgDoBench ) fgBench.Begin("Histos");
592 for (auto & hist : fHistos)
593 hist->Process();
594 if( fgDoBench ) fgBench.Stop("Histos");
595
596 if( fgDoBench ) fgBench.Begin("TreeFill");
597 if (fTree) fTree->Fill();
598 if( fgDoBench ) fgBench.Stop("TreeFill");
599
600 return 0;
601}
602
603//_____________________________________________________________________________
605{
606 if( fgDoBench ) fgBench.Begin("End");
607
608 if (fTree) fTree->Write();
610 for (auto & hist : fHistos)
611 hist->End();
612 if( fgDoBench ) fgBench.Stop("End");
613
614 if( fgDoBench ) {
615 cout << "Output timing summary:" << endl;
616 fgBench.Print("Init");
617 fgBench.Print("Attach");
618 fgBench.Print("Variables");
619 fgBench.Print("Formulas");
620 fgBench.Print("Cuts");
621 fgBench.Print("Histos");
622 fgBench.Print("TreeFill");
623 fgBench.Print("EPICS");
624 fgBench.Print("End");
625 }
626 return 0;
627}
628
629//_____________________________________________________________________________
630Int_t THaOutput::LoadFile( const char* filename )
631{
632 // Process the file that defines the output
633
634 const char* const here = "THaOutput::LoadFile";
635
636 if( !filename || !*filename || strspn(filename," ") == strlen(filename) ) {
637 ::Error( here, "invalid file name, no output definition loaded" );
638 return -2;
639 }
640 string loadfile(filename);
641 ifstream odef(loadfile.c_str());
642 if ( !odef ) {
643 ErrFile(-1, loadfile);
644 return -1;
645 }
646 vector<string> strvect;
647 string sline;
648
649 while (getline(odef,sline)) {
650 // #include
651 if( sline.substr(0,kIncTag.length()) == kIncTag &&
652 sline.length() > kIncTag.length() ) {
653 string incfilename;
654 if( GetIncludeFileName(sline,incfilename) != 0 ) {
655 ostringstream ostr;
656 ostr << "Error in #include specification: " << sline;
657 ::Error( here, "%s", ostr.str().c_str() );
658 return -3;
659 }
660 if( CheckIncludeFilePath(incfilename) != 0 ) {
661 ostringstream ostr;
662 ostr << "Error opening include file: " << sline;
663 ::Error( here, "%s", ostr.str().c_str() );
664 return -3;
665 }
666 if( incfilename == filename ) {
667 // File including itself?
668 // FIXME: does not catch including the same file via full pathname or similar
669 ostringstream ostr;
670 ostr << "File cannot include itself: " << sline;
671 ::Error( here, "%s", ostr.str().c_str() );
672 return -3;
673 }
674 Int_t ret = LoadFile( incfilename.c_str() );
675 if( ret != 0 )
676 return ret;
677 continue;
678 }
679 // Blank line or comment line?
680 string::size_type pos = 0;
681 if( sline.empty() ||
682 (pos = sline.find_first_not_of(kWhiteSpace)) == string::npos ||
683 sline[pos] == comment )
684 continue;
685 // Get rid of trailing comments
686 if( (pos = sline.find(comment)) != string::npos )
687 sline.erase(pos);
688 // Substitute text variables
689 vector<string> lines( 1, sline );
690 if( gHaTextvars->Substitute(lines) )
691 continue;
692 for( auto& str : lines ) {
693 // Split the line into tokens separated by whitespace
694 strvect = vsplit(str);
695 bool special_before = (fOpenEpics);
696 BuildList(strvect);
697 bool special_now = (fOpenEpics);
698 if( special_before || special_now )
699 continue; // strvect already processed
700 if (strvect.size() < 2) {
701 ErrFile(0, str);
702 continue;
703 }
704 fIsScalar = false; // this may be set true by svPrefix
705 string svkey = svPrefix(strvect[0]);
706 Int_t ikey = FindKey(svkey);
707 string sname = StripBracket(strvect[1]);
708 switch (ikey) {
709 case kVar:
710 fVarnames.push_back(sname);
711 break;
712 case kForm:
713 if (strvect.size() < 3) {
714 ErrFile(ikey, str);
715 continue;
716 }
717 fFormnames.push_back(sname);
718 fFormdef.push_back(strvect[2]);
719 break;
720 case kCut:
721 if (strvect.size() < 3) {
722 ErrFile(ikey, str);
723 continue;
724 }
725 fCutnames.push_back(sname);
726 fCutdef.push_back(strvect[2]);
727 break;
728 case kH1f:
729 case kH1d:
730 case kH2f:
731 case kH2d:
732 if( ChkHistTitle(ikey, str) != 1) {
733 ErrFile(ikey, str);
734 continue;
735 }
736 fHistos.push_back(new THaVhist(svkey,sname,stitle));
737 // Tentatively assign variables and cuts as strings.
738 // Later will check if they are actually THaVform's.
739 fHistos.back()->SetX(nx, xlo, xhi, sfvarx);
740 if (ikey == kH2f || ikey == kH2d) {
741 fHistos.back()->SetY(ny, ylo, yhi, sfvary);
742 }
743 if (iscut != fgNocut) fHistos.back()->SetCut(scut);
744// If we know now that its a scalar, inform the histogram to remain that way
745// and over-ride its internal rules for self-determining if its a vector.
746 if (fIsScalar) fHistos.back()->SetScalarTrue();
747 break;
748 case kBlock:
749 // Do not strip brackets for block regexps: use strvect[1] not sname
750 if( BuildBlock(strvect[1]) == 0 ) {
751 cout << "\nTHaOutput::Init: WARNING: Block ";
752 cout << strvect[1] << " does not match any variables. " << endl;
753 cout << "There is probably a typo error... "<<endl;
754 }
755 break;
756 case kBegin:
757 case kEnd:
758 break;
759 default:
760 cout << "Warning: keyword "<<svkey<<" undefined "<<endl;
761 }
762 }
763 }
764
765 // sort thru fVarnames, removing identical entries
766 if( fVarnames.size() > 1 ) {
767 sort(fVarnames.begin(),fVarnames.end());
768 auto Vi = fVarnames.begin();
769 while ( (Vi+1)!=fVarnames.end() ) {
770 if ( *Vi == *(Vi+1) ) {
771 fVarnames.erase(Vi+1);
772 } else {
773 ++Vi;
774 }
775 }
776 }
777
778 return 0;
779}
780
781//_____________________________________________________________________________s
782string THaOutput::svPrefix(string& histtype)
783{
784// If the arg is a string for a histogram type, we strip the initial
785// "s" or "v". If the first character is "s" we set fIsScalar true.
786 const int ldebug=0;
787 fIsScalar = false;
788 string sresult = histtype;
789 if (ldebug) cout << "svPrefix histogram type = "<<histtype<<" histtype length "<<histtype.length()<<endl;
790// For histograms `histtype' is of the form "XthNY"
791// with X="s" or "v" and N=1 or 2, Y = "f" or "d"
792// For example, "sth1f". Note it always has length 5
793 if (histtype.length() != 5) return sresult;
794 string sfirst = histtype.substr(0,1);
795 if (ldebug) cout << "sfirst = "<<sfirst<<endl;
796 if(CmpNoCase(sfirst,"s")==0) fIsScalar = true;
797 sresult=histtype.substr(1);
798// Needs to be a histogram, not something else like block
799 if( (CmpNoCase(sresult,"th1f")!=0) &&
800 (CmpNoCase(sresult,"th2f")!=0) &&
801 (CmpNoCase(sresult,"th1d")!=0) &&
802 (CmpNoCase(sresult,"th2d")!=0) ) return histtype; // return original
803 if (ldebug) {
804 cout << "result "<<sresult<< endl;
805 if (fIsScalar) cout << "fScalar is TRUE"<<endl;
806 }
807 return sresult;
808
809}
810
811//_____________________________________________________________________________
812Int_t THaOutput::FindKey(const string& key) const
813{
814 // Return integer flag corresponding to
815 // case-insensitive keyword "key" if it exists
816
817 // Map of keywords to internal logical type numbers
818 class KeyMap {
819 public:
820 const char* name;
821 EId keyval;
822 };
823 static const vector<KeyMap> keymap = {
824 { "variable", kVar },
825 { "formula", kForm },
826 { "cut", kCut },
827 { "th1f", kH1f },
828 { "th1d", kH1d },
829 { "th2f", kH2f },
830 { "th2d", kH2d },
831 { "block", kBlock },
832 { "begin", kBegin },
833 { "end", kEnd }
834 };
835
836 for( const auto& it : keymap ) {
837 if( CmpNoCase( key, it.name ) == 0 )
838 return it.keyval;
839 }
840 return -1;
841}
842
843//_____________________________________________________________________________
844string THaOutput::StripBracket(const string& var) const
845{
846// If the string contains "[anything]", we strip
847// it away. In practice this should not be fatal
848// because your variable will still show up in the tree.
849 static const string open_brack("[");
850 static const string close_brack("]");
851 string result;
852 auto pos1 = var.find(open_brack,0);
853 auto pos2 = var.find(close_brack,0);
854 if ((pos1 != string::npos) &&
855 (pos2 != string::npos)) {
856 result = var.substr(0,pos1);
857 result += var.substr(pos2+1,var.length());
858// cout << "THaOutput:WARNING:: Stripping away";
859// cout << "unwanted brackets from "<<var<<endl;
860 } else {
861 result = var;
862 }
863 return result;
864}
865
866//_____________________________________________________________________________
867vector<string> THaOutput::reQuote(const vector<string>& input) {
868 // Specialist private function needed by EPICs line parser:
869 // The problem is that the line was split by white space, so
870 // a line like "'RF On'=42" must be repackaged into
871 // one string, i.e. "'RF" and "On'=42" put back together.
872 vector<string> result;
873 int first_quote = 1;
874 int to_add = 0;
875 string temp1,temp2,temp3;
876 for( const auto& str : input ) {
877 temp1 = str;
878 auto pos1 = temp1.find('\'');
879 if (pos1 != string::npos) {
880 if (first_quote) {
881 temp2.assign(temp1.substr(pos1,temp1.length()));
882// But there might be a 2nd "'" with no spaces
883// like "'Yes'" (silly, but understandable & allowed)
884 temp3.assign(temp1.substr(pos1+1,temp1.length()));
885 auto pos2 = temp3.find('\'');
886 if (pos2 != string::npos) {
887 temp1.assign(temp3.substr(0,pos2));
888 temp2.assign(temp3.substr
889 (pos2+1,temp3.length()));
890 temp3 = temp1+temp2;
891 result.push_back(temp3);
892 continue;
893 }
894 first_quote = 0;
895 to_add = 1;
896 } else {
897 temp2 += " ";
898 temp2 += temp1;
899 result.push_back(temp2);
900 temp2.clear();
901 first_quote = 1;
902 to_add = 0;
903 }
904 } else {
905 if (to_add) {
906 temp2 += " ";
907 temp2 += temp1;
908 } else {
909 result.push_back(temp1);
910 }
911 }
912 }
913 return result;
914}
915
916//_____________________________________________________________________________
917string THaOutput::CleanEpicsName( const string& input )
918{
919// To clean up EPICS variable names that contain
920// bad characters like ":" and arithmetic operations
921// that confuse TTree::Draw().
922// Replace all 'badchar' with 'goodchar'
923
924 static const char badchar[]=":+-*/=";
925 static const string goodchar = "_";
926 int numbad = sizeof(badchar)/sizeof(char) - 1;
927
928 string output = input;
929
930 for (int i = 0; i < numbad; i++) {
931 string sbad(&badchar[i]);
932 sbad.erase(1,sbad.size());
933 string::size_type pos = input.find(sbad,0);
934 while (pos != string::npos) {
935 output.replace(pos,1,goodchar);
936 pos = input.find(sbad,pos+1);
937 }
938 }
939 return output;
940}
941
942
943//_____________________________________________________________________________
944void THaOutput::ErrFile(Int_t iden, const string& sline) const
945{
946 // Print error messages about the output definition file.
947 if (iden == -1) {
948 cerr << "<THaOutput::LoadFile> WARNING: file " << sline;
949 cerr << " does not exist." << endl;
950 cerr << "See $ANALYZER/examples/output.def for an example.\n";
951 cerr << "Output will only contain event objects "
952 "(this may be all you want).\n";
953 return;
954 }
955 if (fOpenEpics) return; // No error
956 cerr << "THaOutput::ERROR: Syntax error in output definition file."<<endl;
957 cerr << "The offending line is :\n"<<sline<<endl<<endl;
958 switch (iden) {
959 case kVar:
960 cerr << "For variables, the syntax is: "<<endl;
961 cerr << " variable variable-name"<<endl;
962 cerr << "Example: "<<endl;
963 cerr << " variable R.vdc.v2.nclust"<<endl;
964 break;
965 case kCut:
966 case kForm:
967 cerr << "For formulas or cuts, the syntax is: "<<endl;
968 cerr << " formula(or cut) formula-name formula-expression"<<endl;
969 cerr << "Example: "<<endl;
970 cerr << " formula targetX 1.464*B.bpm4b.x-0.464*B.bpm4a.x"<<endl;
971 break;
972 case kH1f:
973 case kH1d:
974 cerr << "For 1D histograms, the syntax is: "<<endl;
975 cerr << " TH1F(or TH1D) name 'title' ";
976 cerr << "variable nbin xlo xhi [cut-expr]"<<endl;
977 cerr << "Example: "<<endl;
978 cerr << " TH1F tgtx 'target X' targetX 100 -2 2"<<endl;
979 cerr << "(Title in single quotes. Variable can be a formula)"<<endl;
980 cerr << "optionally can impose THaCut expression 'cut-expr'"<<endl;
981 break;
982 case kH2f:
983 case kH2d:
984 cerr << "For 2D histograms, the syntax is: "<<endl;
985 cerr << " TH2F(or TH2D) name 'title' varx vary";
986 cerr << " nbinx xlo xhi nbiny ylo yhi [cut-expr]"<<endl;
987 cerr << "Example: "<<endl;
988 cerr << " TH2F t12 't1 vs t2' D.timeroc1 D.timeroc2";
989 cerr << " 100 0 20000 100 0 35000"<<endl;
990 cerr << "(Title in single quotes. Variable can be a formula)"<<endl;
991 cerr << "optionally can impose THaCut expression 'cut-expr'"<<endl;
992 break;
993 default:
994 cerr << "Illegal line: " << sline << endl;
995 cerr << "See the documentation or ask Bob Michaels"<<endl;
996 break;
997 }
998}
999
1000//_____________________________________________________________________________
1002{
1003 // Printout the definitions. Amount printed depends on verbosity
1004 // level, set with SetVerbosity().
1005
1006 if( fgVerbose > 0 ) {
1007 if( fVarnames.empty() && fFormulas.empty() && fCuts.empty() &&
1008 fHistos.empty() ) {
1009 ::Warning("THaOutput", "no output defined");
1010 } else {
1011 cout << endl << "THaOutput definitions: " << endl;
1012 if( !fVarnames.empty() ) {
1013 cout << "=== Number of variables "<<fVarnames.size()<<endl;
1014 if( fgVerbose > 1 ) {
1015 cout << endl;
1016
1017 UInt_t i = 0;
1018 for (auto ivar = fVarnames.begin(); ivar != fVarnames.end();
1019 i++, ivar++ ) {
1020 cout << "Variable # "<<i<<" = "<<(*ivar)<<endl;
1021 }
1022 }
1023 }
1024 if( !fFormulas.empty() ) {
1025 cout << "=== Number of formulas "<<fFormulas.size()<<endl;
1026 if( fgVerbose > 1 ) {
1027 cout << endl;
1028 UInt_t i = 0;
1029 for (auto iform = fFormulas.begin();
1030 iform != fFormulas.end(); i++, iform++ ) {
1031 cout << "Formula # "<<i<<endl;
1032 if( fgVerbose>2 )
1033 (*iform)->LongPrint();
1034 else
1035 (*iform)->ShortPrint();
1036 }
1037 }
1038 }
1039 if( !fCuts.empty() ) {
1040 cout << "=== Number of cuts "<<fCuts.size()<<endl;
1041 if( fgVerbose > 1 ) {
1042 cout << endl;
1043 UInt_t i = 0;
1044 for (auto icut = fCuts.begin(); icut != fCuts.end();
1045 i++, icut++ ) {
1046 cout << "Cut # "<<i<<endl;
1047 if( fgVerbose>2 )
1048 (*icut)->LongPrint();
1049 else
1050 (*icut)->ShortPrint();
1051 }
1052 }
1053 }
1054 if( !fHistos.empty() ) {
1055 cout << "=== Number of histograms "<<fHistos.size()<<endl;
1056 if( fgVerbose > 1 ) {
1057 cout << endl;
1058 UInt_t i = 0;
1059 for (auto ihist = fHistos.begin(); ihist != fHistos.end();
1060 i++, ihist++) {
1061 cout << "Histogram # "<<i<<endl;
1062 (*ihist)->Print();
1063 }
1064 }
1065 }
1066 cout << endl;
1067 }
1068 }
1069}
1070
1071//_____________________________________________________________________________
1072Int_t THaOutput::ChkHistTitle(Int_t iden, const string& sline)
1073{
1074// Parse the string that defines the histogram.
1075// The title must be enclosed in single quotes (e.g. 'my title').
1076// Ret value 'result' means: -1 == error, 1 == everything ok.
1077 Int_t result = -1;
1078 stitle = ""; sfvarx = ""; sfvary = "";
1079 iscut = fgNocut; scut = "";
1080 nx = 0; ny = 0; xlo = 0; xhi = 0; ylo = 0; yhi = 0;
1081 string::size_type pos1 = sline.find_first_of('\'');
1082 string::size_type pos2 = sline.find_last_of('\'');
1083 if (pos1 != string::npos && pos2 > pos1) {
1084 stitle = sline.substr(pos1+1,pos2-pos1-1);
1085 }
1086 string ctemp = sline.substr(pos2+1,sline.size()-pos2);
1087 vector<string> stemp = Split(ctemp);
1088 if (stemp.size() > 1) {
1089 sfvarx = stemp[0];
1090 UInt_t ssize = stemp.size();
1091 if (ssize == 4 || ssize == 5) {
1092 sscanf(stemp[1].c_str(),"%8d",&nx);
1093 sscanf(stemp[2].c_str(),"%16f",&xlo);
1094 sscanf(stemp[3].c_str(),"%16f",&xhi);
1095 if (ssize == 5) {
1096 iscut = 1; scut = stemp[4];
1097 }
1098 result = 1;
1099 }
1100 if (ssize == 8 || ssize == 9) {
1101 sfvary = stemp[1];
1102 sscanf(stemp[2].c_str(),"%8d",&nx);
1103 sscanf(stemp[3].c_str(),"%16f",&xlo);
1104 sscanf(stemp[4].c_str(),"%16f",&xhi);
1105 sscanf(stemp[5].c_str(),"%8d",&ny);
1106 sscanf(stemp[6].c_str(),"%16f",&ylo);
1107 sscanf(stemp[7].c_str(),"%16f",&yhi);
1108 if (ssize == 9) {
1109 iscut = 1; scut = stemp[8];
1110 }
1111 result = 2;
1112 }
1113 }
1114 if (result != 1 && result != 2) return -1;
1115 if ((iden == kH1f || iden == kH1d) &&
1116 result == 1) return 1; // ok
1117 if ((iden == kH2f || iden == kH2d) &&
1118 result == 2) return 1; // ok
1119 return -1;
1120}
1121
1122//_____________________________________________________________________________
1123Int_t THaOutput::BuildBlock(const string& blockn)
1124{
1125 // From the block name, identify and save a specific grouping
1126 // of global variables by adding them to the fVarnames list.
1127 //
1128 // For efficiency, at the end of building the list we should
1129 // ensure that variables are listed only once.
1130 //
1131 // Eventually, we can have some specially named blocks,
1132 // but for now we simply will use pattern matching, such that
1133 // block L.*
1134 // would save all variables from the left spectrometer.
1135
1136
1137 TRegexp re(blockn.c_str(),true);
1138 TIter next(gHaVars);
1139
1140 Int_t nvars=0;
1141 while( TObject* obj = next() ) {
1142 TString s = obj->GetName();
1143 if ( s.Index(re) != kNPOS ) {
1144 fVarnames.emplace_back(s.Data());
1145 nvars++;
1146 }
1147 }
1148 return nvars;
1149}
1150
1151//_____________________________________________________________________________
1153{
1154 // Set verbosity level for debug messages
1155
1156 fgVerbose = level;
1157}
1158
1159//_____________________________________________________________________________
1160//ClassImp(THaOdata)
int Int_t
unsigned int UInt_t
std::map< std::string, std::string > keyval
Definition DAQconfig.h:1
const Data_t kBig
Definition DataType.h:15
bool Bool_t
const Ssiz_t kNPOS
const Int_t kMinInt
double Double_t
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void input
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
char name[80]
R__EXTERN class THaVarList * gHaVars
Definition THaGlobals.h:11
static const char comment('#')
static Bool_t fgDoBench
Definition THaOutput.cxx:52
static THaBenchmark fgBench
Definition THaOutput.cxx:53
static const char *const here
Definition THaVar.cxx:64
char * Form(const char *fmt,...)
virtual void Stop(const char *name)
virtual void Begin(const char *name)
virtual void Print(Option_t *name="") const
Double_t GetData(const char *tag, UInt_t event=0) const
TString GetString(const char *tag, UInt_t event=0) const
time_t GetTime(const char *tag, UInt_t event=0) const
Bool_t IsLoaded(const char *tag) const
THaEpicsKey(string nm)
Definition THaOutput.cxx:62
void AddAssign(const string &input)
Definition THaOutput.cxx:64
const string & GetName()
map< string, Double_t > fAssign
static string findQuotes(const string &input)
Definition THaOutput.cxx:88
Bool_t IsString()
Double_t Eval(const string &input)
Double_t Eval(const TString &input)
UInt_t GetEvType() const
Definition THaEvData.h:53
UInt_t GetEvNum() const
Definition THaEvData.h:56
virtual Bool_t IsMyEvent(UInt_t type) const
void Clear(Option_t *="")
Definition THaOutput.h:35
TTree * tree
Definition THaOutput.h:55
Double_t * data
Definition THaOutput.h:59
Bool_t Resize(Int_t i)
THaOdata(int n=1)
Definition THaOutput.h:29
THaOdata & operator=(const THaOdata &rhs)
void AddBranches(TTree *T, std::string name)
Int_t ndata
Definition THaOutput.h:57
Int_t nsize
Definition THaOutput.h:58
std::string name
Definition THaOutput.h:56
Int_t Fill(Int_t i, Double_t dat)
Definition THaOutput.h:37
Bool_t fOpenEpics
Definition THaOutput.h:143
std::vector< std::string > fCutnames
Definition THaOutput.h:105
Float_t xhi
Definition THaOutput.h:142
std::vector< THaVar * > fVariables
Definition THaOutput.h:107
virtual std::string StripBracket(const std::string &var) const
TTree * fEpicsTree
Definition THaOutput.h:112
std::vector< std::string > fCutdef
Definition THaOutput.h:105
virtual Int_t FindKey(const std::string &key) const
std::string sfvary
Definition THaOutput.h:137
void Print() const
bool fInit
Definition THaOutput.h:113
virtual Int_t Attach()
std::vector< THaVform * > fCuts
Definition THaOutput.h:108
virtual Int_t Process()
static const Int_t kNbout
Definition THaOutput.h:117
std::vector< std::string > fVNames
Definition THaOutput.h:106
std::vector< THaOdata * > fOdata
Definition THaOutput.h:110
std::vector< THaVar * > fArrays
Definition THaOutput.h:107
std::vector< std::string > fFormnames
Definition THaOutput.h:104
virtual Int_t BuildBlock(const std::string &blockn)
Double_t * fVar
Definition THaOutput.h:102
static const Int_t fgNocut
Definition THaOutput.h:118
virtual Int_t LoadFile(const char *filename)
UInt_t fNvar
Definition THaOutput.h:101
std::vector< std::string > fVarnames
Definition THaOutput.h:103
Float_t yhi
Definition THaOutput.h:142
TObject * fExtra
Definition THaOutput.h:121
std::vector< std::string > fArrayNames
Definition THaOutput.h:106
TTree * fTree
Definition THaOutput.h:112
virtual Int_t Init(const char *filename="output.def")
virtual Int_t ProcEpics(THaEvData *ev, THaEpicsEvtHandler *han)
std::string stitle
Definition THaOutput.h:137
Bool_t fIsScalar
Definition THaOutput.h:143
std::vector< THaVhist * > fHistos
Definition THaOutput.h:109
Int_t ny
Definition THaOutput.h:141
static std::string CleanEpicsName(const std::string &var)
std::string sfvarx
Definition THaOutput.h:137
static Int_t fgVerbose
Definition THaOutput.h:120
Int_t iscut
Definition THaOutput.h:141
static std::vector< std::string > reQuote(const std::vector< std::string > &input)
Double_t * fEpicsVar
Definition THaOutput.h:102
static void SetVerbosity(Int_t level)
std::vector< THaVform * > fFormulas
Definition THaOutput.h:108
Int_t nx
Definition THaOutput.h:141
void BuildList(const std::vector< std::string > &vdata)
std::string svPrefix(std::string &histype)
std::vector< std::string > fFormdef
Definition THaOutput.h:104
Bool_t fFirstEpics
Definition THaOutput.h:143
virtual void ErrFile(Int_t iden, const std::string &sline) const
virtual ~THaOutput()
std::vector< THaEpicsKey * > fEpicsKey
Definition THaOutput.h:111
virtual Int_t ChkHistTitle(Int_t key, const std::string &sline)
std::string scut
Definition THaOutput.h:137
Float_t ylo
Definition THaOutput.h:142
virtual Int_t End()
Float_t xlo
Definition THaOutput.h:142
virtual THaVar * Find(const char *name) const
static Bool_t Initialized()
const char * Data() const
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
virtual Int_t Fill()
virtual void SetAutoSave(Long64_t autos=-300000000)
Int_t Write(const char *name=nullptr, Int_t option=0, Int_t bufsize=0) const override
virtual Int_t Branch(const char *folder, Int_t bufsize=32000, Int_t splitlevel=99)
Double_t x[n]
const string kIncTag
const string kWhiteSpace
Int_t CheckIncludeFilePath(string &incfile)
Int_t GetIncludeFileName(const string &line, string &incfile)
std::vector< std::string > Split(std::string_view str, std::string_view delims, bool skipEmpty)
int CmpNoCase(const string &r, const string &s)
Definition THaString.cxx:19
STL namespace.
#define MAX(x, y)
ClassImp(TPyArg)