diff --git a/lib/README b/lib/README index 95d645f82a..7f65a6be68 100644 --- a/lib/README +++ b/lib/README @@ -27,6 +27,8 @@ cuda NVIDIA GPU routines, USER-CUDA package from Christian Trott (U Tech Ilmenau) gpu general GPU routines, GPU package from Mike Brown (ORNL) +h5md ch5md library for output of MD data in HDF5 format + from Pierre de Buyl (KU Leuven) kim hooks to the KIM library, used by KIM package from Ryan Elliott and Ellad Tadmor (U Minn) kokkos Kokkos package for GPU and many-core acceleration diff --git a/lib/h5md/LICENSE b/lib/h5md/LICENSE new file mode 100644 index 0000000000..ad4d36e885 --- /dev/null +++ b/lib/h5md/LICENSE @@ -0,0 +1,25 @@ +Copyright (C) 2013-2014 Pierre de Buyl + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + a. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + b. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + c. Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/h5md/Makefile b/lib/h5md/Makefile new file mode 100644 index 0000000000..9680387ab9 --- /dev/null +++ b/lib/h5md/Makefile @@ -0,0 +1,30 @@ +EXTRAMAKE=Makefile.lammps.empty + +CC=h5cc +CFLAGS=-D_DEFAULT_SOURCE -O2 +HDF5_PATH=/usr +INC=-I include +AR=ar +ARFLAGS=rc +LIB=libch5md.a + +all: lib Makefile.lammps + +build: + mkdir -p build +build/ch5md.o: src/ch5md.c | build + $(CC) $(INC) $(CFLAGS) -c $< -o $@ + +Makefile.lammps: + cp Makefile.lammps.empty $@ + +.PHONY: all lib clean + +$(LIB): build/ch5md.o + $(AR) $(ARFLAGS) $(LIB) build/ch5md.o + +lib: $(LIB) + +clean: + rm -f build/*.o $(LIB) + diff --git a/lib/h5md/Makefile.lammps.empty b/lib/h5md/Makefile.lammps.empty new file mode 100644 index 0000000000..e4c1c0ed66 --- /dev/null +++ b/lib/h5md/Makefile.lammps.empty @@ -0,0 +1,7 @@ +# Settings that the LAMMPS build will import when this package library is used +# The default settings assume that HDF5 support is integrated into the standard +# distribution and search paths and thus only needs to link the HDF5 library. + +ch5md_SYSINC = +ch5md_SYSLIB = -lhdf5 +ch5md_SYSPATH = diff --git a/lib/h5md/README b/lib/h5md/README new file mode 100644 index 0000000000..62a4979cba --- /dev/null +++ b/lib/h5md/README @@ -0,0 +1,27 @@ +This directory contains the ch5md library, which is bundled with +LAMMPS under its own BSD license; see below. This library is used +when the USER-H5MD package is included in a LAMMPS build and the dump +h5md command is invoked in a LAMMPS input script. + +--------------------- + +ch5md : Read and write H5MD files in C +====================================== + +Copyright (C) 2013-2014 Pierre de Buyl + +ch5md is a set of C routines to manipulate H5MD files. H5MD is a file format +specification based on [HDF5](http://www.hdfgroup.org/HDF5/) for storing +molecular data, whose development is found at . + +ch5md is developped by Pierre de Buyl and is released under the 3-clause BSD +license that can be found in the file LICENSE. + +To use the h5md dump style in lammps, execute make in this directory then 'make +yes-user-h5md' in the src directory of lammps. Rebuild lammps. + +If HDF5 is not in a standard system location, edit Makefile.lammps accordingly. + +In the case of 2015 and more recent debian and ubuntu systems where concurrent +serial and mpi are possible, use the full platform depedent path, i.e. +`HDF5_PATH=/usr/lib/x86_64-linux-gnu/hdf5/serial` diff --git a/lib/h5md/include/ch5md.h b/lib/h5md/include/ch5md.h new file mode 100644 index 0000000000..7710f0f065 --- /dev/null +++ b/lib/h5md/include/ch5md.h @@ -0,0 +1,73 @@ +/* This file is part of ch5md + * Copyright (C) 2013-2015 Pierre de Buyl + * All rights reserved. + * + * This software may be modified and distributed under the terms + * of the BSD license. See the LICENSE file for details. + */ + +#ifndef CH5MD_H +#define CH5MD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "hdf5.h" +#include + +#define CH5MD_RANK_ERROR -10 + +typedef struct h5md_element_struct { + hid_t group; + hid_t step; + hid_t time; + hid_t value; + hid_t datatype; + int is_time; + int current_step; + struct h5md_element_struct *link; + struct h5md_particles_group_struct *particles_group; +} h5md_element; + +typedef struct h5md_particles_group_struct { + hid_t group; + h5md_element position; + hid_t box; + h5md_element box_edges; + h5md_element image; + h5md_element velocity; + h5md_element force; + h5md_element mass; + h5md_element species; + h5md_element id; + h5md_element charge; + int local_size_max; +} h5md_particles_group; + +typedef struct { + hid_t id; + int version[2]; + hid_t particles; + hid_t observables; + hid_t parameters; +} h5md_file; + +h5md_file h5md_create_file (const char *filename, const char *author, const char *author_email, const char *creator, const char *creator_version); +int h5md_close_file(h5md_file file); +hid_t h5md_open_file (const char *filename); +h5md_particles_group h5md_create_particles_group(h5md_file file, const char *name); +h5md_element h5md_create_time_data(hid_t loc, const char *name, int rank, int int_dims[], hid_t datatype, h5md_element *link); +int h5md_close_element(h5md_element e); +h5md_element h5md_create_fixed_data_simple(hid_t loc, const char *name, int rank, int int_dims[], hid_t datatype, void *data); +h5md_element h5md_create_fixed_data_scalar(hid_t loc, const char *name, hid_t datatype, void *data); +int h5md_append(h5md_element e, void *data, int step, double time); +int h5md_create_box(h5md_particles_group *group, int dim, char *boundary[], bool is_time, double value[], h5md_element *link); +int h5md_write_string_attribute(hid_t loc, const char *obj_name, + const char *att_name, const char *value); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/h5md/src/ch5md.c b/lib/h5md/src/ch5md.c new file mode 100644 index 0000000000..19c7c02a8f --- /dev/null +++ b/lib/h5md/src/ch5md.c @@ -0,0 +1,436 @@ +/* This file is part of ch5md + * Copyright (C) 2013-2015 Pierre de Buyl + * All rights reserved. + * + * This software may be modified and distributed under the terms + * of the BSD license. See the LICENSE file for details. + */ + +#include "hdf5.h" +#include "ch5md.h" +#include +#include + +#define MIN_CHUNK 10 +#define MAX_CHUNK 256 +#define MAX_RANK 5 + +h5md_file h5md_create_file (const char *filename, const char *author, const char *author_email, const char *creator, const char *creator_version) +{ + h5md_file file; + hid_t g, g1; + hid_t a, s, t; + hsize_t dims[1]; + + file.version[0] = 1; + file.version[1] = 0; + + file.id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + g = H5Gcreate(file.id, "h5md", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + + dims[0] = 2; + s = H5Screate_simple(1, dims, NULL); + a = H5Acreate(g, "version", H5T_NATIVE_INT, s, H5P_DEFAULT, H5P_DEFAULT); + H5Awrite(a, H5T_NATIVE_INT, file.version); + H5Aclose(a); + H5Sclose(s); + + s = H5Screate(H5S_SCALAR); + + g1 = H5Gcreate(g, "author", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + t = H5Tcopy(H5T_C_S1); + H5Tset_size(t, strlen(author)); + a = H5Acreate(g1, "name", t, s, H5P_DEFAULT, H5P_DEFAULT); + H5Awrite(a, t, author); + H5Aclose(a); + H5Tclose(t); + if (NULL!=author_email) { + t = H5Tcopy(H5T_C_S1); + H5Tset_size(t, strlen(author_email)); + a = H5Acreate(g1, "author_email", t, s, H5P_DEFAULT, H5P_DEFAULT); + H5Awrite(a, t, author_email); + H5Aclose(a); + H5Tclose(t); + } + H5Gclose(g1); + + g1 = H5Gcreate(g, "creator", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + t = H5Tcopy(H5T_C_S1); + H5Tset_size(t, strlen(creator)); + a = H5Acreate(g1, "name", t, s, H5P_DEFAULT, H5P_DEFAULT); + H5Awrite(a, t, creator); + H5Aclose(a); + H5Tclose(t); + t = H5Tcopy(H5T_C_S1); + H5Tset_size(t, strlen(creator_version)); + a = H5Acreate(g1, "version", t, s, H5P_DEFAULT, H5P_DEFAULT); + H5Awrite(a, t, creator_version); + H5Aclose(a); + H5Tclose(t); + H5Gclose(g1); + + file.particles = H5Gcreate(file.id, "particles", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + file.observables = H5Gcreate(file.id, "observables", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + file.parameters = H5Gcreate(file.id, "parameters", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + + return file; +} + +int h5md_close_file(h5md_file file) { + H5Gclose(file.particles); + H5Gclose(file.observables); + H5Gclose(file.parameters); + H5Fclose(file.id); + + return 0; +} + +hid_t h5md_open_file (const char *filename) +{ + hid_t file; + hid_t g; + hid_t a, s; + hsize_t dims[1]; + int version[2]; + int version_ok; + + file = H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT); + + g = H5Gopen(file, "h5md", H5P_DEFAULT); + + version_ok = false; + dims[0] = 2; + a = H5Aopen(g, "version", H5P_DEFAULT); + s = H5Aget_space(a); + if (!(H5Sis_simple(s)>0)) { + printf("H5MD version is not a simple dataspace"); + H5Sclose(s); + H5Aclose(a); + H5Gclose(g); + H5Fclose(file); + } else { + if (H5Sget_simple_extent_ndims(s)==1) { + H5Sget_simple_extent_dims(s, dims, NULL); + if (dims[0]==2) { + H5Aread(a, H5T_NATIVE_INT, version); + if ( (version[0]==1) && (version[1]==0) ) {version_ok = true;} + } + } + } + + H5Aclose(a); + H5Sclose(s); + H5Gclose(g); + + if (!version_ok) H5Fclose(file); + + return file; + +} + +h5md_particles_group h5md_create_particles_group(h5md_file file, const char *name) +{ + h5md_particles_group group; + + group.group = H5Gcreate(file.particles, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + + return group; +} + +h5md_element h5md_create_time_data(hid_t loc, const char *name, int rank, int int_dims[], hid_t datatype, h5md_element *link) +{ + + h5md_element td; + + hid_t spc, plist; + hsize_t dims[MAX_RANK], max_dims[MAX_RANK], chunks[MAX_RANK]; + + int i; + + dims[0] = 0 ; + max_dims[0] = H5S_UNLIMITED ; + for (i=0; igroup, "step", td.group, "step", H5P_DEFAULT, H5P_DEFAULT); + H5Lcreate_hard(link->group, "time", td.group, "time", H5P_DEFAULT, H5P_DEFAULT); + } + + spc = H5Screate_simple( rank+1 , dims, max_dims) ; + plist = H5Pcreate(H5P_DATASET_CREATE); + H5Pset_chunk(plist, rank+1, chunks); + td.value = H5Dcreate(td.group, "value", datatype, spc, H5P_DEFAULT, plist, H5P_DEFAULT); + H5Pclose(plist); + H5Sclose(spc); + + td.datatype = datatype; + td.is_time = true; + + return td; + +} + +int h5md_close_element(h5md_element e) +{ + if (!e.is_time) return 0; + + if (e.link==NULL) { + H5Dclose(e.step); + H5Dclose(e.time); + } + H5Dclose(e.value); + H5Gclose(e.group); + + return 0; + +} + +h5md_element h5md_create_fixed_data_simple(hid_t loc, const char *name, int rank, int int_dims[], hid_t datatype, void *data) +{ + + h5md_element fd; + + hid_t spc; + hsize_t dims[H5S_MAX_RANK]; + int i; + + for (i=0; i H5S_MAX_RANK) { + return CH5MD_RANK_ERROR; + } + H5Sget_simple_extent_dims(file_space, dims, maxdims); + H5Sclose(file_space); + + // Extend dimensions by one + dims[0] = dims[0]+1; + H5Dset_extent(dset, dims); + + return 0; + +} + +int h5md_append(h5md_element e, void *data, int step, double time) { + + hid_t mem_space, file_space; + int i, rank; + hsize_t dims[H5S_MAX_RANK]; + hsize_t start[H5S_MAX_RANK], count[H5S_MAX_RANK]; + + // If not a time-dependent H5MD element, do nothing + if (!e.is_time) return 0; + + if (NULL==e.link) { + h5md_extend_by_one(e.step, dims); + + // Define hyperslab selection + start[0] = dims[0]-1; + count[0] = 1; + + // Select the hyperslab + file_space = H5Dget_space(e.step); + rank = H5Sget_simple_extent_ndims(file_space); + mem_space = H5Screate_simple(rank-1, dims+1, NULL); + // Define hyperslab selection + start[0] = dims[0]-1; + count[0] = 1; + for (i=1 ; ibox = H5Gcreate(group->group, "box", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + + // Create dimension attribute + spc = H5Screate(H5S_SCALAR); + att = H5Acreate(group->box, "dimension", H5T_NATIVE_INT, spc, H5P_DEFAULT, H5P_DEFAULT); + H5Awrite(att, H5T_NATIVE_INT, &dim); + H5Aclose(att); + H5Sclose(spc); + + // Compute the size of the string type for boundary + dims[0] = dim; + boundary_length=0; + for (i=0; iboundary_length) { + boundary_length=tmp; + } + } + char *tmp_boundary = malloc(dim*sizeof(char)*boundary_length); + for (i=0; ibox, "boundary", t, spc, H5P_DEFAULT, H5P_DEFAULT); + H5Awrite(att, t, tmp_boundary); + free(tmp_boundary); + H5Aclose(att); + H5Sclose(spc); + H5Tclose(t); + + // Create edges + // Check if the box is time-dependent or not + int_dims[0]=dim; + if (is_time) { + group->box_edges = h5md_create_time_data(group->box, "edges", 1, int_dims, H5T_NATIVE_DOUBLE, link); + } else { + if (NULL!=value) { + group->box_edges = h5md_create_fixed_data_simple(group->box, "edges", 1, int_dims, H5T_NATIVE_DOUBLE, value); + } + } + + H5Gclose(group->box); + + return 0; +} + +int h5md_write_string_attribute(hid_t loc, const char *obj_name, + const char *att_name, const char *value) +{ + hid_t obj; + hid_t s, t, a; + + obj = H5Oopen(loc, obj_name, H5P_DEFAULT); + + t = H5Tcopy(H5T_C_S1); + H5Tset_size(t, strlen(value)); + s = H5Screate(H5S_SCALAR); + a = H5Acreate(obj, att_name, t, s, H5P_DEFAULT, H5P_DEFAULT); + H5Awrite(a, t, value); + H5Aclose(a); + H5Sclose(s); + H5Tclose(t); + + H5Oclose(obj); + + return 0; +}