Click here to Skip to main content
15,893,814 members
Articles / High Performance Computing / Parallel Processing

Parallel I/O using Parallel HDF5

Rate me:
Please Sign up or sign in to vote.
4.67/5 (7 votes)
25 Apr 2013CPOL7 min read 34.6K   20  
Design and implementation of the parallel I/O of a CFD code
// written by Hoi Yen Loo, 1 September 2012 - 31 March 2013

#include <algorithm>

using std::string;
using std::stringstream;
using std::max;
using std::map;

#define TIME_LENGTH 10

// read in and write out structs for HDF treating
typedef struct {
	DT_INDEX init_grid_spac[3]; // initial grid spacings for top level grid
	DT_INDEX refine_grid_spac[3]; //  grid spacings for adaptive refinement
	DT_INDEX block_size[3]; // block size for each grid
	DT_VAL current_time;	// current time
	DT_VAL vis_time; // time interval in which to visualize data
	DT_VAL dt; // time discretisation step
	DT_VAL end_time; // end time of computation
	DT_VAL alpha; // heat diffusion coefficient
	DT_VAL mu; // dynamic viscosity of the fluid
	DT_VAL g[3]; // gravitational force
	DT_VAL err_tol; // maxmimal error tolerance in Jacoby-Step
	DT_INDEX max_iter; // maximal amount of iterations in Jacoby-Step
	DT_VAL omega; // SOR relaxation
	DT_TYPE write_vtk_result_array[CE_ARRAY_SIZE]; // vtk visualization selection
} fdomain_data;

typedef struct {
	DT_TAG mytag; // grid mytag
	DT_UID supergrid_uid; // uid of supergrid
	DT_DEPTH depth; // depth of the grid
	DT_TYPE ref_type; // indicate whether the grid is refined
	DT_INDEX n[3]; // block size of the grid
	DT_INDEX size_subgrids[3]; // size of the subgrid
} fgrid_data;

FHDF::FHDF(const MPI_Comm &_comm, const int &_comp_size, const int &_rank, FDomain *_domain, bool &success) :
		comm(_comm), comp_size(_comp_size), rank(_rank), domain(_domain), amount_nxyz_incl_ghost(0), first_write(true), latest_time(0) {

	#ifdef USE_HDF5
		if (H5open() < 0) {
			if (rank == 0) printf("Error-HDF5: The HDF5 library at rank %i could not be initialized!\n", rank);
			success = false;
			return;

		} else {
			// grid compound datatype
			hsize_t vector_dim[] = {3};
			hid_t vector_DT_INDEX_tid = H5Tarray_create(DT_INDEX_HDF, 1, vector_dim);

			grid_tid = H5Tcreate (H5T_COMPOUND, sizeof(FGrid));
			H5Tinsert(grid_tid, "mytag", HOFFSET(FGrid, mytag), DT_TAG_HDF);
			H5Tinsert(grid_tid, "supergrid_uid", HOFFSET(FGrid, supergrid_uid), DT_UID_HDF);
			H5Tinsert(grid_tid, "depth", HOFFSET(FGrid, depth), DT_DEPTH_HDF);
			H5Tinsert(grid_tid, "ref_type", HOFFSET(FGrid, ref_type), DT_TYPE_HDF);
			H5Tinsert(grid_tid, "n", HOFFSET(FGrid, n), vector_DT_INDEX_tid);
			H5Tinsert(grid_tid, "size_subgrids", HOFFSET(FGrid, size_subgrids), vector_DT_INDEX_tid);
			H5Tclose(vector_DT_INDEX_tid);

			domain->fhdf = this;
		}

	#endif

	success = true;
}

FHDF::~FHDF() {

	#ifdef USE_HDF5

		H5Tclose(grid_tid);
		H5Pclose(parallel_dataset_pid);

	#endif
}

void FHDF::setFilename(std::string _filename) {
	filename = _filename;
}

bool FHDF::writeHDF5(int *offset_array) {

	if (!fabs(domain->current_time - latest_time) < 1e-5) {
		if (!writeGridData(offset_array)) return false;

	} else if (first_write) {
		if (!writeDomainData(offset_array)) return false;
	}

	return true;

}

inline void FHDF::defineConstant() {

	#ifdef USE_HDF5

		amount_nxyz_incl_ghost = (domain->block_size[X] + 2) * (domain->block_size[Y] + 2) * (domain->block_size[Z] + 2);

		max_subgrid = max(domain->init_grid_spac[X] * domain->init_grid_spac[Y] * domain->init_grid_spac[Z],
						  domain->refine_grid_spac[X] * domain->refine_grid_spac[Y] * domain->refine_grid_spac[Z]);

	#endif

}

bool FHDF::createFile() {

	#ifdef USE_HDF5

		hid_t parallel_file_pid = H5Pcreate(H5P_FILE_ACCESS);
		H5Pset_fapl_mpio(parallel_file_pid, comm, MPI_INFO_NULL);
		file_fid = H5Fcreate(filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, parallel_file_pid);
		H5Pclose(parallel_file_pid);

		parallel_dataset_pid = H5Pcreate(H5P_DATASET_XFER);
		H5Pset_dxpl_mpio(parallel_dataset_pid, H5FD_MPIO_COLLECTIVE);

		// write HDF5_FILE_VERSION and number of computation processes
		common_gid = H5Gcreate(file_fid, "/common", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);

		hid_t file_version_sid = H5Screate(H5S_SCALAR);
		hid_t file_version_aid = H5Acreate(file_fid, "HDF5_DATA_VERSION", DT_TYPE_HDF, file_version_sid, H5P_DEFAULT, H5P_DEFAULT);
		DT_TYPE file_version = HDF5_FILE_VERSION;
		if (H5Awrite(file_version_aid, DT_TYPE_HDF, &file_version) < 0) {
			if (rank == 0) printf("ERROR: %s: Could not write HDF5_DATA_VERSION to HDF5!\n", filename.c_str());
			return false;
		}
		H5Sclose(file_version_sid);
		H5Aclose(file_version_aid);

		hid_t comp_size_sid = H5Screate(H5S_SCALAR);
		hid_t comp_size_aid = H5Acreate(file_fid, "SIZE", DT_RANK_HDF, comp_size_sid, H5P_DEFAULT, H5P_DEFAULT);
		if (H5Awrite(comp_size_aid, DT_RANK_HDF, &comp_size) < 0) {
			if (rank == 0)printf("ERROR: %s: Could not write SIZE to HDF5!\n", filename.c_str());
			return false;
		}
		H5Sclose(comp_size_sid);
		H5Aclose(comp_size_aid);

	#endif

	return true;

}

