Use HDF5 file_open from C side (and remove file_create)

This commit is contained in:
Paul Romano 2018-04-17 14:08:59 -05:00
parent b0c7f07d02
commit c74f4738c1
12 changed files with 261 additions and 287 deletions

View file

@ -435,6 +435,7 @@ set(LIBOPENMC_FORTRAN_SRC
set(LIBOPENMC_CXX_SRC
src/error.h
src/hdf5_interface.h
src/hdf5_interface.cpp
src/random_lcg.cpp
src/random_lcg.h
src/simulation.cpp

View file

@ -12,18 +12,19 @@ namespace openmc {
extern "C" void fatal_error_from_c(const char *message, int message_len);
inline
void fatal_error(const char *message)
{
fatal_error_from_c(message, strlen(message));
}
inline
void fatal_error(const std::string &message)
{
fatal_error_from_c(message.c_str(), message.length());
}
inline
void fatal_error(const std::stringstream &message)
{
std::string out {message.str()};

View file

@ -19,6 +19,7 @@ module hdf5_interface
#ifdef PHDF5
use message_passing, only: mpi_intracomm, MPI_INFO_NULL
#endif
use string, only: to_c_string
implicit none
private
@ -84,7 +85,6 @@ module hdf5_interface
public :: attribute_exists
public :: write_attribute
public :: read_attribute
public :: file_create
public :: file_open
public :: file_close
public :: create_group
@ -101,98 +101,36 @@ module hdf5_interface
contains
!===============================================================================
! FILE_CREATE creates HDF5 file
!===============================================================================
function file_create(filename, parallel) result(file_id)
character(*), intent(in) :: filename ! name of file
logical, optional, intent(in) :: parallel ! whether to write in serial
integer(HID_T) :: file_id
integer(HID_T) :: plist ! property list handle
integer :: hdf5_err ! HDF5 error code
logical :: parallel_
! Check for serial option
parallel_ = .false.
#ifdef PHDF5
if (present(parallel)) parallel_ = parallel
#endif
if (parallel_) then
! Setup file access property list with parallel I/O access
call h5pcreate_f(H5P_FILE_ACCESS_F, plist, hdf5_err)
#ifdef PHDF5
#ifdef OPENMC_MPIF08
call h5pset_fapl_mpio_f(plist, mpi_intracomm%MPI_VAL, &
MPI_INFO_NULL%MPI_VAL, hdf5_err)
#else
call h5pset_fapl_mpio_f(plist, mpi_intracomm, MPI_INFO_NULL, hdf5_err)
#endif
#endif
! Create the file collectively
call h5fcreate_f(trim(filename), H5F_ACC_TRUNC_F, file_id, hdf5_err, &
access_prp = plist)
! Close the property list
call h5pclose_f(plist, hdf5_err)
else
! Create the file
call h5fcreate_f(trim(filename), H5F_ACC_TRUNC_F, file_id, hdf5_err)
end if
end function file_create
!===============================================================================
! FILE_OPEN opens HDF5 file
!===============================================================================
function file_open(filename, mode, parallel) result(file_id)
character(*), intent(in) :: filename ! name of file
character(*), intent(in) :: mode ! access mode to file
logical, optional, intent(in) :: parallel ! whether to write in serial
character(*), intent(in) :: filename ! name of file
character, value :: mode ! access mode to file
logical, optional, intent(in) :: parallel ! whether to write in serial
integer(HID_T) :: file_id
logical :: parallel_
integer(HID_T) :: plist ! property list handle
integer :: hdf5_err ! HDF5 error code
integer :: open_mode ! HDF5 open mode
character(kind=C_CHAR) :: mode_
logical(C_BOOL) :: parallel_
! Check for serial option
interface
function file_open_c(name, mode, parallel) bind(C, name='file_open') result(file_id)
import HID_T, C_CHAR, C_BOOL, C_INT
character(kind=C_CHAR) :: name(*)
character(kind=C_CHAR), value :: mode
logical(C_BOOL), value :: parallel
integer(HID_T) :: file_id
end function file_open_c
end interface
mode_ = mode
parallel_ = .false.
#ifdef PHDF5
if (present(parallel)) parallel_ = parallel
#endif
! Determine access type
open_mode = H5F_ACC_RDONLY_F
if (mode == 'w') open_mode = H5F_ACC_RDWR_F
if (parallel_) then
! Setup file access property list with parallel I/O access
call h5pcreate_f(H5P_FILE_ACCESS_F, plist, hdf5_err)
#ifdef PHDF5
#ifdef OPENMC_MPIF08
call h5pset_fapl_mpio_f(plist, mpi_intracomm%MPI_VAL, &
MPI_INFO_NULL%MPI_VAL, hdf5_err)
#else
call h5pset_fapl_mpio_f(plist, mpi_intracomm, MPI_INFO_NULL, hdf5_err)
#endif
#endif
! Open the file collectively
call h5fopen_f(trim(filename), open_mode, file_id, hdf5_err, &
access_prp = plist)
! Close the property list
call h5pclose_f(plist, hdf5_err)
else
! Open file
call h5fopen_f(trim(filename), open_mode, file_id, hdf5_err)
end if
file_id = file_open_c(to_c_string(filename), mode, parallel_)
end function file_open
!===============================================================================

212
src/hdf5_interface.cpp Normal file
View file

@ -0,0 +1,212 @@
#include "hdf5_interface.h"
#include "error.h"
#include "hdf5.h"
#include "hdf5_hl.h"
#include <array>
#include <string>
#include <sstream>
namespace openmc {
bool
using_mpio_device(hid_t obj_id) {
// Determine file that this object is part of
hid_t file_id = H5Iget_file_id(obj_id);
// Get file access property list
hid_t fapl_id = H5Fget_access_plist(file_id);
// Get low-level driver identifier
hid_t driver = H5Pget_driver(fapl_id);
// Free resources
H5Pclose(fapl_id);
H5Fclose(file_id);
return driver == H5FD_MPIO;
}
hid_t
create_group(hid_t parent_id, char const *name)
{
hid_t out = H5Gcreate(parent_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
if (out < 0) {
std::stringstream err_msg;
err_msg << "Failed to create HDF5 group \"" << name << "\"";
fatal_error(err_msg);
}
return out;
}
hid_t
create_group(hid_t parent_id, const std::string &name)
{
return create_group(parent_id, name.c_str());
}
void
close_dataset(hid_t dataset_id)
{
if (H5Dclose(dataset_id) < 0) fatal_error("Failed to close dataset");
}
void
close_group(hid_t group_id)
{
if (H5Gclose(group_id) < 0) fatal_error("Failed to close group");
}
hid_t
file_open(const char* filename, char mode, bool parallel)
{
bool create;
unsigned int flags;
switch (mode) {
case 'r':
case 'a':
create = false;
flags = (mode == 'r' ? H5F_ACC_RDONLY : H5F_ACC_RDWR);
break;
case 'w':
case 'x':
create = true;
flags = (mode == 'x' ? H5F_ACC_EXCL : H5F_ACC_TRUNC);
break;
default:
std::stringstream err_msg;
err_msg << "Invalid file mode: " << mode;
fatal_error(err_msg);
}
hid_t plist = H5P_DEFAULT;
#ifdef PHDF5
if (parallel) {
// Setup file access property list with parallel I/O access
plist = H5Pcreate(H5P_FILE_ACCESS);
H5Pset_fapl_mpio(plist, mpi_intracomm, MPI_INFO_NULL);
}
#endif
// Open the file collectively
hid_t file_id;
if (create) {
file_id = H5Fcreate(filename, flags, H5P_DEFAULT, plist);
} else {
file_id = H5Fopen(filename, flags, plist);
}
#ifdef PHDF5
// Close the property list
if (parallel) H5Pclose(plist);
#endif
return file_id;
}
hid_t
file_open(const std::string& filename, char mode, bool parallel=false) {
file_open(filename.c_str(), mode, parallel);
}
void file_close(hid_t file_id) {
H5Fclose(file_id);
}
bool
object_exists(hid_t object_id, const char* name) {
htri_t out = H5LTpath_valid(object_id, name, true);
if (out < 0) {
std::stringstream err_msg;
err_msg << "Failed to check if object \"" << name << "\" exists.";
fatal_error(err_msg);
}
return (out > 0);
}
hid_t
open_dataset(hid_t group_id, const char* name){
if (object_exists(group_id, name)) {
return H5Dopen(group_id, name, H5P_DEFAULT);
} else {
std::stringstream err_msg;
err_msg << "Group \"" << name << "\" does not exist";
fatal_error(err_msg);
}
}
hid_t
open_group(hid_t group_id, const char* name){
if (object_exists(group_id, name)) {
return H5Gopen(group_id, name, H5P_DEFAULT);
} else {
std::stringstream err_msg;
err_msg << "Group \"" << name << "\" does not exist";
fatal_error(err_msg);
}
}
void
write_double(hid_t group_id, int ndim, const hsize_t* dims, const char* name,
double* buffer, bool indep) {
hid_t dspace = H5Screate_simple(ndim, dims, nullptr);
hid_t dset = H5Dcreate(group_id, name, H5T_NATIVE_DOUBLE, dspace,
H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
if (using_mpio_device(group_id)) {
#ifdef PHDF5
// Set up collective vs independent I/O
auto data_xfer_mode {indep ? H5FD_MPIO_INDEPENDENT : H5FD_MPIO_COLLECTIVE};
// Create dataset transfer property list
hid_t plist = H5Pcreate(H5P_DATASET_XFER);
H5Pset_dxpl_mpio(plist, data_xfer_mode);
// Write data
H5Dwrite(dset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, plist, buffer);
H5Pclose(plist);
#endif
} else {
H5Dwrite(dset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, buffer);
}
// Free resources
H5Dclose(dset);
H5Sclose(dspace);
}
void
write_string(hid_t group_id, char const *name, char const *buffer)
{
size_t buffer_len = strlen(buffer);
hid_t datatype = H5Tcopy(H5T_C_S1);
H5Tset_size(datatype, buffer_len);
hid_t dataspace = H5Screate(H5S_SCALAR);
hid_t dataset = H5Dcreate(group_id, name, datatype, dataspace,
H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
H5Dwrite(dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, buffer);
H5Tclose(datatype);
H5Sclose(dataspace);
H5Dclose(dataset);
}
void
write_string(hid_t group_id, char const *name, const std::string &buffer)
{
write_string(group_id, name, buffer.c_str());
}
}

View file

@ -1,8 +1,6 @@
#ifndef HDF5_INTERFACE_H
#define HDF5_INTERFACE_H
#include "error.h"
#include "hdf5.h"
#include "hdf5_hl.h"
@ -13,143 +11,17 @@
namespace openmc {
bool
using_mpio_device(hid_t obj_id) {
// Determine file that this object is part of
hid_t file_id = H5Iget_file_id(obj_id);
// Get file access property list
hid_t fapl_id = H5Fget_access_plist(file_id);
// Get low-level driver identifier
hid_t driver = H5Pget_driver(fapl_id);
// Free resources
H5Pclose(fapl_id);
H5Fclose(file_id);
return driver == H5FD_MPIO;
}
hid_t
create_group(hid_t parent_id, char const *name)
{
hid_t out = H5Gcreate(parent_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
if (out < 0) {
std::stringstream err_msg;
err_msg << "Failed to create HDF5 group \"" << name << "\"";
fatal_error(err_msg);
}
return out;
}
hid_t
create_group(hid_t parent_id, const std::string &name)
{
return create_group(parent_id, name.c_str());
}
void
close_dataset(hid_t dataset_id)
{
if (H5Dclose(dataset_id) < 0) fatal_error("Failed to close dataset");
}
void
close_group(hid_t group_id)
{
if (H5Gclose(group_id) < 0) fatal_error("Failed to close group");
}
hid_t
file_open(const char* filename, char mode, bool parallel=false)
{
bool create;
unsigned int flags;
switch (mode) {
case 'r':
case 'a':
create = false;
flags = (mode == 'r' ? H5F_ACC_RDONLY : H5F_ACC_RDWR);
break;
case 'w':
case 'x':
create = true;
flags = (mode == 'x' ? H5F_ACC_EXCL : H5F_ACC_TRUNC);
break;
}
hid_t plist;
if (parallel) {
// Setup file access property list with parallel I/O access
plist = H5Pcreate(H5P_FILE_ACCESS);
#ifdef PHDF5
H5Pset_fapl_mpio(plist, mpi_intracomm, MPI_INFO_NULL);
#endif
} else {
plist = H5P_DEFAULT;
}
// Open the file collectively
hid_t file_id;
if (create) {
file_id = H5Fopen(filename, flags, plist);
} else {
file_id = H5Fcreate(filename, flags, H5P_DEFAULT, plist);
}
// Close the property list
if (parallel) H5Pclose(plist);
return file_id;
}
hid_t
file_open(const std::string& filename, char mode, bool parallel=false) {
file_open(filename.c_str(), mode, parallel);
}
void file_close(hid_t file_id) {
H5Fclose(file_id);
}
bool
object_exists(hid_t object_id, const char* name) {
htri_t out = H5LTpath_valid(object_id, name, true);
if (out < 0) {
std::stringstream err_msg;
err_msg << "Failed to check if object \"" << name << "\" exists.";
fatal_error(err_msg);
}
return (out > 0);
}
hid_t
open_dataset(hid_t group_id, const char* name){
if (object_exists(group_id, name)) {
return H5Dopen(group_id, name, H5P_DEFAULT);
} else {
std::stringstream err_msg;
err_msg << "Group \"" << name << "\" does not exist";
fatal_error(err_msg);
}
}
hid_t
open_group(hid_t group_id, const char* name){
if (object_exists(group_id, name)) {
return H5Gopen(group_id, name, H5P_DEFAULT);
} else {
std::stringstream err_msg;
err_msg << "Group \"" << name << "\" does not exist";
fatal_error(err_msg);
}
}
bool using_mpio_device(hid_t obj_id);
hid_t create_group(hid_t parent_id, const char* name);
hid_t create_group(hid_t parent_id, const std::string& name);
void close_dataset(hid_t dataset_id);
void close_group(hid_t group_id);
extern "C" hid_t file_open(const char* filename, char mode, bool parallel);
hid_t file_open(const std::string& filename, char mode, bool parallel);
void file_close(hid_t file_id);
bool object_exists(hid_t object_id, const char* name);
hid_t open_dataset(hid_t group_id, const char* name);
hid_t open_group(hid_t group_id, const char* name);
template<std::size_t array_len> void
@ -169,61 +41,11 @@ write_double_1D(hid_t group_id, char const *name,
H5Dclose(dataset);
}
void
write_double(hid_t group_id, int ndim, const hsize_t* dims, const char* name,
double* buffer, bool indep) {
hid_t dspace = H5Screate_simple(ndim, dims, nullptr);
hid_t dset = H5Dcreate(group_id, name, H5T_NATIVE_DOUBLE, dspace,
H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
void write_double(hid_t group_id, int ndim, const hsize_t* dims, const char* name,
double* buffer, bool indep);
if (using_mpio_device(group_id)) {
#ifdef PHDF5
// Set up collective vs independent I/O
auto data_xfer_mode {indep ? H5FD_MPIO_INDEPENDENT : H5FD_MPIO_COLLECTIVE};
// Create dataset transfer property list
hid_t plist = H5Pcreate(H5P_DATASET_XFER);
H5Pset_dxpl_mpio(plist, data_xfer_mode);
// Write data
H5Dwrite(dset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, plist, buffer);
H5Pclose(plist);
#endif
} else {
H5Dwrite(dset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, buffer);
}
// Free resources
H5Dclose(dset);
H5Sclose(dspace);
}
void
write_string(hid_t group_id, char const *name, char const *buffer)
{
size_t buffer_len = strlen(buffer);
hid_t datatype = H5Tcopy(H5T_C_S1);
H5Tset_size(datatype, buffer_len);
hid_t dataspace = H5Screate(H5S_SCALAR);
hid_t dataset = H5Dcreate(group_id, name, datatype, dataspace,
H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
H5Dwrite(dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, buffer);
H5Tclose(datatype);
H5Sclose(dataspace);
H5Dclose(dataset);
}
void
write_string(hid_t group_id, char const *name, const std::string &buffer)
{
write_string(group_id, name, buffer.c_str());
}
void write_string(hid_t group_id, char const *name, char const *buffer);
void write_string(hid_t group_id, char const *name, const std::string &buffer);
} // namespace openmc
#endif //HDF5_INTERFACE_H

View file

@ -312,7 +312,7 @@ contains
!$omp critical (WriteParticleRestart)
! Create file
file_id = file_create(filename)
file_id = file_open(filename, 'w')
associate (src => source_bank(current_work))
! Write filetype and version info

View file

@ -371,7 +371,7 @@ contains
p % coord(1) % universe = root_universe
! Open binary plot file for writing
file_id = file_create(pl%path_plot)
file_id = file_open(pl%path_plot, 'w')
! write header info
call write_attribute(file_id, "filetype", 'voxel')

View file

@ -12,7 +12,7 @@ module source
use distribution_multivariate, only: SpatialBox
use error, only: fatal_error
use geometry, only: find_cell
use hdf5_interface, only: file_create, file_open, file_close, read_dataset
use hdf5_interface, only: file_open, file_close, read_dataset
use math
use message_passing, only: rank
use mgxs_header, only: rev_energy_bins, num_energy_groups
@ -88,7 +88,7 @@ contains
if (write_initial_source) then
call write_message('Writing out initial source...', 5)
filename = trim(path_output) // 'initial_source.h5'
file_id = file_create(filename, parallel=.true.)
file_id = file_open(filename, 'w', parallel=.true.)
call write_source_bank(file_id)
call file_close(file_id)
end if

View file

@ -76,7 +76,7 @@ contains
if (master) then
! Create statepoint file
file_id = file_create(filename_)
file_id = file_open(filename_, 'w')
! Write file type
call write_attribute(file_id, "filetype", "statepoint")
@ -476,7 +476,7 @@ contains
! Create separate source file
if (master .or. parallel) then
file_id = file_create(filename, parallel=.true.)
file_id = file_open(filename, 'w', parallel=.true.)
call write_dataset(file_id, "filetype", 'source')
end if
else
@ -485,7 +485,7 @@ contains
filename = trim(filename) // '.h5'
if (master .or. parallel) then
file_id = file_open(filename, 'w', parallel=.true.)
file_id = file_open(filename, 'a', parallel=.true.)
end if
end if
@ -498,7 +498,7 @@ contains
filename = trim(path_output) // 'source' // '.h5'
call write_message("Creating source file " // trim(filename) // "...", 5)
if (master .or. parallel) then
file_id = file_create(filename, parallel=.true.)
file_id = file_open(filename, 'w', parallel=.true.)
call write_dataset(file_id, "filetype", 'source')
end if

View file

@ -38,7 +38,7 @@ contains
call write_message("Writing summary.h5 file...", 5)
! Create a new file using default properties.
file_id = file_create("summary.h5")
file_id = file_open("summary.h5", 'w')
call write_header(file_id)
call write_nuclides(file_id)

View file

@ -115,7 +115,7 @@ contains
end do
!$omp critical (FinalizeParticleTrack)
file_id = file_create(fname)
file_id = file_open(fname, 'w')
call write_attribute(file_id, 'filetype', 'track')
call write_attribute(file_id, 'version', VERSION_TRACK)
call write_attribute(file_id, 'n_particles', n_particle_tracks)

View file

@ -11,7 +11,7 @@ module volume_calc
use error, only: write_message
use geometry, only: find_cell
use geometry_header, only: universes, cells
use hdf5_interface, only: file_create, file_close, write_attribute, &
use hdf5_interface, only: file_open, file_close, write_attribute, &
create_group, close_group, write_dataset
use output, only: header, time_stamp
use material_header, only: materials
@ -435,7 +435,7 @@ contains
character(MAX_WORD_LEN), allocatable :: nucnames(:) ! names of nuclides
! Create HDF5 file
file_id = file_create(filename)
file_id = file_open(filename, 'w')
! Write header info
call write_attribute(file_id, "filetype", "volume")