To create a multi-component vdata, the calling program must contain the following:
C: file_id = Hopen(filename, file_access_mode, n_dds); status = Vstart(file_id); vdata_id = VSattach(file_id, vdata_ref, vdata_access_mode); status = VSsetname(vdata_id, vdata_name); status = VSsetclass(vdata_id, vdata_class); status = VSfdefine(vdata_id, fieldname, data_type, order); status = VSsetfields(vdata_id, fieldname_list); status = VSsetinterlace(vdata_id, interlace_type); status = VSdetach(vdata_id); status = Vend(file_id); status = Hclose(file_id); FORTRAN: file_id = hopen(filename, file_access_mode, n_dds) status = vfstart(file_id) vdata_id = vsfatch(file_id, vdata_ref, vdata_access_mode) status = vsfsnam(vdata_id, vdata_name) status = vsfscls(vdata_id, vdata_class) status = vsffdef(vdata_id, fieldname, data_type, order) status = vsfsfld(vdata_id, fieldname_list) status = vsfsint(vdata_id, interlace_type) status = vsfdtch(vdata_id) status = vfend(file_id) status = hclose(file_id)
In the routines that follow, vdata_id is the vdata identifier returned by VSattach.
4.5.1.1 Creating New Vdatas with VSattach
When a new vdata is created, the value of the VSattach parameter vdata_ref must be -1 and the value of the access_mode parameter must be "w". 4.5.1.2 Assigning a Vdata Name and Class: VSsetname and VSsetclass
VSsetname assigns a name to a vdata object. If not explicitly named by a call to VSsetname, the name of the vdata is set by default to NULL. Names may be assigned and reassigned at any time after the vdata is created. The parameter vdata_name contains the name to be assigned to the vdata.
4.5.1.3 Defining a Field Within Vdatas: VSfdefine
VSfdefine defines a field within a newly-created vdata. Each VSfdefine call assigns the name contained in the fieldname argument, the data type contained in the data_type argument and the order contained in the order argument to one new field. Fields will appear in the vdata in the order they are defined. Once data is written to a vdata, field definitions may not be modified or deleted.
The parameters of VSfdefine are further described below. (See Table 4E on page 113.)
TABLE 4D Predefined Data Types and Field Names for Vdata Fields
Data Type
|
Coordinate Point Field Names
|
Normal Component Field Names
| ||||
x-coordinate
|
y-coordinate
|
z-coordinate
|
x-component
|
y-component
|
z-component
| |
float
|
PX
|
PY
|
PZ
|
NX
|
NY
|
NZ
|
integer
|
IX
|
IY
|
IZ
|
None
|
None
|
None
|
VSsetfields must be called prior to any write operation and may only be called once for each vdata. Any field not named in the fieldname_list parameter is removed from the vdata. The combined width of the fields must be less than 32,767 bytes. If an attempt is made to create a larger record than this, VSsetfields will fail and an error condition will result.
The parameters of VSsetfields are further described below. (See Table 4E on page 113.)
4.5.1.5 Specifying the Interlace Mode: VSsetinterlace
The VS interface supports two modes of interlacing: file interlacing and buffer interlacing. File interlacing determines how data is stored in a vdata and buffer interlacing determines how data is stored in memory. The VS interface can write data from a buffer to a file in an interlaced or non-interlaced manner. It can also read data from a file in an interlaced or non-interlaced manner.
VSsetinterlace sets the file interlacing mode for a vdata. Setting the parameter interlace to FULL_INTERLACE fills the vdata by record, whereas specifying NO_INTERLACE fills the vdata by field. (See Figure 4d.) For multi-component fields, all components are treated as a single field. As with file interlacing, the default vdata interlace mode is FULL_INTERLACE because it is more efficient to write complete records than it is to write fields if the file and memory interlace modes are the same, although both require the same amount of disk space.
FIGURE 4d Interlaced and Non-Interlaced Vdata Contents
VSsetinterlace can only be used for operations on new vdatas as the interlacing cannot be changed once the data has been written to a vdata object. Also, although records in a fully interlaced vdata can be written with one or more write operations, all records in a non-interlaced vdata must be written at the same time. TABLE 4E VSsetname, VSsetclass, VSfdefine, VSsetfields and VSsetinterlace Parameter List
C: file_id = Hopen(filename, file_access_mode, n_dds); status = Vstart(file_id); vdata_id = VSattach(file_id, vdata_ref, vdata_access_mode); status = VSsetfields(vdata_id, *fields); record_pos = VSseek(vdata_id, record_index); num_of_recs = VSwrite(vdata_id, *databuf, n_records, interlace); status = VSdetach(vdata_id); status = Vend(file_id); status = Hclose(file_id); FORTRAN: file_id = hopen(filename, file_access_mode, n_dds) status = vfstart(file_id) vdata_id = vsfatch(file_id, vdata_ref, vdata_access_mode) status = vsfsfld(vdata_id, *fields); record_pos = vsfseek(vdata_id, record_index); num_of_recs = vsfwrit(vdata_id, *databuf, n_records, interlace) status = vsfdtch(vdata_id) status = vfend(file_id) status = hclose(file_id)
4.5.2.1 Resetting the Current Position Within Vdatas: VSseek
VSseek provides a mechanism for random-access write operations within fully-interlaced vdatas. Random-access writes are not available for non-interlaced vdatas. The parameter record_index is the position of the record to be written. The position of the first record in a vdata is specified by record_index=0: any vdata operation will be performed on this vdata before VSseek is called.
FIGURE 4e Setting the Record Pointer at the End of a Vdata Object
In this figure we have a vdata that consists of only four records. Using VSseek to seek to the end of the fourth record by setting the record parameter to 4 results in an error condition. To avoid this situation, we set the record parameter to 3 in order to set the current record pointer to the end of the third record. We then use VSread to read the contents of the fourth record in a buffer and move the current record pointer to the end of the fourth record. The contents of the buffer can then be discarded. This method can be generalized to a vdata of any number of records; seek to the last record with VSseek, then read the last record using VSread. 4.5.2.2 Writing to a Vdata: VSwrite
VSwrite writes buffered data to the vdata in the specified HDF file. The parameter databuf is a buffer containing records to store in the vdata. The n_records parameter is the number of records to be written.
FIGURE 4f Writing Interlaced or Non-Interlaced Buffers into Interlaced or Non-interlaced Vdatas
The data in databuf is assumed to contain the exact amount of data in the order needed to fill the fields defined in the last call to VSsetfields. Because VSwrite writes the contents of databuf contiguously to the vdata, any "padding" due to record alignment must be removed before attempting to write from databuf to the vdata. For more information on removing alignment padding see Section 4.5.2.3 on page 118.
It should be remembered that VSwrite writes whole records, not individual fields. If a modification to one field within a previously-written record is needed, the contents of the record must first be preserved by reading it using VSread, which will be described in Section 4.6.3 on page 123, updating the field then writing it using VSwrite.
To create an empty vdata either VSwrite, VSsetname and VSsetclass must be called before VSdetach. If VSwrite is not called the vdata created will be an empty vdata. If VSsetfields is called and VSwrite, VSsetname or VSsetclass is not called, the vdata will not be written.
TABLE 4F VSseek and VSwrite Parameter List
C:
#include "hdf.h" #define FIELD_NAME "Field Entries" #define NUMBER_OF_ROWS 10 #define ORDER 3 main( ) { int32 file_id, vdata_id, status, num_of_elements; int16 vdata_buf[NUMBER_OF_ROWS * ORDER], i; /* Open the HDF file. */ file_id = Hopen("Example3.hdf", DFACC_CREATE, 0); /* Initialize HDF for subsequent the vgroup/vdata access. */ status = Vstart(file_id); /* Create a new vdata. */ vdata_id = VSattach(file_id, -1, "w"); /* Define the field data name, type and order. */ status = VSfdefine(vdata_id, FIELD_NAME, DFNT_INT16, ORDER); /* Specify the field(s) that will be written to. */ status = VSsetfields(vdata_id, FIELD_NAME); /* Generate the Vset data. */ for (i = 0; i < NUMBER_OF_ROWS * ORDER; i+=ORDER) { vdata_buf[i] = i; vdata_buf[i + 1] = i + 1; vdata_buf[i + 2] = i + 2; } /* Write the data to the Vset. */ num_of_elements = VSwrite(vdata_id, (char *)vdata_buf, NUMBER_OF_ROWS, FULL_INTERLACE); /* Set the name and class. */ status = VSsetname(vdata_id, "Example Vdata"); status = VSsetclass(vdata_id, "Example Vdata"); /* Terminate access to the vdata. */ status = VSdetach(vdata_id); /* Terminate access to the Vset interface and close the file. */ status = Vend(file_id); status = Hclose(file_id); }
PROGRAM WRITE VDATA integer file_id, vdata_id integer status integer vdata_buf(30), i, number_of_rows, num_of_elements integer hopen, vsfatch, vsffdef, vsfsfld integer vsfwrit, vsfsnam, vsfscls, vsfdtch integer hclose, vfstart, vfend C DFACC_CREATE, DFNT_INT16 and FULL_INTERLACE are defined C in hdf.inc. integer DFACC_CREATE, DFNT_INT16, FULL_INTERLACE parameter (DFACC_CREATE = 4, + DFNT_INT16 = 22, + FULL_INTERLACE = 0) character field_name *13 parameter (field_name = `Field Entries') parameter (number_of_rows = 10) C Create an HDF file with full access. file_id = hopen(`Example3.hdf', DFACC_CREATE, 0) C Initialize HDF for subsequent vgroup/vdata access. status = vfstart(file_id) C Create a new vdata. vdata_id = vsfatch(file_id, -1, `w') C Define the field data name, type and order. status = vsffdef(vdata_id, field_name, DFNT_INT16, 3) C Specify the field that will be written to. status = vsfsfld(vdata_id, field_name) C Generate the Vset data. do 10 i = 1, number_of_rows * 3, 3 vdata_buf(i) = i+1 vdata_buf(i + 1) = i+2 vdata_buf(i + 2) = i+3 10 continue C Set the name and class. status = vsfsnam(vdata_id, `Example Vdata') status = vsfscls(vdata_id, `Example Vdata') C Write the data to the Vset. num_of_elements = vsfwrit(vdata_id, vdata_buf, number_of_rows * 3, + FULL_INTERLACE) C Terminate access to the vdata. status = vsfdtch(vdata_id) C Terminate access to the Vset interface and close the file. status = vfend(file_id) status = hclose(file_id) end
4.5.2.3 Filling Records of Mixed Field Data Types
Storing fields of mixed data types is an efficient use of disk space and is useful in applications that use structures. While data structures in memory containing fields of variable lengths often contain padding or alignment bytes, data stored in a vdata does not contain padding. This is true for both fully-interlaced and non-interlaced data. Because of this, when variable-length field types are used it is not generally possible to write data directly from a structure in memory into a vdata in a file with a VSwrite call. Instead, the data from the structure must first be written to a temporary buffer array, removing all alignment bytes. This packed array is then written to a vdata using VSwrite. (See Figure 4b.)
FIGURE 4g Removing Alignment Bytes When Writing Data From a C Structure to a Vdata
EXAMPLE 4. Writing Packed Vdata Data to an HDF File
The following examples write packed data into a vdata. Note that while the memcpy routine is called for each field, the bcopy routine may be used instead.
#include <stdio.h> #include "hdf.h" #define NRECORDS 20 #define FIELD_1 "Temp" #define FIELD_2 "Height" #define FIELD_3 "Speed" #define FIELD_4 "Ident" #define FIELD_NAMES "Temp,Height,Speed,Ident" main( ) { struct { float32 temp; int16 height; float32 speed; char ident; } source[NRECORDS]; int32 file_id, vdata_id; uint8 *pntr; uchar8 *databuf; int i; int32 status; int32 msize = 0; /* Create the HDF file. */ file_id = Hopen("Example4.hdf", DFACC_CREATE, 0); /* Initialize the Vset interface. */ status = Vstart(file_id); /* Create a new vdata. */ vdata_id = VSattach(file_id, -1, "w"); /* Define the field to write. */ status = VSfdefine(vdata_id, FIELD_1, DFNT_FLOAT32, 1); status = VSfdefine(vdata_id, FIELD_2, DFNT_INT16, 1); status = VSfdefine(vdata_id, FIELD_3, DFNT_FLOAT32, 1); status = VSfdefine(vdata_id, FIELD_4, DFNT_CHAR8, 1); /* Set the vdata name. */ status = VSsetname(vdata_id, "Example Vset Name"); /* Set the vdata class. */ status = VSsetclass(vdata_id, "Example Vset Class"); /* Set the field names. */ status = VSsetfields(vdata_id, FIELD_NAMES); databuf = (uint8 *) malloc(((2 * sizeof(float32)) + sizeof(int16) + sizeof(char)) * NRECORDS); pntr = databuf; for (i = 0; i < NRECORDS; i++) { source[i].temp = 1.11 * (i+1); memcpy(pntr, &source[i].temp, sizeof(float32)); pntr += sizeof(float32); source[i].height = i+1; memcpy(pntr, &source[i].height, sizeof(int16)); pntr += sizeof(int16); source[i].speed = 1.11 * (i+1); memcpy(pntr, &source[i].speed, sizeof(float32)); pntr += sizeof(float32); source[i].ident = `A'+i; memcpy(pntr, &source[i].ident, sizeof(char)); pntr += sizeof(char); } /* Write the data to the Vset object. */ status = VSwrite(vdata_id, databuf, NRECORDS, FULL_INTERLACE); /* * Terminate access to the vdata, the VS interface * and the HDF file. */ status = VSdetach(vdata_id); status = Vend(file_id); status = Hclose(file_id); }
PROGRAM DATA PACK integer hopen, vsfatch, vsffdef, vsfsnam integer vsfscls, vsfsfld, vsfwrit, vsfdtch integer hclose, vfstart C Parameter definitions integer*4 DFACC_CREATE, DFNT_FLOAT32, DFNT_INT16, DFNT_CHAR8 integer*4 FULL_INTERLACE parameter (DFACC_CREATE = 4, + DFNT_FLOAT32 = 5, + DFNT_INT16 = 22, + DFNT_CHAR8 = 4, + FULL_INTERLACE = 0) C Example parameters. integer NRECORDS parameter (NRECORDS = 20) C Vdata fields. real temp integer*2 height real speed C Vdata field equivalence names for packing. character ctemp*4 character cheight*2 character cspeed*4 equivalence (temp, ctemp), (height, cheight), (speed, cspeed) C Packing buffer with size (4+2+4+1)*NRECORDS = 220. character buffer*220 C More local variables. integer i, bufptr, status integer*4 file_id, vdata_id character*20 idents /"ABCDEFGHIJKLMNOPQRST"/ C Create the file. file_id = hopen(`Example4.hdf', DFACC_CREATE, 0) C Initialize the interface. status = vfstart(file_id) C Create a new vdata. vdata_id = vsfatch(file_id, -1, `w') C Define the fields to write. status = vsffdef(vdata_id, `Temp', DFNT_FLOAT32, 1) status = vsffdef(vdata_id, `Height', DFNT_INT16, 1) status = vsffdef(vdata_id, `Speed', DFNT_FLOAT32, 1) status = vsffdef(vdata_id, `Ident', DFNT_CHAR8, 1) C Set the vdata name. status = vsfsnam(vdata_id, `Example Vset Name') C Set the vdata class. status = vsfscls(vdata_id, `Example Vset Class') C Set the field names. status = vsfsfld(vdata_id, `Temp,Height,Speed,Ident') C Pack NRECORDS of data into buffer. bufptr = 1 do 10 i = 1, NRECORDS C Pack temp data. temp = 1.1 * i buffer(bufptr:bufptr+3) = ctemp bufptr = bufptr + 4 C Pack height data. height = i buffer(bufptr:bufptr+1) = cheight bufptr = bufptr + 2 C Pack speed data. speed = 11.1 * i buffer(bufptr:bufptr+3) = cspeed bufptr = bufptr + 4 C Pack ident data. buffer(bufptr:bufptr) = idents(i:i) bufptr = bufptr + 1 10 continue status = vsfwrit(vdata_id, buffer, NRECORDS, FULL_INTERLACE) C Terminate access to the vdata object, the interface C and the file. status = vsfdtch(vdata_id) status = vfend(file_id) status = hclose(file_id) end