bool FHDF::writeDomainData(const int *offset_array) {

	#ifndef USE_HDF5
		if (rank == 0) {
			printf("WARNING-WRITING HDF5: %s: No writing to %s because HDF5 capabilities is not activated!\n", filename.c_str(), filename.c_str() );
		}
		return true;
	#else

		createFile();

		hid_t domain_sid = H5Screate(H5S_SCALAR);

		// domain datatype
		hsize_t vector_dim[] = { 3 };
		hid_t domain_vector_DT_INDEX_tid = H5Tarray_create(DT_INDEX_HDF, 1, vector_dim);
		hid_t domain_array_DT_VAL_tid = H5Tarray_create(DT_VAL_HDF, 1, vector_dim);

		hsize_t array_vis_dim[] = { CE_ARRAY_SIZE };
		hid_t domain_array_DT_TYPE_tid = H5Tarray_create(DT_TYPE_HDF, 1, array_vis_dim);

		hid_t domain_tid = H5Tcreate (H5T_COMPOUND, sizeof(FDomain));
		H5Tinsert(domain_tid, "init_grid_spac", HOFFSET(FDomain, init_grid_spac), domain_vector_DT_INDEX_tid);
		H5Tinsert(domain_tid, "refine_grid_spac", HOFFSET(FDomain, refine_grid_spac), domain_vector_DT_INDEX_tid);
		H5Tinsert(domain_tid, "block_size", HOFFSET(FDomain, block_size), domain_vector_DT_INDEX_tid);
		H5Tinsert(domain_tid, "current_time", HOFFSET(FDomain, current_time), DT_VAL_HDF);
		H5Tinsert(domain_tid, "vis_time", HOFFSET(FDomain, vis_time), DT_VAL_HDF);
		H5Tinsert(domain_tid, "dt", HOFFSET(FDomain, dt), DT_VAL_HDF);
		H5Tinsert(domain_tid, "end_time", HOFFSET(FDomain, end_time), DT_VAL_HDF);
		H5Tinsert(domain_tid, "alpha", HOFFSET(FDomain, alpha), DT_VAL_HDF);
		H5Tinsert(domain_tid, "mu", HOFFSET(FDomain, mu), DT_VAL_HDF);
		H5Tinsert(domain_tid, "g", HOFFSET(FDomain, g), domain_array_DT_VAL_tid);
		H5Tinsert(domain_tid, "err_tol", HOFFSET(FDomain, err_tol), DT_VAL_HDF);
		H5Tinsert(domain_tid, "max_iter", HOFFSET(FDomain, max_iter), DT_INDEX_HDF);
		H5Tinsert(domain_tid, "omega", HOFFSET(FDomain, omega), DT_VAL_HDF);
		H5Tinsert(domain_tid, "write vtk result array", HOFFSET(FDomain, write_vtk_result_array), domain_array_DT_TYPE_tid);
		H5Tclose(domain_vector_DT_INDEX_tid);
		H5Tclose(domain_array_DT_VAL_tid);
		H5Tclose(domain_array_DT_TYPE_tid);

		hid_t domain_did = H5Dcreate(common_gid, "domain property", domain_tid, domain_sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);

		if (H5Dwrite(domain_did, domain_tid, domain_sid, H5S_ALL, H5P_DEFAULT, domain) < 0) {
			if (rank == 0) printf("ERROR: %s: Could not write domain data to HDF5!\n", filename.c_str());
			return false;
		}

		H5Tclose(domain_tid);
		H5Dclose(domain_did);
		H5Sclose(domain_sid);

		H5Gclose(common_gid);

		// create simulation group
		simulation_gid = H5Gcreate(file_fid, "/simulation", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);

		defineConstant();

		writeGridData(offset_array);

		return true;

	#endif

}

