Hall A ROOT/C++ Analyzer (podd)
Loading...
Searching...
No Matches
DecData.cxx
Go to the documentation of this file.
1//*-- Author: Ole Hansen, October 2013
2
4//
5// Podd::DecData
6//
7// Miscellaneous decoder data, which typically do not belong to a
8// detector class. Provides a place to rapidly add new channels and to
9// make their data available as analyzer global variables.
10//
11// To use this class, add something like the following to your analysis
12// script:
13//
14// gHaApps->Add( new Podd::DecData("D","Decoder raw data") );
15//
16// This will give your class the name "D", which will be the prefix for
17// all its database keys and global variables.
18//
19// To define channels, corresponding database entries have to be
20// set up. Either use the old-style flat file database format
21// (see examples/decdata.map) or the new key/value format.
22// For each channel, first decide how to identify the data:
23//
24// 1. "crate" variables define single 32-bit data words by crate/slot/channel
25// 2. "multi" is the same as "crate", except it allows multihit channels
26// with an arbitrary number of hits.
27// 3. "word" variables define single data words found in a given crate's
28// event buffer by a 32-bit header word and an offset. Offset = 1
29// means the data word following the header, etc.
30// 4. "roclen" variables contain the event length of a given crate.
31//
32// In the key/value database format, define one database key for ALL
33// the variables of a given type. The key's value is then a long string
34// of n-tuples of configuration parameters, variable name first. For
35// example:
36//
37/*
38// D.crate = syncadc1, 1, 25, 16, \
39// syncadc2, 2, 24, 48
40*/
41//
42// will set up two "crate" variables, for crate/slot/chan = (1/25/16) and
43// (2/24/48), respectively, that will appear as global variables
44// "D.syncadc1" and "D.syncadc2". Note the continuation mark "\".
45//
46// "word" variables are defined similarly, but take header (in hex) and
47// offset as the 3rd and 4th parameters.
48//
49// Alternatively, use the "decdata.map" example file to define channels
50// line by line. (This file format will be phased out in the future.)
51// To add a new variable, if it is on a single-hit channel, you may
52// imitate 'synchadc1' if you know the (crate,slot,chan), and
53// imitate 'timeroc2' if you know the (crate,header,offset).
54//
55// If your variable is more complicated and relies on several
56// channels, you may easily write you own plug-in class derived
57// from BdataLoc (see BdataLoc.[Ch]). Decoding is done in Load().
58// You'll have to define a new, unique type name (like "crate") and
59// initialize the class with a static initialization call to DoRegister
60// (see top of BdataLoc.C). Also, you'll probably need to override
61// Configure() to get additional or different parameters from the
62// database.
63//
64// Originally written by R. Michaels, March 2002
65// Modified by R.J. Feuerbach, April 2004
66// Rewritten by O. Hansen, October 2013
67//
69
70#include "DecData.h"
71#include "THaVarList.h"
72#include "TDatime.h"
73#include "TClass.h"
74#include "TObjArray.h"
75#include "TObjString.h"
76#include "BdataLoc.h"
77#include "THaEvData.h"
78
79#include <iostream>
80#include <cctype>
81#include <cstdlib>
82#include <cstdio>
83#include <cassert>
84#include <memory>
85
86using namespace std;
87
88static const Int_t kInitHashCapacity = 100;
89static const Int_t kRehashLevel = 3;
90
91namespace Podd {
92
93//_____________________________________________________________________________
94DecData::DecData( const char* name, const char* descript )
95 : THaApparatus( name, descript ), evtype(0), evtypebits(0),
97{
98 fProperties &= ~kNeedsRunDB;
99 fBdataLoc.SetOwner(true);
100}
101
102//_____________________________________________________________________________
104{
105 // Destructor. Delete data location objects and global variables.
106
109}
110
111//_____________________________________________________________________________
113{
114 // Reset event-by-event data
115
117
118 TIter next( &fBdataLoc );
119 while( TObject* obj = next() ) {
120 obj->Clear();
121 }
122 evtype = 0;
123 evtypebits = 0;
124
125}
126
127//_____________________________________________________________________________
129{
130 // Reset the class. Removes all data channel definitions
131
132 Clear(opt);
134}
135
136//_____________________________________________________________________________
138{
139 // Register global variables, open decdata map file, and parse it.
140 // If mode == kDelete, remove global variables.
141
142 // Each defined decoder data location defines its own global variable(s)
143 // The BdataLoc have their own equivalent of fIsSetup, so we can
144 // unconditionally call their DefineVariables() here (similar to detetcor
145 // initialization in THaApparatus::Init).
146 Int_t retval = kOK;
147 TIter next( &fBdataLoc );
148 while( auto* dataloc = dynamic_cast<BdataLoc*>( next() ) ) {
149 if( dataloc->DefineVariables( mode ) != kOK )
150 retval = kInitError;
151 }
152 if( retval != kOK )
153 return retval;
154
155 RVarDef vars[] = {
156 { "evtype", "CODA event type", "evtype" },
157 { "evtypebits", "event type bit pattern", "evtypebits" },
158 { nullptr }
159 };
160 return DefineVarsFromList( vars, mode );
161}
162
163//_____________________________________________________________________________
165 const TString& configstr, bool re_init )
166{
167 // Define variables for given loctype using parameters in configstr
168
169 const char* const here = "DefineLocType";
170
171 Int_t err = 0;
172
173 // Split the string from the database into values separated by commas,
174 // spaces, and/or tabs
175 unique_ptr<TObjArray> config( configstr.Tokenize(", \t") );
176 if( !config->IsEmpty() ) {
177 Int_t nparams = config->GetLast()+1;
178 assert( nparams > 0 ); // else bug in IsEmpty() or GetLast()
179
180 if( nparams % loctype.fNparams != 0 ) {
181 Error( Here(here), "Incorrect number of parameters in database key "
182 "%s%s. Have %d, but must be a multiple of %d. Fix database.",
183 GetPrefix(), loctype.fDBkey, nparams, loctype.fNparams );
184 return -1;
185 }
186
187 TObjArray* params = config.get();
188 for( Int_t ip = 0; ip < nparams; ip += loctype.fNparams ) {
189 // Prepend prefix to name in parameter array
190 TString& bname = GetObjArrayString( params, ip );
191 bname.Prepend(GetPrefix());
192 auto* item = dynamic_cast<BdataLoc*>(fBdataLoc.FindObject(bname) );
193 Bool_t already_defined = ( item != nullptr );
194 if( already_defined ) {
195 // Name already exists
196 if( re_init ) {
197 // Changing the variable type during a run makes no sense
198 if( loctype.fTClass != item->IsA() ) {
199 Error( Here(here), "Attempt to redefine existing variable %s "
200 "with different type.\nOld = %s, new = %s. Fix database.",
201 item->GetName(), item->IsA()->GetName(),
202 loctype.fTClass->GetName() );
203 return -1;
204 }
205 if( fDebug>2 )
206 Info( Here(here), "Updating variable %s", bname.Data() );
207 } else {
208 // Duplicate variable name (i.e. duplicate names in database)
209 Error( Here(here), "Duplicate variable name %s. Fix database.",
210 item->GetName() );
211 return -1;
212 }
213 } else {
214 // Make a new BdataLoc
215 if( fDebug>2 )
216 Info( Here(here), "Defining new variable %s", bname.Data() );
217 item = static_cast<BdataLoc*>( loctype.fTClass->New() );
218 if( !item ) {
219 Error( Here(here), "Failed to create variable of type %s. Should "
220 "never happen. Call expert.", loctype.fTClass->GetName() );
221 return -1;
222 }
223 }
224 // Configure the new or existing BdataLoc with current database parameters.
225 // The first parameter is always the name. Note that this object's prefix
226 // was already prepended above.
227 err = item->Configure( params, ip );
228 if( !err && loctype.fOptptr != nullptr ) {
229 // Optional pointer to some type-specific data
230 err = item->OptionPtr( loctype.fOptptr );
231 }
232 if( err ) {
233 Int_t in = ip - (ip % loctype.fNparams); // index of name
234 Error( Here(here), "Illegal parameter for variable %s, "
235 "index = %d, value = %s. Fix database.",
236 GetObjArrayString(params,in).Data(), ip,
237 GetObjArrayString(params,ip).Data() );
238 if( !already_defined )
239 delete item;
240 break;
241 } else if( !already_defined ) {
242 // Add this BdataLoc to the list to be processed
243 fBdataLoc.Add(item);
244 }
245 }
246 } else {
247 Warning( Here(here), "Empty database key %s%s.",
248 GetPrefix(), loctype.fDBkey );
249 }
250
251 return err;
252}
253
254//_____________________________________________________________________________
255static Int_t CheckDBVersion( FILE* file )
256{
257 // Check database version. Similar to emacs mode specs, versions are
258 // determined by an identifier comment "# Version: 2" on the first line
259 // (within first 80 chars). If no such tag is found, version 1 is assumed.
260
261 const TString identifier("Version:");
262
263 const size_t bufsiz = 82;
264 char* buf = new char[bufsiz];
265 rewind(file);
266 const char* s = fgets(buf,bufsiz,file);
267 if( !s ) { // No first line? Not our problem...
268 delete [] buf;
269 return 1;
270 }
271 TString line(buf);
272 delete [] buf;
273 Ssiz_t pos = line.Index(identifier,0,TString::kIgnoreCase);
274 if( pos == kNPOS )
275 return 1;
276 pos += identifier.Length();
277 while( pos < line.Length() && isspace(line(pos)) ) pos++;
278 if( pos >= line.Length() )
279 return 1;
280 TString line2 = line(pos,line.Length() );
281 Int_t vers = line2.Atoi();
282 if( vers == 0 )
283 vers = 1;
284 return vers;
285}
286
287//_____________________________________________________________________________
288Int_t DecData::SetupDBVersion( FILE* /* file */, Int_t db_version )
289{
290 if( db_version == 1 ) {
291 Warning( Here("ReadDatabase"), "Unsupported database format found. "
292 "Check database." );
293 }
294 return 0;
295}
296
297//_____________________________________________________________________________
299 Int_t /* db_version */,
300 const BdataLoc::BdataLocType& loctype,
301 TString& configstr )
302{
303 TString dbkey = loctype.fDBkey;
304 dbkey.Prepend( GetPrefix() );
305 return LoadDBvalue( file, date, dbkey, configstr );
306}
307
308//_____________________________________________________________________________
310{
311 // Read DecData database
312
313 static const char* const here = "ReadDatabase";
314
315 FILE* file = OpenFile( date );
316 if( !file ) return kFileError;
317
318 Bool_t re_init = fIsInit;
319 fIsInit = false;
320 if( !re_init ) {
322 }
323
324 Int_t db_version = CheckDBVersion(file);
325 SetupDBVersion( file, db_version );
326
327 Int_t err = 0;
328 for( auto it = BdataLoc::fgBdataLocTypes().begin();
329 !err && it != BdataLoc::fgBdataLocTypes().end(); ++it ) {
330 const BdataLoc::BdataLocType& loctype = *it;
331
332 // Get the ROOT class for this type
333 assert( loctype.fClassName && *loctype.fClassName );
334 if( !loctype.fTClass ) {
335 loctype.fTClass = TClass::GetClass( loctype.fClassName );
336 if( !loctype.fTClass ) {
337 // Probably typo in the call to BdataLoc::DoRegister
338 Error( Here(here), "No class defined for data type \"%s\". Programming "
339 "error. Call expert.", loctype.fClassName );
340 err = -1;
341 break;
342 }
343 }
344 if( !loctype.fTClass->InheritsFrom( BdataLoc::Class() )) {
345 Error( Here(here), "Class %s is not a BdataLoc. Programming error. "
346 "Call expert.", loctype.fTClass->GetName() );
347 err = -1;
348 break;
349 }
350
351 TString configstr;
352 if( GetConfigstr(file, date, db_version, loctype, configstr) != 0 )
353 continue; // No definitions in database for this BdataLoc type
354
355 err = DefineLocType( loctype, configstr, re_init );
356 }
357
358 fclose(file);
359 if( err )
360 return kInitError;
361
362 fIsInit = true;
363 return kOK;
364}
365
366
367//_____________________________________________________________________________
369{
370 // Custom Init() method. Since this apparatus has no traditional "detectors",
371 // we skip the detector initialization.
372
373 // Standard analysis object init, calls MakePrefix(), ReadDatabase()
374 // and DefineVariables(), and Clear("I")
375 return THaAnalysisObject::Init( run_time );
376}
377
378//_____________________________________________________________________________
380{
381 // Extract the requested variables from the event data
382
383 if( !IsOK() )
384 return -1;
385
386 Clear();
387
388 evtype = evdata.GetEvType(); // CODA event type
389
390 // For each raw data source registered in fBdataLoc, get the data
391
392 //TODO: accelerate search for multiple header words in same crate
393 //- group WordLoc objects by crate
394 //- for each crate with >1 WordLoc defs, make a MultiWordLoc
395 //- MultiWordLoc uses faster search algo to scan crate buffer
396
397 TIter next( &fBdataLoc );
398 while( auto* dataloc = static_cast<BdataLoc*>(next()) ) {
399 dataloc->Load( evdata );
400 }
401
402 if( fDebug>1 )
403 Print();
404
405 return 0;
406}
407
408//_____________________________________________________________________________
409void DecData::Print( Option_t* opt ) const
410{
411 // Print current status of all DecData variables
412
414
415 cout << " event types, CODA = " << evtype
416 << " bit pattern = 0x" << hex << evtypebits << dec
417 << endl;
418
419 if( evtypebits != 0 ) {
420 cout << " trigger bits set = ";
421 bool cont = false;
422 for( size_t i = 0; i < sizeof(evtypebits)*kBitsPerByte-1; ++i ) {
423 if( TESTBIT(evtypebits,i) ) {
424 if( cont ) cout << ", ";
425 else cont = true;
426 cout << i;
427 }
428 }
429 cout << endl;
430 }
431
432 // Print variables in the order they were defined
433 cout << " number of user variables: " << fBdataLoc.GetSize() << endl;
434 TIter next( &fBdataLoc );
435 while( TObject* obj = next() ) {
436 obj->Print(opt);
437 }
438}
439
441
442} // end namespace Podd
443
int Int_t
static const Int_t kRehashLevel
Definition DecData.cxx:89
static const Int_t kInitHashCapacity
Definition DecData.cxx:88
bool Bool_t
const Ssiz_t kNPOS
int Ssiz_t
const ULong_t kBitsPerByte
const char Option_t
#define TESTBIT(n, i)
Option_t Option_t TPoint TPoint const char mode
char name[80]
static const char *const here
Definition THaVar.cxx:64
const char * fClassName
Definition BdataLoc.h:33
const char * fDBkey
Definition BdataLoc.h:34
static TypeSet_t & fgBdataLocTypes()
Definition BdataLoc.cxx:119
virtual Int_t ReadDatabase(const TDatime &date)
Definition DecData.cxx:309
virtual Int_t GetConfigstr(FILE *file, const TDatime &date, Int_t db_version, const BdataLoc::BdataLocType &loctype, TString &configstr)
Definition DecData.cxx:298
virtual Int_t SetupDBVersion(FILE *file, Int_t db_version)
Definition DecData.cxx:288
virtual void Reset(Option_t *opt="")
Definition DecData.cxx:128
Int_t DefineLocType(const BdataLoc::BdataLocType &loctype, const TString &configstr, bool re_init)
Definition DecData.cxx:164
virtual void Print(Option_t *opt="") const
Definition DecData.cxx:409
virtual Int_t Decode(const THaEvData &)
Definition DecData.cxx:379
DecData(const char *name="D", const char *description="Raw decoder data")
Definition DecData.cxx:94
virtual ~DecData()
Definition DecData.cxx:103
UInt_t evtype
Definition DecData.h:36
virtual void Clear(Option_t *opt="")
Definition DecData.cxx:112
virtual Int_t DefineVariables(EMode mode=kDefine)
Definition DecData.cxx:137
THashList fBdataLoc
Definition DecData.h:38
UInt_t evtypebits
Definition DecData.h:37
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Bool_t InheritsFrom(const char *cl) const override
TClass * IsA() const override
virtual void SetOwner(Bool_t enable=kTRUE)
virtual Int_t GetSize() const
static Int_t DefineVarsFromList(const void *list, EType type, EMode mode, const char *def_prefix, const TObject *obj, const char *prefix, const char *here, const char *comment_subst="")
virtual const char * Here(const char *) const
const char * GetPrefix() const
Bool_t IsOK() const
virtual FILE * OpenFile(const TDatime &date)
virtual void Print(Option_t *opt="") const
virtual void Clear(Option_t *opt="")
UInt_t GetEvType() const
Definition THaEvData.h:53
void Clear(Option_t *option="") override
TObject * FindObject(const char *name) const override
void Add(TObject *obj) override
const char * GetName() const override
static TClass * Class()
virtual void Warning(const char *method, const char *msgfmt,...) const
virtual void Error(const char *method, const char *msgfmt,...) const
virtual void Info(const char *method, const char *msgfmt,...) const
Ssiz_t Length() const
Int_t Atoi() const
const char * Data() const
TObjArray * Tokenize(const TString &delim) const
TString & Prepend(char c, Ssiz_t rep=1)
TLine * line
static Int_t CheckDBVersion(FILE *file)
Definition DecData.cxx:255
STL namespace.
ClassImp(TPyArg)