home *** CD-ROM | disk | FTP | other *** search
- 2.1 NCSA HDF Vset
-
-
- Vdatas 2.1
-
-
- National Center for Supercomputing Applications
-
- November 1990
-
-
-
-
-
-
-
-
-
-
-
- Chapter 2 Vdatas
-
-
-
- Chapter Overview
- Interlacing
- Working with Interlacing
- HDF Data Format
- Vdata Options
- Selecting Random-Access Reads
- Writing Fields of Mixed Types
- Specifying Read Fields
- Inquiring About a Vdata
- Using Searching Strategies
- Accessing Vdatas Simultaneously
-
- Chapter Overview
-
- This section points out some properties of vdatas that might not be
- obvious from earlier examples. The section covers important
- concepts and ideas on which the HDF Vset is based. It also gives a
- better idea of how the vdata's properties and various routines may
- be used to gain greater control over data organization and access.
-
-
- Interlacing
-
- Data for all the fields with a vdata are stored according to a
- non-interlaced or fully-interlaced scheme. The concept of
- interlacing is simple but important╤it describes how data of one
- field is related to data of another in a storage area (whether in
- memory or in a vdata in the file). Note that interlacing applies
- only to fields.
-
- In a non-interlaced scheme, all data values for one field are stored
- together contiguously. Think of all the data values for one field
- forming one data chunk, and all the data values for another field
- forming another chunk. Such an interlace scheme emphasizes
- keeping all data values for one field close together. Figure 2.1a
- shows a vdata with non-interlaced fields.
-
- In a fully-interlaced scheme, all data values for one field are
- never located contiguously. Each data value of one field is
- immediately followed by one data value of another field, until a
- data value is taken for all fields. In other words, data values from
- different fields are intertwined together as aggregates, where each
- aggregate comprises exactly one data value from each of the fields.
- Such an interlace scheme emphasizes keeping related data values
- from different fields together. Figure 2.1b shows a vdata with
- fully-interlaced fields.
-
- When talking about interlacing, a distinction is made between
- when data is in memory and when data resides in a vdata in a
- file. The layout of data in memory is its buffer interlace, whereas
- the layout of data within a vdata in the file is the vdata's
- file interlace.
-
-
- Working with Interlacing
-
- Data as it appears in the file may or may not have the same
- interlace as the data appears in memory. This feature allows
- applications to extract data interlaced in the manner most useful to
- it, independent of the file interlace. In the same way, data may be
- stored in the file with an interlace different from how it appears in
- memory.
-
- The HDF Vset interface always requires that the buffer interlace
- be specified in any data transfer. However, it does not require the
- file interlace be specified. By default, this buffer interlace is
- always set to FULL_INTERLACE for every newly created vdata.
- Thus, fields in a vdata are always fully-interlaced by default. You
- may change the interlace for any particular vdata to
- NO_INTERLACE with the routine VSsetinterlace. Vdatas within
- an HDF file may be set to different file interlaces if so desired.
- However, note that the file interlace of existing vdatas cannot be
- changed.
-
- The buffer interlace must be specified when reading or writing
- data. Both the read/write routines, Vsread and VSwrite, require
- the buffer interlace to be specified as the fourth argument. When
- reading data, the buffer interlace tells the read routine how the
- returned data should be interlaced in the read buffer. When
- writing data, the buffer interlace informs the write routine how
- data in the write buffer is interlaced.
-
- Finally, note that when only one field is read or written, or when
- there is only one field in a vdata or in memory, interlacing is not
- relevant. In such cases, specifying FULL_INTERLACE or
- NO_INTERLACE yields identical results.
-
- Figure 2.1 Interlacing Within
- Vdatas
-
-
-
-
- HDF Data Format
-
- Data stored in a vdata is in IEEE 32-bit floating-point format.
- When data is read or written, the calling interface always convert
- from IEEE format to the correct data format and byte length for that
- particular machine, and vice versa. For instance, 4-byte floats
- created on a VMS machine are stored as 4-byte IEEE floats in the
- vset in the HDF file. Later when a Cray (running UNICOS) reads
- the data, the 4-byte float value is converted to an 8-byte Cray float
- value.
-
- The data stored within a vdata is always contiguous; i.e., the vdata
- does not contain any non-data spaces or holes. This is true for both
- fully-interlaced and non-interlaced data. Consequently, any call
- to VSread always returns data that is contiguous, and any call to
- VSwrite expects data to be contiguous.
-
-
- Vdata Options
-
- Selecting Random-Access
- Reads
- The access routine VSseek is used together with a VSread to affect a
- random-access read within a vdata. VSseek requires an
- argument that specifies the element location within that vdata.
- This value will be an integer, with 0 for the first element position, 1
- as the second element position, etc.
-
- Thus, the following code segment seeks to the 51st element in the
- vdata vs, and then reads data for four elements according to the
- fields specified by the last VSsetfields call:
-
- VSseek(vs,50);
- VSread(vs,buf,4,interlace);
-
-
- Writing Fields of Mixed
- Types
- The fields within one vdata need not all be of the same type. You
- may store fields of integer, float, and character types together
- within one vdata.
-
- Assume that the fields "F1", "F2", "I1" and "C1" represent data
- fields of float, float, character, and integer types of order 1,
- respectively. The code segment below first defines these fields,
- and then specifies that the data from buffer buf be written
- contiguously into the vdata vs according to the format
- "F1,I1,F2,C1".
-
- ...
- VSfdefine (vs, ╥F1╙, LOCAL_FLOATTYPE, 1);
- VSfdefine (vs, ╥I1╙, LOCAL_INTTYPE, 1);
- VSfdefine (vs, ╥F2╙, LOCAL_FLOATTYPE, 1);
- VSfdefine (vs, ╥C1╙, LOCAL_CHARTYPE, 1);
- VSsetfields(vs,"F1,I1,F2,C1 ");
- VSwrite(vs,buf,nvertices,interlace);
-
-
- The data in buf must also be contiguous. There must be no padding
- or alignment, or non-data spaces.
-
- Storing mixed field types within a vdata is very efficient, and is
- useful to applications that use structures. Such usage intuitively
- associates a structure in memory to a vdata in the file. However, in
- general, structures contain padding or alignment bytes (Figure
- 2.2) and as such, may not be directly written out into a vdata with a
- VSwrite call. The data from such a structure must first be packed
- into an array so that the array does not contain holes or non-data
- spaces. This packed array may then be written out into one vdata
- using VSwrite.
-
-
- Figure 2.2 Structure Array Vs. Packed Array
-
-
-
-
-
- The following code segment (Figure 2.3) illustrates packing data
- in the fields from a structure array ss into a contiguous array pp,
- and then writing the array pp into a vdata.
-
- Figure 2.3 Packing Data
-
- #define NVERTICES 500
- main() {
-
- struct {
- float F1;
- int I1;
- float F2;
- char C1;
- } ss[NVERTICES];
-
- unsigned char *pp, *p;
- int i;
-
- ...
- pp = (unsigned char*) malloc( NVERTICES* (2*sizeof(float) + sizeof(char) +
- sizeof(int)) );
- p = pp;
- for(i=0;i<NVERTICES ;i++) {
- movebytes (p, &ss[i].F1, sizeof(float) ); p+=sizeof(float);
- movebytes (p, &ss[i].I1, sizeof(int) ); p+=sizeof(int);
- movebytes (p, &ss[i].F2, sizeof(float) ); p+=sizeof(float);
- movebytes (p, &ss[i].C1, sizeof(char) ); p+=sizeof(char);
- }
-
- VSsetfields(vs,"F1,I1,F2,C1");
- VSwrite(vs,pp,NVERTICES, FULL_INTERLACE);
- ...
-
- } /* main */
-
- movebytes(dest, src, nbytes) unsigned char *dest, *src; int nbytes; {
- int i;
- for(i=0;i<nbytes;i++) *dest++ = *src++:
- }
-
-
- Note the following points:
-
- 1. The exact amount of memory is allocated (i.e., NVERTICES
- times the size of 2 floats, 1 char and 1 integer).
-
- 2. The routine movebytes is called for each field in the sequence
- desired (i.e., "F1,I1,F2,C1"). The movebytes routine may be
- replaced by any efficient routine.
-
- 3. Data in one structure record is packed each time the code moves
- through the loop.
-
- 4. The contiguous data in array pp may now be stored with by
- VSwrite.
-
-
- Specifying Read Fields
- The data read from a vdata depends only on the fields specified by
- the VSsetfields call. Thus, for reading, you can select one or
- more fields from the vdata.
-
- For example, assume that the vdata vs contains fields specified by
- "AFLOAT, BFLOAT, CCHAR, DINT, EINT, FCHAR" and is stored in
- that sequence. (The type of each field is suggested by the
- fieldname.) Each of the following VSsetfields calls is valid
- before a VSread call:
-
- VSsetfields(vs,"BFLOAT");
- VSsetfields(vs,"BFLOAT,AFLOAT");
- VSsetfields(vs,"EINT,AFLOAT");
- VSsetfields(vs,"CCHAR,DINT,FCHAR");
- VSsetfields(vs," FCHAR, EINT, DINT, CCHAR,BFLOAT, AFLOAT")
-
-
- The last call specifies all fields be read in reverse sequence.
-
- Note that the VSread call always returns contiguous data for the
- fields specified. Furthermore, the data is returned in the sequence
- specified.
-
- Several calls to VSsetfield and VSread may follow one another to
- read data from the same vdata. However, note that the read
- operations are sequential. Thus, in the following code segment, the
- first VSread returns 10 "AFLOAT" data values from the first 10
- elements in the vdata, while the second VSread returns 10
- "BFLOAT" data values from the second 10 elements (i.e., 11-20) in
- the vdata.
-
- VSsetfields(vs,"AFLOAT");
- VSread(vs,buf1,10, interlace);
-
- VSsetfields(vs,"BFLOAT");
- VSread(vs,buf2,10, interlace);
-
-
- To actually read the first 10 "BFLOAT" data values, the access
- routine VSseek must be explicitly called to position the read pointer
- back to the first element positions. The following code segment
- correctly reads the first 10 "AFLOAT" and "BFLOAT" values into two
- separate float arrays buf1 and buf2.
-
- VSsetfields(vs,"AFLOAT");
- VSread(vs,buf1,10, interlace);
-
- VSseek(vs,0); /*seeks to first element /
- VSsetfields(vs,"BFLOAT");
- VSread(vs,buf2,10, interlace);
-
-
- Inquiring About a Vdata
- The inquire routine VSinquire is the general inquiry routine for
- requesting information about the contents of a vdata. It returns the
- number of elements in the vdata; the interlace, a string containing
- (comma-separated) names of the fields in the vdata; the byte size of
- a element in the vdata; and the name of the vdata itself, if any.
-
- This routine is useful when searching through the HDF file for a
- particular vdata by name or by fieldname.
-
-
- Using Searching Strategies
- Applications that allow users to specify which vgroup or vdata to
- access should contain general search strategies. The most general
- search strategy searches by the name of a vgroup or vdata. The
- names of vgroups and vdatas are the best means for the user to
- identify them by, since names are readable and mnemonic as
- compared to integer identifiers (ids) of vgroups and vdatas).
-
-
- Searching for a Vgroup by Name
- Locating a vgroup by name is simple. It merely involves
- searching through all vgroups in the file, and then inquiring for
- the name of the vgroup. The search routine Vgetid sequences
- through the file and returns the vgids of the vgroups one at a time,
- or returns -1 when no more vgids are found. The code in Figure
- 2.4 illustrates the search for a vgroup named "transistor P╙.
-
- Figure 2.4 Searching for a Vgroup
-
- char vsname[50];
- VGROUP *vg;
- int vgid;
- ...
- vgid = -1;
- found = 0;
- while( (vgid = Vgetid(f, vgid)) != -1) {
- vg = (VGROUP*) Vattach(f,vgid,"r");
- Vinquire(vs,&nentries, vgname);
- if (!strcpy(vsname,"transistor P")) { found = 1; break; }
- else VSdetach(vs);
- }
- if (! found) { printf("vgroup 'transistor P' not found"); return; }
- ...
-
-
-
- Searching for a Vdata by Name
- Similar code is used for searching for a specific vdata by name.
- The code in Figure 2.5 looks for the vdata named "transistor P
- voltages"; Here, the routines VSinquire and VSgetid are used
- instead of Vinquire and Vgetid.
-
- Figure 2.5 Searching for a Vdata
-
- char vgname[50];
- VDATA *vs;
- int vsid;
- ...
- vsid = -1;
- found = 0;
- while( (vsid = VSgetid(f, vsid)) != -1) {
- vs = (VDATA*) VSattach(f,vsid,"r");
- VSinquire(vs,&nvertices, &interlace, fields, &vsize, vsname);
- if (!strcpy(vsname,"transistor P voltages")) { found = 1; break; }
- else VSdetach(vs);
- }
- if (! found) { printf("vdata 'transistor P' not found"); return; }
- ...
-
- Hierarchical Search for a Vdata by Name
- A more systematic way of searching for a vdata takes into account
- the hierarchical nature of the vset. Thus, you would first go through
- all vgroups and examine each entry in the vgroup. Each entry is
- either a vgroup or a vdata identifier. If it is a vdata identifier, just
- inquire for its name. However, if it is a vgroup identifier, all the
- entries in that vgroup need to be searched in a similar manner.
-
- The code in Figure 2.6 looks for the vdata named "pressure
- site#9". The search routine Vgetid is used to locate all the
- vgroups one by one, while the search routine VSgetnext is used to
- locate the identifiers of all the entities in a vgroup. Finally, the
- inquiry routines Visvg and Visvs each test whether an identifier
- in a vgroup is a vgroup or vdata.
-
- Figure 2.6 Hierarchical Searching
-
-
- VGROUP *vg;
- VDATA *vs;
- int vgid, vsid,id;
- ...
- found = 0;
- vgid = -1;
- while( (vgid = Vgetid(f, vgid)) != -1) {
- vg = (VGROUP*) Vattach(f,vgid,"r");
- id = -1;
- while((id = Vgetnext(vg, id)) != -1) {
- if (Visvs(vg,id) ) { /* vdata id */
- vs = (VDATA*) VSattach(f,id,"r");
- VSinquire(vs,&nvertices, &interlace, fields, &vsize, vsname);
- if (!strcpy(vsname,"pressure site#9")) { found=1; break; }
- else VSdetach(vs);
- }
- else (Visvg(vg,id) ) { /* vgroup id */
- ... /* perform similar search on vgroup vg */
- }
- }
- if (found) break;
- Vdetach(vg);
- }
- if(!found) { printf("vdata 'pressure site#9' not found"); return; }
- ...
-
-
- Searching for a Vdata by Fieldname
- Finally, to search for a vdata by specifying only the fieldnames,
- use the inquiry routine VSfexist. This routine takes a vdata
- pointer as an argument, and returns true if all the specified fields
- exist in that vdata. In the following code segment (Figure 2.7), all
- vdatas in the file are searched through until the first vdata to
- contain the fields "PZ, PX" is found.
-
- Figure 2.7 Search Using Fieldnames
-
-
- VDATA *vs;
- int vsid;
- ...
- vsid = -1;
- found = 0;
- while( (vsid = VSgetid(f, vsid)) != -1) {
- vs= (VDATA*) VSattach(f,vsid,"r");
- if( VSfexist(vs,"PZ,PX")) { found = 1; break; }
- else VSdetach(vs);
- }
- if (! found) { printf("fields 'PZ,PX' not found in any vdata"); return; }
- ...
-
-
-
- Note that VSfexist returns true only if all the specified fields, in
- any order, exist in the vdata. For instance, specifying "PZ,PX" or
- "PX,PZ" in the call to VSfexist will return true for a vdata that
- contains the fields "PX,PY,PZ".
-
-
- Accessing Vdatas
- Simultaneously
- Several vdatas may be attached for simultaneous access. This is
- analogous to having several files opened at the same time.
-
-
- Reading Data
- Reading data from several vdatas at the same time is efficient and
- easy, as the code segment in Figure 2.8 shows.
-
- Figure 2.8 Accessing Vdatas
- Simultaneously
- float xval, yval;
- v1 = (VDATA*)VSattach(f,vsid1,"r");
- v2 = (VDATA*)VSattach(f,vsid2,"r");
-
- VSsetfields(v1,"PX");
- VSsetfields(v2,"DENSITY");
-
- for(i=0;i<1000;i++) {
- VSread(v1,&xval,1,FULL_INTERLACE);
- VSread(v2,&yval,1,FULL_INTERLACE);
- plot_point (xval,yval);
- }
- ...
- VSdetach(v1);
- VSdetach(v2);
-
-
- Note the following points about the above code:
-
- 1. Two vdatas v1 and v2 are opened simultaneously.
-
- 2. The VSread from v1 returns one "PX" value in xval, while the
- VSread from v2 returns one "DENSITY" value in yval.
-
- 3. A plotting routine, plot_point, processes each pair of data in
- xval and yval.
- Writing Data
- Writing data to several vdatas in the same file simultaneously is
- supported, but can be inefficient since each vgroup and each vdata
- is always maintained as a contiguous data block in the file.
-
- As an example, assume that two vdatas, A and B, exist in an HDF
- file such that B immediately follows A in the file. When new data
- is to be written out (appended) to A, the file storage for A has to be
- expanded; however, this cannot be done since B immediately
- follows A. Thus, A must be copied to the end of the file, and only
- then can new data be appended to it. This procedure creates an area
- of useless space in the file where the original vdata A was located.
- As a result, file space becomes fragmented and the file grows
- unnecessarily large.
-
- As a rule, when writing data out to several vdatas, it is more
- efficient to completely write out data for one vdata before
- proceeding to write data for the next vdata.
-