// ---------------------------------------------------------------------- // // HepHBookNtuple.cc - implementation of HBook n-tuple // // HepHBookNtuple is the implementation of the HBook n-tuple // It is derived from HepNtuple (the generic interface). // It is mainly a C++ wrapper around the CERNlib HBook // Fortran histogramming libraries. // // No HepHBookNtuple objects are ever directly // instantiated by the programmer. When creating new HepNtuple* objects, // the manager is in charge of creating the appropriate HepHBook object. // // To use generate HBook n-tuple, HepHBookFileManager must be used: // // int lunit = 10; // HepFileManager* m = new HepHBookFileManager("filename.rz", lunit); // : // : // HepNtuple & h(m->newHepNtuple("Title")); // [define HepNtuple] // : // [gather data] // : // h->capture(); // // // Note that the constructor can take an ID number which is used by // the HBook implementation of HepNtuple. If omitted, the ID number is // generated automatically (which is recommended). The ID number is // available through the id() method. // // // History: // 18-Jul-1997 Philippe Canal Bare Creation // 07-Jul-1998 Philippe Canal Make Sure Directory is correctly set // when using objects. // 15-Jun-1999 J. Marraffino Make sure the index column is included // when reading an indexed array from an ntuple. // // ---------------------------------------------------------------------- #ifndef HEPTRACE_H #include "HepTuple/HepTrace.h" #endif #ifndef HepHBookTuple_H #include "HepTuple/HepHBookNtuple.h" #endif #ifndef HEPHBOOKWRAPPERS_H #include "HepTuple/HepHBookWrappers.h" #include "ZMtools/pretendToUse.h" #endif #include "HepTuple/HBookNameTag.h" #include "ZMutility/iostream" #include USING( std::string ) #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 #include "HepTuple/HBookColumnLess.h" #include "ZMutility/itos.h" ZM_BEGIN_NAMESPACE( zmht ) /* namespace zmht { */ #define BLOCKNAMELENGTH 8 #define BLOCKFORMLENGTH 1300 static const int defNwbuff = 1024; static const int defDemandNbytes = defNwbuff; // create a ntuple HepHBookNtuple::HepHBookNtuple( HepHBookFileManager * manager , const string& title , const int idReq ) : HepNtuple( manager, title, idReq ), _nColumnCreated(0), _lastRwnArray(0), _lastArrayRead(0), _lastRowRead(-1), _addrSetUp(false) { HEP_DEBUG( "HepHBookNtuple::constructor( \"" << title << "\", " << idReq << " )" ); // set the default values. setColumnWise(); setDiskResident(); setNwbuff(defNwbuff); setDemandBuffers(defDemandNbytes); allowNewColumns(); } // HepHBookNtuple::HepHBookNtuple() // clone an existing Tuple HepHBookNtuple::HepHBookNtuple( HepNtuple * original , const string& title , const int idReq ) : HepNtuple( original->manager(), title, idReq ), _nColumnCreated(0), _lastRwnArray(0), _lastArrayRead(0), _lastRowRead(-1), _addrSetUp(false) { HEP_DEBUG( "HepHBookNtuple::constructor( \"" << original->title() << "\", " << title << "\", " << idReq << " )" ); // make the Fortran object int oldID = original->id(); int newId = idReq; HCOPY( oldID, newId, const_cast(title.c_str()) ); } // HepHBookNtuple::HepHBookNtuple() // Used for dummy construction ... // the object is then not valid ... HepHBookNtuple::HepHBookNtuple() : HepNtuple() { HEP_DEBUG( "HepHBookNtuple::constructor( )" ); } // HepHBookNtuple::HepHBookNtuple() void HepHBookNtuple::silenceCompiler() { pretendToUse(&(__cf__HEXIST)); pretendToUse(&(__cf__HSUM)); pretendToUse(&(__cf__HI)); pretendToUse(&(__cf__HIE)); pretendToUse(&(__cf__HIF)); pretendToUse(&(__cf__HIJ)); pretendToUse(&(__cf__HIJE)); pretendToUse(&(__cf__HMIN)); pretendToUse(&(__cf__HMAX)); pretendToUse(&(__cf__HRNDM1)); pretendToUse(&(__cf__HSPFUN)); pretendToUse(&(__cf__HLNXTF)); pretendToUse(&(__cf__HSTATI)); pretendToUse(&(__cf__HX)); pretendToUse(&(__cf__HXE)); pretendToUse(&(__cf__HXY)); pretendToUse(&(__cf__ISCWN)); pretendToUse(&c2fstrv); pretendToUse(&f2cstrv); pretendToUse(&vkill_trailing); pretendToUse(&num_elem); } HepHBookNtuple::~HepHBookNtuple() { HEP_DEBUG( "HepHBookNtuple::destructor( ) on ntuple #" << *id_ ); delete [] _lastRwnArray; } // HepHBookNtuple::~HepHBookNtuple() //////////////////////////////////// // isXxxxxEnabled() family // // // // virtual function indicating // // which part of the interface // // is supported // //////////////////////////////////// bool HepHBookNtuple::isRowWiseEnabled() const { return true; } bool HepHBookNtuple::isColumnWiseEnabled() const { return true; } bool HepHBookNtuple::isBlockWiseEnabled() const { return true; } bool HepHBookNtuple::isDiskResidentEnabled() const { return true; } bool HepHBookNtuple::isMemResidentEnabled() const { return true; } bool HepHBookNtuple::isSharedMemoryEnabled() const { return true; } bool HepHBookNtuple::isNwbuffEnabled(int nwbuff) const { return true; } bool HepHBookNtuple::isBuffLimitEnabled(int limit) const { return true; } bool HepHBookNtuple::isDemandBuffersEnabled() const { return true; } bool HepHBookNtuple::isCircularBufferEnabled() const { return true; } bool HepHBookNtuple::isCaseSensitive() const { return false; } ////////////////////////////////////////////////////// // 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 HepHBookNtuple::isTypeEnabled(ColumnData_t type,Block *bk) { int need_char = false; if ( type > Bool4_ct ) { need_char = true; } Column * col; for ( Block::columnsVec::const_iterator iterateCol(bk->columns().begin()); iterateCol != bk->columns().end(); iterateCol++ ) { col = (*iterateCol); ColumnAttribs CA = col->attributes(); ColumnData_t colType = CA.type; if ( ( (colType <= Bool4_ct) && need_char ) ||( (colType > Bool4_ct) && !need_char ) ) { return false; } } return isTypeEnabled(type); } // HepHBookNtuple::isTypeEnabled bool HepHBookNtuple::isTypeEnabled(ColumnData_t type) { switch(type) { case Int1_ct: case Int2_ct: return false; 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 false; case Ptr_ct: return false; default: return true; } } // HepHBookNtuple::isTypeEnabled ////////////////////////////////////////////////////// // setStorageGeometry // ////////////////////////////////////////////////////// bool HepHBookNtuple::setStorageGeometry(StorageGeometryName newStrategy) { if ( (newStrategy != storageGeometry()) && isCreated() ) { ZMthrow(ZMxHepLockedItem("Unable to change storage geometry after first booking")); return false; } return HepNtuple::setStorageGeometry(newStrategy); } // HepHBookNtuple::setStorageGeometry ////////////////////////////////////////////////////// // setStorageLocation // ////////////////////////////////////////////////////// bool HepHBookNtuple::setStorageLocation(unsigned char newLocation) { if ( (newLocation != resident() ) && isCreated() ) { ZMthrow(ZMxHepLockedItem("Unable to change storage location after first booking")); return false; } return HepNtuple::setStorageLocation(newLocation); } // HepHBookNtuple::setStorageLocation ////////////////////////////////////////////////////// // setNwbuffValue // ////////////////////////////////////////////////////// bool HepHBookNtuple::setNwbuffValue(int nwbuff) { int ierror; int nw = nwbuff; char* chopt = "BSIZE"; HBSET( chopt, nw, ierror ); if ( ierror != 0 ) { ZMthrow(ZMxHepBadRequest("HBook hbset failed")); return false; } return HepNtuple::setNwbuffValue(nwbuff); } // HepHBookNtuple::setNwbuffValue ////////////////////////////////////////////////////// // setBuffLimitValue // ////////////////////////////////////////////////////// bool HepHBookNtuple::setBuffLimitValue(int limit) { // int lpaw = limit; // HLIMIT(&lpaw); return HepNtuple::setBuffLimitValue(limit); } // HepHBookNtuple::setBuffLimitValue /*******************/ /* */ /* isNameAvailable */ /* */ /*******************/ // // This version verifies that the column name in the nameTag AS // is unique in the heptuple. bool HepHBookNtuple::isNameAvailable ( const string& nameTag ) const { TupleNameTag tag; parseNameTag(tag, nameTag); if ( tag.isValid() ) { bool result = (findColumn(tag.column()) == NULL); return result; } else { return false; } } // HepHBookNtuple::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& HepHBookNtuple::parseNameTag (TupleNameTag& what, const string& nametag, bool withIndices) const { static HBookNameTag tag; tag.init(nametag, withIndices, what); return what; } /* parseNameTag */ /****************/ /* */ /* bookRowWise */ /* */ /****************/ // Boook a row wise N-Tuple in HBook. 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 HepHBookNtuple::bookRowWise() { HEP_DEBUG( "HepHBookNtuple::bookRowWise" ); int nrows=0, ncol=0; // in case of deleting and recreating float *dat = 0; int id = HepNtuple::id(); int nColumns = HepNtuple::nColumns(); // First go to the proper directory HBookPushd( dir() ); if ( isCreated() ) { // somebody added a column after the hbook ntuple was created // we must delete the old ntuple and create a new one. // since the user may have specified the id, keep the id constant ncol = _nColumnCreated; HNOENT ( id, nrows ); dat = new float[nrows*ncol]; int rc; char* parent = "HepHBookNtuple::book"; HGNPAR ( id, parent ); for (int r=1; r<=nrows; r++) HGNF ( id, r, dat[(r-1)*ncol], rc); HDELET ( id); } // if ( isCreated() ) isCreated(true); _nColumnCreated = nColumns; // hbookn wants an array of strings for the labels. The strings // have to be all the same length and contiguous in memory. // We do not have an ordered list of column at the HepTuple level // but each block has one ( Block::columns() ) thus we use the // extra precaution of going through blocks here to preserver the order. // It is expected (and for HBook it will be true when loading back from // file) that there is only on block per ROW WISE Ntuple. std::string::size_type llen = 0; int colNum = 0; Column* col; std::STL_VECTOR(Column*) colVec(10); for ( blocksMap::const_iterator iterateBlock (blocks.begin()); iterateBlock != blocks.end(); iterateBlock++ ) { Block *bk = (*iterateBlock).second; for ( Block::columnsVec::const_iterator iterateCol(bk->columns().begin()); iterateCol != bk->columns().end(); iterateCol++ ) { col = (*iterateCol); colVec[colNum] = col; if ( llen < col->name().length() ) { llen = col->name().length(); } ColumnAttribs CA = col->attributes(); // At the same time we verify that all column are floats if ( CA.type != Float4_ct ) { ZMthrow(ZMxHepUnsupported( "HBook Row Wise N-Tuple can only contain column of floats")); // Revert to the original directory HBookPopd(); return false; } if ( CA.ndim != 0 ) { ZMthrow(ZMxHepUnsupported( "HBook Row Wise N-Tuple can NOT contain array of column")); // Revert to the original directory HBookPopd(); return false; } colNum++; } // for each Columns } // for each Blocks // some compilers don't allow "char foo[x*y];", so use new/delete char* hblabels = new char[nColumns*llen]; char *c1 = hblabels; for ( int i = 0; i < nColumns; i++ ) { col = colVec[i]; string colName(col->name()); const char *c2 = colName.c_str(); const char *cend = c2 + colName.length(); for ( ; c2 < cend; c2++, c1++) { if (isalnum(*c2)) *c1 = *c2; else *c1 = '_'; } // pad with blanks cend = (const char *)&hblabels[(i+1)*llen]; for ( ; c1 < cend; c1++) *c1 = ' '; } int foo = nwbuff(); char* title_c = ((char*)title().c_str()); char* directory_c = ((char*)dir().c_str()); HBOOKN(id,title_c,nColumns, directory_c ,foo, hblabels, nColumns, llen ); delete hblabels; if (dat) { // need to put the data back in float *d = new float[nColumns]; // Initialize the data to the default values int i = 0; Column *col; for ( i = 0; i < nColumns; i++ ) { col = colVec[i]; ColumnAttribs CA = col->attributes(); if ( CA.defaultVal != 0 ) { memcpy(d+i,(CA.defaultVal),sizeof(float)); } } // for each columns for (int r=1; r<=nrows; r++) { memcpy(d, &dat[(r-1)*ncol], ncol*sizeof(float) ); if ( isCircularBuffer() ) { HFNOV ( id, d); } else { HFN ( id, d); } } // for each row delete [] dat; delete [] d; } // if (dat) // Revert to the original directory HBookPopd(); return true; } // HepHBookNtuple::bookRowWise /******************/ /* */ /* bookColumnWise */ /* */ /******************/ // Do booking for column wise N-Tuple in HBook. // If a block happen to have been changed since booked, we // simply IGNORE it (actually we do not know about it ...) bool HepHBookNtuple::bookColumnWise() { HEP_DEBUG( "bookColumnWise" ); int id = HepNtuple::id(); // First go to the proper directory HBookPushd( dir() ); if ( ! isCreated() ) { char res[2]; res[0] = resident(); res[1]='\0'; HBNT ( id, ((char*)title().c_str()), res ); isCreated( true); } // 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 ) { Column * ci = 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; } } // First we sort the column so that we have: // indexes first then all other columns sorted in decreasing size // order. This allow use to make sure that the data is properly // aligned. // NOTE: we assume that alignment is 8 bytes. HBookColumnLess compare; bk->sortColumn( &compare ) ; // Count the indexes because we may need to pre-pad the array of // data bytes. Also check if the we have characters arrays. bool hasCharacters = false; int indexesSize = 0; for (std::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(); } if ( CA.type >= Char_ct ) { hasCharacters = true; } } // capturedData will add bytes to align the data // if indexesSizes is not a multiple of 8 int neededPadding = ((indexesSize+7)/8)*8 - indexesSize; void *addr = bk->capturedData(neededPadding); if ( ! hasCharacters ) { // if block do not contain char string variables HBNAME ( id,((char*)bk->name().c_str()), addr, ((char*)bk->format().c_str()) ); } else { // We need to create an array of: // (addr,format) for each portion (all numerical) or (all characters). HBNAMC ( id,((char*)bk->name().c_str()),((char*)addr), ((char*)bk->format().c_str())); } bk->book(); // If this block is added to an ntuple with existing rows, we // force the value of its columns to be the default value for all // this existing rows. int nrows; HNOENT ( id, nrows); 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 _addrSetUp = true; // Revert to the original directory HBookPopd(); return true; } // end of HepHBookNtuple::bookColumnWise /**********/ /* */ /* book */ /* */ /**********/ bool HepHBookNtuple::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(); } // HepHBookNtuple::book() /*******************/ /* */ /* storeWholeRow */ /* */ /*******************/ bool HepHBookNtuple::storeWholeRow() { HEP_DEBUG ( "HepHBookNtuple::storeWholeRow" ); int id = HepNtuple::id(); if ( isRowWise() ) { // First get the data in a single block float * d = NULL; bool needToDelete_d = false; if (nBlocks() == 1) { Block *bk = findBlock(blockName(0)); d = (float*)bk->capturedData(); } else { // Humm somehow more than one block made it into this // row-wise ntuple. We have to gather the information // in a chunk of memory. (row wise ntuple in hbook have // only one "block" of columns) Block* bk; int ncol = 0; // Count the number of columns // NOTE: isn't it the values of this->nColumns() ? blocksMap::iterator iterateBlock; for ( iterateBlock = blocks.begin(); iterateBlock != blocks.end(); iterateBlock++ ) { bk = (*iterateBlock).second; ncol += bk->nColumns(); } // Copy the columns data in one memory chunk d = new float[ncol]; needToDelete_d = true; ncol = 0; for ( iterateBlock = blocks.begin(); iterateBlock != blocks.end(); iterateBlock++ ) { bk = (*iterateBlock).second; for ( int i = 0; i < bk->nColumns() ; i++ ) { // the array return by capturedData is linear collation of // all the elements of the column in the block with no // insurance that it is aligned (thus the memcpy instead // of d[ncol+i] = (bk->capturedData())[i] memcpy(&(d[ncol+i]), (char*)bk->capturedData()+(i*sizeof(float)),sizeof(float)); } ncol += bk->nColumns(); } } // Now change to the proper directory HBookPushd( dir() ); // Next fill the HBook ntuple if ( isCircularBuffer() ) { HFNOV ( id, d); } else { HFN ( id, d); } // And revert to the orginal directory HBookPopd(); if ( needToDelete_d ) delete [] d; /* in case of more than one block */ } // end of if ( isRowWise() ) else { // Now change to the proper directory HBookPushd( dir() ); if ( setCwnAddresses() ) { // isColumnWise() HFNT ( id); } // And revert to the orginal directory HBookPopd(); } // end of if ( ! isRoWise() ) columnsMap::iterator iterateCol = columns.begin(); while ( ! (iterateCol == columns.end()) ) { ((*iterateCol).second)->setHasBeenStored(); iterateCol++; } return true; } // HepHBookNtuple::storeWholeRow /*********************/ /* */ /* storeSingleBlock */ /* */ /*********************/ bool HepHBookNtuple::storeSingleBlock(Block* bk) { HEP_DEBUG( " HepHBookNtuple::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 { // First go to the proper directory HBookPushd( dir() ); // isColumnWise() if ( setCwnAddresses() ) { HFNTB ( id, ((char*)bk->name().c_str()) ); } // Revert to the original directory HBookPopd(); } return true; } // HepHBookNtuple::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 HBook routine */ /* */ /*****************************/ // read a Row Wise Ntuple row // return the HBook error code. // array must point to a array of float of size NVAR Float4* HepHBookNtuple::readRWNrow ( int row ) { HEP_DEBUG( "HepHBookNtuple::readRWNrow" ); string routineName ( "readRWNrow" ); int id = HepNtuple::id(); // First go to the proper directory HBookPushd( dir() ); // verify if we already read this row if ( row == _lastRowRead ) { return _lastRwnArray; } // One time set-up if ( ! _addrSetUp ) { HGNPAR ( id, ((char*)routineName.c_str()) ); _addrSetUp = true; } // get array for data Float4* array = _lastRwnArray; if ( array == NULL ) { _lastRwnArray = new Float4[nColumns()]; array = _lastRwnArray; } // read the row int ierror = 0; HGNF ( id, row, *array, ierror); if ( ierror != 0 ) { ZMthrow(ZMxHepCantReadFile("Unable to read RWN")); return NULL; } _lastRowRead = row; // Revert to the original directory HBookPopd(); return array; } // HepHBookNtuple::readRWNrow bool HepHBookNtuple::restoreNtuple() { // Fill in a lot of details about the internal structure of an ntuple object bool isCWN; bool result = true; char tmpName[BLOCKNAMELENGTH+1]; char tmpForm[BLOCKFORMLENGTH+1]; // Prefill tmpName to keep Purify happy for(int i=0; irestoreBlock( blockName, blockForm ); } } } else { // Tell the HepNtuple object that it is a row wise ntuple. setRowWise(); // The thing on the file is Row Wise. Again, reconstruct the chForm string FORMATRWN ( *id_, tmpForm ); string blockForm(tmpForm); result &= this->restoreBlock( "", blockForm ); } // If all is well so far, fill in the number of rows and set the addresses if( result ) { int nrows; HNOENT ( *id_, nrows); result &= setNrowsValue( nrows ); _nColumnCreated = nColumns(); if ( isCWN ) result &= setCwnAddresses(); } if( result ) isCreated( true); return result; } // HepHBookNtuple::restoreNtuple() // This function makes the needed set-up to read the Column Wise Ntuple bool HepHBookNtuple::setCwnAddresses() { // One time set-up if ( ! _addrSetUp ) { _addrSetUp = true; string space(" "); string clear("$CLEAR"); string set("$SET"); char *dummy = NULL; HBNAME ( *id_, ((char*)space.c_str()), dummy, ((char*)clear.c_str()) ); for ( blocksMap::const_iterator iterateBlock (blocks.begin()); iterateBlock != blocks.end(); iterateBlock++ ) { Block *bk = (*iterateBlock).second; // Count the indexes because we may need to pre-padded the array of // data bytes. Also check if the we have characters arrays. bool hasCharacters = false; int indexesSize = 0; for (std::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(); } if ( CA.type >= Char_ct ) { hasCharacters = true; } } int neededPadding = indexesSize - (indexesSize/8); // add bytes if indexesSizes is not a multiple of 8 void *addr = bk->dataArray(neededPadding); // NOTE: I was wondering if a clear statement per block would be better // I did not look into it that much. PGC. // HBNAME(*id_,((char*)bk->name().c_str()),dummy,((char*)clear.c_str())); if ( ! hasCharacters ) { // if block do not contain char string variables HBNAME ( *id_,((char*)bk->name().c_str()),addr, ((char*)set.c_str() )); } else { // We need to create an array of: // (addr,format) for each portion (all numerical) or (all characters). HBNAMC ( *id_,((char*)bk->name().c_str()),((char*)addr), ((char*)set.c_str() )); } } // block loop } // if (_addrSetup) return true; } // HepHBookNtuple::setCwnAddresses // This function makes the needed set-up to read // a single column from a Column Wise Ntuple void HepHBookNtuple::setCwnColumnRead(Column* col, void* addr) { // we are going to wipe out any setup already done // and the one we are putting in place is not generic enough // to be cached // NOTE: we may want to add a way to avoid redoing this // setup if we are reading twice the same column!! _addrSetUp = false; int id = HepNtuple::id(); string space(" "); string clear("$CLEAR"); string setVar( string("$SET:") + col->name() ); void *dummy = NULL; HBNAME ( id,((char*)space.c_str()),dummy,((char*)clear.c_str()) ); // NOTE: I was wondering if a clear statement per block would be better // I did not look into it that much. PGC. // HBNAME(id,((char*)col->block()->name().c_str()), // dummy,((char*)clear.c_str()) ); bool isCharacters = false; ColumnAttribs CA = col->attributes(); if ( CA.type >= Char_ct ) { isCharacters = true; } if ( addr == NULL ) { addr = col->getValueAddr(); } if ( ! isCharacters ) { // if block do not contain char string variables // Check if this column is indexed. If so, make sure the index variable is // read too. JMM string indexColName = columnIndex( col->name() ); if( indexColName.length() != 0 ) { Column *icol = findColumn( indexColName ); void *iaddr = icol->getValueAddr(); string setIndex( string("$SET:") + icol->name() ); HBNAME ( id, ((char*)col->block()->name().c_str()), iaddr, ((char*)setIndex.c_str())); } // Then go deal with the original column HBNAME ( id, ((char*)col->block()->name().c_str()), addr, ((char*)setVar.c_str())); } else { // We need to create an array of: // (addr,format) for each portion (all numerical) or (all characters). // Check if this column is indexed. If so, make sure the index variable is // read too. JMM string indexColName = columnIndex( col->name() ); if( indexColName.length() != 0 ) { Column *icol = findColumn( indexColName ); void *iaddr = icol->getValueAddr(); string setIndex( string("$SET:") + icol->name() ); HBNAME ( id, ((char*)col->block()->name().c_str()), iaddr, ((char*)setIndex.c_str())); } // Then go deal with the original column HBNAMC ( id, ((char*)col->block()->name().c_str()),((char*)addr), ((char*)setVar.c_str() )); } } // HepHBookNtuple::setCwnColumnRead int HepHBookNtuple::readWholeRow(int irow) { HEP_DEBUG( "HepHBookNtuple::readWholeRow(int)" ); // First go to the proper directory HBookPushd( dir() ); int id = HepNtuple::id(); // read the data in if ( isRowWise() ) { Float4* array = readRWNrow(irow); if ( array != NULL ) { // loop through all columns in order and set the values int i = 0; for ( blocksMap::const_iterator iterateBlock (blocks.begin()); iterateBlock != blocks.end(); iterateBlock++ ) { Block *bk = (*iterateBlock).second; for ( Block::columnsVec::const_iterator iterateCol(bk->columns().begin()); iterateCol != bk->columns().end(); iterateCol++ ) { Column* col = (*iterateCol); col->read(array+i); i++; } // Block::columnsVec loop } // blocksMap loop } // if ( array != NULL ) } // if ( isRowWise() ) else { // isColumnWise if ( setCwnAddresses() ) { int ierror = 0; // read whole row HGNT ( id, irow, ierror); 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; current->read(); } // blocksMap loop } } // isColumnWise() // Revert to the original directory HBookPopd(); return nBlocks(); } // HepHBookNtuple::readWholeRow int HepHBookNtuple::readWholeBlock(Block* bk, int irow) { HEP_DEBUG( "HepHBookNtuple::readWholeBlock" ); // Check if column has been stored // NOTE: the above is not done !? int id = HepNtuple::id(); // First go to the proper directory HBookPushd( dir() ); // read the data in if ( isRowWise() ) { Float4* array = readRWNrow(irow); if ( array != NULL ) { // loop through all columns of the Block in order and set the values int i = 0; for ( blocksMap::const_iterator iterateBlock (blocks.begin()); iterateBlock != blocks.end(); iterateBlock++ ) { Block *current = (*iterateBlock).second; if ( bk == current ) { for ( Block::columnsVec::const_iterator iterateCol(bk->columns().begin()); iterateCol != bk->columns().end(); iterateCol++ ) { Column * col = (*iterateCol); col->read(array+i); i++; } // Block::columnsVec loop } // if ( bk == current ) i += current->nColumns(); } // blocksMap loop } // if ( array != NULL ) } // if ( isRowWise() ) else { // isColumnWise if ( setCwnAddresses() ) { int ierror = 0; // read whole block HGNTB ( id, ((char*)bk->name().c_str()), irow, ierror ); if ( ierror != 0 ) { ZMthrow(ZMxHepCantReadFile("Unable to read CWN")); return 0; } // set column values. bk->read(); } } // isColumnWise() // Revert to the original directory HBookPopd(); return bk->nColumns(); } // HepHBookNtuple::readWholeBlock( int HepHBookNtuple::readSingleColumn(Column* col, int irow) { HEP_DEBUG( "HepHBookNtuple::readSingleColumn" ); // Check if column has been stored // NOTE: the above is not done !? int id = HepNtuple::id(); // First go to the proper directory HBookPushd( dir() ); // read the data in if ( isRowWise() ) { Float4* array = readRWNrow(irow); if ( array != NULL ) { // find the column number int i = 0; int colNumber = 0; for ( blocksMap::const_iterator iterateBlock (blocks.begin()); iterateBlock != blocks.end(); iterateBlock++ ) { Block *current = (*iterateBlock).second; for ( Block::columnsVec::const_iterator iterateCol(current->columns().begin()); iterateCol != current->columns().end(); iterateCol++ ) { Column * current = (*iterateCol); if ( current == col ) { colNumber = i; } i++; } // Block::columnsVec loop } // blocksMap loop // set the values col->read(&(array[colNumber])); } } else { // isColumnWise setCwnColumnRead(col); int ierror = 0; int one = 1; // read single column HGNTV_NOARRAY ( id, ((char*)col->name().c_str()), one, irow, ierror ); if ( ierror != 0 ) { ZMthrow(ZMxHepCantReadFile("Unable to read CWN")); return 0; } // set column values. col->read(); } // if isColumnWise() // Revert to the original directory HBookPopd(); return true; } // readSingleColumn int HepHBookNtuple::readSingleColumn(Column* col, int irow, void * val) { HEP_DEBUG( "HepHBookNtuple::readSingleColumn" ); int id = HepNtuple::id(); // First go to the proper directory HBookPushd( dir() ); // Check if column has been stored // read the data in if ( isRowWise() ) { Float4* array = readRWNrow(irow); if ( array != NULL ) { // find the column number int i = 0; int colNumber = 0; for ( blocksMap::const_iterator iterateBlock (blocks.begin()); iterateBlock != blocks.end(); iterateBlock++ ) { Block *bk = (*iterateBlock).second; for ( Block::columnsVec::const_iterator iterateCol(bk->columns().begin()); iterateCol != bk->columns().end(); iterateCol++ ) { Column * current = (*iterateCol); if ( current == col ) { colNumber = i; } i++; } // Block::columnsVec loop } // blocksMap loop // set the values *((Float4*)val) = array[colNumber]; } } else { // isColumnWise setCwnColumnRead(col,val); int ierror = 0; int one = 1; // read single column HGNTV_NOARRAY ( id, ((char*)col->name().c_str()), one, irow, ierror ); if ( ierror != 0 ) { ZMthrow(ZMxHepCantReadFile("Unable to read CWN")); return 0; } // read from the column values. // since we set the hbook address to be val, we do not need this // its already done ! // col->copyToMem(val); } // isColumnWise() // Revert to the original directory HBookPopd(); return 1; } // readSingleColumn with value int HepHBookNtuple::readSingleColumn(Column* col, const string& indices, int irow, void * val) { HEP_DEBUG( "HepHBookNtuple::readSingleColumn" ); if ( isRowWise() ) { ZMthrow(ZMxHepUnsupported( "HBook Row Wise Ntuple do not handle array of Columns")); return 0; } else { // First go to the proper directory HBookPushd( dir() ); setCwnColumnRead(col); int ierror = 0; int one = 1; // read complete single column HGNTV_NOARRAY ( *id_, ((char*)col->name().c_str()), one, irow, ierror); if ( ierror != 0 ) { ZMthrow(ZMxHepCantReadFile("Unable to read CWN")); return 0; } // Now transfer the value to val // Revert to the original directory HBookPopd(); return col->copyToMem(val,indices); } } // readSingleColumn with indices // ************************************************************************* // // int readWholeColumn(Column* col, const string& indices, // int start_row, int nrows, char * dest, std::string::size_type size); // ************************************************************************* // // Instruct the manager to read a whole column and store it into val // which is assumed to be array of the same type as the column and of size // nrows. This function are called from bulkReadColumn // The manager independent implementation loop over the equivalent // readSingleColumn function int HepHBookNtuple::readWholeColumn(Column* col, const string& indices, int start_row, int n_rows, char * dest, std::string::size_type size) { int i; int end = start_row + n_rows; int status = true; int ierror = 0; int one = 1; int id = HepNtuple::id(); char colname[256]; strcpy(colname,((char*)col->name().c_str())); for ( char * p = colname+254; (p > colname) && (*p == '\0'); --p ) *p = ' '; HBookPushd(dir()); if ( isRowWise() ) { ZMthrow(ZMxHepUnsupported( "HBook Row Wise Ntuple do not handle array of Columns")); return 0; } else { // isColumnWise setCwnColumnRead(col); for (i=start_row; i < end && (i <= nrows()) ; i++ , dest += size ) { HGNTV_NOARRAY ( id, colname , one, i, ierror ); status &= (ierror == 0); // grab the values from the colum. col->copyToMem(dest,indices); } HBookPopd(); } return i-start_row; } // ************************************************************************* // // int readWholeColumn(Column* col, // int start_row, int nrows, char * val, std::string::size_type size); // ************************************************************************* // // Instruct the manager to read a whole column and store it into val // which is assume to be array of the same type as the column and of size // nrows. This function are called from bulkReadColumn // The manager independent implementation loop over the equivalent // readSingleColumn function int HepHBookNtuple::readWholeColumn(Column* col, int start_row, int n_rows, char * dest, std::string::size_type size) { int i=0; int end = start_row + n_rows; int status = true; int ierror = 0; int one = 1; int id = HepNtuple::id(); char colname[256]; strcpy(colname,((char*)col->name().c_str())); for ( char * p = colname+254; (p > colname) && (*p == '\0'); --p ) *p = ' '; HBookPushd(dir()); // read the data in if ( isRowWise() ) { // this will do the set up and read the start_row Float4* array = readRWNrow(start_row); if ( array != NULL ) { int ierror = 0; // find the column number i = 0; int colNumber = 0; for ( blocksMap::const_iterator iterateBlock (blocks.begin()); iterateBlock != blocks.end(); iterateBlock++ ) { Block *bk = (*iterateBlock).second; for ( Block::columnsVec::const_iterator iterateCol(bk->columns().begin()); iterateCol != bk->columns().end(); iterateCol++ ) { Column * current = (*iterateCol); if ( current == col ) { colNumber = i; } i++; } // Block::columnsVec loop } // blocksMap loop for (i=start_row; i < end && (i <= nrows()) ; i++ , dest += size ) { // Read the current row (for simplicity for read // the first one again) HGNF ( id, i, *array, ierror); if ( ierror != 0 ) { ZMthrow(ZMxHepCantReadFile("Unable to read RWN")); return 0; } // set the values *((Float4*)dest) = array[colNumber]; } // for each row } // if array != NULL } else { // isColumnWise setCwnColumnRead(col); for (i=start_row; i < end && (i <= nrows()) ; i++ , dest += size ) { HGNTV_NOARRAY ( id, colname , one, i, ierror ); status &= (ierror == 0); // grab column values. col->copyToMem(dest); } } HBookPopd(); return i-start_row; } ZM_END_NAMESPACE( zmht ) /* } // namespace zmht */