diff --git a/acinclude.m4 b/acinclude.m4 index 034ca55..b22f990 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -232,4 +232,311 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl fi ]) +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_lib_hdf5.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_LIB_HDF5([serial/parallel]) +# +# DESCRIPTION +# +# This macro provides tests of the availability of HDF5 library. +# +# The optional macro argument should be either 'serial' or 'parallel'. The +# former only looks for serial HDF5 installations via h5cc. The latter +# only looks for parallel HDF5 installations via h5pcc. If the optional +# argument is omitted, serial installations will be preferred over +# parallel ones. +# +# The macro adds a --with-hdf5 option accepting one of three values: +# +# no - do not check for the HDF5 library. +# yes - do check for HDF5 library in standard locations. +# path - complete path to the HDF5 helper script h5cc or h5pcc. +# +# If HDF5 is successfully found, this macro calls +# +# AC_SUBST(HDF5_VERSION) +# AC_SUBST(HDF5_CC) +# AC_SUBST(HDF5_CFLAGS) +# AC_SUBST(HDF5_CPPFLAGS) +# AC_SUBST(HDF5_LDFLAGS) +# AC_SUBST(HDF5_LIBS) +# AC_SUBST(HDF5_FC) +# AC_SUBST(HDF5_FFLAGS) +# AC_SUBST(HDF5_FLIBS) +# AC_DEFINE(HAVE_HDF5) +# +# and sets with_hdf5="yes". Additionally, the macro sets +# with_hdf5_fortran="yes" if a matching Fortran wrapper script is found. +# Note that Autconf's Fortran support is not used to perform this check. +# H5CC and H5FC will contain the appropriate serial or parallel HDF5 +# wrapper script locations. +# +# If HDF5 is disabled or not found, this macros sets with_hdf5="no" and +# with_hdf5_fortran="no". +# +# Your configuration script can test $with_hdf to take any further +# actions. HDF5_{C,CPP,LD}FLAGS may be used when building with C or C++. +# HDF5_F{FLAGS,LIBS} should be used when building Fortran applications. +# +# To use the macro, one would code one of the following in "configure.ac" +# before AC_OUTPUT: +# +# 1) dnl Check for HDF5 support +# AX_LIB_HDF5() +# +# 2) dnl Check for serial HDF5 support +# AX_LIB_HDF5([serial]) +# +# 3) dnl Check for parallel HDF5 support +# AX_LIB_HDF5([parallel]) +# +# One could test $with_hdf5 for the outcome or display it as follows +# +# echo "HDF5 support: $with_hdf5" +# +# You could also for example, override the default CC in "configure.ac" to +# enforce compilation with the compiler that HDF5 uses: +# +# AX_LIB_HDF5([parallel]) +# if test "$with_hdf5" = "yes"; then +# CC="$HDF5_CC" +# else +# AC_MSG_ERROR([Unable to find HDF5, we need parallel HDF5.]) +# fi +# +# LICENSE +# +# Copyright (c) 2009 Timothy Brown +# Copyright (c) 2010 Rhys Ulerich +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +AC_DEFUN([AX_LIB_HDF5], [ + +AC_REQUIRE([AC_PROG_SED]) +AC_REQUIRE([AC_PROG_AWK]) +AC_REQUIRE([AC_PROG_GREP]) + +dnl Check first argument is one of the recognized values. +dnl Fail eagerly if is incorrect as this simplifies case statements below. +if test "m4_normalize(m4_default([$1],[]))" = "" ; then + : # Recognized value +elif test "m4_normalize(m4_default([$1],[]))" = "serial" ; then + : # Recognized value +elif test "m4_normalize(m4_default([$1],[]))" = "parallel"; then + : # Recognized value +else + AC_MSG_ERROR([ +Unrecognized value for AX[]_LIB_HDF5 within configure.ac. +If supplied, argument 1 must be either 'serial' or 'parallel'. +]) +fi + +dnl Add a default --with-hdf5 configuration option. +AC_ARG_WITH([hdf5], + AS_HELP_STRING( + [--with-hdf5=[yes/no/PATH]], + m4_case(m4_normalize([$1]), + [serial], [location of h5cc for serial HDF5 configuration], + [parallel], [location of h5pcc for parallel HDF5 configuration], + [location of h5cc or h5pcc for HDF5 configuration]) + ), + [if test "$withval" = "no"; then + with_hdf5="no" + elif test "$withval" = "yes"; then + with_hdf5="yes" + else + with_hdf5="yes" + H5CC="$withval" + fi], + [with_hdf5="yes"] +) + +dnl Set defaults to blank +HDF5_CC="" +HDF5_VERSION="" +HDF5_CFLAGS="" +HDF5_CPPFLAGS="" +HDF5_LDFLAGS="" +HDF5_LIBS="" +HDF5_FC="" +HDF5_FFLAGS="" +HDF5_FLIBS="" + +dnl Try and find hdf5 compiler tools and options. +if test "$with_hdf5" = "yes"; then + if test -z "$H5CC"; then + dnl Check to see if H5CC is in the path. + AC_PATH_PROGS( + [H5CC], + m4_case(m4_normalize([$1]), + [serial], [h5cc], + [parallel], [h5pcc], + [h5cc h5pcc]), + []) + else + AC_MSG_CHECKING([Using provided HDF5 C wrapper]) + AC_MSG_RESULT([$H5CC]) + fi + AC_MSG_CHECKING([for HDF5 libraries]) + if test ! -f "$H5CC" || test ! -x "$H5CC"; then + AC_MSG_RESULT([no]) + AC_MSG_WARN(m4_case(m4_normalize([$1]), + [serial], [ +Unable to locate serial HDF5 compilation helper script 'h5cc'. +Please specify --with-hdf5= as the full path to h5cc. +HDF5 support is being disabled (equivalent to --with-hdf5=no). +], [parallel],[ +Unable to locate parallel HDF5 compilation helper script 'h5pcc'. +Please specify --with-hdf5= as the full path to h5pcc. +HDF5 support is being disabled (equivalent to --with-hdf5=no). +], [ +Unable to locate HDF5 compilation helper scripts 'h5cc' or 'h5pcc'. +Please specify --with-hdf5= as the full path to h5cc or h5pcc. +HDF5 support is being disabled (equivalent to --with-hdf5=no). +])) + with_hdf5="no" + with_hdf5_fortran="no" + else + dnl Get the h5cc output + HDF5_SHOW=$(eval $H5CC -show) + + dnl Get the actual compiler used + HDF5_CC=$(eval $H5CC -show | $AWK '{print $[]1}') + if test "$HDF5_CC" = "ccache"; then + HDF5_CC=$(eval $H5CC -show | $AWK '{print $[]2}') + fi + + dnl h5cc provides both AM_ and non-AM_ options + dnl depending on how it was compiled either one of + dnl these are empty. Lets roll them both into one. + + dnl Look for "HDF5 Version: X.Y.Z" + HDF5_VERSION=$(eval $H5CC -showconfig | $GREP 'HDF5 Version:' \ + | $AWK '{print $[]3}') + + dnl A ideal situation would be where everything we needed was + dnl in the AM_* variables. However most systems are not like this + dnl and seem to have the values in the non-AM variables. + dnl + dnl We try the following to find the flags: + dnl (1) Look for "NAME:" tags + dnl (2) Look for "H5_NAME:" tags + dnl (3) Look for "AM_NAME:" tags + dnl + HDF5_tmp_flags=$(eval $H5CC -showconfig \ + | $GREP 'FLAGS\|Extra libraries:' \ + | $AWK -F: '{printf("%s "), $[]2}' ) + + dnl Find the installation directory and append include/ + HDF5_tmp_inst=$(eval $H5CC -showconfig \ + | $GREP 'Installation point:' \ + | $AWK '{print $[]NF}' ) + + dnl Add this to the CPPFLAGS + HDF5_CPPFLAGS="-I${HDF5_tmp_inst}/include" + + dnl Now sort the flags out based upon their prefixes + for arg in $HDF5_SHOW $HDF5_tmp_flags ; do + case "$arg" in + -I*) echo $HDF5_CPPFLAGS | $GREP -e "$arg" 2>&1 >/dev/null \ + || HDF5_CPPFLAGS="$arg $HDF5_CPPFLAGS" + ;; + -L*) echo $HDF5_LDFLAGS | $GREP -e "$arg" 2>&1 >/dev/null \ + || HDF5_LDFLAGS="$arg $HDF5_LDFLAGS" + ;; + -l*) echo $HDF5_LIBS | $GREP -e "$arg" 2>&1 >/dev/null \ + || HDF5_LIBS="$arg $HDF5_LIBS" + ;; + esac + done + + HDF5_LIBS="$HDF5_LIBS -lhdf5" + AC_MSG_RESULT([yes (version $[HDF5_VERSION])]) + + dnl See if we can compile + ax_lib_hdf5_save_CC=$CC + ax_lib_hdf5_save_CPPFLAGS=$CPPFLAGS + ax_lib_hdf5_save_LIBS=$LIBS + ax_lib_hdf5_save_LDFLAGS=$LDFLAGS + CC=$HDF5_CC + CPPFLAGS=$HDF5_CPPFLAGS + LIBS=$HDF5_LIBS + LDFLAGS=$HDF5_LDFLAGS + AC_CHECK_HEADER([hdf5.h], [ac_cv_hadf5_h=yes], [ac_cv_hadf5_h=no]) + AC_CHECK_LIB([hdf5], [H5Fcreate], [ac_cv_libhdf5=yes], + [ac_cv_libhdf5=no]) + if test "$ac_cv_hadf5_h" = "no" && test "$ac_cv_libhdf5" = "no" ; then + AC_MSG_WARN([Unable to compile HDF5 test program]) + fi + dnl Look for HDF5's high level library + AC_HAVE_LIBRARY([hdf5_hl], [HDF5_LIBS="$HDF5_LIBS -lhdf5_hl"], [], []) + + CC=$ax_lib_hdf5_save_CC + CPPFLAGS=$ax_lib_hdf5_save_CPPFLAGS + LIBS=$ax_lib_hdf5_save_LIBS + LDFLAGS=$ax_lib_hdf5_save_LDFLAGS + + AC_MSG_CHECKING([for matching HDF5 Fortran wrapper]) + dnl Presume HDF5 Fortran wrapper is just a name variant from H5CC + H5FC=$(eval echo -n $H5CC | $SED -n 's/cc$/fc/p') + if test -x "$H5FC"; then + AC_MSG_RESULT([$H5FC]) + with_hdf5_fortran="yes" + AC_SUBST([H5FC]) + + dnl Again, pry any remaining -Idir/-Ldir from compiler wrapper + for arg in `$H5FC -show` + do + case "$arg" in #( + -I*) echo $HDF5_FFLAGS | $GREP -e "$arg" >/dev/null \ + || HDF5_FFLAGS="$arg $HDF5_FFLAGS" + ;;#( + -L*) echo $HDF5_FFLAGS | $GREP -e "$arg" >/dev/null \ + || HDF5_FFLAGS="$arg $HDF5_FFLAGS" + dnl HDF5 installs .mod files in with libraries, + dnl but some compilers need to find them with -I + echo $HDF5_FFLAGS | $GREP -e "-I${arg#-L}" >/dev/null \ + || HDF5_FFLAGS="-I${arg#-L} $HDF5_FFLAGS" + ;; + esac + done + + dnl Make Fortran link line by inserting Fortran libraries + for arg in $HDF5_LIBS + do + case "$arg" in #( + -lhdf5_hl) HDF5_FLIBS="$HDF5_FLIBS -lhdf5hl_fortran $arg" + ;; #( + -lhdf5) HDF5_FLIBS="$HDF5_FLIBS -lhdf5_fortran $arg" + ;; #( + *) HDF5_FLIBS="$HDF5_FLIBS $arg" + ;; + esac + done + else + AC_MSG_RESULT([no]) + with_hdf5_fortran="no" + fi + + AC_SUBST([HDF5_VERSION]) + AC_SUBST([HDF5_CC]) + AC_SUBST([HDF5_CFLAGS]) + AC_SUBST([HDF5_CPPFLAGS]) + AC_SUBST([HDF5_LDFLAGS]) + AC_SUBST([HDF5_LIBS]) + AC_SUBST([HDF5_FC]) + AC_SUBST([HDF5_FFLAGS]) + AC_SUBST([HDF5_FLIBS]) + AC_DEFINE([HAVE_HDF5], [1], [Defined if you have HDF5 support]) + fi +fi +]) diff --git a/configure.ac b/configure.ac index 00b84bd..0774ab6 100644 --- a/configure.ac +++ b/configure.ac @@ -58,10 +58,14 @@ AC_ARG_WITH([LatCore], [AM_LDFLAGS="$AM_LDFLAGS -L$with_LatCore/lib"], [] ) - -CFLAGS="$AM_CFLAGS $CFLAGS" -CXXFLAGS="$AM_CXXFLAGS $CXXFLAGS" -LDFLAGS="$AM_LDFLAGS $LDFLAGS" +AX_LIB_HDF5() +if test x$with_hdf5 = xno; then + AC_MSG_ERROR([HDF5 library not found]) +fi +CFLAGS="$AM_CFLAGS $HDF5_CFLAGS $CFLAGS" +CXXFLAGS="$AM_CXXFLAGS $HDF5_CPPFLAGS $CXXFLAGS" +LDFLAGS="$AM_LDFLAGS $HDF5_LDFLAGS $LDFLAGS" +LIBS="$LIBS $HDF5_LIBS -lhdf5_cpp" # Get compilers informations AX_COMPILER_VENDOR diff --git a/examples/exMat.cpp b/examples/exMat.cpp index d396cb0..f838353 100644 --- a/examples/exMat.cpp +++ b/examples/exMat.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include @@ -8,9 +8,8 @@ using namespace Latan; int main(void) { - AsciiFile F; DMat A(2, 3), B(3, 2); - const string fileName = "exMat.dat"; + const string fileName = "exMat.h5"; A << 1, 2, 3, 4, 5, 6; @@ -26,9 +25,11 @@ int main(void) cout << "cos(A)=\n" << A.unaryExpr(StdMath::cos) << '\n' << endl; // write - cout << "-- saving A*B..." << endl; - F.open(fileName, File::Mode::append); - F.save(A*B, "AB"); - + cout << "-- saving and loading A*B using '" + fileName + "'..." << endl; + Io::save(A*B, fileName, File::Mode::write, "AB"); + + DMat C = Io::load(fileName); + cout << C << endl; + return EXIT_SUCCESS; } diff --git a/examples/exRand.cpp b/examples/exRand.cpp index c88e79d..3ee2ece 100644 --- a/examples/exRand.cpp +++ b/examples/exRand.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include diff --git a/lib/AsciiFile.cpp b/lib/AsciiFile.cpp index 72d9697..a7c8d64 100644 --- a/lib/AsciiFile.cpp +++ b/lib/AsciiFile.cpp @@ -89,6 +89,12 @@ void AsciiFile::save(const RandGenState &state, const std::string &name) fileStream_ << "#L latan_end rg_state " << endl; } +// read first name //////////////////////////////////////////////////////////// +string AsciiFile::getFirstName(void) +{ + return load(); +} + // tests /////////////////////////////////////////////////////////////////////// bool AsciiFile::isOpen() const { @@ -118,7 +124,9 @@ void AsciiFile::open(const string &name, const unsigned int mode) else { ios_base::openmode stdMode = static_cast(0); - + + name_ = name; + mode_ = mode; if (mode & Mode::write) { stdMode |= ios::out|ios::trunc; @@ -131,8 +139,6 @@ void AsciiFile::open(const string &name, const unsigned int mode) { stdMode |= ios::out|ios::app; } - name_ = name; - mode_ = mode; isParsed_ = false; fileStream_.open(name_.c_str(), stdMode); if (mode_ & Mode::read) diff --git a/lib/AsciiFile.hpp b/lib/AsciiFile.hpp index f6c92e5..4385e02 100644 --- a/lib/AsciiFile.hpp +++ b/lib/AsciiFile.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -67,6 +68,8 @@ public: virtual void save(const DMat &m, const std::string &name); virtual void save(const DMatSample &s, const std::string &name); virtual void save(const RandGenState &state, const std::string &name); + // read first name + virtual std::string getFirstName(void); // tests virtual bool isOpen(void) const; // IO diff --git a/lib/File.hpp b/lib/File.hpp index cd6d434..d180248 100644 --- a/lib/File.hpp +++ b/lib/File.hpp @@ -17,12 +17,11 @@ * along with LatAnalyze 3. If not, see . */ -#ifndef Latan_Io_hpp_ -#define Latan_Io_hpp_ +#ifndef Latan_File_hpp_ +#define Latan_File_hpp_ #include #include -#include #include #include #include @@ -64,6 +63,8 @@ public: virtual void save(const DMat &m, const std::string &name) = 0; virtual void save(const DMatSample &state, const std::string &name) = 0; virtual void save(const RandGenState &state, const std::string &name) = 0; + // read first name + virtual std::string getFirstName(void) = 0; // tests virtual bool isOpen(void) const = 0; // IO @@ -114,39 +115,6 @@ const IoT& File::getData(const std::string &name) const } } -/****************************************************************************** - * Static IO functions * - ******************************************************************************/ -class Io -{ -public: - template - static IoT load(const std::string &fileName, const std::string &name = ""); - template - static void save(const IoT &data, const std::string &fileName, - const unsigned int mode = File::Mode::write, - const std::string &name = ""); -}; - -// template implementation ///////////////////////////////////////////////////// -template -IoT Io::load(const std::string &fileName, const std::string &name) -{ - FileType file(fileName, File::Mode::read); - - return file.template read(name); -} - -template -void Io::save(const IoT &data, const std::string &fileName, - const unsigned int mode, const std::string &name) -{ - FileType file(fileName, mode); - std::string realName = (name.empty()) ? fileName : name; - - file.save(data, realName); -} - END_LATAN_NAMESPACE #endif diff --git a/lib/Hdf5File.cpp b/lib/Hdf5File.cpp new file mode 100644 index 0000000..d604fa4 --- /dev/null +++ b/lib/Hdf5File.cpp @@ -0,0 +1,315 @@ +/* + * Hdf5File.cpp, part of LatAnalyze 3 + * + * Copyright (C) 2013 - 2015 Antonin Portelli + * + * LatAnalyze 3 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LatAnalyze 3 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LatAnalyze 3. If not, see . + */ + +#include +#include +#include + +using namespace std; +using namespace Latan; +#ifndef H5_NO_NAMESPACE +using namespace H5NS; +#endif + +constexpr unsigned int maxGroupNameSize = 1024u; + +const short dMatType = static_cast(IoObject::IoType::dMat); +const short dMatSampleType = static_cast(IoObject::IoType::dMatSample); +const short rgStateType = static_cast(IoObject::IoType::rgState); + +/****************************************************************************** + * Hdf5File implementation * + ******************************************************************************/ +// constructors //////////////////////////////////////////////////////////////// +Hdf5File::Hdf5File(void) +{} + +Hdf5File::Hdf5File(const std::string &name, const unsigned int mode) +{ + open(name, mode); +} + +// destructor ////////////////////////////////////////////////////////////////// +Hdf5File::~Hdf5File(void) +{ + close(); +} + +// access ////////////////////////////////////////////////////////////////////// +void Hdf5File::save(const DMat &m, const string &name) +{ + Group group; + Attribute attr; + DataSet dataset; + hsize_t dim[2] = {static_cast(m.rows()), + static_cast(m.cols())}; + hsize_t attrDim = 1; + + DataSpace dataSpace(2, dim), attrSpace(1, &attrDim); + + group = h5File_->createGroup(name.c_str()); + attr = group.createAttribute("type", PredType::NATIVE_SHORT, attrSpace); + attr.write(PredType::NATIVE_SHORT, &dMatType); + dataset = group.createDataSet("data", PredType::NATIVE_DOUBLE, dataSpace); + dataset.write(m.data(), PredType::NATIVE_DOUBLE); +} + +void Hdf5File::save(const DMatSample &sample, const string &name) +{ + Group group; + Attribute attr; + DataSet dataset; + hsize_t dim[2] = {static_cast(sample[central].rows()), + static_cast(sample[central].cols())}; + hsize_t attrDim = 1; + DataSpace dataSpace(2, dim), attrSpace(1, &attrDim); + const long int nSample = sample.size(); + string datasetName; + + group = h5File_->createGroup(name.c_str()); + attr = group.createAttribute("type", PredType::NATIVE_SHORT, attrSpace); + attr.write(PredType::NATIVE_SHORT, &dMatSampleType); + attr = group.createAttribute("nSample", PredType::NATIVE_LONG, attrSpace); + attr.write(PredType::NATIVE_LONG, &nSample); + FOR_STAT_ARRAY(sample, s) + { + datasetName = (s == central) ? "data_C" : ("data_S_" + strFrom(s)); + dataset = group.createDataSet(datasetName, PredType::NATIVE_DOUBLE, + dataSpace); + dataset.write(sample[s].data(), PredType::NATIVE_DOUBLE); + } +} + +void Hdf5File::save(const RandGenState &state, const string &name) +{ + Group group; + Attribute attr; + DataSet dataset; + hsize_t dim = RLXG_STATE_SIZE; + hsize_t attrDim = 1; + DataSpace dataSpace(1, &dim), attrSpace(1, &attrDim); + + group = h5File_->createGroup(name.c_str()); + attr = group.createAttribute("type", PredType::NATIVE_SHORT, attrSpace); + attr.write(PredType::NATIVE_SHORT, &rgStateType); + dataset = group.createDataSet("data", PredType::NATIVE_DOUBLE, dataSpace); + dataset.write(state.data(), PredType::NATIVE_DOUBLE); +} + +// read first name //////////////////////////////////////////////////////////// +string Hdf5File::getFirstName(void) +{ + return getFirstGroupName(); +} + +// tests /////////////////////////////////////////////////////////////////////// +bool Hdf5File::isOpen(void) const +{ + return (h5File_ != nullptr); +} + +// IO ////////////////////////////////////////////////////////////////////////// +void Hdf5File::close(void) +{ + if (isOpen()) + { + h5File_->close(); + } + h5File_.reset(nullptr); + name_ = ""; + mode_ = Mode::null; + deleteData(); +} + +void Hdf5File::open(const string &name, const unsigned int mode) +{ + if (isOpen()) + { + LATAN_ERROR(Io, "file already opened with name '" + name_ + "'"); + } + else + { + unsigned int h5Mode = 0; + + name_ = name; + mode_ = mode; + if (mode & Mode::write) + { + h5Mode |= H5F_ACC_TRUNC; + } + if (mode & Mode::read) + { + h5Mode |= H5F_ACC_RDONLY; + } + if (mode & Mode::append) + { + h5Mode |= H5F_ACC_RDWR|H5F_ACC_CREAT; + } + h5File_.reset(new H5File(name_.c_str(), h5Mode)); + } +} + +string Hdf5File::getFirstGroupName(void) +{ + string res; + + if ((mode_ & Mode::read)&&(isOpen())) + { + auto firstGroupName = [](hid_t loc_id, const char *name, void *fname) + { + H5G_stat_t statbuf; + + H5Gget_objinfo(loc_id, name, 0, &statbuf); + if ((statbuf.type == H5G_GROUP) && (strlen((char *)fname) == 0)) + { + strncpy((char *)fname, name, maxGroupNameSize); + } + + return 0; + }; + + char groupName[maxGroupNameSize]; + + h5File_->iterateElems("/", nullptr, firstGroupName, groupName); + res = groupName; + } + else + { + if (isOpen()) + { + LATAN_ERROR(Io, "file '" + name_ + "' is not opened in read mode"); + } + else + { + LATAN_ERROR(Io, "file '" + name_ + "' is not opened"); + } + + return ""; + } + + return res; +} + +void Hdf5File::load(DMat &m, const DataSet &d) +{ + DataSpace dataspace; + hsize_t dim[2]; + + dataspace = d.getSpace(); + dataspace.getSimpleExtentDims(dim); + m.resize(dim[0], dim[1]); + d.read(m.data(), PredType::NATIVE_DOUBLE); +} + +void Hdf5File::load(RandGenState &state, const DataSet &d) +{ + DataSpace dataspace; + hsize_t dim[1]; + + dataspace = d.getSpace(); + dataspace.getSimpleExtentDims(dim); + if (dim[0] != RLXG_STATE_SIZE) + { + // error here + } + d.read(state.data(), PredType::NATIVE_INT); +} + +string Hdf5File::load(const string &name) +{ + if ((mode_ & Mode::read)&&(isOpen())) + { + string groupName; + Group group; + Attribute attribute; + DataSet dataset; + IoObject::IoType type; + + groupName = (name.empty()) ? getFirstGroupName() : name; + group = h5File_->openGroup(groupName.c_str()); + attribute = group.openAttribute("type"); + attribute.read(PredType::NATIVE_SHORT, &type); + switch (type) + { + case IoObject::IoType::dMat: + { + DMat *pt = new DMat; + + data_[groupName].reset(pt); + dataset = group.openDataSet("data"); + load(*pt, dataset); + break; + } + case IoObject::IoType::dMatSample: + { + DMatSample *pt = new DMatSample; + long int nSample; + + data_[groupName].reset(pt); + attribute = group.openAttribute("nSample"); + attribute.read(PredType::NATIVE_LONG, &nSample); + pt->resize(nSample); + FOR_STAT_ARRAY(*pt, s) + { + if (s == central) + { + dataset = group.openDataSet("data_C"); + } + else + { + dataset = group.openDataSet("data_S_" + strFrom(s)); + } + load((*pt)[s], dataset); + } + break; + } + case IoObject::IoType::rgState: + { + RandGenState *pt = new RandGenState; + + data_[groupName].reset(pt); + dataset = group.openDataSet("data"); + load(*pt, dataset); + break; + } + default: + { + LATAN_ERROR(Io, "unknown data type (" + + strFrom(static_cast(type)) + ") " + " (" + name_ + ":" + groupName + ")"); + break; + } + } + + return groupName; + } + else + { + if (isOpen()) + { + LATAN_ERROR(Io, "file '" + name_ + "' is not opened in read mode"); + } + else + { + LATAN_ERROR(Io, "file '" + name_ + "' is not opened"); + } + + return ""; + } +} diff --git a/lib/Hdf5File.hpp b/lib/Hdf5File.hpp new file mode 100644 index 0000000..b86b892 --- /dev/null +++ b/lib/Hdf5File.hpp @@ -0,0 +1,72 @@ +/* + * Hdf5File.hpp, part of LatAnalyze 3 + * + * Copyright (C) 2013 - 2015 Antonin Portelli + * + * LatAnalyze 3 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LatAnalyze 3 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LatAnalyze 3. If not, see . + */ + +#ifndef Latan_Hdf5File_hpp_ +#define Latan_Hdf5File_hpp_ + +#include +#include +#include +#include +#include +#include + +BEGIN_LATAN_NAMESPACE + +#ifndef H5_NO_NAMESPACE +#define H5NS H5 +#endif + +/****************************************************************************** + * HDF5 datafile class * + ******************************************************************************/ +class Hdf5File: public File +{ +public: + // constructors + Hdf5File(void); + Hdf5File(const std::string &name, const unsigned int mode); + // destructor + virtual ~Hdf5File(void); + // access + virtual void save(const DMat &m, const std::string &name); + virtual void save(const DMatSample &s, const std::string &name); + virtual void save(const RandGenState &state, const std::string &name); + // read first name + virtual std::string getFirstName(void); + // tests + virtual bool isOpen(void) const; + // IO + virtual void close(void); + virtual void open(const std::string &name, const unsigned int mode); +private: + // IO + std::string getFirstGroupName(void); + virtual std::string load(const std::string &name = ""); + void load(DMat &m, const H5NS::DataSet &d); + void load(DMatSample &s, const H5NS::DataSet &d); + void load(RandGenState &state, const H5NS::DataSet &d); +private: + // file name + std::unique_ptr h5File_{nullptr}; +}; + +END_LATAN_NAMESPACE + +#endif // Latan_Hdf5File_hpp_ diff --git a/lib/Io.cpp b/lib/Io.cpp new file mode 100644 index 0000000..1390734 --- /dev/null +++ b/lib/Io.cpp @@ -0,0 +1,42 @@ +/* + * Io.cpp, part of LatAnalyze 3 + * + * Copyright (C) 2013 - 2015 Antonin Portelli + * + * LatAnalyze 3 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LatAnalyze 3 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LatAnalyze 3. If not, see . + */ + +#include +#include + +using namespace std; +using namespace Latan; + +string Io::getFirstName(const string &fileName) +{ + string ext = extension(fileName); + + if (ext == "h5") + { + return getFirstName(fileName); + } + else if ((ext == "dat")||(ext == "sample")||(ext == "seed")) + { + return getFirstName(fileName); + } + else + { + LATAN_ERROR(Io, "unknown file extension '" + ext + "'"); + } +} diff --git a/lib/Io.hpp b/lib/Io.hpp new file mode 100644 index 0000000..ae68f4b --- /dev/null +++ b/lib/Io.hpp @@ -0,0 +1,120 @@ +/* + * Io.hpp, part of LatAnalyze 3 + * + * Copyright (C) 2013 - 2015 Antonin Portelli + * + * LatAnalyze 3 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LatAnalyze 3 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LatAnalyze 3. If not, see . + */ + +#ifndef Latan_Io_hpp_ +#define Latan_Io_hpp_ + +#include +#include +#include + +BEGIN_LATAN_NAMESPACE + +/****************************************************************************** + * Static IO functions * + ******************************************************************************/ +class Io +{ +public: + template + static IoT load(const std::string &fileName, const std::string &name = ""); + template + static IoT load(const std::string &fileName, const std::string &name = ""); + template + static void save(const IoT &data, const std::string &fileName, + const unsigned int mode = File::Mode::write, + const std::string &name = ""); + template + static void save(const IoT &data, const std::string &fileName, + const unsigned int mode = File::Mode::write, + const std::string &name = ""); + template + static std::string getFirstName(const std::string &fileName); + static std::string getFirstName(const std::string &fileName); +}; + +// template implementation ///////////////////////////////////////////////////// +template +IoT Io::load(const std::string &fileName, const std::string &name) +{ + FileType file(fileName, File::Mode::read); + + return file.template read(name); +} + +template +IoT Io::load(const std::string &fileName, const std::string &name) +{ + std::string ext = extension(fileName); + + if (ext == "h5") + { + return load(fileName, name); + } + else if ((ext == "dat")||(ext == "sample")||(ext == "seed")) + { + return load(fileName, name); + } + else + { + LATAN_ERROR(Io, "unknown file extension '" + ext + "'"); + } +} + +template +void Io::save(const IoT &data, const std::string &fileName, + const unsigned int mode, const std::string &name) +{ + FileType file(fileName, mode); + std::string realName = (name.empty()) ? fileName : name; + + file.save(data, realName); +} + +template +void Io::save(const IoT &data, const std::string &fileName, + const unsigned int mode, const std::string &name) +{ + std::string ext = extension(fileName); + + if (ext == "h5") + { + save(data, fileName, mode, name); + } + else if ((ext == "dat")||(ext == "sample")||(ext == "seed")) + { + save(data, fileName, mode, name); + } + else + { + LATAN_ERROR(Io, "unknown file extension '" + ext + "'"); + } +} + +template +std::string Io::getFirstName(const std::string &fileName) +{ + FileType file(fileName, File::Mode::read); + + return file.getFirstName(); +} + +END_LATAN_NAMESPACE + +#endif // Latan_Io_hpp_ diff --git a/lib/IoObject.hpp b/lib/IoObject.hpp index bdcd14d..922b343 100644 --- a/lib/IoObject.hpp +++ b/lib/IoObject.hpp @@ -30,7 +30,7 @@ BEGIN_LATAN_NAMESPACE class IoObject { public: - enum class IoType + enum class IoType: short int { noType = 0, dMat = 1, diff --git a/lib/Makefile.am b/lib/Makefile.am index 0df21a3..447e76a 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -29,8 +29,10 @@ libLatAnalyze_la_SOURCES = \ Global.cpp \ GslHybridRootFinder.cpp\ GslQagsIntegrator.cpp \ + Hdf5File.cpp \ Histogram.cpp \ includes.hpp \ + Io.cpp \ Mat.cpp \ Math.cpp \ MathInterpreter.cpp \ @@ -62,8 +64,10 @@ libLatAnalyze_la_HEADERS = \ Global.hpp \ GslHybridRootFinder.hpp\ GslQagsIntegrator.hpp \ + Hdf5File.hpp \ Histogram.hpp \ Integrator.hpp \ + Io.hpp \ IoObject.hpp \ Mat.hpp \ Math.hpp \ diff --git a/utils/make_fake_sample.cpp b/utils/make_fake_sample.cpp index de83d3e..8b8b5dd 100644 --- a/utils/make_fake_sample.cpp +++ b/utils/make_fake_sample.cpp @@ -18,7 +18,7 @@ */ #include -#include +#include #include using namespace std; @@ -56,7 +56,7 @@ int main(int argc, char *argv[]) res[s](0, 0) = gen.gaussian(val, err); } } - Io::save(res, outFileName); + Io::save(res, outFileName); return EXIT_SUCCESS; } diff --git a/utils/resample.cpp b/utils/resample.cpp index 485052a..7311de9 100644 --- a/utils/resample.cpp +++ b/utils/resample.cpp @@ -21,8 +21,8 @@ #include #include #include -#include #include +#include #ifndef DEF_NSAMPLE #define DEF_NSAMPLE 100 @@ -109,15 +109,30 @@ int main(int argc, char *argv[]) } for (unsigned int i = 0; i < dataFileName.size(); ++i) { - AsciiFile dataFile; - + std::unique_ptr dataFile; + + if (extension(dataFileName[i]) == "dat") + { + dataFile.reset(new AsciiFile); + } + else if (extension(dataFileName[i]) == "h5") + { + dataFile.reset(new Hdf5File); + } + else + { + cerr << "error: '" << dataFileName[i]; + cerr << "' has an unknown extension" << endl; + + return EXIT_FAILURE; + } cout << '\r' << ProgressBar(i + 1, dataFileName.size()); - dataFile.open(dataFileName[i], AsciiFile::Mode::read); + dataFile->open(dataFileName[i], AsciiFile::Mode::read); for (const string &n: name) { - data[n][i] = dataFile.read(n); + data[n][i] = dataFile->read(n); } - dataFile.close(); + dataFile->close(); } cout << endl; @@ -129,7 +144,7 @@ int main(int argc, char *argv[]) cout << "-- resampling data..." << endl; if (!stateFileName.empty()) { - state = Io::load(stateFileName); + state = Io::load(stateFileName); } for (unsigned int i = 0; i < name.size(); ++i) { @@ -142,8 +157,8 @@ int main(int argc, char *argv[]) g.setState(state); } s = data[name[i]].bootstrapMean(nSample, g); - Io::save(s, outDirName + "/" + outFileName, - File::Mode::write, outFileName); + Io::save(s, outDirName + "/" + outFileName, + File::Mode::write, outFileName); } cout << endl; diff --git a/utils/sample_combine.cpp b/utils/sample_combine.cpp index 343f53d..7b85a73 100644 --- a/utils/sample_combine.cpp +++ b/utils/sample_combine.cpp @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include using namespace std; diff --git a/utils/sample_read.cpp b/utils/sample_read.cpp index e8e458c..59bf2f3 100644 --- a/utils/sample_read.cpp +++ b/utils/sample_read.cpp @@ -18,27 +18,32 @@ */ #include -#include +#include using namespace std; using namespace Latan; int main(int argc, char *argv[]) { - if (argc != 2) + if ((argc < 2) || (argc > 3)) { - cerr << "usage: " << argv[0] << " " << endl; + cerr << "usage: " << argv[0] << " []" << endl; return EXIT_FAILURE; } - - string fileName = argv[1]; + + string fileName = argv[1], copy = (argc >= 3) ? argv[2] : ""; cout << "-- loading sample from '" << fileName << "'..." << endl; - DMatSample s = Io::load(fileName); + DMatSample s = Io::load(fileName); + string name = Io::getFirstName(fileName); cout << scientific; cout << "central value:\n" << s[central] << endl; cout << "standard deviation:\n" << s.variance().cwiseSqrt() << endl; + if (!copy.empty()) + { + Io::save(s, copy, File::Mode::write, name); + } return EXIT_SUCCESS; }