#ifndef HEPNTUPLE_H #define HEPNTUPLE_H // ---------------------------------------------------------------------- // // HepNtuple.h - class declaration for NTuple, // To use: // create a HepTuple manager* M // create the HepNtuple by M->newHepNtuple(title, id=0) // Attach to an existing one by M->oldHepNtuple(title) or // M->oldHepNtuple(id) // Open Issues: // In the HepNtuple Manager should we call the HepNtuple ''constructor'' // newHepNtuple or newNtuple or ntuple. // We must comment oldHepNtuple (and oldHist1D etc) as follows: // Make a new pointer to an **existing HepNtuple (or Hist1D...) in // the manager that has this supplied title. The user will be // responsible for deleting this HepNtuple* when through with it, // or the memory assignment will persist till the end of the job. // There are ways of finding out which Ntuples the manager has in this // directory. So it is right to make a clash (new with same name or id, old // based on one we can't find) either an error or return null pointer. We // have no way to prevent constructs like // HepNtuple* h1 = M->newHepNtuple(title, id=0). // HepNtuple* h2 = h1 // but we don't encourage that. We DON'T allow attaching to an Ntuple where // you already have attached to it. Our manager WILL track pointers it knows // about and, if the user deletes the manager, they will be marked as // Unmanaged so that attempts to use them will fail in a predictable way. // Copying pointers defeats this safety feature. // // To get around this difficulties we will actually return a reference to the // current HepNtuple. In addition the function isValid() will return false // as soon as an exception arise during an heptuple operation. When the // HepNtuple is invalid, no actual usefull operation will be done (like capture // and booking or adding new column.) #ifdef COMMENT Mods in development: 7/11/97 mf Codeguard name is HEPTUPLE_H: Rule is if a file name starts with the package''s name-guard because the class it represents does, we don''t repeat that name-guard twice: not HEPHEPTUPLE_H. Added clearDataColumn(), and changed name for clearDataBlock(). Changed name of capture for a block to captureBlock(). Added lockOutNewColumns() and allowNewColumns(). Added private variables and methods area. Added to private area: unspecifiedBlock unspecifiedBlockNumber formUnspecifiedBlock() lockNoNewColumns 7/14/97 mf Added declarations of ZMx classes. These are temporary, and will need to be fleshed out even before full ZM exception mechanism is done. 7/22/97 pc added isLockedNewColumns() returns whether the addition of new columns is blocked. 7/28/97 web Granted friendship to HepFileManager 7/30/97 web Made use of new base class HepObj for consistency in naming 1/20/98 pc Change all pertinent char* and char[] to std::string 2/21/00 web Improved C++ standard compliance #endif // COMMENT #ifdef COMMENT In this preliminary version of the header for HepNtuple we don''t know yet how we will want to handle colums of characters (in HBOOK they have 8 types, CHAR4 thru CHAR32). This decision won''t seriously affect the rest of the interface. #endif /* COMMENT */ #ifndef ZMENVIRONMENT_H #include "ZMutility/ZMenvironment.h" #endif #include // Work around a bug in Gnu map. #ifndef ISOCXX__ISOCXX #include #include #endif #include "ZMutility/map" #include #ifndef HEPOBJ_H #include "HepTuple/HepObj.h" #endif #ifndef FIXEDTYPES_H #include "ZMutility/FixedTypes.h" #endif ZM_USING_NAMESPACE( zmfxt ) #include "HepTuple/ColumnAttribs.h" #include ZM_BEGIN_NAMESPACE( zmht ) /* namespace zmht { */ class HepFileManager; class Block; class Column; template class ColumnT; class TupleNameTag; class HepNtuple : public HepObj { friend class HepFileManager; // --- Original HepNtuple form of column definition/filling // --- Other ways of defining columns // --- Refining column properties // --- Defining blocks // --- Storage Strategy // --- How to fill the histogram // --- Clearing captured data // --- Retrieving Ntuple data // --- Establishing destination variables // --- Accessing information about the HepNtuple structure // --- Data types other than float #ifdef COMMENT Methods summary (Only the float forms of Tuple data are shown in this summary) bool column (const std::string& nametag, float value, float defval=0); /*H*/ bool newColumn (const std::string& nametag, float val, float defval=0); /*H*/ HepNtuple& columnAt (const std::string& nametag, float* address, float defval=0); HepNtuple& columnVia (const std::string& nametag, ZMuseMethod* method, float defval=0); HepNtuple& columnVia (const std::string& nametag, float(*function)(), float defval=0); HepNtuple& columnArray (const std::string& nametag, int ncolumns, float defval=0); HepNtuple& columnDirect (const std::string& nametag, float defval=0); HepNtuple& pack ( float min, float max, int nbits); HepNtuple& pack (const std::string& nametag,float min, float max, int nbits); HepNtuple& span ( int min, int max); HepNtuple& span (const std::string& nametag,int min, int max); HepNtuple& dimension (const std::string& nametag, int dim); HepNtuple& dimension ( int dim); HepNtuple& dimension (const std::string& nametag, int dim1, int dim2, int dim3=0, int dim4=0, int dim5=0, int dim6=0, int dim7=0, int dim8=0, int dim9=0, int dim10=0); HepNtuple& dimension ( int dim1, int dim2, int dim3=0, int dim4=0, int dim5=0, int dim6=0, int dim7=0, int dim8=0, int dim9=0, int dim10=0); HepNtuple& index (const std::string& nametag, const std::string& indextag); HepNtuple& index ( const std::string& indextag); HepNtuple& characters (const std::string& nametag, int length); HepNtuple& characters ( int length); bool block (const std::string& blockName, const std::string& format, std::STL_VECTOR(void*) addresses); bool lockOutNewColumns (); bool allowNewColumns (); bool isLockNewColumns(); bool setRowWise (); bool setColumnWise (); bool setBlockWise (); bool setDiskResident (); bool setMemResident (); bool setSharedMemory (char sharedMemoryArea[]); bool setNwbuff (int nwbuff); bool setBuffLimit (int nbytes); bool setCircularBuffer (int nwbuff); bool setDemandBuffers (int nbytes); bool captureThenStore ( ); bool capture (const std::string& nametag, float value); int setExistingColumn (const std::string& lbl, float val); /*H*/ bool capture (const std::string& nametag, float value[]); bool capture (const std::string& nametag, float value[], int indexval); bool captureColumn (const std::string& nametag); bool captureBlock (const std::string& blockName); bool capture ( ); bool storeCapturedData ( ); bool clearData ( ); \*H*\ bool clearDataBlock (const std::string& blockName); bool clearDataColumn(const std::string& nametag); bool readColumn (int irow, const std::string& nametag, float* value); int readColumnArray (int irow, const std::string& nametag, float values[]); int readBlock (int irow, const std::string& blockName); int readRow (int irow); int bulkReadColumn (const int irow, const int nrows, const std::string& nametag, float destination[]); HepNtuple destinationAt (const std::string& nametag, float* address); HepNtuple destinationVia (const std::string& nametag, void (* setMethod) (float)); HepNtuple destinationVia (const std::string& nametag, void (* setMethod) (float[])); bool blockDestinations (const std::string& blockName, const std::string& format, std::STL_VECTOR(void*) addresses); std::string title ( ); // provided by HepObj std::string dir ( ); // provided by HepObj HepFileManager* manager ( ); // provided by HepObj int id ( ); // provided by HepObj bool isRowWise ( ); bool isColumnWise ( ); bool isBlockWise ( ); char resident ( ); Std::String sharedAreaName ( ); int nwbuff ( ); int buffLimit ( ); bool isCircularBuffer ( ); bool isDemandBuffers ( ); int nBlocks ( ); std::string blockName (int blockNumber); std::string blockFormat (int blockNumber); std::string blockFormat (const std::string& blockName); int nColumns ( ); int nColumns (const std::string& blockName); std::string nametag (int columnNumber); std::string nametag (int columnNumber, const std::string& blockName); std::string tag (int columnNumber); std::string tag (int columnNumber, const std::string& blockName); std::string columnBlock (const std::string& tag); std::string columnNametag (const std::string& tag); type_info columnType_info (const std::string& nametag); ColumnData_t columnDataType (const std::string& nametag); int columnDimensions (const std::string& nametag, int dims[] ); std::string columnIndex (const std::string& nametag); bool columnDefault (const std::string& nametag, float* default); bool setColumnDefault (const std::string& nametag, float default); bool columnSpan (const std::string& nametag, int* min, int* max); void* columnDesignatedVariable (const std::string& nametag); void* columnDestinationVariable (const std::string& nametag); bool columnPacking (const std::string& nametag, float* low, float* high, int* inbits); #endif /* COMMENT */ public: // type identifier ( is equal to type() for this object ) static const char typeId; // For routines which take a float or float* refering to a datum, // there are analogous routines for int, short, long, and double. // These require no separate explanation, and are grouped together // later in the class definition. // - - - - - // --- Constructor, destructor and copy functions HepNtuple (HepFileManager* manager, const std::string& title, int id = 0); // HepNtuple (const HepNtuple& from); // HepNtuple& operator=(const HepNtuple& from); // These are not enabled yet ... we think that byte-wise copy // is what we want in this case. Otherwise use duplicate. virtual ~HepNtuple (); // makeClone copy the structure and the content of the HepTuple to // a new HepTuple with the new title and the new id. // When the manager is not precised, the new HepTuple is created in // the same manager of the copied HepTuple __BUT__ in the current // directory (as opposed to the same directory as the copied HepTuple) // makeEmpty only copies the structure ! virtual ZM_COVARIANT_TYPE(HepObj, HepNtuple ) & makeClone(const std::string& new_title, int new_id = 0) const; virtual ZM_COVARIANT_TYPE(HepObj, HepNtuple ) & makeClone(HepFileManager* manager, const std::string& new_title, int new_id = 0) const; virtual ZM_COVARIANT_TYPE(HepObj, HepNtuple ) & makeEmpty(const std::string& new_title, int new_id = 0) const; virtual ZM_COVARIANT_TYPE(HepObj, HepNtuple ) & makeEmpty(HepFileManager* manager, const std::string& new_title, int new_id = 0) const; // Append an existing ntuple to the current one. Both nutple needs to // have the same columns in the same orders (column name excepted) virtual HepNtuple & append ( const HepNtuple& from ); // Return true if the argument HepTuple has a column layout compatible // with the current one. virtual bool isCompatible ( const HepNtuple& hep ); // --- Original HepNtuple form of column definition/filling --- // We indicate routines present in the original HepNtuple with /*H*/ // ************************************************************************* // bool column (const std::string& nametag, float value, float defval=0); /*H*/ bool newColumn (const std::string& nametag, float val, float defval=0); /*H*/ // ************************************************************************* // // This creates the column if it is not yet there and at the same time fills // it. (The newColumn form fails if the column already exists.) // Type checking at runtime happens, if you create via float and // later fill Via int or whatever. // We call this the Direct form; it is an amalgam of creation and filling. // You cannot mix the designated variable form with the column. // nametag is described in **[1]** // This form, which supplies a value, might routinely be used for filling // data. Therefore it ought not to return anything costly; it returns a // bool indicating sucess (for instance, new columns may have been locked // out, in which case it fails but we shouldn't destroy the job). // - - - - - // --- Other ways of defining columns: --- // All other column-definition methods return HepNtuple& this, // so that a convenient syntax can be used. See **[2]** // They will return null pointer if for some reason you cannot do the // requested action. // ************************************************************************* // HepNtuple& columnAt (const std::string& nametag, float* address , float defval=0); // ************************************************************************* // // Designated Variable form. See **[7]** // You cannot mix this with the definition of a whole block including // this tag or with the Direct form. // ************************************************************************* // HepNtuple& columnVia (const std::string& nametag, ZMuseMethod* method, float defval=0); HepNtuple& columnVia (const std::string& nametag, float(*function)(), float defval=0); // ************************************************************************* // // Designated Accessor form. For objects which avoid public data members. // An example is needed here: See **[3]** // ************************************************************************* // HepNtuple& columnArray (const std::string& nametag, int ncolumns , float defval=0); // ************************************************************************* // // No-Designated-Variable form. // Intended for a 1-D array which will be filled by Direct capture only. // To use this method to define column arrays of non-float data, see **[15]** // ************************************************************************* // HepNtuple& columnDirect (const std::string& nametag, float defval=0); // ************************************************************************* // // No-Designated-Variable form. // Intended for a single column which will be filled by Direct capture only. // To use this method to define a column of non-float data, see **[15]** // - - - - - // --- Refining column properties --- // The following methods allow the user to refine the column definition. // For syntatic brevity, they also support a signature omitting the nametag // (assuming the previous one). See **[2]** // ************************************************************************* // HepNtuple& pack ( float min, float max, int nbits); HepNtuple& pack (const std::string& nametag,float min, float max, int nbits); // ************************************************************************* // // Pack the floats in a lossy manner, dividing the range into 2**nbits // possible n-bit integers. Even if the column data type is not float, // the range is expressed as floats. // ************************************************************************* // HepNtuple& span ( int min, int max); HepNtuple& span (const std::string& nametag, int min, int max); // ************************************************************************* // // This column becomes eligible to use as an index (see **[4]**) for // other columns. The maximum supplied delimits how many columns are // defined based on the index. An index column is packed in a lossless // manner, assuming all values lie in the defined span. // ************************************************************************* // HepNtuple& dimension (const std::string& nametag, int dim); HepNtuple& dimension ( int dim); // ************************************************************************* // // A one-dimensional array of columns. These will end up with // tags derived from nametag. For example, if the tag is "XM" // and dim is 100, the tags made by HBook would be XM(0), XM(1), // ... XM(99). // ************************************************************************* // HepNtuple& dimension (const std::string& nametag, int dim1, int dim2, int dim3=0, int dim4=0, int dim5=0, int dim6=0, int dim7=0, int dim8=0, int dim9=0, int dim10=0); HepNtuple& dimension ( int dim1, int dim2, int dim3=0, int dim4=0, int dim5=0, int dim6=0, int dim7=0, int dim8=0, int dim9=0, int dim10=0); // ************************************************************************* // // An N-dimensional array of columns -- up to 10 dimensions is supported. // Indices in each dimension are 0-based. The data is of course supplied // in a C "array" which implies a "first-index-varies-slowest" storage. // The underlying manager may make column tags reflecting its own idea // of how an array is labeled. Our policy is to set up the dimensions // such that The C++ array ends up as an array of columns of that same // shape -- see **[5]** // ************************************************************************* // HepNtuple& index (const std::string& nametag, const std::string& indextag); HepNtuple& index ( const std::string& indextag); // ************************************************************************* // // Associates an index variable to an array of columns; this is how // "variable length arrays" are supported. Of course, depending on // what storage mode is chosen, the underlying manager may or may not // yield space savings when an index does not have its maximum value. // indextag must refer to a column which is or will be set up as an index -- // it has (or will have) a defined span. The column being refined must // have defined dimensions. The index variable applies to the first // slowest varying dimension and its span replaces the stated extent // of that dimension. // ************************************************************************* // HepNtuple& characters (const std::string& nametag, int length); HepNtuple& characters ( int length); // ************************************************************************* // // Define a fixed-length character std::string column. // When the type of column is char, a column holding single-byte integer // data is formed. An array of these may be formed in the usual way by // the dimensions() method. // However, sometimes you may want instead a character std::string in the // HepNtuple. This can be delared by the charcters() method, supplying // a fixed length for the std::string. The semantics for these are quite // different from the semantics for an array of floats or ints. A // particular restriction in the HBOOK implementtion is that it must be // 4*K where K is between 1 and 8. See **[13]**. // - - - - - // --- Defining blocks --- // Here is how to define a whole block at once. The HBOOK chform is used. // ************************************************************************* // bool block (const std::string& blockName, const std::string& format, std::STL_VECTOR(void*) addresses); // ************************************************************************* // // The designated variables for capturing data are specified by the // addresses. These need not be contiguous in memory, though typical // usage might have See **[7]** // If not all the columns are to be captured via memory access, it is // preferable to create each column separately using: // columnDirect, columnAt or columnVia. // An awkward point is that the addresses must match the variable // definitions in format. That is, if format starts with IMAX, XMAX // and the first two addresses supplied are those of a pair of floats, // there will be no notice taken of the fact that you are storing the // first float as an int. Better safety can be achieved by doing // columnAt() for each column. // There is, by the way, to be an extension to the format so that // if the column name is followed by empty parens, this specifies // the "address" supplied is that of an accessor function. Again // see **[3]**. // --- Preventing accidental creation of new columns --- // ************************************************************************* // bool lockOutNewColumns (); bool allowNewColumns (); bool isLockedNewColumns () const; // ************************************************************************* // // Prevents (or permits) new columns from being created after any data in // the HepNtuple has been stored. Returns the previous state of this: true // if new columns were already locked out. // HepFileManger::newNtuple() sets up a HepNtuple with new columns allowed; // HepFileManger::oldNtuple() sets up a HepNtuple with new columns // locked out. // Adding a new column to a row-wise Ntuple may be implemented in a manner // taking O(nrows) steps, so locking out new columns may be prudent. // isLockedNewColumns() returns the current state. // - - - - - // --- Storage Strategy // These calls must be made before one starts to fill the HepNtuple. // The default is a Column-wise Disk-resident Ntuple with 8K-entry buffers. // However, if the manager does not support Column-Wise (or for that matter // disk-resident) storage, other supported defaults will apply. // ************************************************************************* // bool setRowWise (); bool setColumnWise (); bool setBlockWise (); // ************************************************************************* // // Choose either row-wise (an entire row is contiguous) column-wise // (each column is buffered in memory such that a large chunk of data // for a single column is contiguous) or -- if the underlying manager // supports it (HBOOK does not) block-wise storage. // Returns false if the manager does not support this mode. // ************************************************************************* // bool setDiskResident (); bool setMemResident (); bool setSharedMemory (char sharedMemoryArea[]); // ************************************************************************* // // Return false if the manager does not support this mode. // ************************************************************************* // bool setNwbuff (int nwbuff); bool setBuffLimit (int nbytes); // ************************************************************************* // // Set the number of entries per column to be kept in the in-memory buffers. // set buffLimit() sets a limit on total buffer space used, which may cause // the buffer sizes to be LESS that those implied by nwbuff. Default is // 8K entries per column for column-wise Ntuples, or the greater of 128K // bytes and the size of a full row for row-wise. // ************************************************************************* // bool setCircularBuffer (int nwbuff); bool setDemandBuffers (int nbytes); // ************************************************************************* // // For in-memory or shared-memory HepNtuple, specifies whether to create a // circular buffer in memory, dropping the oldest rows to make room for the // newest, or to allocate another buffer of space any time you run out of // room. Default is demand buffers. // - - - - - // --- How to fill the histogram --- // Capture of data, and storing captured data for a row and moving to next // row, is handled by the following methods. Some semantics are explained // in note **[6]**, and are summarized here. // The act of supplying data for one or more columns is called // capturing that data. The act of adding the captured data for // a row to the Ntuple is called storing the data. // The row number semantics for storing data is that of automatic // append: Store increments the row, and the user does not explicitly // specify the row. // Capture of data can be done on a per-column basis. Another // option is to capture data for an entire block or row by supplying // designated variables. These are explained in note **[7]**. // The definition of the columns composing the HepNtuple may be extended // after some data has been captured, and even after rows of data have been // stored. In particular, the use of the column(name, val) method without // a specified block name can be done at any time. Rules for other cases // are described in **[6]**. // We do not permit data to be captured twice via multiple-column // methods or by single column. Capture methods that go over multiple // columns (block or row) fill only the ones that were not filled for // this row. Users can overwrite a filled column by clearing it first. // ************************************************************************* // bool captureThenStore ( ); // ************************************************************************* // // Capture data for all designated variables **[7]** in the entire row // THAT HAVE NOT ALREADY BEEN CAPTURED, // then store the data in the Ntuple, advancing to the next row. // This is equivalent to the sequence capture(); storeCapturedData(); // and is the convenient way of filling a row. // ************************************************************************* // bool capture (const std::string& nametag, float value); int setExistingColumn (const std::string& nametag, float val); /*H*/ // ************************************************************************* // // Capture data for the one column specified. The column must have // preveously been defined. Assuming it has been, this is equivalent // in effect to calling column() with the same arguments. We call this // "Direct" capture since the value is supplied rather than found in a // designated variable. // ************************************************************************* // bool capture (const std::string& nametag, const float value[]); bool capture (const std::string& nametag, const float value[], int indexval); // ************************************************************************* // // Capture data for an array of columns. The nametag must match that // of an array of columns which had been defined. This is a way to do // "Direct" capture, if you wish not to capture the entire block. // The value[] array should match in size the size defined for this array // of columns; if an indexval is supplied, only that number of values for // the slowest-varying dimension are captured. // See **[14]** // ************************************************************************* // bool captureColumn (const std::string& nametag); // ************************************************************************* // // Capture data for one column entire block, via its designated variable // (or access method). See **[7]** and **[3]**. // ************************************************************************* // bool captureBlock (const std::string& blockName); // ************************************************************************* // // Capture data for an entire block, via its designated variables **[7]**. // Not permitted if the block was already captured for this row; permitted if // some columns were already captured--these will be skipped now. // ************************************************************************* // bool capture ( ); // ************************************************************************* // // Capture data for all designated variables in the entire row. **[7]** // ************************************************************************* // bool storeCapturedData ( ); // ************************************************************************* // // Store the data previously captured for this row of the Ntuple, advancing // to the next row. Captured data may include data capture both by Direct // calls and by designated variables. This **replaces** the method in // HepNtuple named dumpData(). // - - - - - // --- Clearing captured data --- // These are analogous to the capture routines, but used when rejecting // data that had tentatively been captured. // ************************************************************************* // bool clearData ( ); /*H*/ // ************************************************************************* // // Clear previously captured data for this row: all columns of all blocks. // ************************************************************************* // bool clearDataBlock (const std::string& blockName); // ************************************************************************* // // Clear previously captured data for this row: columns in specified block. // ************************************************************************* // bool clearDataColumn (const std::string& nametag); // ************************************************************************* // // Clear previously captured data for this row: This specific column or // column array. // - - - - - // --- Retrieving Ntuple data --- // The Ntuple must have been attached to using the manager method // oldNtuple (or must be an active one created via newNtuple). // Direct-style access to individual columns requires no other // preparations; access to entire blocks or rows using designated // destinations, will require preparation described below. // Retrieval methods have explicit row specification semantics; the user // must provide the row number desired (zero-based) and increment it // explicitly if he wants to loop over all the rows. // Read methods return the number of columns, blocks, or rows read. Since // zero is a valid return value, negative ints will be returned to signify // erroneous operation (e.g. supplying an invalid nametag[].) **[8]** // ************************************************************************* // int nrows ( ) const; // ************************************************************************* // // Returns the number of rows of data stored for the Ntuple. // ************************************************************************* // bool readColumn (int irow, const std::string& nametag, float* value); // ************************************************************************* // // Direct read of the value of a column, into *value. In the case of an // array of columns the nametag[] should include the specification of which // element was wanted, e.g. "mycols(3,5)". // ************************************************************************* // int readColumnArray (int irow, const std::string& nametag, float values[]); // ************************************************************************* // // Direct read of the value of a column, into an array at values[]. // The nametag[] should be that of the array of columns. // The user must provide a large enough array at value[] to fit the array // of columns. // The method returns the number of data elements actually captured which, // in the case of indexed arrays, will be the value of its index variable // (and may be less than the maximum number of columns possible). // ************************************************************************* // int readBlock (int irow, const std::string& blockName); // ************************************************************************* // // Read contents of specified block for this row, into the destination // variables established. All destination variables pertaining to this block // will be filled; this need not be the whole block as written to the Ntuple // but must include at least one variable. // Will return the number of columns filled. // ************************************************************************* // int readRow (int irow); // ************************************************************************* // // Read contents of specified block for this row, into the destination // variables established. All destination variables established // will be filled; this need not be the whole row but must include at // least one variable. // Will return numbr of BLOCKS filled. // ************************************************************************* // int bulkReadColumn (int irow, int nrows, const std::string& nametag, float destination[]); // ************************************************************************* // // Retrieve data from one column (which may be one element of an array of // columns) for a whole range of rows. Data not captured for a row will // be reflected by the default value being placed in that slot of the // destination array. // Bulk reads of a column may be particularly efficient for column-wise // storage strategies, and gain no practical efficiency for row-wise. // The destination must be an array big enough to hold nrows floats. // The return value is the number of values placed; normally nrows, unless // the end of the Ntuple is reached before getting nrows rows. // - - - - - // --- Establishing destination variables --- // A destination variable is to reading in Ntuple rows what a designated // variable is to capturing rows: Except for Direct forms, data read in // is placed in the destination variables. Note that for an Ntuple which // is both being written and read back (not necessarily a recommended // practice but certainly permitted), the destination variables may be // the same or distinct from the designated variables for capture. // Destination definition methods return HepNtuple this, so that the // convenient syntax for refining column definitions can be used. // In general, the destination definition has to match the column // definition used when the column was stored, but the match is tolerant // of differences such as not specifying packing for read back. See **[9]**. // These methods will return null pointer if for some reason you cannot do // the requested action. // ************************************************************************* // HepNtuple& destinationAt (const std::string& nametag, float* address); // ************************************************************************* // // Destination for one column OR array of columns. // For an array of columns, you need not refine the column definition using // the method dimension(), since this information is available from the // existing HepNtuple. However, in this case address had better point to // an array of floats, big enough to hold the column array. Methods // are available to check the dimensions of a column array. // For a single column within an array, the nametag form of "nametag(3,4)" // is supported. // ************************************************************************* // HepNtuple& destinationVia (const std::string& nametag, void (* setMethod) (float)); HepNtuple& destinationVia (const std::string& nametag, ZMsetMethod* setMethod); HepNtuple& destinationVia (const std::string& nametag, void (* setMethod) (float[])); HepNtuple& destinationVia (const std::string& nametag, ZMsetMethod* setMethod); // ************************************************************************* // // Accessor form for destinations. For destination objects which avoid // public data members, requiring calling a method to set the desired data. // See **[10]** // ************************************************************************* // bool blockDestinations (const std::string& blockName, const std::string& format, std::STL_VECTOR(void*) addresses); // ************************************************************************* // // Set up destinations for a whole block at a time. See **[9]** for // information on which aspects of format must match the original definition. // - - - - - // --- Accessing information about the HepNtuple structure --- // These routines provide information about how the columns and blocks were // defined, and so forth, as well as general information about this instance // of HepNtuple. They do not provide information that would change when each // row of data is stored; the retrieval routines do that. // ************************************************************************* // bool isRowWise ( ) const; bool isColumnWise ( ) const; bool isBlockWise ( ) const; unsigned char resident ( ) const; // **[11]** std::string sharedAreaName ( ) const; // **[11]** int nwbuff ( ) const; int buffLimit ( ) const; bool isCircularBuffer ( ) const; // **[11]** bool isDemandBuffers ( ) const; // **[11]** // ************************************************************************* // // - - - // General information // ************************************************************************* // int nBlocks ( ) const; std::string blockName (int blockNumber) const; // ************************************************************************* // // Find the names of each of the blocks. The semantics is that the user // can learn how many blocks there are, and then find the name of each in // turn, forming whatever sort of list or array is prefered. // ************************************************************************* // std::string blockFormat (int blockNumber) const; std::string blockFormat (const std::string& blockName) const; // ************************************************************************* // // Return the format std::string for the columns in a block. This might not // look the same as the std::string used to define the block because it // includes both those columns, followed by any columns in that same block // that were directly created by the column() method. // - - - // Information about columns // ************************************************************************* // int nColumns ( ) const; int nColumns (const std::string& blockName) const; // ************************************************************************* // // Number of columns in the whole HepNtuple or in a block. A defined array // of columns counts one here, as the purpose is to support looping over // all the column definitions to get information. // ************************************************************************* // std::string nametag (int columnNumber) const; std::string nametag (int columnNumber, const std::string& blockname) const; std::string tag (int columnNumber) const; std::string tag (int columnNumber, const std::string& blockname) const; // ************************************************************************* // // Obtain the nametag (which can include blockname::tag), or just the column // tag, of the n-th column in the HepTUple, or the n-th column in a block. // The blockname can be blank (or empty) to find out about columns defined // by column(), with no block information supplied in their nametag. // ************************************************************************* // std::string columnBlock (const std::string& tag) const; std::string columnNametag (const std::string& tag) const; // ************************************************************************* // // Find out what block a column is in (meaningful because tags must // be unique). // - - - // The following methods provide information about a column specified by // its nametag. // ************************************************************************* // // type_info columnType_info (const std::string& nametag) const; ColumnData_t columnDataType (const std::string& nametag) const; // ************************************************************************* // // WARNING: Still need to define ColumnData_t or use a compliant compiler for // type_info // Returns the type of variable in each column. On fully compliant // compilers, the standard type_info mechanism is supported used. // For the convenience of users with not-yet-standard compliers, the header // provides a ColumnData_t enum. **[12]** // ************************************************************************* // int columnDimensions (const std::string& nametag, int dims[] ) const; // ************************************************************************* // // Returns number of dimensions, zero if this was not defined as an array of // columns. The extents in each dimension are put into dims[]; if an // index variable is used, dims[0] will be the maximum value of that. // dims[] should be an array of length 10, in case a 10-dimensional // column array (the most we support) was established. // ************************************************************************* // std::string columnIndex (const std::string& nametag) const; // ************************************************************************* // // Returns the nametag of the index column established for this array of // columns. Returns an empty Std::String if the column is not an indexed // array. // ************************************************************************* // bool columnDefault (const std::string& nametag, float* defval) const; bool setColumnDefault (const std::string& nametag, float defval) const; // ************************************************************************* // // Provides the default value for an un-captured column. There are other // signatures taking int*, long*, short*, double*, bool*, and Std::String*. // They return false if the wrong type of pointer was provided for this // column type. // ************************************************************************* // bool columnSpan (const std::string& nametag, int* min, int* max) const; // ************************************************************************* // // Returns false if this column was not set up as an index column, with // a defined span. // - - - // The following are provided for completeness, though generally the user // either has established the information which he now seeks, or would not // normally care what the answer might be. // ************************************************************************* // void* columnDesignatedVariable (const std::string& nametag) const; void* columnDestinationVariable (const std::string& nametag) const; // ************************************************************************* // // Will return 0 if designated or destination variable was not established. // ************************************************************************* // bool columnPacking (const std::string& nametag, float* low, float* high, int* inbits) const; // ************************************************************************* // // False if no packing was specified. // - - - - - // --- Data types other than float --- // For routines which take a float or float* refering to a datum, // there are analogous routines for int, short, long, and double. #define HEPTUPLE_METHOD_LIST(TYPE) \ bool column (const std::string& nametag, TYPE value, TYPE defval=0); \ bool newColumn (const std::string& nametag, const TYPE value, \ const TYPE defval=0); \ HepNtuple& columnAt (const std::string& nametag, TYPE* address, \ TYPE defval=0); \ HepNtuple& columnVia (const std::string& nametag, ZMuseMethod* method,\ TYPE defval=0); \ HepNtuple& columnVia (const std::string& nametag, TYPE (*function)(), \ TYPE defval=0); \ HepNtuple& columnArray (const std::string& nametag, int ncolumns, \ TYPE defval=0); \ HepNtuple& columnDirect (const std::string& nametag, TYPE defval=0); \ bool capture (const std::string& nametag, const TYPE value); \ bool capture (const std::string& nametag, const TYPE value[]); \ bool capture (const std::string& nametag, const TYPE value[], \ int indexval); \ int setExistingColumn (const std::string& nametag, TYPE val); /*H*/ \ bool readColumn (int irow, const std::string& nametag, TYPE* value); \ int readColumnArray (int irow, const std::string& nametag, TYPE values[]); \ int bulkReadColumn (int irow, int nrows, \ const std::string& nametag, TYPE destination[]); \ HepNtuple& destinationAt ( const std::string& nametag, TYPE* address); \ HepNtuple& destinationVia ( const std::string& nametag, \ void (* setMethod) (TYPE)); \ HepNtuple& destinationVia ( const std::string& nametag, \ ZMsetMethod* setMethod); \ HepNtuple& destinationVia ( const std::string& nametag, \ void (* setMethod) (TYPE[])); \ HepNtuple& destinationVia ( const std::string& nametag, \ ZMsetMethod* setMethod); \ bool columnDefault (const std::string& nametag, TYPE* defval) const; \ bool setColumnDefault (const std::string& nametag, TYPE defval) const; // the Float4 version is already instiated above. HEPTUPLE_METHOD_LIST(Float8) #ifdef Float16 HEPTUPLE_METHOD_LIST(Float16) #endif HEPTUPLE_METHOD_LIST(Int1) HEPTUPLE_METHOD_LIST(Int2) HEPTUPLE_METHOD_LIST(Int4) #ifdef Int8 HEPTUPLE_METHOD_LIST(Int8) #endif HEPTUPLE_METHOD_LIST(bool) HEPTUPLE_METHOD_LIST(void*) protected: /////////////////////// // // // Protected Methods // // // /////////////////////// // Used for dummy construction ... // the object is then not valid ... HepNtuple( ); // default constructor // Method use to retore block from existing file. bool restoreBlock (const std::string& blockName, const std::string& format); Block* unspecifiedBlock(); // The name will be #0000001 for the first unspecified block, // and after it is frozen and fUB() is called again, #0000002, etc. // For row-wise, it will start as the title of the Ntuple, and after it // is frozen forming new blocks will require the special rewind() // action so the same name will be retained. Column* findColumn(const std::string& nameTag) const; // if the block name is not expressed in the name tag, it returns // "A" column with the given name unless the sub-class insure through // isAvalaible that each name is unique in the tuple Block* findBlock(const std::string& blockName) const; Column* currentColumn() const; void setCurrentColumn(Column* c); // query/set the last column used. virtual bool isNameAvailable(const std::string& nameTag) const; // returns true if nameTag can be used for a new column in this // HepNtuple virtual const TupleNameTag& parseNameTag(TupleNameTag& what, const std::string& nameTag, bool WithIndices = false) const; // Modify and return 'What' to contain the column name and the // eventual block name. // These functions might worth being public virtual bool isRowWiseEnabled() const = 0; virtual bool isColumnWiseEnabled() const = 0; virtual bool isBlockWiseEnabled() const = 0; virtual bool isDiskResidentEnabled() const = 0; virtual bool isMemResidentEnabled() const = 0; virtual bool isSharedMemoryEnabled() const = 0; virtual bool isNwbuffEnabled(int nwbuff) const = 0; virtual bool isBuffLimitEnabled(int limit) const = 0; virtual bool isDemandBuffersEnabled() const = 0; virtual bool isCircularBufferEnabled() const = 0; // virtual bool isEnabled() const = 0; virtual bool isCaseSensitive() const = 0; // These methods tell if a manager can handle a certain type in // the given block. virtual bool isTypeEnabled(ColumnData_t type,Block *bk) = 0; virtual bool isTypeEnabled(ColumnData_t type) = 0; enum StorageGeometryName { ROW, COLUMN, BLOCK }; enum BufferTypeName { CIRCULAR, DEMAND }; StorageGeometryName storageGeometry() const; BufferTypeName bufferType () const; // simple-minded mutable accessor to the strategy ... it does // NOT verify if the newStrategy is possible. Use the // specific setter for that (setRowWise, setColumnWise etc...) virtual bool setStorageGeometry(StorageGeometryName newStrategy); virtual bool setStorageLocation(unsigned char newLocation); virtual bool setSharedMemoryName(char sharedMemoryArea[]); virtual bool setNwbuffValue(int nwbuff); virtual bool setNrowsValue(int nrows); virtual bool setBuffLimitValue(int limit); virtual bool setBufferType(BufferTypeName type); // from a NULL-terminated character std::string (a valid chForm in HBOOK) to // create a block containing an array of ColumnAttribs. // Also, the number of columns can be obtain through the nColumns(). std::STL_VECTOR(ColumnAttribs*) parseFormat(const std::string& chform); virtual bool addBlock(Block *b); virtual bool addColumn(Column *c); virtual bool addColumn(Block *b,Column *c); // methods to set/check if definition change happened. void changedDefinition(); bool isDefinitionChanged(); // methods to book and prepare for storage. virtual bool book() = 0; // this method should implement the booking the ntuple parts virtual bool prepareBlockForStoring(Block* bk); // Copy the captured data to the proper location for the manager. virtual bool storeWholeRow() = 0; virtual bool storeSingleBlock(Block* bk) =0; // Instruct the manager to store the row/block virtual int readWholeRow(int irow) = 0; virtual int readWholeBlock(Block* bk, int irow) = 0; virtual int readSingleColumn(Column* col, int irow) = 0; virtual int readSingleColumn(Column* col, const std::string& indices, int irow, void * val) = 0; virtual int readSingleColumn(Column* col, int irow, void * val) = 0; // 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 functions 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); virtual int readWholeColumn(Column* col, const std::string& indices, int start_row, int nrows, char * val, std::string::size_type size); virtual 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 readBlock(Block *bk, int irow); // utility function used by readRow and readBlock // data members containing the columns/block definitions typedef std::STL_MAP_COMP(std::string, Column*, std::less ) columnsMap; typedef std::STL_MAP_COMP(std::string, Block*, std::less ) blocksMap; blocksMap blocks; columnsMap columns; bool _changedDefinition; // Used to check if any definition of the heptuple changed since // the last store. #ifdef NEVER // JMM experimenting with pretendToUse for overleaded functions 4 Dec. 2001 void silenceCompiler(); #endif private: ////////////////// // // // Private Data // // // ////////////////// // data members for the storage strategy StorageGeometryName _storageGeometry; unsigned char _storageLocation; char *_sharedMemoryAreaName; int _nwbuff; int _buffLimit; BufferTypeName _bufferType; Block * _unspecifiedBlock; // = 0; // A block currently suitable for adding new columns with unspecified // block name. If the block gets frozen, then unspecifiedBlock // must become 0 to indicate that there is none at the moment. int _unspecifiedBlockNumber; // = 0; // Last trailing number that has previously been used to name an // unspecified block. Eg, if this is 17, the next unspecified block // formed will be named #0000018. bool _lockNoNewColumns; // = false; // New columns may not be added to this HepNtuple because a store has // already been done AND the lockOutNewColumns method has been invoked. mutable Column* _currentColumn; // 0 // Keep track of the last column used. int _nrows; ///////////////////// // // // Private Methods // // // ///////////////////// /////////////////////// // // // Exception Classes // // // /////////////////////// #ifdef COMMENT The following classes will change when we implement the exception mechanism, and will in particular become publicly derived from the ZMxGeneral base in HepNtuple class, which in turn is derived from the ZMexception base. For now we keep it minimal to just compile; ZMthrow will lead to an exit. #endif // COMMENT public: class ZMxGeneral; class ZMxProblem; class ZMxColumn; class ZMxNewColumn; class ZMxCapture; #if (defined(__GNUC__) && (__GNUC__ < 3) && __GNUC_MINOR__ < 90) || defined(WIN32) // GNU can not handle templated friends but we can trick it with the // following. // This could (should) be remplaced by a __NOTEMPLATEDFRIEND defined // in SoftRelTools/arch_spec.mk #define HEPTUPLE_TEMPLATE_FRIENDS(TYPE) \ friend bool captureF(const std::string& nametag, TYPE, HepNtuple* tuple); \ friend bool captureArrF(const std::string& nametag, const TYPE val[], \ int indexVal, \ HepNtuple* tuple); \ friend bool columnF(const std::string& nametag, TYPE value, TYPE defval, \ HepNtuple* tuple); \ friend bool columnAtF(const std::string& nametag, TYPE* value, TYPE defval, \ HepNtuple* tuple); \ friend bool columnViaF(const std::string& nametag, TYPE (*function)(), \ TYPE defval, HepNtuple* tuple); \ friend bool columnViaM(const std::string& nametag, ZMuseMethod* method, \ TYPE defval, HepNtuple* tuple); \ friend Column* newColumnF(const std::string& nametag, TYPE value, TYPE defval,\ HepNtuple* tuple); \ friend ColumnT* addNewColumnF(const std::string& nameTag, \ TYPE defaultValue, \ HepNtuple* tuple); \ friend bool columnDefaultTmpl(const std::string& nametag, TYPE* def, \ const HepNtuple* tuple); \ friend bool setColumnDefaultTmpl(const std::string& nametag, TYPE def, \ const HepNtuple* tuple); \ friend bool readColumnF(int irow, const std::string& nametag, \ TYPE* destination, HepNtuple *tuple); \ friend int bulkReadColumnF(int irow, int nrows, const std::string& nametag, \ TYPE* destination, HepNtuple *tuple); \ friend int readColumnArrayF ( int irow, const std::string& nametag, \ TYPE *destination, HepNtuple* tuple); \ friend ColumnT* getColumnT(const std::string &nametag,HepNtuple *hep, \ TYPE fortype); \ friend ColumnT* getOrCreateColumnT(const std::string& nametag, \ TYPE defVal, \ HepNtuple *hep); HEPTUPLE_TEMPLATE_FRIENDS(Int1) HEPTUPLE_TEMPLATE_FRIENDS(Int2) HEPTUPLE_TEMPLATE_FRIENDS(Int4) #ifdef Int8 HEPTUPLE_TEMPLATE_FRIENDS(Int8) #endif HEPTUPLE_TEMPLATE_FRIENDS(Float4) HEPTUPLE_TEMPLATE_FRIENDS(Float8) #ifdef Float16 HEPTUPLE_TEMPLATE_FRIENDS(Float16) #endif HEPTUPLE_TEMPLATE_FRIENDS(bool) HEPTUPLE_TEMPLATE_FRIENDS(void*) #else template friend bool captureF(const std::string& nametag,TYPE, HepNtuple* tuple); template friend bool captureArrF(const std::string& nametag, const TYPE val[], int indexVal, HepNtuple* tuple); template friend bool columnF(const std::string& nametag, TYPE value, TYPE defval,HepNtuple* tuple); template friend bool columnAtF(const std::string& nametag, TYPE* value, TYPE defval,HepNtuple* tuple); template friend bool columnViaF(const std::string& nametag, TYPE (*function)(),TYPE defval, HepNtuple* tuple); template friend bool columnViaM(const std::string& nametag, ZMuseMethod* method,TYPE defval, HepNtuple* tuple); template friend Column* newColumnF(const std::string& nametag, TYPE value, TYPE defval,HepNtuple* tuple); template friend ColumnT* addNewColumnF(const std::string& nameTag, TYPE defaultValue, HepNtuple* tuple); template friend bool columnDefaultTmpl(const std::string& nametag, TYPE* def, const HepNtuple* tuple); template friend bool setColumnDefaultTmpl(const std::string& nametag, TYPE def, const HepNtuple* tuple); template friend bool readColumnF(int irow, const std::string& nametag, TYPE* destination, HepNtuple *tuple); template friend int bulkReadColumnF(int irow, int nrows, const std::string& nametag,TYPE* destination, HepNtuple *tuple); template friend int readColumnArrayF ( int irow, const std::string& nametag, TYPE *destination, HepNtuple* tuple); template friend ColumnT* getColumnT(const std::string& nametag, HepNtuple *hep,TYPE fortype); template friend ColumnT* getOrCreateColumnT(const std::string& nametag,TYPE defVal, HepNtuple *hep); #endif }; // end of class HepNtuple ZM_END_NAMESPACE( zmht ) /* } // namespace zmht */ // include the inline methods #include "HepTuple/HepNtuple.icc" #ifdef COMMENT NOTES ----- **[1]** Block and column name and tag Column tags have no length limit but must be unique within any given block. (For HBook, column tags must be unique over the entire ntuple and the concatenation of all column tags in any block may not exceed 1300 characters.) A column may be defined with no specified block (for example defined by the direct capture routine column(tag[], value). What this means is that the user does not care what block this is grouped with, and does not intend to retrieve that data "by whole block." Actually, all columns with no specified block which were defined between one row-store and another will end up in the same block. Block names are treated as their first 8 characters. When a column is defined, you may use a longer form for its name than just its column tag -- the format is bname::ctag and we call this a nametag. For example, in the nametag "BLOCK5::PxDev" the column tag is PxDev and it is in block BLOCK5. Unfortunately, one cannot use block names as a namespace mechanism to allow disjoint users to choose their column tags arbitrarily: The column tag must be unique across the entire HepNtuple when using the HBOOK manager. Some other form of column tag naming agreement must be reached for a given program. Other than the un-named ("don't care") block, which can be assigned anew when new columns are added after a store has been done, the block name assigned is the block name used. We have abandoned the thought of automatically changing the block name under various conditions. This has a manager-specific consequence for HBOOK: Character string columns may have to be placed into distinct blocks from ordinary variables. The manual implies this is necessary. If so, it will be an error to mix character and numeric values in the same block if an HBOOK manager is used. **[2]** Convenient syntax for column definition You can combine definition of column nametag/designated variable, with refinements concerning packing, array dimensions, and so forth, in the following compact syntax: HepNtuple *mytup; float whereItIs; mytup->columnAt ("mytag", &whereItIs).dimension(4,2).pack(0.1, 1.5, 12).index("JNUM"); That is why these methods return a HepNtuple* (this). The one method which does double-duty as a capture method -- and therefore may be called thousands of times after the single column definition -- can still afford to return HepNtuple* (this). For now, it returns a bool but that may change. **[3]** Example of designating an accessor function Say you have a structure SpaceVector v, and you want to put r into the HepNtuple, but r is accessed by the method v.r(). class SpaceVector { public: float r(); // and other stuff } SpaceVector v; HepNtuple *mytup; mytup->columnVia ("ThisBLK::Radius", v.r()); // which is filled elsewhere in some loop, which then does ... mytup->capture("ThisBLK"); // captures data in ThisBLK, including // calling v.r() to capture r. Of course, now v had better stick around as long as ThisBLK is being captured, otherwise the call to v.r() will be invlaid. This is the same as always with designated variables: They must remain in scope if their block is to be captured. **[4]** Arrays of columns, and Index variables An array of columns is treated as a collection of separate columns. They all share the same array name, but the HBOOK column names, for example, will be like NAME(0,0) NAME(1,0) ... NAME(3,5), ... etc. You in fact can retrieve a column by that specific array element name (but you cannot capture just one element at a time). So for example, with columnwise storage you can get just X(3,2) for all rows stored, and do it very efficiently. Note that indices are zero-based. An index variable is how varying-length arrays are done. It delimits the slowest-varying dimension, which in C++ is the first dimension (a in X[a][b][c]) but in Fortran is the last one (c in X(a,b,c)). That first dimension of an indexed array is REPLACED in extent by the maximum set in the span of the index variable. When the index variable is less than its maximum possible value the remaining columns may not have anything stored for them. HBOOK benefits from this optimization for column-wise Ntuples. Such un-captured columns, if read back, will give the default value. **[5]** Array ordering Because the most important implementation assigns column array element names using the Fortran convention X(0,0) X(1,0), ... X(M, 0), X(0,1), ... X(M,N) the HepTuple package will go along with that. This presents no problem at all on the side of filling the HepNtuple. The confusion happens when a user knows he has stored an array shaped as x[40][20] in column array X, and wants to retrieve specific element -- he would have to say X(15,35) to get back the element which was in the C++ array as x[35][15]. That is what we get for mixing the two languages; further attempts to rectify the confusion will only make things worse. At least all our users KNOW to expect something cloudy whien this mixing goes on... **[6]** Semantics of filling an Ntuple The act of supplying data for one or more columns is called capturing that data. The act of adding the captured data for a row to the Ntuple is called storing the data. Data which is captured is not inevitably to be stored since the user can clearData for the row (for example when rejecting an event). Also, a subsequent capture for the same column will replace the earlier captured data. For managers which can benefit from the knowledge of which blocks were not filled, by not storing a block for a particular row, the information is kept. A block which has been captured is "marked"; clearing the block will "unmark" it, as well as setting all values to their defaults. The row number semantics for storing data is that of automatic append: The "active" row in an empty Ntuple would start at zero, and each time a row is stored, will increment. Thus you cannot overwrite a previously stored row, or leave a gap in row number. Capture of data can be done on a per-column basis using the "Direct" forms column(tag, value, defval) or capture(tag, value). Another way is to capture data for an entire block or row by supplying designated variables. These are explained in note **[7]**. The definition of the columns composing the HepNtuple may be extended after some data has been captured, and even after rows of data have been stored. The rules are: * A column in an unnamed block may be defined at ANY time, as long as the column tag is unique. Adding colummns after data has been stored is even reasonably efficient for columns-wise storage, but can be quite time-consuming for row-wise HepNtuple with lots of data already stored. * A column in a specific named block may be defined only if that block has not yet been stored. That is, if you capture a block (or data in a column in that block, then do storeCapturedData, then that block may no longer be added to. * A column in a specific named block may be defined even if that block has been captured (but not stored). Of course, the value for that column would be the default value until it is captured. * A column may not be defined with the same tag as some other column previously defined (even if they are in different blocks). * The definition of a defined column may not be refined (adding packing information and so forth) after data has been captured for that column. * For completeness: Storage strategy for the HepNtuple may be refined up until the first storeCapturedData is done, and no later. The mode of operation where column(name, val) without a specified block name is done at arbitrary times for definition and Direct capture is a preferred mode of operation prefered at BaBar, where their framework allows different contributors to add their own information to a common Ntuple, but may not call every contributor for every event. The act of adding a new column to an **EXISTING** ntuple, supplying data for each row for that column, is treated as part of the concept of manipulating ntuples, specifically, as a mode of combining two ntuples. This will be implemented later. **[7]** Designated Variables and Destination Variables HBOOK has the convenience of allowing (forcing for heterogeneous column-wise Ntuples) the user to designate variables meaning that, ""Here is where the data will be when I want to fill a block or row."" Those have to be in a COMMON block in HBOOK, to enforce a known pattern of word-alignment (namely, none). HepTuple, of course, retains this convenience, but allows the designated variables to be in any struct or structs, not necessarily contiguous. C++ compilers are free to word-align structs by adding padding. So even if all the designated variables are in one struct, there would be a need to specify the addresses of each. In HepTuple this is done either by columnAt(), or for a whole block at a time by the vector of addresses in block(). We distinguish designated variables for filling the HepNtuple, from destination variables for retrieval. To retrieve data other than one column or column array at a time, you must set up destinations for the data using destinationAt(). Don''t forget to keep the designated and destination variables in scope! If you don''t then either the HepTUple is being filled from meaningless data, or your retrival is putting data in a meaningless place! **[8]** Possible error returns for Read routines -1 Name not found -2 irow past end of Ntuple -3 No designated variables were established for desired block or row -4 Element of Column array read using tag without indices -5 Ordinary column read using readColumnArray Since accessing an existing Ntuple is inherently subject to these problems, we choose (for now) to return a code RATHER THAN to throw exceptions. In particular, placing all access inside individual try constructs will be badly inefficient in an area that might matter. **[9]** Refining destination definitions To specify a destination well enough for retrieval to proceed, you need to specify: * The nametag and address, as in destinationAt(). You do not need to specify, because the HepNtuple knows about, the following: - The dimensions of a column array - Packing information - The span of an index column - The tag of the column used as an index It you do specify unneeded information, and it clashes in a meaningful way with the actual information, the specification routine will return 0 instead of a pointer to the HepNtuple. This should not be ignored; it probably means you will fou up badly if you try to retrive data into space tailored to your wrong information! When an entire block is specified at a time, by blockDestinations(), the format supplied must match reality in tags, index variable, dimensions, and spans -- otherwise, there is too great a likelihood that reading into the supplied list of addresses will be blowing storage. For example, if you think index variable J has a span of 0-200 and it can really go to 210, you probably are allocating 200 words of space to hold a possible 210-word output. Similarly, the number of columns in the format string must match the number of addressses in the list. But these do not have to match the total number of columns in the block, or be in the same order -- you can skip columns on retrieval. And packing information in the destination format string is ignored. **[10]** SetMethods for destinations This is for purists who wish to fill their structures (from retireved Ntuple data) via "mutator methods" rather than direcly writing to their data. Say you have a structure SpaceVector v, and you have a method v.r(float) that would take one float value (IT MUST TAKE 1 VALUE FOR THIS FEATURE TO BE APPLICABLE) for r, and change the vector to keep the same theta and phi but use the new r. This is not just storing r in a place; the actual x, y, and z all change. class SpaceVector { public: void r(float); // and other stuff } SpaceVector v; HepNtuple *mytup; mytup->distinationVia ("ThisBLK::Radius", v.r()); // which is filled elsewhere in some loop, which then does ... mytup->readBlock("ThisBLK"); // When up to Radius, it supplies that // value as the agrument to a call to // calling v.r(). Of course, now v had better stick around as long as ThisBLK is being read, otherwise the call to v.r() will be invlaid. (Frankly, v.r(x) can do anything it wants to with x. We just imagine it being used to modify some aspects of v.) You can use this mechanism to work with a single column or an array of columns. In the latter case, you have mutator method which takes as an argument an float[] instead of a float. **[11]** Memory resident information The resident() method returns: 'D' disk resident 'M' memory resident 'S' shared memory resident If shared memory resident, the method sharedAreaName returns the name of the shared section (otherwise, it returns a blank Std::String). If the Ntuple is not disk resident, either a circular buffer is being used, or demand strategy (where additional buffers are added as the Ntuple grows). **[12]** Column data type identification On a compliant compiler one could do type_info x = mytup.columnType_info(ncol); if ( x == typeid(double) ) doWhatever; The alternative we supply is ColumnData_t x = mytup.columnDataType(ncol); if ( x == ColumnData_FLOAT8 ) doWhatever; Actually, that alternative may be more than a kludge for the compliance- differently-abled, because our types (FLOAT8 vs FLOAT4 etc.) more directly correspond to the types used underneath, R*8, R*4 and so forth. **[13]** Fixed-length character strings These correspond to the HBOOK C*4, C*8, ... C*32 formats. They are different than ordinary char arrays in at least two ways: - Even with columnwise storage, all 4 or 8 or ... or 32 bytes are stored together. - If there is any differnece in byte swap issues, the underlying manager will treat these as character strings and apply the proper swap for those. Arrays of columns of fixed-length character strings -- e.g., the concept expressed by the format string X:C*16(3,4) -- are not supported. By the way, what if you want a true array (of arbitrary length, perhaps with an index, maybe mulit-dimensional) of "integer*1" objects? Then you don''t invoke characters(), you invoke dimension(). The HBOOK implementation MAY NOT ??? ALLOW YOU TO MIX CHARACTER STD::STRINGS AND ORDINARY DATA IN THE SAME BLOCK. **[14]** Direct capture of arrays of columns Notice that although a 1-dimensional array can be defined without designated variables (the columnArray() method), multi-dimensional arrays will always have designated variables. Nonetheless, the capture (const string& nametag, float values[]) method allows Direct capture; but if designated variables were assigned for that column array, one should be careful not to capture the block later lest the directly captured values be over-written. **[15]** columnArray method for non-float data In this method the default value is not required if float data is to be used -- the signature without defval assumes float and sets defval=0. But for coulmns of int, double, or other non-float data, the default value must be supplied. And if a constant is supplied, the user must be careful that the constant is of the desired data type, as that is the only way the method caln tell what type of columns the user wants. Similarly, columnDirect() requires a default value if non-float data is to be used, and the user must be careful that this is of the desired data type. #endif /* COMMENT */ #endif // Code Guard HEPNTUPLE_H