Write the data for a field

saf_write_field is a function defined in field.c.

Synopsis:

int saf_write_field(SAF_ParMode pmode, SAF_Field *field, int member_count, SAF_RelRep *req_type, int *member_ids, int nbufs, hid_t buf_type, void **bufs, SAF_Db *file)

Formal Arguments:

  • pmode: The parallel mode.
  • field: The field to write.
  • member_count: A count of the number of members of the collection in which the field’s dofs are n:1 associated that are actually being written in this call. This value is ignored if you are writing the entire field’s dofs in this call (i.e., req_type is SAF__TOTALITY). Also note that as a convenience, we provide the macro SAF__WHOLE_FIELD which expands to a comma separated list of appropriate values for this argument and the next two, for the case in which the whole field is being written in this call.
  • req_type: The type of I/O request. We use a relation representation type here to specify the type of the partial request because it captures the necessary information. Pass SAF__HSLAB if you are writing the dofs of a partial hyperslab of the members of the associated collection. In this case, member_ids points to 3 N-tuples of starts, counts and strides of the hyperslab (hypersample) request. Pass SAF__TUPLES, if you are writing the dofs for an arbitrary list of members of the associated collection. In this case, the member_ids points to a list of N-tuples. In both cases, ‘N’ is the number of indexing dimensions in the associated collection. Finally, pass SAF__TOTALITY if you are writing the entire field’s set of dofs.
  • member_ids: Depending on the value of req_type, this argument points to 3 N-tuples storing, respectively, the starts, counts and strides in each dimension of the associated collection or to a list of member_count N-tuples, each one identifying a single member of the associated collection or to NULL in the case of a SAF__TOTALITY request.
  • nbufs: The number of buffers. Valid values are either 1 or a value equal to the number of components of the field. A value greater than 1 indicates that the field is stored component by component, one buffer for each component. Note, however, that current limitations of partial requests support only fields that are interleaved by SAF__INTERLEAVE_VECTOR. This, in turn, means that in a partial I/O request, nbufs can only ever be one.
  • buf_type: The type of the objects in the buffer(s). If the buffer datatype was provided in the saf_declare_field call that produced the field handle then this parameter should have a negative value. If however the datatype was not provided in the saf_declare_field or if the handle was the result of a find operation then the datatype must be provided in this call.
  • bufs: The buffers.
  • file: Optional file into which the data is written. If none is supplied then the data is written to the same file as the field.

Description: This function is used to write a field’s data. If the field is not an indirect reference to other fields, this call involves real disk I/O. All functions in SAF with either “read” or “write” in the name potentially involve real disk I/O.

This function allows a client to write either the entire field’s data or a portion of the field’s data. Recall that the degrees of freedom (dofs) of a field are n:1 associated with the members of some collection in the set upon which the field is defined. We call this collection the associated collection.

In order to specify a partial request, the client is required to specify which members of the associated collection it is writing the dofs for. Ultimately, those members may be specified using a N dimensional hyperslab (or hypersample) or an arbitrary list of N-tuples. In either case, the number of dimensions, ‘N’, is the number of indexing dimensions in the associated collection.

At present, there are several limitations. First, the collection must be 1 dimensionally indexed. Next, only the hyperslab mode or a single member in tuple-mode are supported, not hypersamples and not an arbitrary list. Finally, if the field is a multi-component field, then the only supported interleave mode is SAF__INTERLEAVE_VECTOR.

For indirect fields, the notion of writing on the composite or component fields is lost. On an indirect, composite field, the values written must be handles to other composite fields. Likewise for its component fields. The values written must be handles for other component fields.

Finally, we provide as a convenience the macro SAF__WHOLE_FIELD which expands to a comma separated list of values, 0, SAF__TOTALITY, NULL, for the three arguments member_count, req_type, member_ids for the case in which the client is writing the whole field in this call.

Preconditions:

  • pmode must be valid. (low-cost)
  • field must be a valid field handle. (low-cost)
  • bufs must be specified here or in the saf_declare_field call (not both). (low-cost)
  • Pass either valid bufs and nbufs``>0 or ``NULL and ``nbufs``==0. (low-cost)
  • If partial I/O request, collection must be 1D indexed, req_type must be SAF__HSLAB. (high-cost)
  • Buffer datatype must be specified in field declaration or write. (low-cost)
  • Buffer datatype must be consistent between field declaration and write. (low-cost)

Return Value: The constant SAF__SUCCESS is returned when this function is successful. Otherwise this function either returns an error number or throws an exception, depending on the value of the library’s error handling property.

Parallel Notes: SAF_EACH mode is a collective call where each of the N tasks provides a unique relation. SAF will create a single HDF5 dataset to hold all the data and will create N blobs to point into nonoverlapping regions in that dataset. In SAF__EACH mode the call must still be collective across the file communicator (or the communicator of the dataset to which field belongs if file is null). This requirement is due to the fact that an HDF5 dataset may need to be created and such an operation is collective.

Issues: A partial I/O request looks a lot like a subset relation. In fact, we even use the same data type, SAF__SRType, to identify the type of partial I/O request. It may be difficult for a client to distinguish between making a partial I/O request and making real subsets. In theory, there really should be no difference. The act of writing a portion of a field is the act of defining a subset of the base space the field is defined on and then restricting the field to that subset. In the current implementation, this requires, at a minimum, the ability to create transient objects such as the subset representing the piece of the field being written in this call. In addition, it really requires decoupling the storage containers into which field’s data goes from declaring and writing fields.

For a compound data-type on a composite field, we probably ought to confirm a) the rank of the compound type is equal to the number of components, b) the type of each member of the compound type is equal to the type of each of the component fields (assuming both are ordered the same), and c) the names of the member types are the same as the component fields. Currently we are only checking a).

Computing the actual size of the I/O request here is NO SMALL TASK. It depends on a combination of factors including the number of buffers, the number of members whose dofs are being written, the association ratio, the data-type and whether the field is direct or indirect.

Is it possible that a SAF__EACH call will have a different offset and data for each task? If so we’ll have to do some communicating first otherwise :file:`ss_file_synchronize ../sslib_refman.rest/ss_file_synchronize.rst` will see that each task made incompatible modifications to this object. This code just checks that for now. [rpm 2004-06-07]

See Also: