This section is intended to be a quick overview of reading and writing data sets. For more detailed function descriptions see section 4.11. Setting up a model to write datasets to an XMDF file requires more information than is needed for reading geometry. Part of the reason more information is required is because more of the file organization is created by the model. Another source of complexity is that datasets can be written to either new or existing files.
Individual datasets are grouped in special folders that hold all the datasets for a specific geometry. These folders are called multi-dataset groups. Multi-dataset groups may or may not be in the same file as the geometry. In Figure 6 the multi-data group for the mesh has the path 2DMeshModule/mesh/Datasets. Multi-dataset groups store the GUID of the geometry to which they belong. Within a multi-dataset group, generic groups may be used to organize the data sets. In Figure 6 the folder named Solution under the multi-dataset group is an example of using generic groups to organize data sets. These generic groups would be especially useful for stochastic simulations and could be used to organize the datasets belonging to individual runs.
When writing datasets using XMDF the following items of information are necessary:
- the filename to write the data to
- the path for multi-dataset group to write the datasets
- the GUID for the geometry that the data sets belong to
- the path to a generic group inside the multi-dataset group (may be blank)
- What existing data to clear before saving. If the model is writing to a file that is intended only for solutions for the particular simulation, the entire file should be over-written. If the data sets are to be written to an existing XMDF file, either the folder to write the datasets should be cleared or only existing datasets with the same name as the datasets that will be written should be cleared. Each of these options is supported.
Inside XMDF there is a function to make it easier for models to set up the paths to begin writing data sets. This function takes for arguments the five items mentioned above and returns the File ID and the ID of the group to begin writing datasets to. This function should always be used to setup a model to begin writing data sets using XMDF because it ensures that everything is setup regardless of whether or not the file or the required paths exist. The function is named xfSetupToWriteDatasets.
Once the file id and group id to start writing datasets has been obtained from xfSetupToWriteDatasets, the following steps are used to add each dataset to the file:
- Create the dataset using xfCreateScalarDataset or xfCreateVectorDataset
- If desired, use the function xfDatasetReftime to specify the reference time for the dataset. The reference time is the Julian date for time zero for the dataset. Each timestep is treated as an offset from this reference time.
- For each timestep, set the data using xfWriteScalarTimestep. If necessary, use xfWriteActivityTimestep to set active element information for each timestep.
- Close the dataset using xfCloseGroup.
- When all datasets are closed, close the group that all the datasets are written to using xfCloseGroup and close the file using xfCloseFile.
Often steps 1 and 2 will be done together for all of the datasets to be written at the beginning of the model execution. Then when timesteps are computed, step 3 will be performed for each dataset. When all the timesteps are completed steps 4 and 5 are used to close the file and all the resources.
- Example:
The example below has a function to write a scalar dataset to an XMDF file. The arguments to the function are those included in the xfSetupToWriteDatasets, a compression level (-1 for none). The number of times, time values, number of values per time step, and the values for the dataset are stored in file globals. The function follows the XMDF convention of using negative values to indicate errors.
C/C++
static int fg_nTimes;
static double *fg_Times;
static int fg_nValues;
static float **fg_Values;
int WriteDataset (const char *a_Filename,
const char *a_MultiDatasetsGroupPath,
const char *a_SpatialDataObjectGuid,
int a_OverwriteOption,
int a_Compression)
{
xid xFileId, xDsetsId, xScalarId;
int iTimestep, iActive;
double dTime;
int status;
status = xfSetupToWriteDatasets(a_Filename, a_MultiDatasetsGroupPath,
a_SpatialDataObjectGuid, a_OverwriteOption, &xFileId, &xDsetsId);
if (status < 0) {
printf("Error initializing files to write datasets.");
return status;
}
status = xfCreateScalarDataset(xDsetsId, "Concentration",
"mg/L", TS_HOURS, a_Compression,
&xScalarId);
if (status < 0) {
printf("Error creating scalar datasets.");
xfCloseGroup(xDsetsId);
xfCloseFile(xFileId);
return FALSE;
}
for (iTimestep = 0; iTimestep < fg_nTimes; iTimestep++) {
dTime = fg_Times[iTimestep];
status = xfWriteScalarTimestep(xScalarAId, dTime, fg_nValues,
fg_Values[iTimestep]);
if (status < 0) {
xfCloseGroup(xScalarId);
xfCloseGroup(xDsetsId);
xfCloseFile(xFileId);
return status;
}
}
xfCloseGroup(xScalarId);
xfCloseGroup(xDsetsId);
xfCloseFile(xFileId);
return FALSE;
}
FORTRAN
INTEGER fg_nTimes;
REAL(DOUBLE), ALLOCATABLE :: fg_Times(:)
INTEGER fg_nValues
REAL, ALLOCATABLE :: fg_Values(:,:)
SUBROUTINE WRITE_DATASET (a_Filename,
a_MultiDatasetsGroupPath,
a_SpatialDataOjbectGuid,
a_OverwriteOption,
a_Compression, error)
CHARACTER(LEN=*), INTENT(IN) :: a_Filename, a_MultiDatasetsGroupPath
CHARACTER(LEN=*), INTENT(IN) :: a_SpatialDataObjectGuid
INTEGER, INTENT(IN) :: a_OverwriteOption, a_Compression
INTEGER, INTENT(OUT) :: error
INTEGER(HID_T) xFileId, xDsetsId, xScalarId
INTEGER iTimestep, iActive
REAL(DOUBLE) dTime
REAL, ALLOCATABLE :: Values(:)
call XF_SETUP_TO_WRITE_DATASETS(a_Filename, a_MultiDatasestsGroupPath, &
a_SpatialDataObjectGuid, a_OverwriteOption, &
xFileId, xScalarId, error)
if (error .LT. 0) then
WRITE(*,*) 'Error initializing files to write datasets.'
return
endif
! Create the scalar A dataset group
call XF_CREATE_SCALAR_DATASET(xDsetsId, 'Concentration', 'mg/L', &
TS_HOURS, a_Compression, xScalarAd, error)
if (error .LT. 0) then
! close the dataset
call XF_CLOSE_GROUP(xScalarId, error)
call XF_CLOSE_GROUP(xDsetsId, error)
call XF_CLOSE_FILE(xFileId, error)
return
endif
! allocate the values for an individual timestep
allocate (Values(fg_nValues))
! Loop through timesteps adding them to the file
do iTimestep = 1, fg_nTimes
! We will have an 0.5 hour timestep
dTime = fg_Times(iTimestep)
do iVal = 1, fg_nValues
Values(iVal) = fg_Values(iTimestep, iVal)
enddo
! write the dataset array values
call XF_WRITE_SCALAR_TIMESTEP(xScalarId, dTime, fg_nValues, &
Values, error)
if (error .LT. 0) then
deallocate (Values)
call XF_CLOSE_GROUP(xScalarAId, error)
call XF_CLOSE_GROUP(xDsetsId, error)
call XF_CLOSE_FILE(xFileId, error)
return
endif
enddo
deallocate (Values)
! close the dataset
call XF_CLOSE_GROUP(xScalarAId, error)
call XF_CLOSE_GROUP(xDsetsId, error)
call XF_CLOSE_FILE(xFileId, error)
return
END SUBROUTINE