bool FHDF::writeGridData(const int *offset_array) {

	#ifdef USE_HDF5

		if (!first_write) {
			hid_t parallel_file_pid = H5Pcreate(H5P_FILE_ACCESS);
			H5Pset_fapl_mpio(parallel_file_pid, comm, MPI_INFO_NULL);
			file_fid = H5Fopen(filename.c_str(), H5F_ACC_RDWR, parallel_file_pid);
			H5Pclose(parallel_file_pid);

			simulation_gid = H5Gopen(file_fid, "/simulation", H5P_DEFAULT);
		}

		latest_time = domain->current_time;

		// write current time step for restarting simulation
		stringstream ss;
		ss << "/simulation/" << domain->current_time;
		string time_str = ss.str();

		// write latest time for restarting simulation
		ss.str("");
		ss << domain->current_time;

		char time_char[TIME_LENGTH];
		strcpy((char *)&time_char, ss.str().c_str());
		hid_t time_tid = H5Tcopy(H5T_C_S1);
		H5Tset_size(time_tid, TIME_LENGTH);

		hid_t time_sid;
		hid_t time_aid;
		if (first_write) {
			time_sid = H5Screate(H5S_SCALAR);
			time_aid = H5Acreate(simulation_gid, "TIME", time_tid, time_sid, H5P_DEFAULT, H5P_DEFAULT);
			first_write = false;

		} else {
			time_aid = H5Aopen(simulation_gid, "TIME", H5P_DEFAULT);
			time_sid = H5Aget_space(time_aid);
		}

		if (H5Awrite(time_aid, time_tid, time_char) < 0) {
			if (rank == 0) printf("ERROR: %s: Could not write TIME to HDF5!\n", filename.c_str());
			return false;
		}
		H5Tclose(time_tid);
		H5Sclose(time_sid);
		H5Aclose(time_aid);

		// write time group
		hid_t time_gid = H5Gcreate(file_fid, time_str.c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);

		// write offset array for restarting simulation
		hsize_t offset_array_dim = comp_size + 2;
		hid_t offset_array_sid = H5Screate_simple(1, &offset_array_dim, NULL);
		hid_t offset_array_aid = H5Acreate(time_gid, "OFFSET ARRAY", DT_RANK_HDF, offset_array_sid, H5P_DEFAULT, H5P_DEFAULT);
		if (H5Awrite(offset_array_aid, DT_RANK_HDF, &(offset_array)[0]) < 0) {
			if (rank == 0) printf("ERROR: %s: Could not write OFFSET ARRAY to HDF5!\n", filename.c_str());
			return false;;
		}
		H5Sclose(offset_array_sid);
		H5Aclose(offset_array_aid);

		// write time in DT_VAL for setting domain->current_time
		hid_t time_DT_VAL_sid = H5Screate(H5S_SCALAR);
		hid_t time_DT_VAL_aid = H5Acreate(time_gid, "TIME", DT_VAL_HDF, time_DT_VAL_sid, H5P_DEFAULT, H5P_DEFAULT);
		H5Awrite(time_DT_VAL_aid, DT_VAL_HDF, &(domain->current_time));
		H5Sclose(time_DT_VAL_sid);
		H5Aclose(time_DT_VAL_aid);

		// write grid information
		hsize_t grid_dim[] = { offset_array[comp_size], 1 };
		hsize_t bbox_dim[] = { offset_array[comp_size], 6 };
		hsize_t subgrid_dim[] = { offset_array[comp_size], max_subgrid };
		hsize_t cell_data_dim[] = { offset_array[comp_size], amount_nxyz_incl_ghost * CE_ARRAY_SIZE };
		hsize_t temp_cell_data_dim[] = { offset_array[comp_size], amount_nxyz_incl_ghost * CT_TEMP_ARRAY_SIZE };
		hsize_t cell_type_dim[] = { offset_array[comp_size], amount_nxyz_incl_ghost };

		hid_t grid_sid = H5Screate_simple(2, grid_dim, NULL);
		hid_t bbox_sid = H5Screate_simple(2, bbox_dim, NULL);
		hid_t subgrid_sid = H5Screate_simple(2, subgrid_dim, NULL);
		hid_t current_cell_data_sid = H5Screate_simple(2, cell_data_dim, NULL);
		hid_t previous_cell_data_sid = H5Screate_simple(2, cell_data_dim, NULL);
		hid_t temp_cell_data_sid = H5Screate_simple(2, temp_cell_data_dim, NULL);
		hid_t cell_type_sid = H5Screate_simple(2, cell_type_dim, NULL);

		hid_t grid_did = H5Dcreate(time_gid, "grid property", grid_tid, grid_sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
		hid_t bbox_did = H5Dcreate(time_gid, "bounding box", DT_GEOM_HDF, bbox_sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
		hid_t subgrid_did = H5Dcreate(time_gid, "subgrid uid", DT_UID_HDF, subgrid_sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
		hid_t current_cell_data_did = H5Dcreate(time_gid, "current cell data", DT_VAL_HDF, current_cell_data_sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
		hid_t previous_cell_data_did = H5Dcreate(time_gid, "previous cell data", DT_VAL_HDF, previous_cell_data_sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
		hid_t temp_cell_data_did = H5Dcreate(time_gid, "temp cell data", DT_VAL_HDF, temp_cell_data_sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
		hid_t cell_type_did = H5Dcreate(time_gid, "cell type", DT_TYPE_HDF, cell_type_sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);

		grid_dim[0] = 1;
		bbox_dim[0] = 1;
		subgrid_dim[0] = 1;
		cell_data_dim[0] = 1;
		temp_cell_data_dim[0] = 1;
		cell_type_dim[0] = 1;
		hsize_t write_grid_offset[] = { offset_array[rank], 0 };

		int grid_each_rank = domain->all_grids.size();

		hid_t grid_memspace_sid;
		hid_t bbox_memspace_sid;
		hid_t subgrid_memspace_sid;
		hid_t current_cell_data_memspace_sid;
		hid_t previous_cell_data_memspace_sid;
		hid_t temp_cell_data_memspace_sid;
		hid_t cell_type_memspace_sid;

		hid_t grid_filespace_sid;
		hid_t bbox_filespace_sid;
		hid_t subgrid_filespace_sid;
		hid_t current_cell_data_filespace_sid;
		hid_t previous_cell_data_filespace_sid;
		hid_t temp_cell_data_filespace_sid;
		hid_t cell_type_filespace_sid;

		// -----------------------------------------------------
		// write grid data
		//------------------------------------------------------
		map<DT_GRIDID, FGrid*>::const_iterator grid_it = domain->all_grids.begin();
		for (int num_grid = 0; num_grid != offset_array[comp_size + 1]; ++num_grid) {

			grid_filespace_sid = H5Dget_space(grid_did);
			bbox_filespace_sid = H5Dget_space(bbox_did);
			current_cell_data_filespace_sid = H5Dget_space(current_cell_data_did);
			previous_cell_data_filespace_sid = H5Dget_space(previous_cell_data_did);
			temp_cell_data_filespace_sid = H5Dget_space(temp_cell_data_did);
			cell_type_filespace_sid = H5Dget_space(cell_type_did);

			FGrid *grid = 0;
			DT_GEOM *bbox = 0;
			DT_VAL *current_cell_data = 0;
			DT_VAL *previous_cell_data = 0;
			DT_VAL *temp_cell_data = 0;
			DT_TYPE *cell_type = 0;

			if (num_grid < grid_each_rank) {

				grid = &(grid_it->second)[0];
				bbox = &(grid_it->second->bbox)[0];
				current_cell_data = &(grid_it->second->array_val_current)[0];
				previous_cell_data = &(grid_it->second->array_val_previous)[0];
				temp_cell_data = &(grid_it->second->array_val_temp)[0];
				cell_type = &(grid_it->second->array_type)[0];

			} else {
				grid_dim[0] = grid_dim[1] = 0;
				bbox_dim[0] = bbox_dim[1] = 0;
				subgrid_dim[0] = subgrid_dim[1] = 0;
				cell_data_dim[0] = cell_data_dim[1] = 0;
				temp_cell_data_dim[0] = temp_cell_data_dim[1] = 0;
				cell_type_dim[0] = cell_type_dim[1] = 0;
				write_grid_offset[0] = write_grid_offset[1] = 0;
			}

			grid_memspace_sid = H5Screate_simple(2, grid_dim, NULL);
			bbox_memspace_sid = H5Screate_simple(2, bbox_dim, NULL);
			current_cell_data_memspace_sid = H5Screate_simple(2, cell_data_dim, NULL);
			previous_cell_data_memspace_sid = H5Screate_simple(2, cell_data_dim, NULL);
			temp_cell_data_memspace_sid = H5Screate_simple(2, temp_cell_data_dim, NULL);
			cell_type_memspace_sid = H5Screate_simple(2, cell_type_dim, NULL);

			H5Sselect_hyperslab(grid_filespace_sid, H5S_SELECT_SET, write_grid_offset, NULL, grid_dim, NULL);
			H5Sselect_hyperslab(bbox_filespace_sid, H5S_SELECT_SET, write_grid_offset, NULL, bbox_dim, NULL);
			H5Sselect_hyperslab(current_cell_data_filespace_sid, H5S_SELECT_SET, write_grid_offset, NULL, cell_data_dim, NULL);
			H5Sselect_hyperslab(previous_cell_data_filespace_sid, H5S_SELECT_SET, write_grid_offset, NULL, cell_data_dim, NULL);
			H5Sselect_hyperslab(temp_cell_data_filespace_sid, H5S_SELECT_SET, write_grid_offset, NULL, temp_cell_data_dim, NULL);
			H5Sselect_hyperslab(cell_type_filespace_sid, H5S_SELECT_SET, write_grid_offset, NULL, cell_type_dim, NULL);

			if (H5Dwrite(grid_did, grid_tid, grid_memspace_sid, grid_filespace_sid, parallel_dataset_pid, &grid[0]) < 0) {
				if (rank == 0) printf("ERROR: %s: Could not write grid property to HDF5!\n", filename.c_str());
				return false;
			}
			if (H5Dwrite(bbox_did, DT_GEOM_HDF, bbox_memspace_sid, bbox_filespace_sid, parallel_dataset_pid, bbox) < 0) {
				if (rank == 0) printf("ERROR: %s: Could not write bounding box to HDF5!\n", filename.c_str());
				return false;
			}
			if (H5Dwrite(current_cell_data_did, DT_VAL_HDF, current_cell_data_memspace_sid, current_cell_data_filespace_sid, parallel_dataset_pid, &current_cell_data[0]) < 0) {
				if (rank == 0) printf("ERROR: %s: Could not write current cell data to HDF5!\n", filename.c_str());
				return false;
			}
			if (H5Dwrite(previous_cell_data_did, DT_VAL_HDF, previous_cell_data_memspace_sid, previous_cell_data_filespace_sid, parallel_dataset_pid, &previous_cell_data[0]) < 0) {
				if (rank == 0) printf("ERROR: %s: Could not write previous cell data to HDF5!\n", filename.c_str());
				return false;
			}
			if (H5Dwrite(temp_cell_data_did, DT_VAL_HDF, temp_cell_data_memspace_sid, temp_cell_data_filespace_sid, parallel_dataset_pid, &temp_cell_data[0]) < 0) {
				if (rank == 0) printf("ERROR: %s: Could not write temp cell data to HDF5!\n", filename.c_str());
				return false;
			}
			if (H5Dwrite(cell_type_did, DT_TYPE_HDF, cell_type_memspace_sid, cell_type_filespace_sid, parallel_dataset_pid, &cell_type[0]) < 0) {
				if (rank == 0) printf("ERROR: %s: Could not write cell type to HDF5!\n", filename.c_str());
				return false;
			}

			H5Sclose(grid_filespace_sid);
			H5Sclose(grid_memspace_sid);
			H5Sclose(bbox_filespace_sid);
			H5Sclose(bbox_memspace_sid);
			H5Sclose(current_cell_data_filespace_sid);
			H5Sclose(current_cell_data_memspace_sid);
			H5Sclose(previous_cell_data_filespace_sid);
			H5Sclose(previous_cell_data_memspace_sid);
			H5Sclose(temp_cell_data_filespace_sid);
			H5Sclose(temp_cell_data_memspace_sid);
			H5Sclose(cell_type_filespace_sid);
			H5Sclose(cell_type_memspace_sid);

			// -----------------------------------------------------
			// write subgrid_uid
			//------------------------------------------------------
			DT_UID *write_subgrid = 0;

			int counter = 0;
			int subgrid_each_grid = 0;
			if (num_grid < grid_each_rank) {
				subgrid_each_grid = grid_it->second->subgrids_uid.size();
			}

			if(subgrid_each_grid != 0) {
				write_subgrid = (DT_UID *) calloc (max_subgrid, sizeof(DT_UID));

				DT_GRIDHASH ghash = 0;
				std::map<DT_GRIDHASH,DT_UID>::const_iterator sgit;
				for(DT_INDEX i = 0; i < grid_it->second->size_subgrids[X]; ++i) {
					for(DT_INDEX j = 0; j < grid_it->second->size_subgrids[Y]; ++j) {
						for(DT_INDEX k = 0; k < grid_it->second->size_subgrids[Z]; ++k) {
							ghash = UID::computeGridHash(i,j,k);

							sgit = grid_it->second->subgrids_uid.find(ghash);
							if(sgit == grid_it->second->subgrids_uid.end()) {
								printf("WARNING: Unable to find subgrid with hash %u\n", ghash);
							}

							write_subgrid[counter] = sgit->second;
							++counter;

						}
					}
				}
			}

			subgrid_filespace_sid = H5Dget_space(subgrid_did);

			if (subgrid_each_grid != 0) {
				subgrid_dim[0] = 1;
				subgrid_dim[1] = max_subgrid;

			} else {
				subgrid_dim[0] = subgrid_dim[1] = 0;
			}

			H5Sselect_hyperslab(subgrid_filespace_sid, H5S_SELECT_SET, write_grid_offset, NULL, subgrid_dim, NULL);

			subgrid_memspace_sid = H5Screate_simple(2, subgrid_dim, NULL);
			if (H5Dwrite(subgrid_did, DT_UID_HDF, subgrid_memspace_sid, subgrid_filespace_sid, parallel_dataset_pid, &(write_subgrid)[0]) < 0) {
				if (rank == 0) printf("ERROR: %s: Could not write subgrid uid to HDF5!\n", filename.c_str());
				return false;
			}

			H5Sclose(subgrid_filespace_sid);
			H5Sclose(subgrid_memspace_sid);

			if (write_subgrid != 0) free(write_subgrid);

			// -----------------------------------------------------
			// finish writing subgrid_uid for a particular grid
			// -----------------------------------------------------

			++write_grid_offset[0];
			++grid_it;

		}
		// -----------------------------------------------------
		// finish writing grid data
		//------------------------------------------------------

		H5Dclose(grid_did);
		H5Sclose(grid_sid);

		H5Dclose(bbox_did);
		H5Sclose(bbox_sid);

		H5Dclose(subgrid_did);
		H5Sclose(subgrid_sid);

		H5Dclose(current_cell_data_did);
		H5Sclose(current_cell_data_sid);

		H5Dclose(previous_cell_data_did);
		H5Sclose(previous_cell_data_sid);

		H5Dclose(temp_cell_data_did);
		H5Sclose(temp_cell_data_sid);

		H5Dclose(cell_type_did);
		H5Sclose(cell_type_sid);

		H5Gclose(time_gid);
		H5Gclose(simulation_gid);
		H5Fclose(file_fid);

	#endif

	return true;
}

bool FHDF::readHDF5() {

	#ifndef USE_HDF5

		if (rank == 0) {
			printf("ERROR-READING HDF5: %s: No reading from %s because HDF5 capabilities is not activated!\n",
					filename.c_str(), filename.c_str() );
		}
	return false;
	#else

		hid_t parallel_file_pid = H5Pcreate(H5P_FILE_ACCESS);
		H5Pset_fapl_mpio(parallel_file_pid, comm, MPI_INFO_NULL);
		hid_t read_file_fid = H5Fopen(filename.c_str(), H5F_ACC_RDWR, parallel_file_pid);
		H5Pclose(parallel_file_pid);

		parallel_dataset_pid = H5Pcreate(H5P_DATASET_XFER);
		H5Pset_dxpl_mpio(parallel_dataset_pid, H5FD_MPIO_COLLECTIVE);

		// check file version
		hid_t file_version_aid = H5Aopen(read_file_fid, "HDF5_DATA_VERSION", H5P_DEFAULT);
		DT_TYPE file_version;
		H5Aread(file_version_aid, DT_TYPE_HDF, &file_version);
		H5Aclose(file_version_aid);

		if (file_version != HDF5_FILE_VERSION) {
			if (rank == 0) {
				printf("ERROR-READING HDF5: %s: Mismatch between file version of %s and HDF5_FILE_VERSION of the code!\n"
						"      Please rerun the simulation with the correct file version!\n", filename.c_str(), filename.c_str() );
			}
			return false;
		}

		// check number of processes
		hid_t size_aid = H5Aopen(read_file_fid, "SIZE", H5P_DEFAULT);
		DT_RANK size;
		H5Aread(size_aid, DT_RANK_HDF, &size);
		H5Aclose(size_aid);

		if (size != comp_size) {
			if (rank == 0) {
				printf("ERROR-READING HDF5: %s: Mismatch between number of available processes and number of processes required for the grid distribution!\n"
						"      Please rerun the simulation with %i computation processes!\n", filename.c_str(), size );
			}
			return false;
		}

		// -----------------------------------------------------
		// read domain data
		// -----------------------------------------------------

		hsize_t vector_dim[] = { 3 };
		hid_t domain_vector_DT_INDEX_tid = H5Tarray_create(DT_INDEX_HDF, 1, vector_dim);
		hid_t domain_array_DT_VAL_tid = H5Tarray_create(DT_VAL_HDF, 1, vector_dim);

		hsize_t array_vis_dim[] = { CE_ARRAY_SIZE };
		hid_t domain_array_DT_TYPE_tid = H5Tarray_create(DT_TYPE_HDF, 1, array_vis_dim);

		hid_t domain_tid = H5Tcreate (H5T_COMPOUND, sizeof(fdomain_data));
		H5Tinsert(domain_tid, "init_grid_spac", HOFFSET(fdomain_data, init_grid_spac), domain_vector_DT_INDEX_tid);
		H5Tinsert(domain_tid, "refine_grid_spac", HOFFSET(fdomain_data, refine_grid_spac), domain_vector_DT_INDEX_tid);
		H5Tinsert(domain_tid, "block_size", HOFFSET(fdomain_data, block_size), domain_vector_DT_INDEX_tid);
		H5Tinsert(domain_tid, "current_time", HOFFSET(fdomain_data, current_time), DT_VAL_HDF);
		H5Tinsert(domain_tid, "vis_time", HOFFSET(fdomain_data, vis_time), DT_VAL_HDF);
		H5Tinsert(domain_tid, "dt", HOFFSET(fdomain_data, dt), DT_VAL_HDF);
		H5Tinsert(domain_tid, "end_time", HOFFSET(fdomain_data, end_time), DT_VAL_HDF);
		H5Tinsert(domain_tid, "alpha", HOFFSET(fdomain_data, alpha), DT_VAL_HDF);
		H5Tinsert(domain_tid, "mu", HOFFSET(fdomain_data, mu), DT_VAL_HDF);
		H5Tinsert(domain_tid, "g", HOFFSET(fdomain_data, g), domain_array_DT_VAL_tid);
		H5Tinsert(domain_tid, "err_tol", HOFFSET(fdomain_data, err_tol), DT_VAL_HDF);
		H5Tinsert(domain_tid, "max_iter", HOFFSET(fdomain_data, max_iter), DT_INDEX_HDF);
		H5Tinsert(domain_tid, "omega", HOFFSET(fdomain_data, omega), DT_VAL_HDF);
		H5Tinsert(domain_tid, "write vtk result array", HOFFSET(fdomain_data, write_vtk_result_array), domain_array_DT_TYPE_tid);
		H5Tclose(domain_vector_DT_INDEX_tid);
		H5Tclose(domain_array_DT_VAL_tid);
		H5Tclose(domain_array_DT_TYPE_tid);

		hid_t read_common_gid = H5Gopen(read_file_fid, "/common", H5P_DEFAULT);
		hid_t read_domain_did = H5Dopen(read_common_gid, "domain property", H5P_DEFAULT);
		hid_t read_domain_sid = H5Dget_space(read_domain_did);

		fdomain_data *read_domain = new fdomain_data;
		H5Dread(read_domain_did, domain_tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, read_domain);

		H5Dclose(read_domain_did);
		H5Sclose(read_domain_sid);
		H5Gclose(read_common_gid);

		for (int i = 0; i != 3; ++i) {
			domain->init_grid_spac[i] = read_domain->init_grid_spac[i];
			domain->refine_grid_spac[i] = read_domain->refine_grid_spac[i];
			domain->block_size[i] = read_domain->block_size[i];
			domain->g[i] = read_domain->g[i];
		}

		for (int i = 0; i != CE_ARRAY_SIZE; ++i) {
			domain->write_vtk_result_array[i] = read_domain->write_vtk_result_array[i];
		}

		domain->vis_time = read_domain->vis_time;
		domain->dt = read_domain->dt;
		domain->end_time = read_domain->end_time;
		domain->alpha = read_domain->alpha;
		domain->mu = read_domain->mu;
		domain->err_tol = read_domain->err_tol;
		domain->max_iter = read_domain->max_iter;
		domain->omega = read_domain->omega;

		if (rank == 0) domain->domain_with_master_grid = true;
		else domain->domain_with_master_grid = false;

		// -----------------------------------------------------
		// read TIME
		// -----------------------------------------------------

		hid_t read_simulation_gid = H5Gopen(read_file_fid, "/simulation", H5P_DEFAULT);

		hid_t time_aid = H5Aopen(read_simulation_gid, "TIME", H5P_DEFAULT);

		char read_time[TIME_LENGTH];
		hid_t time_tid = H5Tcopy(H5T_C_S1);
		H5Tset_size(time_tid, TIME_LENGTH);

		H5Aread(time_aid, time_tid, read_time);
		H5Aclose(time_aid);
		H5Tclose(time_tid);

		// -----------------------------------------------------
		// read OFFSET ARRAY and DT_VAL TIME
		// -----------------------------------------------------

		string time = read_time;
		string time_str = "/simulation/" + time;

		hid_t read_time_gid = H5Gopen(read_file_fid, time_str.c_str(), H5P_DEFAULT);

		hid_t offset_array_aid = H5Aopen(read_time_gid, "OFFSET ARRAY", H5P_DEFAULT);
		DT_RANK *offset_array = new DT_RANK[comp_size + 2];
		H5Aread(offset_array_aid, DT_RANK_HDF, &(offset_array)[0]);
		H5Aclose(offset_array_aid);

		int grid_per_rank = offset_array[rank + 1] - offset_array[rank];

		hid_t time_DT_VAL_aid = H5Aopen(read_time_gid, "TIME", H5P_DEFAULT);
		H5Aread(time_DT_VAL_aid, DT_VAL_HDF, &(domain->current_time));
		H5Aclose(time_DT_VAL_aid);

		read_domain->current_time = domain->current_time;

		if (fabs(domain->current_time - domain->end_time) < 1e-8) {
			if (rank == 0) {
				printf("ERROR: %s: No simulation because the current time is equal to the end time!\n"
						"      Please change the end time in %s and rerun the simulation!\n", filename.c_str(), filename.c_str() );
			}
			return false;
		}

		// -----------------------------------------------------
		// write domain data
		// -----------------------------------------------------

		filename = filename.substr(0, filename.size() - 3) + "_restart.h5";
		createFile();

		hid_t domain_sid = H5Screate(H5S_SCALAR);
		hid_t domain_did = H5Dcreate(file_fid, "domain property", domain_tid, domain_sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);

		H5Dwrite(domain_did, domain_tid, domain_sid, H5S_ALL, H5P_DEFAULT, read_domain);

		H5Tclose(domain_tid);
		H5Sclose(domain_sid);
		H5Dclose(domain_did);
		H5Gclose(common_gid);

		delete read_domain;

		// -----------------------------------------------------
		// read grid data
		// -----------------------------------------------------

		hid_t read_grid_did = H5Dopen(read_time_gid, "grid property", H5P_DEFAULT);
		hid_t read_grid_filespace_sid = H5Dget_space(read_grid_did);
		hid_t read_bbox_did = H5Dopen(read_time_gid, "bounding box", H5P_DEFAULT);
		hid_t read_bbox_filespace_sid = H5Dget_space(read_bbox_did);
		hid_t read_subgrid_did = H5Dopen(read_time_gid, "subgrid uid", H5P_DEFAULT);
		hid_t read_subgrid_filespace_sid = H5Dget_space(read_subgrid_did);
		hid_t read_current_cell_data_did = H5Dopen(read_time_gid, "current cell data", H5P_DEFAULT);
		hid_t read_current_cell_data_filespace_sid = H5Dget_space(read_current_cell_data_did);
		hid_t read_previous_cell_data_did = H5Dopen(read_time_gid, "previous cell data", H5P_DEFAULT);
		hid_t read_previous_cell_data_filespace_sid = H5Dget_space(read_previous_cell_data_did);
		hid_t read_temp_cell_data_did = H5Dopen(read_time_gid, "temp cell data", H5P_DEFAULT);
		hid_t read_temp_cell_data_filespace_sid = H5Dget_space(read_temp_cell_data_did);
		hid_t read_cell_type_did = H5Dopen(read_time_gid, "cell type", H5P_DEFAULT);
		hid_t read_cell_type_filespace_sid = H5Dget_space(read_cell_type_did);

		hid_t vector_DT_INDEX_tid = H5Tarray_create(DT_INDEX_HDF, 1, vector_dim);

		hid_t read_grid_tid = H5Tcreate (H5T_COMPOUND, sizeof(fgrid_data));
		H5Tinsert(read_grid_tid, "mytag", HOFFSET(fgrid_data, mytag), DT_TAG_HDF);
		H5Tinsert(read_grid_tid, "supergrid_uid", HOFFSET(fgrid_data, supergrid_uid), DT_UID_HDF);
		H5Tinsert(read_grid_tid, "depth", HOFFSET(fgrid_data, depth), DT_DEPTH_HDF);
		H5Tinsert(read_grid_tid, "ref_type", HOFFSET(fgrid_data, ref_type), DT_TYPE_HDF);
		H5Tinsert(read_grid_tid, "n", HOFFSET(fgrid_data, n), vector_DT_INDEX_tid);
		H5Tinsert(read_grid_tid, "size_subgrids", HOFFSET(fgrid_data, size_subgrids), vector_DT_INDEX_tid);
		H5Tclose(vector_DT_INDEX_tid);

		defineConstant();

		hsize_t read_grid_dim[] = { 1, 1 };
		hsize_t read_bbox_dim[] = { 1, 6 };
		hsize_t read_subgrid_dim[] = { 1, max_subgrid };
		hsize_t read_cell_data_dim[] = { 1, amount_nxyz_incl_ghost * CE_ARRAY_SIZE };
		hsize_t read_temp_cell_data_dim[] = { 1, amount_nxyz_incl_ghost * CT_TEMP_ARRAY_SIZE };
		hsize_t read_cell_type_dim[] = { 1, amount_nxyz_incl_ghost };
		hsize_t read_grid_offset[] = { offset_array[rank], 0 };

		hid_t read_grid_memspace_sid = H5Screate_simple(2, read_grid_dim, NULL);
		hid_t read_bbox_memspace_sid = H5Screate_simple(2, read_bbox_dim, NULL);
		hid_t read_subgrid_memspace_sid = H5Screate_simple(2, read_subgrid_dim, NULL);
		hid_t read_current_cell_data_memspace_sid = H5Screate_simple(2, read_cell_data_dim, NULL);
		hid_t read_previous_cell_data_memspace_sid = H5Screate_simple(2, read_cell_data_dim, NULL);
		hid_t read_temp_cell_data_memspace_sid = H5Screate_simple(2, read_temp_cell_data_dim, NULL);
		hid_t read_cell_type_memspace_sid = H5Screate_simple(2, read_cell_type_dim, NULL);

		fgrid_data *read_grid = new fgrid_data;
		DT_GEOM *read_bbox = new DT_GEOM[6];
		DT_UID *read_subgrid = new DT_UID[max_subgrid];

		for (int num_grid = 0; num_grid != grid_per_rank; ++num_grid) {

			read_grid_dim[0] = read_grid_dim[1] = 1;
			read_grid_offset[0] = offset_array[rank] + num_grid;

			H5Sselect_hyperslab(read_grid_filespace_sid, H5S_SELECT_SET, read_grid_offset, NULL, read_grid_dim, NULL);
			H5Sselect_hyperslab(read_bbox_filespace_sid, H5S_SELECT_SET, read_grid_offset, NULL, read_bbox_dim, NULL);
			H5Sselect_hyperslab(read_subgrid_filespace_sid, H5S_SELECT_SET, read_grid_offset, NULL, read_subgrid_dim, NULL);
			H5Sselect_hyperslab(read_current_cell_data_filespace_sid, H5S_SELECT_SET, read_grid_offset, NULL, read_cell_data_dim, NULL);
			H5Sselect_hyperslab(read_previous_cell_data_filespace_sid, H5S_SELECT_SET, read_grid_offset, NULL, read_cell_data_dim, NULL);
			H5Sselect_hyperslab(read_temp_cell_data_filespace_sid, H5S_SELECT_SET, read_grid_offset, NULL, read_temp_cell_data_dim, NULL);
			H5Sselect_hyperslab(read_cell_type_filespace_sid, H5S_SELECT_SET, read_grid_offset, NULL, read_cell_type_dim, NULL);

			if (H5Dread(read_grid_did, read_grid_tid, read_grid_memspace_sid, read_grid_filespace_sid, H5P_DEFAULT, read_grid) < 0) {
				if (rank == 0) printf("ERROR: %s: Could not write grid property to HDF5!\n", filename.c_str());
				return false;
			}
			if (H5Dread(read_bbox_did, DT_GEOM_HDF, read_bbox_memspace_sid, read_bbox_filespace_sid, H5P_DEFAULT, &(read_bbox)[0]) < 0) {
				if (rank == 0) printf("ERROR: %s: Could not write bounding box to HDF5!\n", filename.c_str());
				return false;
			}
			if (H5Dread(read_subgrid_did, DT_UID_HDF, read_subgrid_memspace_sid, read_subgrid_filespace_sid, H5P_DEFAULT, &(read_subgrid)[0]) < 0) {
				if (rank == 0) printf("ERROR: %s: Could not write subgrid uid to HDF5!\n", filename.c_str());
				return false;
			}

			// construct new grid
			DT_GRIDID grid_id = UID::getGridIDFromTag(read_grid->mytag);
			DT_GRIDHASH grid_hash = UID::getGridHashFromTag(read_grid->mytag);
			FGrid* newgrid = new FGrid(domain, read_grid->supergrid_uid, grid_hash, read_bbox, read_grid->depth, grid_id);

			if(newgrid->n[X] != read_grid->n[X] || newgrid->n[Y] != read_grid->n[Y] || newgrid->n[Z] != read_grid->n[Z]) {
				printf("The fields n do not fit from rereading!!! Danger Danger!\n");
			}

			if(newgrid->size_subgrids[X] != read_grid->size_subgrids[X] || newgrid->size_subgrids[Y] != read_grid->size_subgrids[Y] || newgrid->size_subgrids[Z] != read_grid->size_subgrids[Z]) {
				printf("The fields n do not fit from rereading!!! Danger Danger!\n");
			}

			newgrid->subgrids_uid.clear();

			// set grid ref_type
			newgrid->ref_type = read_grid->ref_type;

			// construct subgrid
			int counter = 0;
			if(read_grid->ref_type == TP_GDREF_YES) {

				DT_GRIDHASH ghash = 0;

				for(DT_INDEX i = 0; i < newgrid->size_subgrids[X]; ++i) {
					for(DT_INDEX j = 0; j < newgrid->size_subgrids[Y]; ++j) {
						for(DT_INDEX k = 0; k < newgrid->size_subgrids[Z]; ++k) {
							ghash = UID::computeGridHash(i,j,k);

							newgrid->subgrids_uid[ghash] = read_subgrid[counter];
							++counter;
						}
					}
				}
			}

			// read current cell data, previous cell data, temp cell data and cell type
			if (H5Dread(read_current_cell_data_did, DT_VAL_HDF, read_current_cell_data_memspace_sid, read_current_cell_data_filespace_sid, H5P_DEFAULT, &(newgrid->array_val_current)[0]) < 0) {
				if (rank == 0) printf("ERROR: %s: Could not write current cell data to HDF5!\n", filename.c_str());
				return false;
			}
			if (H5Dread(read_previous_cell_data_did, DT_VAL_HDF, read_previous_cell_data_memspace_sid, read_previous_cell_data_filespace_sid, H5P_DEFAULT, &(newgrid->array_val_previous)[0]) < 0) {
				if (rank == 0) printf("ERROR: %s: Could not write previous cell data to HDF5!\n", filename.c_str());
				return false;
			}
			if (H5Dread(read_temp_cell_data_did, DT_VAL_HDF, read_temp_cell_data_memspace_sid, read_temp_cell_data_filespace_sid, H5P_DEFAULT, &(newgrid->array_val_temp)[0]) < 0) {
				if (rank == 0) printf("ERROR: %s: Could not write temp cell data to HDF5!\n", filename.c_str());
				return false;
			}
			if (H5Dread(read_cell_type_did, DT_TYPE_HDF, read_cell_type_memspace_sid, read_cell_type_filespace_sid, H5P_DEFAULT, &(newgrid->array_type)[0]) < 0) {
				if (rank == 0) printf("ERROR: %s: Could not write cell type to HDF5!\n", filename.c_str());
				return false;
			}

		}

		delete read_grid;
		delete [] read_bbox;
		delete [] read_subgrid;

		H5Tclose(read_grid_tid);
		H5Dclose(read_grid_did);
		H5Sclose(read_grid_filespace_sid);
		H5Sclose(read_grid_memspace_sid);

		H5Dclose(read_bbox_did);
		H5Sclose(read_bbox_filespace_sid);
		H5Sclose(read_bbox_memspace_sid);

		H5Dclose(read_subgrid_did);
		H5Sclose(read_subgrid_filespace_sid);
		H5Sclose(read_subgrid_memspace_sid);

		H5Dclose(read_current_cell_data_did);
		H5Sclose(read_current_cell_data_filespace_sid);
		H5Sclose(read_current_cell_data_memspace_sid);

		H5Dclose(read_previous_cell_data_did);
		H5Sclose(read_previous_cell_data_filespace_sid);
		H5Sclose(read_previous_cell_data_memspace_sid);

		H5Dclose(read_temp_cell_data_did);
		H5Sclose(read_temp_cell_data_filespace_sid);
		H5Sclose(read_temp_cell_data_memspace_sid);

		H5Dclose(read_cell_type_did);
		H5Sclose(read_cell_type_filespace_sid);
		H5Sclose(read_cell_type_memspace_sid);

		H5Gclose(read_time_gid);
		H5Gclose(read_simulation_gid);
		H5Fclose(read_file_fid);

		// -----------------------------------------------------
		// write grid data
		// -----------------------------------------------------

		simulation_gid = H5Gcreate(file_fid, "/simulation", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
		writeGridData(offset_array);

		return true;

	#endif

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions