// ---------------------------------------------------------------------- // // HepRootNtuple.cc - implementation of Root n-tuple // // HepRootNtuple is the implementation of the Root n-tuple // It is derived from HepNtuple (the generic interface). // It is mainly a C++ wrapper around Root // // No HepRootNtuple objects are ever directly // instantiated by the programmer. When creating new HepNtuple* objects, // the manager is in charge of creating the appropriate HepRoot object. // // To use generate Root n-tuple, HepRootFileManager must be used: // // int lunit = 10; // HepFileManager* m = new HepRootFileManager("filename.rz", lunit); // : // : // HepNtuple & h(m->newHepNtuple("Title")); // [define HepNtuple] // : // [gather data] // : // h->capture(); // // // History: // 02-Aug-1999 Philippe Many changes have done. See cvs log // 03-Dec-1998 Philippe Canal Bare Creation // // ---------------------------------------------------------------------- #include "ZMutility/iostream" #include USING( std::string ) #ifndef HEPTRACE_H #include "HepTuple/HepTrace.h" #endif #ifndef HepRootTuple_H #include "HepTuple/HepRootNtuple.h" #endif #include "HepTuple/RootNameTag.h" #ifndef HEPCOLUMN_H #include "HepTuple/Column.h" #endif #ifndef HEPFILEMANAGER_H #include "HepTuple/HepFileManager.h" #endif #ifndef HEPCOLUMN_H #include "HepTuple/Column.h" #endif #ifndef HEPBLOCK_H #include "HepTuple/Block.h" #endif #ifndef ROOTCOLUMNLESS_H #include "HepTuple/RootColumnLess.h" #endif #include "ZMutility/itos.h" #include #include #include #include #include #include "TLeaf.h" #include "TLeafObject.h" #include "TLeafB.h" #include "TLeafC.h" #include "TLeafI.h" #include "TLeafF.h" #include "TLeafS.h" #include "TLeafD.h" #include "TBasket.h" R__EXTERN TTree *gTree; ZM_BEGIN_NAMESPACE( zmht ) /* namespace zmht { */ class HepBranch : public TBranch { public: HepBranch(const Text_t *name, void *address, const Text_t *leaflist, Int_t basketsize=32000, Int_t compress=-1) :TBranch(name,address,"",basketsize,compress) { // *-*-*-*-*-*-*-*-*-*-*-*-*Create a Branch*-*-*-*-*-*-*-*-*-*-*-*-*-*-* // *-* ===================== // // * address is the address of the first item of a structure // or the address of a pointer to an object (see example). // * leaflist is the concatenation of all the variable names and types // separated by a colon character : // The variable name and the variable type are separated by a slash (/). // The variable type may be 0,1 or 2 characters. If no type is given, // the type of the variable is assumed to be the same as the previous // variable. If the first variable does not have a type, it is assumed // of type F by default. The list of currently supported types is given below: // - C : a character string terminated by the 0 character // - B : an 8 bit signed integer (Char_t) // - b : an 8 bit unsigned integer (UChar_t) // - S : a 16 bit signed integer (Short_t) // - s : a 16 bit unsigned integer (UShort_t) // - I : a 32 bit signed integer (Int_t) // - i : a 32 bit unsigned integer (UInt_t) // - F : a 32 bit floating point (Float_t) // - D : a 64 bit floating point (Double_t) // // By default, a variable will be copied to the buffer with the number of // bytes specified in the type descriptor character. However, if the type // consists of 2 characters, the second character is an integer that // specifies the number of bytes to be used when copying the variable // to the output buffer. Example: // X ; variable X, type Float_t // Y/I : variable Y, type Int_t // Y/I2 ; variable Y, type Int_t converted to a 16 bits integer // // See an example of a Branch definition in the TTree constructor. // // Note that in case the data type is an object, this branch can contain // only this object. // // Note that this function is invoked by TTree::Branch // // *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* // *-*- Clean-up the wrong work done by the TBranch constructor TObject *todel = fLeaves.Last(); fLeaves.RemoveLast(); gTree->GetListOfLeaves()->RemoveLast(); delete todel; fNleaves--; SetTitle(leaflist); // *-*- Decode the leaflist (search for : as separator) char * varcur = (char*)leaflist; char * var = varcur; Int_t lenvar = 0; Int_t offset = 0; Int_t lentype = 4; char *leafname = new char[64]; char *leaftype = new char[32]; strcpy(leaftype,"F"); while (1) { lenvar++; if (*var == ':' || *var == 0) { strncpy(leafname,varcur,lenvar-1); leafname[lenvar-1] = 0; char *ctype = strstr(leafname,"/"); if (ctype) { *ctype=0; strcpy(leaftype,ctype+1);} TLeaf *leaf = 0; if (*leaftype == 'C') { lentype = 1; leaf = new TLeafC(leafname,leaftype); } else if (*leaftype == 'B') { lentype = 1; leaf = new TLeafB(leafname,leaftype); } else if (*leaftype == 'b') { lentype = 1; leaf = new TLeafB(leafname,leaftype); leaf->SetUnsigned(); } else if (*leaftype == 'S') { lentype = 2; leaf = new TLeafS(leafname,leaftype); } else if (*leaftype == 's') { lentype = 2; leaf = new TLeafS(leafname,leaftype); leaf->SetUnsigned(); } else if (*leaftype == 'I') { lentype = 4; leaf = new TLeafI(leafname,leaftype); } else if (*leaftype == 'i') { lentype = 4; leaf = new TLeafI(leafname,leaftype); leaf->SetUnsigned(); } else if (*leaftype == 'F') { lentype = 4; leaf = new TLeafF(leafname,leaftype); } else if (*leaftype == 'D') { lentype = 8; leaf = new TLeafD(leafname,leaftype); } else if ( gROOT->GetClass(leaftype) ) { lentype = 4; leaf = new TLeafObject(leafname,leaftype); } if (!leaf) { Error("TLeaf","Illegal data type"); return; } leaf->SetBranch(this); leaf->SetAddress((char*)(fAddress+offset)); leaf->SetOffset(offset); if (leaf->GetLeafCount()) SetEntryOffsetLen(1000); if (leaf->InheritsFrom("TLeafC")) SetEntryOffsetLen(1000); fNleaves++; fLeaves.Add(leaf); gTree->GetListOfLeaves()->Add(leaf); if (*var == 0) break; varcur = var+1; offset += lentype*leaf->GetLen(); lenvar = 0; } var++; } delete [] leafname; delete [] leaftype; todel = fBaskets.Last(); fBaskets.RemoveLast(); delete todel; TBasket *basket = new TBasket(name,fTree->GetName(),this); fBaskets.AddAt(basket,0); } }; static char RootType( ColumnData_t hep_type ) { switch( hep_type ) { case Int1_ct: return 'B'; case Int2_ct: return 'S'; case Int4_ct: return 'I'; case Int8_ct: return ' '; case Uint1_ct: return 'b'; case Uint2_ct: return 's'; case Uint4_ct: return 'i'; case Uint8_ct: return ' '; case Float4_ct: return 'F'; case Float8_ct: return 'D'; case Float16_ct: return ' '; case Bool_ct: case Bool2_ct: case Bool4_ct: return 'b';//compatible to Logical*2: *4 in HBOOK case Char_ct: return 'b'; case Char4_ct: case Char8_ct: case Char12_ct: case Char16_ct: case Char20_ct: case Char24_ct: case Char28_ct: case Char32_ct: return 'C'; default: return ' '; } } #ifdef NEVER static ColumnData_t HepTupleType( char root_type) { switch( root_type ) { case 'B': return Int1_ct; case 'S': return Int2_ct; case 'I': return Int4_ct; case 'b': return Uint1_ct; case 's': return Uint2_ct; case 'i': return Uint4_ct; case 'F': return Float4_ct; case 'D': return Float8_ct; case 'C': return Char32_ct; default: return ColumnData_t_End; } } #endif static ColumnData_t HepTupleType( const char* root_type) { if ( !strcmp( root_type, "Char_t" ) ) return Int1_ct; if ( !strcmp( root_type, "UChar_t" ) ) return Uint1_ct; if ( !strcmp( root_type, "Short_t" ) ) return Int2_ct; if ( !strcmp( root_type, "UShort_t" ) ) return Uint2_ct; if ( !strcmp( root_type, "Int_t" ) ) return Int4_ct; if ( !strcmp( root_type, "UInt_t" ) ) return Uint4_ct; if ( !strcmp( root_type, "Float_t" ) ) return Float4_ct; if ( !strcmp( root_type, "Double_t" ) ) return Float8_ct; return ColumnData_t_End; } static const int defNwbuff = 1024; static const int defDemandNbytes = defNwbuff; // create a ntuple HepRootNtuple::HepRootNtuple( HepRootFileManager * manager , TTree * tree ) : HepNtuple( manager, tree->GetTitle(), tree->GetUniqueID() ), HepRootObj( tree ), _nColumnCreated(0), _lastRwnArray(0), _lastArrayRead(0), _lastRowRead(-1), _addrSetUp(false) { HEP_DEBUG( "HepRootNtuple::constructor( \"" << tree->GetTitle() << "\", " << " )" ); } HepRootNtuple::HepRootNtuple( HepRootFileManager * manager , const string& title , const int idReq ) : HepNtuple( manager, title.c_str(), idReq ), _nColumnCreated(0), _lastRwnArray(0), _lastArrayRead(0), _lastRowRead(-1), _addrSetUp(false) { HEP_DEBUG( "HepRootNtuple::constructor( \"" << title << "\", " << idReq << " )" ); // set the default values. setColumnWise(); setDiskResident(); allowNewColumns(); string name = mkname(title, *id_); // error= sigma/sqrt(N) data( new TTree( name.c_str(), title.c_str() ) ); if ( data() == 0 ) { ZMthrow(ZMxHepCantMakeHist(string("Histo failed to create the hist 1d: ") + title ) ); isValid(false); } else { data()->SetUniqueID( idReq ); } } // HepRootNtuple::HepRootNtuple() // clone an existing Tuple HepRootNtuple::HepRootNtuple( HepRootNtuple * original , const string& title , const int idReq ) : HepNtuple( original->manager(), title.c_str(), idReq ), _nColumnCreated(0), _lastRwnArray(0), _lastArrayRead(0), _lastRowRead(-1), _addrSetUp(false) { HEP_DEBUG( "HepRootNtuple::constructor( \"" << original->title() << "\", " << title << "\", " << idReq << " )" ); string name = mkname(title, *id_); // error= sigma/sqrt(N) data( reinterpret_cast( original->data()->Clone() ) ); if ( data() == 0 ) { ZMthrow(ZMxHepCantMakeHist(string("Histo failed to create the hist 1d: ") + title ) ); isValid(false); } else { data()->SetTitle( title.c_str() ); data()->SetUniqueID( idReq ); } } // HepRootNtuple::HepRootNtuple() // Used for dummy construction ... // the object is then not valid ... HepRootNtuple::HepRootNtuple() : HepNtuple() { HEP_DEBUG( "HepRootNtuple::constructor( )" ); } // HepRootNtuple::HepRootNtuple() HepRootNtuple::~HepRootNtuple() { HEP_DEBUG( "HepRootNtuple::destructor( ) on ntuple #" << *id_ ); } // HepRootNtuple::~HepRootNtuple() //////////////////////////////////// // isXxxxxEnabled() family // // // // virtual function indicating // // which part of the interface // // is supported // //////////////////////////////////// bool HepRootNtuple::isRowWiseEnabled() const { return true; } bool HepRootNtuple::isColumnWiseEnabled() const { return true; } bool HepRootNtuple::isBlockWiseEnabled() const { return true; } bool HepRootNtuple::isDiskResidentEnabled() const { return true; } bool HepRootNtuple::isMemResidentEnabled() const { return true; } bool HepRootNtuple::isSharedMemoryEnabled() const { return true; } bool HepRootNtuple::isNwbuffEnabled(int nwbuff) const { return true; } bool HepRootNtuple::isBuffLimitEnabled(int limit) const { return true; } bool HepRootNtuple::isDemandBuffersEnabled() const { return false; } bool HepRootNtuple::isCircularBufferEnabled() const { return false; } bool HepRootNtuple::isCaseSensitive() const { return true; } ////////////////////////////////////////////////////// // isTypeEnabled // ////////////////////////////////////////////////////// // These methods tell if a manager can handle a certain type in // the given block. // It relies on the enum ColumnData_t to be ordered correctly // i.e.: numerical type first, then boolean, then character strings bool HepRootNtuple::isTypeEnabled(ColumnData_t type,Block *bk) { // Branches that have TObject can only have one column return isTypeEnabled(type); #if 0 if ( bk->nColumns() <= 0 ) { return isTypeEnabled(type); } else if ( bk->nColumns() == 1 ) { return ( bk->columns()[0]->attributes().type != Ptr_ct && isTypeEnabled(type) ); } else { return (type!=Ptr_ct && isTypeEnabled(type) ); } #endif } // HepRootNtuple::isTypeEnabled bool HepRootNtuple::isTypeEnabled(ColumnData_t type) { switch(type) { case Uint8_ct: case Int8_ct: case Float16_ct: return false; case Int1_ct: case Int2_ct: return true; case Char_ct: case Char4_ct: case Char8_ct: case Char12_ct: case Char16_ct: case Char20_ct: case Char24_ct: case Char28_ct: case Char32_ct: return true; case Ptr_ct: return true; default: return true; } } // HepRootNtuple::isTypeEnabled ////////////////////////////////////////////////////// // setStorageGeometry // ////////////////////////////////////////////////////// bool HepRootNtuple::setStorageGeometry(StorageGeometryName newStrategy) { // in root the two strategy are the same so let's just pass any change along. return HepNtuple::setStorageGeometry(newStrategy); } // HepRootNtuple::setStorageGeometry ////////////////////////////////////////////////////// // setStorageLocation // ////////////////////////////////////////////////////// bool HepRootNtuple::setStorageLocation(unsigned char newLocation) { if ( (newLocation != resident() ) && isCreated() ) { ZMthrow(ZMxHepLockedItem("Unable to change storage location after first booking")); return false; } return HepNtuple::setStorageLocation(newLocation); } // HepRootNtuple::setStorageLocation ////////////////////////////////////////////////////// // setNwbuffValue // ////////////////////////////////////////////////////// bool HepRootNtuple::setNwbuffValue(int nwbuff) { ZMthrow(ZMxHepBadRequest("Root can not set nwbuff")); return HepNtuple::setNwbuffValue(nwbuff); } // HepRootNtuple::setNwbuffValue ////////////////////////////////////////////////////// // setBuffLimitValue // ////////////////////////////////////////////////////// bool HepRootNtuple::setBuffLimitValue(int limit) { return HepNtuple::setBuffLimitValue(limit); } // HepRootNtuple::setBuffLimitValue /*******************/ /* */ /* isNameAvailable */ /* */ /*******************/ // // This version verifies that the column name in the nameTag // is unique in the heptuple. bool HepRootNtuple::isNameAvailable ( const string& nameTag ) const { TupleNameTag tag; parseNameTag(tag, nameTag); bool result; if ( tag.isValid() ) { if ( tag.block().length() != 0 ) { Block *bk = findBlock(tag.block()); if ( bk == NULL ) { return true; } result = (bk->findColumn(tag.column()) == NULL); } else { result = (findColumn(tag.column()) == NULL); } return result; } else { return false; } } // HepRootNtuple::isNameAvailable /****************/ /* */ /* parseNametag */ /* */ /****************/ // // Parse the nametag for a column, providing block and column names. // return a TupleNameTag with the method isValid(), block() and column() // returning the proper result const TupleNameTag& HepRootNtuple::parseNameTag (TupleNameTag& what, const string& nametag, bool withIndices) const { static RootNameTag tag; tag.init(nametag, withIndices, what); return what; } /* parseNameTag */ /****************/ /* */ /* bookRowWise */ /* */ /****************/ // Boook a row wise N-Tuple in Root. If the n-tuple was already // created we must delete the old ntuple and create a new one. // since the user may have specified the id, keep the id constant bool HepRootNtuple::bookRowWise() { HEP_DEBUG( "HepRootNtuple::bookRowWise" ); // Unlike in the other managers we do not re-write the row-wise // ntuple if we add a new column. We just add new branches and // fill them with default values.... so we do the same as for // Column-Wise ntuple return bookColumnWise(); } // HepRootNtuple::bookRowWise /******************/ /* */ /* bookColumnWise */ /* */ /******************/ string RootColFormat( Column * col ) { const ColumnAttribs ca = col->attributes(); string format = ca.tag; if ( ca.ndim > 0 ) { // it is an array int j = ca.ndim - 1; if ( ca.index.length() != 0 ) { // j==ndim-1 AND index is not empty // we used an 'undefined' TupleNameTag because we // are already sure that index is a valid tag for the // current manager. TupleNameTag tag; tag.init(ca.index, false, tag); format += '[' + tag.column() + ']'; --j; } for ( ; j >= 0; --j ) { format += '[' + itos( ca.extents[j] ) + ']'; } } // NOTE: For some reason combining this two lines does not give the right // result. format += "/"; if ( ca.type == Ptr_ct ) { TObject ** addr = (TObject**) col->getValueAddr(); if (*addr == 0 ) { ZMthrow(ZMxHepBadRequest("Pointer to TObject need to be initialized before the first HepTuple storing")); format += 'I'; } else { format += (*addr)->ClassName(); } } else { format += RootType( ca.type ); } return format; } // Do booking for column wise N-Tuple in Root. // If a block happen to have been changed since booked, we // simply IGNORE it (actually we do not know about it ...) bool HepRootNtuple::bookColumnWise() { HEP_DEBUG( "HepRootNtuple::bookColumnWise" ); // if ( _nColumnCreated!=0 && // _nColumnCreated != HepNtuple::nColumns() ) { // ZMthrow(ZMxHepNotYet("Adding column to a ROOT ntuple")); // return false; // } TTree * tree = reinterpret_cast ( data() ); // Now the N-Tuple is created add all the blocks that have not // been created yet. Block* bk; for ( blocksMap::iterator iterateBlock = blocks.begin(); iterateBlock != blocks.end(); iterateBlock++ ) { bk = (*iterateBlock).second; if ( ! bk->isBooked() ) { // Check if the current column is indexed by some other column. If so, // verify that the index column span matched the specified array size. for (std::string::size_type i=0; i < bk->columns().size(); i++ ) { Column *c = bk->columns()[i]; string colName = c->name(); string indexName = c->getIndex(); if( indexName.size() != 0 ) { int * pdim = new int[10]; int numDim = c->getDimension(pdim); if( numDim != 0 ) { // Restrict column name search to the current block - not all blocks! // JMM 25 Feb. 2003 // Column * ci = findColumn(indexName); Column * ci = bk->findColumn(indexName); ColumnAttribs CAI = ci->attributes(); if( *(pdim+numDim-1) != CAI.indexHi ) ZMthrow(ZMxHepIllFormedItem(colName+string("'s dimension [0,")+ itos(*pdim)+string("] does not match the span [0,")+ itos(CAI.indexHi)+string("] of its index, ")+indexName)); } delete [] pdim; } } void *addr; if ( bk->columns().size() == 1 && bk->columns()[0]->attributes().type == Ptr_ct ) { addr = bk->capturedData(0); Column *c = bk->columns()[0]; TObject ** obj = (TObject**) addr; // Pass the name of the column so that the leaf is // properly named TBranch * br = tree->Branch( (c->name()).c_str(), (*obj)->ClassName(), addr, 32000, 0 ); // rename the branch br->SetName(bk->name().c_str()); br->SetTitle(bk->name().c_str()); } else { // First we sort the column so that we have: // indexes first then all other columns sorted in decreasing size // order. This allow us to make sure that the data is properly // aligned. // NOTE: we assume that alignment is 8 bytes. RootColumnLess compare; bk->sortColumn( &compare ) ; // Count the indexes because we may need to pre-padded the array of // data bytes. int indexesSize = 0; for (std::string::size_type i=0; i < bk->columns().size(); i++ ) { Column *c = bk->columns()[i]; if ( c->isIndex() ) { indexesSize += c->sizeofElem(); } } // capturedData will add bytes to align the data // if indexesSizes is not a multiple of 8 int neededPadding = ((indexesSize+7)/8)*8 - indexesSize; addr = bk->capturedData(neededPadding); Column* col; Block::columnsVec::const_iterator iterateCol(bk->columns().begin()); col = (*iterateCol); string format = RootColFormat(col); for ( iterateCol++; iterateCol != bk->columns().end(); iterateCol++ ) { col = (*iterateCol); format += ":" + RootColFormat(col); } // To behave properly the content of the memory // passed to TTree::Branch needs to be zeroed out // for the index. Let's be overzealous for now memset( addr, 0, bk->capturedDataSize() ); gTree = tree; TBranch * br = new HepBranch((bk->name()).c_str(), addr, format.c_str()); tree->GetListOfBranches()->Add(br); // TBranch * br = tree->Branch( (bk->name()).c_str(), // addr, // format.c_str() ); // uses default buffer size for now // Set the span of the index variables: std::string index_name; for ( iterateCol = bk->columns().begin(); iterateCol != bk->columns().end(); iterateCol++ ) { col = (*iterateCol); if ( col->isIndex() ) { TLeafI *index = (TLeafI*)br->GetListOfLeaves()->FindObject( col->name().c_str() ); int min, max; col->getSpan( &min, &max ); index->SetMaximum( max ); } else { // This code is needed for ROOT 3.01.06 and below. // It fixes that if there is more than 1 leaf with the name of // the index, then the wrong leaf is used. index_name = col->getIndex(); if (index_name.length()>0) { TLeaf* index = (TLeaf*)br->GetListOfLeaves()->FindObject( index_name.c_str() ); if (!index) index = (TLeaf*)tree->GetListOfLeaves()->FindObject( index_name.c_str() ); if (!index) { std::string msg = "Missing index leaf ("; msg += index_name; msg += ") in ROOT tree ("; msg += tree->GetName(); msg += ")"; ZMthrow(ZMxHepImproperUse(msg)); } else { TLeaf* leaf = (TLeaf*)br->GetListOfLeaves() ->FindObject(col->name().c_str() ); if (leaf->GetLeafCount() != index) { // something is odd in ROOT, let's fix it. leaf->SetLeafCount(index); } } } } } // Work around the fact that TTree::Branch(...) does not allow the // specification of a variable range. The consequence is that if // the index and the array are in the same branch, the size of // of the array is calculated as 0!!! TObjArray * leaves = br->GetListOfLeaves(); Int4 nl = leaves->GetEntriesFast(); Int4 offset = 0; for ( int j=0;jUncheckedAt(j); if ( leaf != 0 ) { Column * c = bk->findColumn( leaf->GetName() ); leaf->SetAddress( ((char*)addr)+offset ); leaf->SetOffset(offset); offset += c->sizeofElem(); } } } // if only one TObject column bk->book(); int nrows = (int) tree->GetEntries(); if ( nrows != 0 ) { // first copy in the block capturedData array (addr) the // current value from the columns void* copyOfBlock = (void*)new char[bk->capturedDataSize()]; memcpy(copyOfBlock,addr,bk->capturedDataSize()); // Second set the columns of the block to default, without reseting // the isCaptured flag for ( Block::columnsVec::const_iterator iterateCol(bk->columns().begin()); iterateCol != bk->columns().end(); iterateCol++ ) { (*iterateCol)->setToDefault(); } // Block::columnsVec loop // reset the captured data area to the default value // (see just above). bk->capturedData(); for ( int i = 1; i <= nrows; i++ ) { storeSingleBlock(bk); } // copy the data back in the block and each columns memcpy(addr,copyOfBlock,bk->capturedDataSize()); delete (char*) copyOfBlock; void * current = addr; for ( Block::columnsVec::const_iterator iterateCol(bk->columns().begin()); iterateCol != bk->columns().end(); iterateCol++ ) { current = (*iterateCol)->copyFromMem(current); } // Block::columnsVec loop } } // end of if not block booked } // end of for each block loop return true; } // end of HepRootNtuple::bookColumnWise /**********/ /* */ /* book */ /* */ /**********/ bool HepRootNtuple::book() { if ( ! isDefinitionChanged() ) { return true; } if ( !mayUse() ) { ZMthrow(ZMxHepUnmanagedItem("attempt to book an unmanaged ntuple")); return false; } if ( !isValid() ) { ZMthrow(ZMxHepVacuousItem("attempt to book an invalidated ntuple")); return false; } if ( isRowWise() ) { bookRowWise(); } else { // isColumnWise() bookColumnWise(); } // this should make isDefinitionChanged() false return HepNtuple::book(); } // HepRootNtuple::book() /*******************/ /* */ /* storeWholeRow */ /* */ /*******************/ bool HepRootNtuple::storeWholeRow() { HEP_DEBUG ( "HepRootNtuple::storeWholeRow" ); TTree * tree = reinterpret_cast ( data() ); tree->Fill(); columnsMap::iterator iterateCol = columns.begin(); while ( ! (iterateCol == columns.end()) ) { ((*iterateCol).second)->setHasBeenStored(); iterateCol++; } return true; } // HepRootNtuple::storeWholeRow /*********************/ /* */ /* storeSingleBlock */ /* */ /*********************/ bool HepRootNtuple::storeSingleBlock(Block* bk) { HEP_DEBUG( " HepRootNtuple::storeSingleBlock " ); //int id = HepNtuple::id(); for ( Block::columnsVec::const_iterator iterateCol(bk->columns().begin()); iterateCol != bk->columns().end(); iterateCol++ ) { (*iterateCol)->setHasBeenStored(); } if ( isRowWise() ) { // Storing a single block have to mean store the whole row. return storeWholeRow(); } else { TTree * tree = reinterpret_cast ( data() ); TBranch * br = tree->GetBranch( bk->name().c_str() ); return (br->Fill() != 0); } } // HepRootNtuple::storeSingleBlock /*********************/ /* */ /* read methods */ /* */ /*********************/ // Instruct the manager to read from file/memory into the destination variable // of all the columns of repectively the row, block, single column For the // first three methods ALL the listed columns are expected to have destination // variables (i,e. get the value at an address and send it to col->set(void // *addr); /*****************************/ /* */ /* helper Root routine */ /* */ /*****************************/ bool HepRootNtuple::restoreNtuple() { bool result = true; // All tree are Column wise equivalent setColumnWise(); TTree * tree = reinterpret_cast ( data() ); TObjArray * branches = tree->GetListOfBranches(); Int_t nb = branches->GetEntriesFast(); TBranch *branch; int i,j,nl; for (i=0;iUncheckedAt(i); bool valid = true; if ( (branch != 0) ) { bool isSplit = false; if ( branch->InheritsFrom("TBranchObject") ) { // If the branch is NOT split, then we only have // a leaf // If the branch is split, we have one branch per // elements. isSplit = branch->GetListOfBranches()->GetEntries() > 0; } string blockName = branch->GetName(); string format; string title,flipTitle; TLeaf * leaf; TObjArray * leaves; if ( isSplit ) { leaves = branch->GetListOfBranches(); } else { leaves = branch->GetListOfLeaves(); } nl = leaves->GetEntriesFast(); for ( j=0;jUncheckedAt(j); } else { TBranch * subBranch = (TBranch*)leaves->UncheckedAt(j); if ( subBranch ) { leaf = (TLeaf*)subBranch->GetListOfLeaves()->UncheckedAt(0); } else { leaf = 0; } } if ( (leaf != 0) ) { if ( !( leaf->InheritsFrom("TLeafObject") ) ) { ColumnData_t colType = HepTupleType( leaf->GetTypeName() ); // the result is the same for a characters a array or just a char // we need to figure our if we should use C*?? int min = leaf->GetMinimum(); int max = leaf->GetMaximum(); title = leaf->GetTitle(); // replace [x][y] by (x,y) in the title string::size_type where = title.find('['); if ( where != string::npos ) { title[where] = '('; where = title.rfind(']'); if ( where != string::npos ) { title[where] = ')'; } where = title.find(']'); while ( where != string::npos ) { title.replace( where, 2, "," ); where = title.find(']'); } } if ( j!=0 ) format += ","; flipTitle = flipString( title ); title = flipTitle; format += title; format += ':'; format += TypeInformation[colType].shortcut; if ( (min!=0)||(max!=0) ) { format += "::"; // skip packing info format += "[" + itos(min) + "," + itos(max) + "]"; }; } else { // We have a TLeafObject! ColumnData_t colType = Ptr_ct; title = leaf->GetName(); if ( j!=0 ) format += ","; format += title; format += ':'; format += TypeInformation[colType].shortcut;; } } else { // leaf does not exit or is of an unsupported type valid = false; } // if leaf exist } // for each leaf result &= valid && this->restoreBlock( blockName, format ); } // if branch exist } // for each branch // If all is well so far, fill in the number of rows and set the addresses if( result ) { int nrows = (int) tree->GetEntries(); result &= setNrowsValue( nrows ); _nColumnCreated = nColumns(); result &= setAddresses(); } if( result ) isCreated( true); return result; } // HepRootNtuple::restoreNtuple() // String manipulation to correct the order of the format variable string HepRootNtuple::flipString( string chunk ) { string::size_type open,close; string result; int chunklen = chunk.length()-1; open = chunk.find('('); close = chunk.rfind(')'); if( close != string::npos ) { string frontend = chunk.substr(0,open+1); string backend = chunk.substr(close,chunklen-close-1); string middle = chunk.substr(open+1,close-open-1); int nfields = 1; string temp = middle; string::size_type where = temp.find(','); while( where != string::npos ) { ++nfields; temp.replace(where,1," "); where = temp.find(','); } string flip = frontend; string field; int lensub; for( int k=0; k ( data() ); _addrSetUp = true; for ( blocksMap::const_iterator iterateBlock (blocks.begin()); iterateBlock != blocks.end(); iterateBlock++ ) { Block *bk = (*iterateBlock).second; // NOTE. The following computation of required padding assumes that // all the index variables come at the beginning of the block. // That is commonly the case but NOT absolutely necessary. In // the case where it isn't true, odd things may happen, the // most common being complaints about unaligned accesses on // OSF1 machines. // Count the indexes because we may need to pre-padded the array of // data bytes. int indexesSize = 0; for (string::size_type i=0; i < bk->columns().size(); i++ ) { Column *c = bk->columns()[i]; ColumnAttribs CA = c->attributes(); if ( c->isIndex() ) { indexesSize += c->sizeofElem(); } } int neededPadding = indexesSize - (indexesSize/8); // add bytes if indexesSizes is not a multiple of 8 void *addr = bk->dataArray(neededPadding); tree->SetBranchAddress( bk->name().c_str(), addr ); } // block loop } // if (_addrSetup) return true; } // HepRootNtuple::setCwnAddresses int HepRootNtuple::readWholeRow(int irow) { HEP_DEBUG( "HepRootNtuple::readWholeRow(int)" ); TTree * tree = reinterpret_cast ( data() ); if ( setAddresses() ) { int ierror = 0; // read whole row ierror = tree->GetEvent(irow-1, 1); if ( ierror == 0 ) { ZMthrow(ZMxHepCantReadFile("Unable to read CWN")); return 0; } // set column values. for ( blocksMap::const_iterator iterateBlock (blocks.begin()); iterateBlock != blocks.end(); iterateBlock++ ) { Block *current = (*iterateBlock).second; // send column values to the destination. current->read(); } // blocksMap loop } return nBlocks(); } // HepRootNtuple::readWholeRow int HepRootNtuple::readWholeBlock(Block* bk, int irow) { HEP_DEBUG( "HepRootNtuple::readWholeBlock" ); TTree * tree = reinterpret_cast ( data() ); if ( setAddresses() ) { int nbytes = 0; TBranch *br = tree->GetBranch( bk->name().c_str() ); nbytes = br->GetEvent( irow-1 ); if ( nbytes == 0 ) { ZMthrow(ZMxHepCantReadFile("Unable to read CWN")); return 0; } // send column values to the destination. bk->read(); } return bk->nColumns(); } // HepRootNtuple::readWholeBlock( int HepRootNtuple::readSingleColumn(Column* col, int irow) { HEP_DEBUG( "HepRootNtuple::readSingleColumn" ); TTree * tree = reinterpret_cast ( data() ); if ( setAddresses() ) { int nbytes = 0; TBranch *br = tree->GetBranch( col->block()->name().c_str() ); nbytes = br->GetEvent( irow-1 ); if ( nbytes == 0 ) { ZMthrow(ZMxHepCantReadFile("Unable to read CWN")); return 0; } // send column values to the destination. col->read(); } return true; } // readSingleColumn int HepRootNtuple::readSingleColumn(Column* col, int irow, void * val) { HEP_DEBUG( "HepRootNtuple::readSingleColumn" ); TTree * tree = reinterpret_cast ( data() ); if ( setAddresses() ) { int nbytes = 0; TBranch *br = tree->GetBranch( col->block()->name().c_str() ); nbytes = br->GetEvent( irow-1 ); if ( nbytes == 0 ) { ZMthrow(ZMxHepCantReadFile("Unable to read CWN")); return 0; } // Grab the column value. col->block()->load(); col->copyToMem(val); } // isColumnWise() return 1; } // readSingleColumn with value int HepRootNtuple::readSingleColumn(Column* col, const string& indices, int irow, void * val) { HEP_DEBUG( "HepRootNtuple::readSingleColumn" ); if ( isRowWise() ) { ZMthrow(ZMxHepUnsupported( "Root Row Wise Ntuple do not handle array of Columns")); return 0; } else { TTree * tree = reinterpret_cast ( data() ); if ( setAddresses() ) { int nbytes = 0; TBranch *br = tree->GetBranch( col->block()->name().c_str() ); nbytes = br->GetEvent( irow-1 ); if ( nbytes == 0 ) { ZMthrow(ZMxHepCantReadFile("Unable to read CWN")); return 0; } col->block()->load(); return col->copyToMem(val,indices); } } return 0; } // readSingleColumn with indices ZM_END_NAMESPACE( zmht ) /* } // namespace zmht */