diff --git a/src/serial_io.c b/src/serial_io.c index 62306bb879e85411b49cb0edbea99241e678fba3..2e4b9076dbd3677f2bd4c7c353890226759b16ab 100644 --- a/src/serial_io.c +++ b/src/serial_io.c @@ -66,12 +66,13 @@ * * Calls #error() if an error occurs. */ -void readArrayBackEnd(hid_t grp, char* name, enum DATA_TYPE type, int N, int dim, char* part_c, enum DATA_IMPORTANCE importance) +void readArrayBackEnd(hid_t grp, char* name, enum DATA_TYPE type, int N, int dim, long long N_total, long long offset, char* part_c, enum DATA_IMPORTANCE importance) { - hid_t h_data=0, h_err=0, h_type=0; + hid_t h_data=0, h_err=0, h_type=0, h_memspace=0, h_filespace=0; + hsize_t shape[2], offsets[2]; htri_t exist=0; void* temp; - int i=0; + int i=0, rank=0; const size_t typeSize = sizeOfType(type); const size_t copySize = typeSize * dim; const size_t partSize = sizeof(struct part); @@ -91,23 +92,18 @@ void readArrayBackEnd(hid_t grp, char* name, enum DATA_TYPE type, int N, int dim } else { - /* message("Optional data set '%s' not present. Zeroing this particle field...", name); */ - for(i=0; i<N; ++i) - memset(part_c+i*partSize, 0, copySize); - + memset(part_c+i*partSize, 0, copySize); return; } - } + } /* message( "Reading %s '%s' array...", importance == COMPULSORY ? "compulsory": "optional ", name); */ /* Open data space */ h_data = H5Dopen1(grp, name); if(h_data < 0) - { - error( "Error while opening data space '%s'." , name ); - } + error( "Error while opening data space '%s'." , name ); /* Check data type */ h_type = H5Dget_type(h_data); @@ -121,10 +117,32 @@ void readArrayBackEnd(hid_t grp, char* name, enum DATA_TYPE type, int N, int dim if(temp == NULL) error("Unable to allocate memory for temporary buffer"); + /* Prepare information for hyperslab */ + if(dim > 1) + { + rank = 2; + shape[0] = N; shape[1] = dim; + offsets[0] = offset; offsets[1] = 0; + } + else + { + rank = 1; + shape[0] = N; shape[1] = 0; + offsets[0] = offset; offsets[1] = 0; + } + + /* Create data space in memory */ + h_memspace = H5Screate_simple(rank, shape, NULL); + + /* Select hyperslab in file */ + h_filespace = H5Dget_space(h_data); + H5Sselect_hyperslab(h_filespace, H5S_SELECT_SET, offsets, NULL, shape, NULL); + + /* Read HDF5 dataspace in temporary buffer */ /* Dirty version that happens to work for vectors but should be improved */ /* Using HDF5 dataspaces would be better */ - h_err = H5Dread(h_data, hdf5Type(type), H5S_ALL, H5S_ALL, H5P_DEFAULT, temp); + h_err = H5Dread(h_data, hdf5Type(type), h_memspace, h_filespace, H5P_DEFAULT, temp); if(h_err < 0) { error( "Error while reading data array '%s'." , name ); @@ -137,6 +155,8 @@ void readArrayBackEnd(hid_t grp, char* name, enum DATA_TYPE type, int N, int dim /* Free and close everything */ free(temp); + H5Sclose(h_filespace); + H5Sclose(h_memspace); H5Tclose(h_type); H5Dclose(h_data); } @@ -150,11 +170,13 @@ void readArrayBackEnd(hid_t grp, char* name, enum DATA_TYPE type, int N, int dim * @param N The number of particles. * @param dim The dimension of the data (1 for scalar, 3 for vector) * @param part The array of particles to fill + * @param N_total Total number of particles + * @param offset Offset in the array where this task starts reading * @param field The name of the field (C code name as defined in part.h) to fill * @param importance Is the data compulsory or not * */ -#define readArray(grp, name, type, N, dim, part, field, importance) readArrayBackEnd(grp, name, type, N, dim, (char*)(&(part[0]).field), importance) +#define readArray(grp, name, type, N, dim, part, N_total, offset, field, importance) readArrayBackEnd(grp, name, type, N, dim, N_total, offset, (char*)(&(part[0]).field), importance) /** * @brief Reads an HDF5 initial condition file (GADGET-3 type) @@ -180,79 +202,118 @@ void read_ic_serial ( char* fileName, double dim[3], struct part **parts, int* hid_t h_file=0, h_grp=0; double boxSize[3]={0.0,-1.0,-1.0}; /* GADGET has only cubic boxes (in cosmological mode) */ int numParticles[6]={0}; /* GADGET has 6 particle types. We only keep the type 0*/ + int numParticles_highWord[6]={0}; + long long offset = 0; + long long N_total = 0; + int rank; + + /* First read some information about the content */ + if (mpi_rank == 0) { + + /* Open file */ + /* message("Opening file '%s' as IC.", fileName); */ + h_file = H5Fopen(fileName, H5F_ACC_RDONLY, H5P_DEFAULT); + if(h_file < 0) + error( "Error while opening file '%s' for inital read." , fileName ); + + /* Open header to read simulation properties */ + /* message("Reading runtime parameters..."); */ + h_grp = H5Gopen1(h_file, "/RuntimePars"); + if(h_grp < 0) + error("Error while opening runtime parameters\n"); + + /* Read the relevant information */ + readAttribute(h_grp, "PeriodicBoundariesOn", INT, periodic); - /* Open file */ - /* message("Opening file '%s' as IC.", fileName); */ - h_file = H5Fopen(fileName, H5F_ACC_RDONLY, H5P_DEFAULT); - if(h_file < 0) - { - error( "Error while opening file '%s'." , fileName ); - } + /* Close runtime parameters */ + H5Gclose(h_grp); + + /* Open header to read simulation properties */ + /* message("Reading file header..."); */ + h_grp = H5Gopen1(h_file, "/Header"); + if(h_grp < 0) + error("Error while opening file header\n"); + + /* Read the relevant information and print status */ + readAttribute(h_grp, "BoxSize", DOUBLE, boxSize); + readAttribute(h_grp, "NumPart_Total", UINT, numParticles); + readAttribute(h_grp, "NumPart_Total_HighWord", UINT, numParticles_highWord); + + N_total = ((long long) numParticles[0]) + ((long long) numParticles_highWord[0] << 32); + dim[0] = boxSize[0]; + dim[1] = ( boxSize[1] < 0 ) ? boxSize[0] : boxSize[1]; + dim[2] = ( boxSize[2] < 0 ) ? boxSize[0] : boxSize[2]; + + /* message("Found %d particles in a %speriodic box of size [%f %f %f].", */ + /* *N, (periodic ? "": "non-"), dim[0], dim[1], dim[2]); */ + + /* Close header */ + H5Gclose(h_grp); - /* Open header to read simulation properties */ - /* message("Reading runtime parameters..."); */ - h_grp = H5Gopen1(h_file, "/RuntimePars"); - if(h_grp < 0) - error("Error while opening runtime parameters\n"); + /* Close file */ + H5Fclose(h_file); + } - /* Read the relevant information */ - readAttribute(h_grp, "PeriodicBoundariesOn", INT, periodic); - /* Close runtime parameters */ - H5Gclose(h_grp); + /* Now need to broadcast that information to all ranks. */ + MPI_Bcast(periodic, 1, MPI_INT, 0, comm); + MPI_Bcast(&N_total, 1, MPI_LONG_LONG, 0, comm); + MPI_Bcast(dim, 3, MPI_DOUBLE, 0, comm); - /* Open header to read simulation properties */ - /* message("Reading file header..."); */ - h_grp = H5Gopen1(h_file, "/Header"); - if(h_grp < 0) - error("Error while opening file header\n"); - - /* Read the relevant information and print status */ - readAttribute(h_grp, "BoxSize", DOUBLE, boxSize); - readAttribute(h_grp, "NumPart_Total", UINT, numParticles); - *N = numParticles[0]; - dim[0] = boxSize[0]; - dim[1] = ( boxSize[1] < 0 ) ? boxSize[0] : boxSize[1]; - dim[2] = ( boxSize[2] < 0 ) ? boxSize[0] : boxSize[2]; + /* Divide the particles among the tasks. */ + offset = mpi_rank * N_total / mpi_size; + *N = (mpi_rank + 1) * N_total / mpi_size - offset; - /* message("Found %d particles in a %speriodic box of size [%f %f %f].", */ - /* *N, (periodic ? "": "non-"), dim[0], dim[1], dim[2]); */ - - /* Close header */ - H5Gclose(h_grp); /* Allocate memory to store particles */ - if(posix_memalign( (void*)parts , part_align , *N * sizeof(struct part)) != 0) + if(posix_memalign( (void*)parts , part_align , (*N) * sizeof(struct part)) != 0) error("Error while allocating memory for particles"); bzero( *parts , *N * sizeof(struct part) ); - /* message("Allocated %8.2f MB for particles.", *N * sizeof(struct part) / (1024.*1024.)); */ - - /* Open SPH particles group */ - /* message("Reading particle arrays..."); */ - h_grp = H5Gopen1(h_file, "/PartType0"); - if(h_grp < 0) - error( "Error while opening particle group.\n"); - - /* Read arrays */ - readArray(h_grp, "Coordinates", DOUBLE, *N, 3, *parts, x, COMPULSORY); - readArray(h_grp, "Velocities", FLOAT, *N, 3, *parts, v, COMPULSORY); - readArray(h_grp, "Masses", FLOAT, *N, 1, *parts, mass, COMPULSORY); - readArray(h_grp, "SmoothingLength", FLOAT, *N, 1, *parts, h, COMPULSORY); - readArray(h_grp, "InternalEnergy", FLOAT, *N, 1, *parts, u, COMPULSORY); - readArray(h_grp, "ParticleIDs", ULONGLONG, *N, 1, *parts, id, COMPULSORY); - readArray(h_grp, "TimeStep", FLOAT, *N, 1, *parts, dt, OPTIONAL); - readArray(h_grp, "Acceleration", FLOAT, *N, 3, *parts, a, OPTIONAL); - readArray(h_grp, "Density", FLOAT, *N, 1, *parts, rho, OPTIONAL ); - /* Close particle group */ - H5Gclose(h_grp); + /* Now loop over ranks and read the data */ + for ( rank = 0; rank < mpi_size ; ++ rank ) { + + /* Is it this rank's turn to read ? */ + if ( rank == mpi_rank ) { + + h_file = H5Fopen(fileName, H5F_ACC_RDONLY, H5P_DEFAULT); + if(h_file < 0) + error( "Error while opening file '%s' on rank %d." , fileName, mpi_rank ); + + /* Open SPH particles group */ + /* message("Reading particle arrays..."); */ + h_grp = H5Gopen1(h_file, "/PartType0"); + if(h_grp < 0) + error( "Error while opening particle group on rank %d.\n", mpi_rank); + + /* Read arrays */ + readArray(h_grp, "Coordinates", DOUBLE, *N, 3, *parts, N_total, offset, x, COMPULSORY); + readArray(h_grp, "Velocities", FLOAT, *N, 3, *parts, N_total, offset, v, COMPULSORY); + readArray(h_grp, "Masses", FLOAT, *N, 1, *parts, N_total, offset, mass, COMPULSORY); + readArray(h_grp, "SmoothingLength", FLOAT, *N, 1, *parts, N_total, offset, h, COMPULSORY); + readArray(h_grp, "InternalEnergy", FLOAT, *N, 1, *parts, N_total, offset, u, COMPULSORY); + readArray(h_grp, "ParticleIDs", ULONGLONG, *N, 1, *parts, N_total, offset, id, COMPULSORY); + readArray(h_grp, "TimeStep", FLOAT, *N, 1, *parts, N_total, offset, dt, OPTIONAL); + readArray(h_grp, "Acceleration", FLOAT, *N, 3, *parts, N_total, offset, a, OPTIONAL); + readArray(h_grp, "Density", FLOAT, *N, 1, *parts, N_total, offset, rho, OPTIONAL ); + + /* Close particle group */ + H5Gclose(h_grp); + + /* Close file */ + H5Fclose(h_file); + + } + + /* Wait for the read of the reading to complete */ + MPI_Barrier(comm); + + } /* message("Done Reading particles..."); */ - /* Close file */ - H5Fclose(h_file); }