sandbox/acastillo/output_fields/xdmf/output_xdmf_facets.h
#ifndef OUTPUT_XDMF_FACETS_H
#define OUTPUT_XDMF_FACETS_H
#include "acastillo/output_fields/output_common_helpers_facets.h"
#include "output_xdmf_facets_populate.h"output_facets_xmf(): Exports the VOF interface.
This function writes a surface from field data using the built-in VOF
PLIC surface. Heavy data is stored using the Hierarchical Data Format
HDF5 in parallel. Because the cell sizes vary, it relies on XDMF’s
Mixed topology.
The arguments and their default values are:
- c
- vof scalar field.
- s
- scalar field to store, for instance, curvature.
- subname
- subname to be used for the output file.
- mode
- HDF5 writing mode.
- compression_level
- HDF5 compression level.
trace
void output_facets_xmf(scalar c, scalar s, char *subname, int mode = HDF5_CHUNKED, int compression_level = 6){
#ifdef HAVE_HDF5
hid_t file_id; // HDF5 file ID
hid_t group_id; // HDF5 group ID
hsize_t count[2]; // Hyperslab selection parameters
hsize_t offset[2]; // Offset for hyperslab
// Construct the HDF5 file name
char name[260]; // Buffer for file name construction
snprintf(name, sizeof(name), "%s.h5", subname);
// Obtain the number of vertices and facets
long num_points_loc = 0, num_cells_loc = 0;
long num_points = 0, num_cells = 0;
count_vertices_and_facets(c, &num_points_loc, &num_cells_loc);
// In Mixed topology, each cell requires `2 + m` integers: `[type, m, id1, ..., id_m]`.
// The total 1D size is exactly `2 * num_cells_loc + num_points_loc`.
long topo_size_loc = 2 * num_cells_loc + num_points_loc;
long topo_size = 0;
// Calculate offsets for parallel I/O
long offset_points[npe()], offset_cells[npe()], offset_topo[npe()];
calculate_offsets(offset_points, offset_cells, num_points_loc, num_cells_loc, offset);
// Re-use offset logic for topology size
calculate_offsets2(offset_topo, topo_size_loc, offset);
// Determine global counts
#if _MPI
MPI_Allreduce(&num_points_loc, &num_points, 1, MPI_LONG, MPI_SUM, MPI_COMM_WORLD);
MPI_Allreduce(&num_cells_loc, &num_cells, 1, MPI_LONG, MPI_SUM, MPI_COMM_WORLD);
MPI_Allreduce(&topo_size_loc, &topo_size, 1, MPI_LONG, MPI_SUM, MPI_COMM_WORLD);
#else
num_points = num_points_loc;
num_cells = num_cells_loc;
topo_size = topo_size_loc;
#endif
// Write the light data
if (pid() == 0) {
// Custom logic to write XDMF header, mixed topology, and attributes for facets
char xmf_name[111];
sprintf(xmf_name, "%s.xmf", subname);
FILE *fp = fopen(xmf_name, "w");
write_xdmf_header(fp, name);
fputs("\t<Domain>\n", fp);
fputs("\t\t<Grid Name=\"Unstructured Grid\" GridType=\"Uniform\">\n", fp);
fprintf(fp, "\t\t\t<Time Type=\"Single\" Value=\"%g\" />\n", t);
// Write Mixed Topology
fprintf(fp, "\t\t\t<Topology TopologyType=\"Mixed\" NumberOfElements=\"%ld\">\n", num_cells);
fprintf(fp, "\t\t\t\t<DataItem Format=\"HDF\" Dimensions=\"%ld\" DataType=\"Int\" Precision=\"8\" >\n", topo_size);
fputs("\t\t\t\t\t&HeavyData;/Topology\n", fp);
fputs("\t\t\t\t</DataItem>\n", fp);
fputs("\t\t\t</Topology>\n", fp);
// Write Geometry
fputs("\t\t\t<Geometry GeometryType=\"XYZ\">\n", fp);
fprintf(fp, "\t\t\t\t<DataItem Format=\"HDF\" NumberType=\"Float\" Dimensions=\"%ld 3\" Precision=\"8\" >\n", num_points);
fputs("\t\t\t\t\t&HeavyData;/Geometry/Points\n", fp);
fputs("\t\t\t\t</DataItem>\n", fp);
fputs("\t\t\t</Geometry>\n", fp);
// Write Attribute
fprintf(fp, "\t\t\t<Attribute Name=\"%s\" AttributeType=\"Scalar\" Center=\"Cell\">\n", s.name);
fprintf(fp, "\t\t\t\t<DataItem Dimensions=\"%ld\" NumberType=\"Float\" Precision=\"8\" Format=\"HDF\">\n", num_cells);
fprintf(fp, "\t\t\t\t\t&HeavyData;/Cells/%s\n", s.name);
fputs("\t\t\t\t</DataItem>\n", fp);
fputs("\t\t\t</Attribute>\n", fp);
write_xdmf_footer(fp);
fflush(fp);
fclose(fp);
}
// Write the heavy data
file_id = create_hdf5_file(name);
if (file_id < 0) return; // Exit if file creation failed
// Centralized chunk size calculation
hsize_t chunk_size = compute_chunk_size(topo_size);
// Populate and write the topology dataset
long *topo_dset;
populate_topo_dset_facets_xdmf(c, &topo_dset, topo_size_loc, offset_topo, offset_points, count, offset);
write_dataset(file_id, count, offset, "/Topology", topo_size, topo_size_loc, 1, topo_dset, H5T_NATIVE_LONG, mode, chunk_size, compression_level);
free(topo_dset);
// Create group for mesh geometry data
group_id = H5Gcreate(file_id, "Geometry", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
// Populate and write the points dataset
double *points_dset;
populate_points_dset_facets_xdmf(c, &points_dset, num_points_loc, offset_points, count, offset);
write_dataset(group_id, count, offset, "/Geometry/Points", num_points, num_points_loc, 3, points_dset, H5T_NATIVE_DOUBLE, mode, compute_chunk_size(num_points), compression_level);
free(points_dset);
H5Gclose(group_id);
// Create group for cell data
group_id = H5Gcreate(file_id, "Cells", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
// Allocate memory and write scalar datasets
double *scalar_dset = (double *)malloc(num_cells_loc * sizeof(double));
char substamp[1024];
sprintf(substamp, "/Cells/%s", s.name);
populate_scalar_dset_facets_xdmf(c, s, scalar_dset, num_cells_loc, offset_cells, count, offset);
write_dataset(group_id, count, offset, substamp, num_cells, num_cells_loc, 1, scalar_dset, H5T_NATIVE_DOUBLE, mode, compute_chunk_size(num_cells), compression_level);
free(scalar_dset);
H5Gclose(group_id);
// Close HDF5 resources
H5Fflush(file_id, H5F_SCOPE_GLOBAL);
H5Fclose(file_id);
#else
// HDF5 not available - print warning and return
static int warning_printed = 0;
if (!warning_printed && pid() == 0) {
fprintf(stderr, "Warning: output_facets_xmf() called but HDF5 is not available. Output skipped.\n");
warning_printed = 1;
}
#endif
}
#endif // OUTPUT_XDMF_FACETS_H