# The numerical gromacs version. It is 40600 for 4.6.0.
# The #define GMX_VERSION in gromacs/version.h is set to this value.
-math(EXPR NUM_VERSION
+math(EXPR NUM_VERSION
"${CPACK_PACKAGE_VERSION_MAJOR}*10000 + ${CPACK_PACKAGE_VERSION_MINOR}*100")
if(CPACK_PACKAGE_VERSION_PATCH)
math(EXPR NUM_VERSION
option(GMX_GPU "Enable GPU acceleration" ON)
option(GMX_OPENMP "Enable OpenMP-based multithreading" ON)
+option(GMX_USE_TNG "Use the TNG library for trajectory I/O" ON)
+
option(GMX_GIT_VERSION_INFO "Generate git version information" ${SOURCE_IS_GIT_REPOSITORY})
mark_as_advanced(GMX_GIT_VERSION_INFO)
if(NOT GMX_OPENMP)
#Unset all OpenMP flags in case OpenMP was disabled either by the user
#or because it was only partially detected (e.g. only for C but not C++ compiler)
- unset(OpenMP_C_FLAGS CACHE)
+ unset(OpenMP_C_FLAGS CACHE)
unset(OpenMP_CXX_FLAGS CACHE)
else()
set(GMX_EXE_LINKER_FLAGS ${GMX_EXE_LINKER_FLAGS} ${OpenMP_LINKER_FLAGS})
endif ()
endif()
+# TODO The Windows builds are still broken (we are avoiding some
+# unknown bug, perhaps with checkpointing?), because defaulting to
+# .tng output leads to calling null-op implementation functions, so
+# regressiontests will fail on Windows at the post-mdrun stages. We
+# can fix this during the 5.0 beta phase.
+gmx_add_cache_dependency(GMX_USE_TNG BOOL "NOT GMX_NATIVE_WINDOWS" OFF)
+
+if(GMX_USE_TNG)
+ find_package(ZLIB)
+ set(TNG_BUILD_FORTRAN OFF CACHE BOOL "Build Fortran compatible TNG library and examples for testing")
+ set(TNG_BUILD_EXAMPLES OFF CACHE BOOL "Build examples showing usage of the TNG API")
+ set(TNG_BUILD_COMPRESSION_TESTS OFF CACHE BOOL "Build tests of the TNG compression library")
+ # TODO reconsider use of OpenMP in TNG if/when trajectory writing is not serial in mdrun
+ set(TNG_USE_OPENMP ${GMX_OPENMP} CACHE BOOL "Try to use the OpenMP library (if available) with TNG")
+ set(TNG_BUILD_DOCUMENTATION OFF CACHE BOOL "Use Doxygen to create the HTML based TNG API documentation")
+ set(TNG_BUILD_TEST OFF CACHE BOOL "Build TNG testing binary.")
+ add_subdirectory(${CMAKE_SOURCE_DIR}/src/external/tng_io)
+ set(GMX_TNG_LIBRARIES tng_io)
+endif()
+mark_as_advanced(TNG_BUILD_FORTRAN)
+mark_as_advanced(TNG_BUILD_EXAMPLES)
+mark_as_advanced(TNG_BUILD_COMPRESSION_TESTS)
+mark_as_advanced(TNG_USE_OPENMP)
+mark_as_advanced(TNG_BUILD_DOCUMENTATION)
+mark_as_advanced(TNG_BUILD_TEST)
+mark_as_advanced(TNG_EXAMPLE_FILES_DIR)
+
if (GMX_BUILD_FOR_COVERAGE)
# Code heavy with asserts makes conditional coverage close to useless metric,
# as by design most of the false branches are impossible to trigger in
%
% This file is part of the GROMACS molecular simulation package.
%
-% Copyright (c) 2013, by the GROMACS development team, led by
+% Copyright (c) 2013,2014, by the GROMACS development team, led by
% Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
% and including many others, as listed in the AUTHORS file in the
% top-level source directory and at http://www.gromacs.org.
use the same groups for temperature coupling and center of mass motion
removal.
-\item[\swapindex{XTC output}{group}]
-In order to reduce the size of the {\tt .xtc{\index{XTC}}} trajectory file, only a subset
-of all particles can be stored. All XTC groups that are specified
-are saved, the rest is not. If no XTC groups are specified, than all
-atoms are saved to the {\tt .xtc} file.
+\item[\swapindex{Compressed position output}{group}]
+
+In order to further reduce the size of the compressed trajectory file
+({\tt .xtc{\index{XTC}}} or {\tt .tng{\index{TNG}}}), it is possible
+to store only a subset of all particles. All x-compression groups that
+are specified are saved, the rest are not. If no such groups are
+specified, than all atoms are saved to the compressed trajectory file.
\end{description}
The use of groups in {\gromacs} tools is described in
% LocalWords: GROningen MAchine BIOSON Groningen GROMACS Berendsen der Spoel
% LocalWords: Drunen Comp Phys Comm ROck NS FFT pbc EM ifthenelse gmxlite ff
% LocalWords: octahedra triclinic Ewald PME PPPM trjconv xy solvated
-% LocalWords: boxtypes boxshapes editconf Lennard mdpopt COM XTC kT defunits
+% LocalWords: boxtypes boxshapes editconf Lennard mdpopt COM XTC TNG kT defunits
% LocalWords: Boltzmann's Mueller nb int mdrun chargegroup simplerc prefactor
% LocalWords: pme waterloops CH NH CO df com virial integrator Verlet vverlet
% LocalWords: integrators ref timepoint timestep timesteps mdp md vv avek NVE
% LocalWords: zy zz se barostat compressibilities MTTK NPT Martyna al isobaric
% LocalWords: Tuckerman vir PV fkT iLt iL Liouville NHC Eq baro mu trj mol bc
% LocalWords: freezegroup Shannon's polarizability Overhauser barostats iLn KE
-% LocalWords: negligibly thermostatted Tobias rhombic maxwell et xtc TC rlist
+% LocalWords: negligibly thermostatted Tobias rhombic maxwell et xtc tng TC rlist
% LocalWords: waals LINCS holonomic plincs lincs unc ang SA Langevin SD amu BD
% LocalWords: bfgs Broyden Goldfarb Shanno mkT kJ DFLEXIBLE Nocedal diag nmeig
% LocalWords: diagonalization anaeig nmens covanal ddg feia BT dp dq pV dV dA
rtp
tex
top
+tng
tpa
tpb
tpr
<br><dt><h3>Trajectory files</h3>
<dd><dl compact>
+<dt><a href="tng.html">tng</a> <dd>Any kind of data (compressed, portable, any precision)
<dt><a href="trj.html">trj</a> <dd>x, v and f (binary, full precision)
<dt><a href="trr.html">trr</a> <dd>x, v and f (binary, full precision, portable)
<dt><a href="xtc.html">xtc</a> <dd>x only (compressed, portable, any precision)
<dt><a href="gro.html">gro</a> <dd>x and v (ascii, any precision)
<dt><a href="g96.html">g96</a> <dd>x only (ascii, fixed high precision)
<dt><a href="pdb.html">pdb</a> <dd>x only (ascii, reduced precision)
-<dt><b>Full precision formats:</b>
+<dt><b>Formats for full-precision data:</b>
+<a href="tng.html">tng</a>,
<a href="trr.html">trr</a> or
<a href="trj.html">trj</a>
<dt><b>Generic trajectory formats:</b>
+<a href="tng.html">tng</a>,
<a href="xtc.html">xtc</a>,
<a href="trr.html">trr</a>,
<a href="trj.html">trj</a>,
nstvout = 5000
nstlog = 5000
nstenergy = 250
-nstxtcout = 250
-xtc-grps = Protein
+nstxout-compressed = 250
+compressed-x-grps = Protein
energygrps = Protein SOL
nstlist = 10
ns-type = grid
nstlog = 5000
nstenergy = 250
; Output frequency and precision for xtc file =
-nstxtcout = 250
-xtc-precision = 1000
+nstxout-compressed = 250
+compressed-x-precision = 1000
; This selects the subset of atoms for the xtc file. You can =
; select multiple groups. By default all atoms will be written. =
-xtc-grps = Protein
+compressed-x-grps = Protein
; Selection of energy groups =
energygrps = Protein SOL
<li><A HREF="#em"><b>energy minimization</b></A> (emtol, emstep, nstcgsteep)
<li><a HREF="#shellmd"><b>shell molecular dynamics</b></a>(emtol,niter,fcstep)
<li><a HREF="#tpi"><b>test particle insertion</b></a>(rtpi)
-<li><A HREF="#out"><b>output control</b></A> (nstxout, nstvout, nstfout, nstlog, nstcalcenergy, nstenergy, nstxtcout, xtc-precision, xtc-grps, energygrps)
+<li><A HREF="#out"><b>output control</b></A> (nstxout, nstvout, nstfout, nstlog, nstcalcenergy, nstenergy, nstxout-compressed, compressed-x-precision, compressed-x-grps, energygrps)
<li><A HREF="#nl"><b>neighbor searching</b></A> (cutoff-scheme, nstlist, nstcalclr, ns-type, pbc, periodic-molecules, verlet-buffer-tolerance, rlist, rlistlong)
<li><A HREF="#el"><b>electrostatics</b></A> (coulombtype, coulomb-modifier, rcoulomb-switch, rcoulomb, epsilon-r, epsilon-rf)
<li><A HREF="#vdw"><b>VdW</b></A> (vdwtype, vdw-modifier, rvdw-switch, rvdw, DispCorr)
<h3>Output control</h3>
<dl>
<dt><b>nstxout: (0) [steps]</b></dt>
-<dd>frequency to write coordinates to output
+<dd>number of steps that elapse between writing coordinates to output
<!--Idx-->trajectory file<!--EIdx-->, the last coordinates are always written</dd>
<dt><b>nstvout: (0) [steps]</b></dt>
-<dd>frequency to write velocities to output trajectory,
+<dd>number of steps that elapse between writing velocities to output trajectory,
the last velocities are always written</dd>
<dt><b>nstfout: (0) [steps]</b></dt>
-<dd>frequency to write forces to output trajectory.</dd>
+<dd>number of steps that elapse between writing forces to output trajectory.</dd>
<dt><b>nstlog: (1000) [steps]</b></dt>
-<dd>frequency to write energies to <!--Idx-->log file<!--EIdx-->,
+<dd>number of steps that elapse between writing energies to the <!--Idx-->log file<!--EIdx-->,
the last energies are always written</dd>
<dt><b>nstcalcenergy: (100)</b></dt>
-<dd>frequency for calculating the energies, 0 is never.
+<dd>number of steps that elapse between calculating the energies, 0 is never.
This option is only relevant with dynamics.
With a twin-range cut-off setup <b>nstcalcenergy</b> should be equal to
or a multiple of <b>nstlist</b>.
processes which can become a bottleneck at high parallelization.
</dd>
<dt><b>nstenergy: (1000) [steps]</b></dt>
-<dd>frequency to write energies to energy file,
+<dd>number of steps that else between writing energies to energy file,
the last energies are always written,
should be a multiple of <b>nstcalcenergy</b>.
Note that the exact sums and fluctuations over all MD steps
modulo <b>nstcalcenergy</b> are stored in the energy file,
so <tt>g_energy</tt> can report exact
energy averages and fluctuations also when <b>nstenergy</b><tt>>1</tt></dd>
-<dt><b>nstxtcout: (0) [steps]</b></dt>
-<dd>frequency to write coordinates to xtc trajectory</dd>
-<dt><b>xtc-precision: (1000) [real]</b></dt>
-<dd>precision to write to xtc trajectory</dd>
-<dt><b>xtc-grps:</b></dt>
-<dd>group(s) to write to xtc trajectory, default the whole system is written
-(if <b>nstxtcout</b> > 0)</dd>
+<dt><b>nstxout-compressed: (0) [steps]</b></dt>
+<dd>number of steps that elapse between writing position coordinates using lossy compression</dd>
+<dt><b>compressed-x-precision: (1000) [real]</b></dt>
+<dd>precision with which to write to the compressed trajectory file</dd>
+<dt><b>compressed-x-grps:</b></dt>
+<dd>group(s) to write to the compressed trajectory file, by default the whole system is written
+(if <b>nstxout-compressed</b> > 0)</dd>
<dt><b>energygrps:</b></dt>
<dd>group(s) to write to energy file</dd>
</dl>
<A HREF="#tc">nsttcouple</A><br>
<A HREF="#out">nstvout</A><br>
<A HREF="#out">nstxout</A><br>
-<A HREF="#out">nstxtcout</A><br>
+<A HREF="#out">nstxout-compressed</A><br>
<A HREF="#expanded">nst-transition-matrix</A><br>
<A HREF="#nl">ns-type</A><br>
<A HREF="#wall">nwall</A><br>
<A HREF="#vdw">vdwtype</A><br>
<A HREF="#vdw">vdw-modifier</A><br>
<A HREF="#nl">verlet-buffer-tolerance</A><br>
-<A HREF="#out">xtc-grps</A><br>
-<A HREF="#out">xtc-precision</A><br>
+<A HREF="#out">compressed-x-grps</A><br>
+<A HREF="#out">compressed-x-precision</A><br>
<A HREF="#sa">zero-temp-time</A><br>
<A HREF="#walls">wall-atomtype</A><br>
<A HREF="#walls">wall-density</A><br>
--- /dev/null
+<title>tng file format</title>
+<h3>Description</h3>
+Files with the .tng file extension can contain all kinds of data
+related to the trajectory of a simulation. For example, it might
+contain coordinates, velocities, forces and/or energies. Various .mdp
+file options control which of these are written by mdrun, whether data
+is written with compression, and how lossy that compression can be.
+This file is in portable binary format an can be read
+with <a href="../programs/gmx-dump.html">gmx dump</a>.
+<PRE>
+% <a href="../programs/gmx-dump.html">gmx dump</a> -f traj.tng
+</PRE>
+or if you're not such a fast reader:
+<PRE>
+% gmxdump -f traj.tng | more
+</PRE>
+
+<p>
+You can also get a quick look in the contents of the file (number of
+frames etc.) using:
+<PRE>
+% <a href="../programs/gmx-check.html">gmx check</a> -f traj.tng
+</PRE>
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2009,2010,2011,2012,2013, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
/* Use our own instead of system XDR libraries */
#cmakedefine GMX_INTERNAL_XDR
+/* Compile to use TNG library */
+#cmakedefine GMX_USE_TNG
+
/* Use MPI (with mpicc) for parallelization */
#cmakedefine GMX_LIB_MPI
--- /dev/null
+The TNG trajectory format is developed by:
+
+Magnus Lundborg <magnus.lundborg@scilifelab.se>
+Daniel Spångberg <daniels@mkem.uu.se>
+Rossen Apostolov <rossen@kth.se>
+
+The API is implemented mainly by:
+
+Magnus Lundborg
+Daniel Spångberg (TNG-MF1 compression)
+Anders Gärdenäs (C++ wrapper)
\ No newline at end of file
--- /dev/null
+cmake_minimum_required(VERSION 2.8)
+
+if(CMAKE_BUILD_TOOL MATCHES "(msdev|devenv|nmake)")
+ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /W2")
+else()
+ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall")
+endif()
+
+project(TNG_IO)
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
+
+option(BUILD_SHARED_LIBS "Enable shared libraries" ON)
+
+option(TNG_BUILD_FORTRAN "Build Fortran compatible library and examples for testing" OFF)
+
+option(TNG_BUILD_EXAMPLES "Build examples showing usage of the TNG API" ON)
+option(TNG_BUILD_TEST "Build TNG testing binary." ON)
+option(TNG_BUILD_COMPRESSION_TESTS "Build tests of the TNG compression library" OFF)
+
+option(TNG_USE_OPENMP "Try to use the OpenMP library (if available)" OFF)
+if(TNG_USE_OPENMP)
+ find_package(OpenMP)
+ if(OPENMP_FOUND)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
+ endif()
+endif()
+
+find_package(ZLIB)
+
+include(CheckIncludeFile)
+check_include_file(inttypes.h HAVE_INTTYPES_H)
+
+add_subdirectory(src)
+
+install(FILES include/tng_io.h DESTINATION include/)
+
+#-- Add an Option to toggle the generation of the API documentation
+option(TNG_BUILD_DOCUMENTATION "Use Doxygen to create the HTML based API documentation" OFF)
+if(TNG_BUILD_DOCUMENTATION)
+ find_package(Doxygen)
+ if (NOT DOXYGEN_FOUND)
+ message(FATAL_ERROR
+ "Doxygen is needed to build the documentation. Please install it correctly")
+ endif()
+ #-- Configure the Template Doxyfile for our specific project
+ configure_file(Doxyfile.in
+ ${PROJECT_BINARY_DIR}/Doxyfile @ONLY IMMEDIATE)
+ #-- Add a custom target to run Doxygen when ever the project is built
+ add_custom_target (Docs ALL
+ COMMAND ${DOXYGEN_EXECUTABLE} ${PROJECT_BINARY_DIR}/Doxyfile
+ SOURCES ${PROJECT_BINARY_DIR}/Doxyfile)
+ # IF you do NOT want the documentation to be generated EVERY time you build the project
+ # then leave out the 'ALL' keyword from the above command.
+endif()
+
--- /dev/null
+Copyright (c) 2012-2013, The GROMACS development team,
+check out http://www.gromacs.org for more information.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+ * Neither the name of the GROMACS development team 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 <COPYRIGHT HOLDER> 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.
\ No newline at end of file
--- /dev/null
+# Doxyfile 1.7.6.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or sequence of words) that should
+# identify the project. Note that if you do not use Doxywizard you need
+# to put quotes around the project name if it contains spaces.
+
+PROJECT_NAME = "TNG API"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = "1.4"
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = "A flexible binary trajectory format"
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = @PROJECT_BINARY_DIR@/Documentation
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH = @PROJECT_SOURCE_DIR@/src/lib
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding
+# "class=itcl::class" will allow you to use the command class in the
+# itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this
+# tag. The format is ext=language, where ext is a file extension, and language
+# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
+# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
+# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
+# unions are shown inside the group in which they are included (e.g. using
+# @ingroup) instead of on a separate page (for HTML and Man pages) or
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
+# unions with only public data fields will be shown inline in the documentation
+# of the scope in which they are defined (i.e. file, namespace, or group
+# documentation), provided this scope is documented. If set to NO (the default),
+# structs, classes, and unions are shown on a separate page (for HTML and Man
+# pages) or section (for LaTeX and RTF).
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
+# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
+# their name and scope. Since this can be an expensive process and often the
+# same symbol appear multiple times in the code, doxygen keeps a cache of
+# pre-resolved symbols. If the cache is too small doxygen will become slower.
+# If the cache is too large, memory is wasted. The cache size is given by this
+# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
+# do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even
+# if there is only one candidate or it is obvious which candidate to choose
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. The create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files
+# containing the references data. This must be a list of .bib files. The
+# .bib extension is automatically appended if omitted. Using this command
+# requires the bibtex tool to be installed. See also
+# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
+# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
+# feature you need bibtex and perl available in the search path.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = @PROJECT_SOURCE_DIR@/src/lib @PROJECT_SOURCE_DIR@/include
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE = @PROJECT_SOURCE_DIR@/src/lib/md5.c @PROJECT_SOURCE_DIR@/include/md5.h @PROJECT_SOURCE_DIR@/include/tng_io.hpp @PROJECT_SOURCE_DIR@/src/lib/tng_io.c
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS = *_
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header. Note that when using a custom header you are responsible
+# for the proper inclusion of any scripts and style sheets that doxygen
+# needs, which is dependent on the configuration options used.
+# It is advised to generate a default header using "doxygen -w html
+# header.html footer.html stylesheet.css YourConfigFile" and then modify
+# that header. Note that the header is subject to change so you typically
+# have to redo this when upgrading to a newer version of doxygen or when
+# changing the value of configuration settings such as GENERATE_TREEVIEW!
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# style sheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the style sheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+# will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
+# at top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it. Since the tabs have the same information as the
+# navigation tree you can set this option to NO if you already set
+# GENERATE_TREEVIEW to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+# Since the tree basically has the same information as the tab index you
+# could consider to set DISABLE_INDEX to NO when enabling this option.
+
+GENERATE_TREEVIEW = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML
+# documentation. Note that a value of 0 will completely suppress the enum
+# values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the
+# mathjax.org site, so you can quickly see the result without installing
+# MathJax, but it is strongly recommended to install a local copy of MathJax
+# before deployment.
+
+MATHJAX_RELPATH = http://www.mathjax.org/mathjax
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
+# names that should be enabled during MathJax rendering.
+
+MATHJAX_EXTENSIONS =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvantages are that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
+# the generated latex document. The footer should contain everything after
+# the last chapter. If it is left blank doxygen will generate a
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
+# http://en.wikipedia.org/wiki/BibTeX for more info.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load style sheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that
+# overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS = 0
+
+# By default doxygen will use the Helvetica font for all dot files that
+# doxygen generates. When you want a differently looking font you can specify
+# the font name using DOT_FONTNAME. You need to make sure dot is able to find
+# the font, which can be done by putting it in a standard location or by setting
+# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the Helvetica font.
+# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
+# set the path where dot can find it.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are svg, png, jpg, or gif.
+# If left blank png will be used. If you choose svg you need to set
+# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible in IE 9+ (other browsers do not have this requirement).
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+# Note that this requires a modern browser other than Internet Explorer.
+# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
+# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible. Older versions of IE do not have SVG support.
+
+INTERACTIVE_SVG = NO
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = YES
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
--- /dev/null
+mkdir build
+cd build
+cmake ..
+make
+
+
+Test by running:
+bin/tng_testing
+
+Make a system-wide installation by:
+make install
+(this will require administrative privileges on most systems, i.e. 'sudo make install'
+on a Unix like system with a sudoers file)
+
+
+Useful cmake flags:
+-DTNG_BUILD_DOCUMENTATION=ON to build the API documentation (requires doxygen)
+-DCMAKE_BUILD_TYPE=Debug to compile with debug flags (recommended for
+feedback during development)
+-DTNG_BUILD_FORTRAN=ON to build the Fortran MD simulations example, saving results
+in the TNG format (requires a Fortran compiler allowing cray-pointers).
\ No newline at end of file
--- /dev/null
+Trajectory format specification
+
+1. Release notes
+ =============
+
+General notes:
+--------------
+
+\* Currently the API is lacking many data retrieval and getter
+functions. This will be fixed soon.
+
+\* It might be problematic searching for a specific time if frames are
+not consecutive. This problem is somewhat hypothetical, but might be
+good to point out.
+
+\* Currently we cannot track a specific molecule in a grand canonical
+ensemble.
+
+\* We should request comments on the specs from other groups - after v1.
+
+Erik's comments:
+
+\* Keep the number of calls small
+
+\* Use a prefix for the calls, e.g. tng\_open, tng\_close, etc.; use
+e.g. adv\_ prefix for advanced API
+
+\* Help routine to return the full list of atom types
+
+\* In general info:
+
+- number of stride pointers
+
+- for each pointer, the number of frame sets that it skips
+
+=\> have 3 stride pointers with defaults 1, 100 and 10,000 frame sets
+
+\* include zlib as a supported compressor
+
+To do:
+------
+
+\* Make a drawing
+
+\* Include API function for signing of the trajectory
+
+\* Sanity checklist:
+
+1. Block header size
+2. Block contents size
+3. Compare hashes (currently doesn’t abort only prints warning)
+
+1. maybe add a flag to choose between abort/warning
+2. empty hash is always accepted
+
+4.
+
+Version 0.98
+------------
+
+\* Use signed int instead of unsigned.
+
+\* Changed names from ‘trg’ to ‘tng’.
+
+Version 0.97
+------------
+
+\* Added chains and residues to the molecule description.
+
+Version 0.96
+------------
+
+\*Renamed “Trajectory Box Shape”, “Trajectory Positions” etc.
+
+\*Renamed “Trajectory Index Block” to “Particle Mapping Block”
+
+Version 0.95
+------------
+
+\* Changed name of ‘Atom name block’ to ‘Molecule block’ and included
+connectivity in that block. The number of each molecule is also
+specified there, unless using variable number of particles (grand
+canonical ensemble).
+
+\* Removed ‘variable number of particles’ and ‘variable number of
+values’ flags from data blocks.
+
+\* Updated the API and headers
+
+Version 0.9
+-----------
+
+\* Removed endianness/string block
+
+\* Added PGP signature to General Info block
+
+\* Removed reserved ‘user data blocks’. Those are already handled as
+normal ‘data blocks’. Reserved are only box, positions, velocities and
+forces.
+
+Version 0.8
+
+\* Use only MD5 hashes
+
+\* Changed time (in general info block) to 64 bit int.
+
+Version 0.7
+-----------
+
+\* New hierarchy rules
+
+\* Changed "Trajectory Info" to "General Info" block
+
+\* Moved "BOX SHAPE" before the index and trajectory frame blocks
+
+\* general, int., bin32, bin64 user data is explicitly not frame
+dependent
+
+\* Variable number of atoms will be supported in version 1
+
+\* Made more clear the nesting in the "trajectory group blocks"
+
+\* Allow header only files, i.e. no trajectory blocks
+
+\* Removed number of frames from the "index block" description
+
+\* Removed ASCII recommendation from the string description, i.e. [1]
+
+\* Added molecule ID to “atom name block”
+
+Version 0.6
+-----------
+
+Changed endianness block to endianness and string length block.
+
+Changed order of hash specifications in the header block.
+
+Added initial API specifications
+
+Version 0.5
+-----------
+
+Included an additional header block that specifies the endianness. It
+comes before all other blocks.
+
+2. Specifications
+ ==============
+
+General specifications are given below. Others are described in the
+relevant block sections.
+
+1. The file contains a number of blocks.
+2. The order of the blocks follows the order specified in section 4
+ “Description of blocks”
+3. All integers and floating point (floats and doubles) values are
+ stored using big endian byte ordering. Conversions to and from the
+ native format of the computer is performed during reading and
+ writing of numerical fields.
+4. MD5 hashes are used to verify the integrity of the data.
+5. Strings are limited to a max length of 1023 characters and are
+ terminated by a null character (‘\\000’). If longer text data must
+ be saved a data block containing multiple entries of general
+ (character/string) data can be used.
+6. If a trajectory converter program encounters errors during reading a
+ block which format is not recognized, the block is to be written out
+ as binary object without modification.
+7. Each group of blocks to contain a Table of Contents which lists the
+ included blocks within the group.^[[a]](#cmnt1)^
+8. No compression (in ver.1) for general data streams such as integers,
+ floating point numbers, particle indices etc.
+
+3. Each block contains the following fields (header):
+ ==================================================
+
+1. 64 bit size of the header
+2. 64 bit size of the block contents (except header)
+3. 64 bit block type identifier
+4. 16 characters MD5 Hash (or 16 “\\0” characters)
+5. name[1]
+6. 64 bit version of the block ^[[b]](#cmnt2)^(allows addition of more
+ fields in the future to existing blocks, although old fields should
+ never be removed, to allow older readers read new files)
+
+4. Description of blocks (each with a unique 64 bit identifier and a matching "name"):
+ ===================================================================================
+
+1. info block (1) "GENERAL INFO" (required)
+2. molecules block (2) "MOLECULES" (optional)
+3. trajectory ids and names (4) “TRAJECTORY IDS AND NAMES” (optional)
+4. trajectory frames, box shape block (10000) "BOX SHAPE" (optional,
+ can be present before the frame sets if it does not change or inside
+ the frame sets if it varies)
+5. trajectory frame set block (5) "TRAJECTORY FRAME SET" (required)
+ (multiple “trajectory frame sets” are allowed)
+
+1. trajectory table of contents block (6) “BLOCK TABLE OF CONTENTS”
+ (required)
+2. trajectory frames, box shape block (10000) "BOX SHAPE" (optional,
+ can be present before the frame sets if it does not change or inside
+ the frame sets if it varies)
+3. trajectory particle mapping block (7) "PARTICLE MAPPING" (required
+ if there are trajectory frames blocks) (multiple particle mapping
+ blocks with corresponding trajectory frames blocks are allowed, e.g.
+ to allow parallel writes of different atom sets)
+
+1. trajectory frames, positions, block (10001) "POSITIONS" (optional)
+2. trajectory frames, velocities, block (10002) "VELOCITIES" (optional)
+3. trajectory frames, forces, block (10003) "FORCES" (optional)
+
+6. ...other specified blocks, both non-trajectory and trajectory
+ blocks, each with unique id & name
+
+Data blocks can be used to store whatever data is needed. Data blocks
+with IDs in the range 10000 to 10999 are reserved for standard data
+(such as box shape, positions, velocities etc.), whereas IDs from 11000
+and above can be used for any kind of user data.
+
+5. NOTES ABOUT BLOCK KINDS:
+ ========================
+
+There can be only one block at the beginning of the file in the standard
+case with fixed charges throughout the simulation (that’s the case for
+version 1 of the format). For simulations where charges vary each frame
+will include a block with the values.
+
+The trajectory frame blocks must be collected into frame sets, each
+
+such frame set has as its first block the "trajectory frame set block".
+Each frame set will contain (multiple) particle mapping blocks,
+positions, velocities, forces etc.^[[c]](#cmnt3)^
+
+6. Requirements on block order:
+ ============================
+
+1. The order follows section 4. “Description of blocks” with the
+ corresponding nesting of multiple “trajectory frame sets” and
+ “particle mapping blocks”.
+2. All non-trajectory frame blocks (e.g. user ones) must appear before
+ the trajectory blocks
+3. Trajectory particle mapping blocks are optional. If they are
+ present, they must appear before the corresponding trajectory data
+ blocks. If there are multiple trajectory data blocks, the
+ corresponding particle mapping blocks come right before them. I.e.
+ ParticleMappingBlock1-\>DataBlock1-\>P.MappingBlock2-\>DataBlock2.
+4. Blocks within a group of blocks are ordered by their ID.
+
+7. Other requirements:
+ ===================
+
+1. Most blocks are optional except for the “general info” blocks
+2. No limit on the number of times that trajectory related blocks are
+ allowed to appear
+
+8. Specification of the block contents (all blocks have the same header as described above) for version 1 of each block type.
+ ==========================================================================================================================
+
+BLOCK: general info block
+-------------------------
+
+1. name and version of the program used to perform the simulation (upon
+ file creation)[1]
+2. name and version of the program used when finishing the file[1]
+3. name of the force field used to perform the simulation
+ [1]^[[d]](#cmnt4)^
+4. name of the person who created the file [1]
+5. name of the person who last modified the file [1]
+6. 64 bit time of initial file creation, seconds since 1970
+7. 64 bit time of completing the simulation, seconds since 1970
+8. name of computer/other info where the file was created [1]
+9. name of computer/other info where the file was completed [1]
+10. PGP signature (optional and 0 terminated string)
+11. 8 bit flag Use variable number of atoms.
+12. 64 bit number of frames in each frame set (this is the expected
+ number of frames in each set, but it does not have to be constant,
+ it is OK to have frame sets with fewer or more frames, e.g. after
+ concatenating multiple trajectory files. This avoids the need to
+ recompress all data after a concatenation, but it means that
+ searching for a specific frame might need a few more steps between
+ frame sets.). For simulations using a grand canonical ensemble it is
+ best to set this to 1 so that the number of atoms in the frame sets
+ can be updated regularly.
+13. 64 bit pointer from the beginning of the info block to the beginning
+ of the first trajectory frame set [2]
+14. 64 bit pointer from the beginning of the info block to the beginning
+ of the last trajectory frame set [2] (updated when finishing writing
+ the trajectory file - otherwise set to -1)
+15. 64 bit length of steps (number of “trajectory frame set blocks”) for
+ long stride pointers (default 100 “trajectory frame set blocks”).
+
+BLOCK: molecules block (optional)
+---------------------------------
+
+1. 64 bit number of molecules
+2. For each molecule:
+
+1. 64 bit Molecule ID
+2. Molecule name [1]
+3. 64 bit quaternary structure, e.g. 1 means monomeric, 4 means
+ tetrameric etc.
+4. 64 bit number of molecules of this kind - only if not using
+ “variable number of atoms” in the “general info block”.
+5. 64 bit number of chains in the molecule
+6. 64 bit number of residues in the molecule
+7. 64 bit number of atoms in the molecule^[[e]](#cmnt5)^
+8. For each chain:
+
+1. 64 bit Chain ID (unique in molecule)
+2. Chain name [1]
+3. 64 bit number of residues in the chain
+4. For each residue:
+
+1. 64 bit Residue ID (unique in the chain)
+2. Residue name [1]
+3. 64 bit number of atoms in the residue
+4. For each atom:
+
+1. 64 bit Atom ID (unique in the molecule)
+2. Atom name [1]
+3. Atom type [1]
+
+9. 64 bit number of bonds in the molecule
+10. For each bond:
+
+5. 64 bit integer From Atom ID.
+6. 64 bit integer To Atom ID.
+
+BLOCK: trajectory frame set block
+---------------------------------
+
+1. 64 bit number of first frame (zero based numbering)
+2. 64 bit number of frames (NF)
+3. Array of 64 bit integers specifying the count of each molecule type.
+ The molecule types are listed in the “Atom names block” and should
+ be listed in the same order here. This should only be present when
+ the variable number of atoms flag in the “General info block” is set
+ to TRUE. This is used for e.g. simulations using a grand canonical
+ ensemble (in which case the number of frames in each frame set
+ should be 1).
+4. 64 bit pointer to the next “trajectory frame set block”.
+5. 64 bit pointer the previous “trajectory frame set block”.
+6. 64 bit long stride pointer to the next e.g. 100th “trajectory frame
+ set block”. (Stride length specified in “general info” block.)
+7. 64 bit long stride pointer to the previous e.g. 100th “trajectory
+ frame set block”.
+
+BLOCK: trajectory table of contents
+-----------------------------------
+
+1. 64 bit number of blocks
+
+Contains a listing of all data blocks \_present\_ in the frame set. It
+is possible to have multiple blocks with the same ID, but the ID is only
+listed once in the “trajectory table of contents” block.
+
+It includes for each block type:
+
+1. Block name [1]
+
+BLOCK: data blocks
+------------------
+
+Frame dependent data blocks should come after the frame set block to
+which it belongs. Frame and particle dependent data blocks should come
+after the relevant particle mapping block (if using any particle mapping
+block).
+
+1. Char data type flag. 0 = character/string data, 1 = 64 bit integer
+ data, 2 = float data (32 bit), 3 = double data (64 bit)
+2. Char dependency flag. 1 = frame dependent, 2 = particle dependent.
+ Can be combined, i.e. 3 = frame and particle dependent.
+3. Char sparse data flag to signify if not all frames in the frame sets
+ have data entries in this data block, e.g. energies and positions
+ might be saved at different intervals meaning that at least one of
+ them would be saved as sparse data. Only present if the data is
+ frame dependent.
+4. 64 bit number of values.
+5. 64 bit id of the CODEC used to store the positions
+6. Double (64 bit) multiplier for integers to obtain the appropriate
+ floating point number, for compressed frames [3] [\*\*] (only
+ present if the above CODEC id is \> 0 and if the data type is double
+ or float)
+
+If using sparse data the following fields are required:
+
+1. 64 bit number of first frame containing data.
+2. 64 bit number of frames between data points
+
+Particle dependent data blocks contain the following fields:
+
+1. 64 bit number of first particle as stored in the trajectory, zero
+ based numbering) (J), this must be the same as in the preceding
+ trajectory particle mapping block, if present.
+
+1. 64 bit number of particles in block, this must be the same as in the
+ preceding trajectory particle mapping block, if present.
+
+Example 1:
+
+Box shape block (10000) in a frame set with frames 0-99:
+
+1. Data type: 3 (double)
+2. Dependency: 1 (frame dependent)
+3. Sparse data: 1
+4. Number of values: 9
+5. Codec ID: 0
+6. First frame containing data: 0
+7. Number of frames between data points: 50
+8. For each frame (2 frames with data in this block):
+
+1. 9 double (64 bit) values describing the shape of the block
+
+Example 2:
+
+Positions block (ID 10001) in a frame set with frames 1000-1099:
+
+1. Data type: 2 (float)
+2. Dependency: 3 (frame and particle dependent)
+3. Sparse data: 1
+4. Number of values: 3 (x, y and z)
+5. Coded ID: 0
+6. First frame containing data: 100
+7. Number of frames between data points: 10
+8. Number of first particle: 0
+9. Number of particles in block: 1000
+10. For each frame (10 frames with data in this block):
+
+1. For each particle (1000 particles):
+
+1. 32 bit float x coordinate
+2. 32 bit float y coordinate
+3. 32 bit float z coordinate
+
+Example 3:
+
+Forces block (ID 10003) in a frame set with frames 0-99:
+
+11. Data type: 2 (float)
+12. Dependency: 3 (frame and particle dependent)
+13. Sparse data: 0
+14. Number of values: 3 (x, y and z)
+15. Coded ID: 0
+16. Number of first particle: 0
+17. Number of particles in block: 100
+18. For each frame (100 frames with data in this block):
+
+2. For each particle (100 particles):
+
+1. 32 bit float x coordinate
+2. 32 bit float y coordinate
+3. 32 bit float z coordinate
+
+BLOCK: particle mapping block
+-----------------------------
+
+1. 64 bit number of first particle (particle number as stored in the
+ trajectory, zero based numbering) (J)
+2. 64 bit number of particles in this particle mapping block (M)
+3. 64 bit array of particle numbers^[[f]](#cmnt6)^ (M values):
+
+1. Each value is the number of the real particle corresponding to the
+ particle number as stored in the trajectory.
+
+Should no particle mapping block be present, the mapping is the number
+
+of the real particle == the particle number as stored in the trajectory.
+
+It is possible to have several trajectory/velocities etc. frame blocks
+within a frame set, e.g. when faster parallel writes or memory
+considerations are needed. In that case a separate particle mapping
+block is needed for each of the trajectory/velocities etc. blocks.
+
+Relation between trajectory blocks:
+===================================
+
+Particle mapping blocks contain the remapping of actual particle index
+and the particle index as appearing in the trajectory file. They are
+optional. If they are not given, there is no remapping. All trajectory
+blocks for the same set of particles must follow each other, i.e.
+positions for particle 0-99, then velocities for particle 0-99, then
+positions for particle 100-199, then velocities for particle 100-199.
+All non-particle trajectory blocks must appear before any particle
+containing trajectory blocks.
+
+Limitations on the number of particles in trajectory frame blocks: In
+order to be able to read and uncompress data there must be a limit on
+the number of particles in each trajectory frame block, therefore most
+trajectory frame sets will contain multiple particle mapping / positions
+/ velocities / ... blocks. The limit on the number of particles per
+trajectory frame blocks should be XXXX. This should be a good value, and
+not allowed to be set by the user, since this may prevent reading of the
+files on smaller memory machines.
+
+CODEC specifications (id) "name"
+================================
+
+1. uncompressed (0) "UNCOMPRESSED"
+2. XTC positions (1) "XTC"
+3. TNG (2) "TNG"
+4. …
+
+[](#)
+
+[\*\*] Storage of compressed positions / velocities / ...: These are now
+all converted to integers before stored. In order to facilitate
+recompression without loss of precision it is essential that these are
+visible as integers. Therefore the compression blocks all must contain
+somewhere a conversion factor from integer to float.
+
+Notes
+=====
+
+[1] UTF-8 text string. Make all text strings zero terminated.
+
+[2] 64 bit pointer format: -1UL (all ones), means "not set", which is
+what should be written whenever a pointer needs to be written when the
+appropriate value is not yet known, while 0 (all zeros), typically means
+the end of the list.
+
+[3] Floating point format is big-endian IEEE-754, float (32 bit) or
+double (64 bit).
+
+API
+===
+
+(The API should be separated into one high- and one low-level API, using
+e.g. a tng\_low tag for the low-level functions.)
+
+API documentation is generated using the -DTNG_BUILD_DOCUMENTATION=ON option
+when running cmake. Requires a doxygen installation.
+
+
+^[[g]](#cmnt7)^
+
+[[a]](#cmnt_ref1)magnus.lundborg:
+
+Currently sizes and offsets are not in the TOC block. I think it needs
+further testing to decide if it is good or not.
+
+* * * * *
+
+Sander Pronk:
+
+So how can you find out where the block is?
+
+* * * * *
+
+magnus.lundborg:
+
+If the offsets are not listed in the TOC block you would have to read
+the whole frame set, or at least all the block headers in the frame set,
+which shouldn't be too bad.
+
+[[b]](#cmnt_ref2)Roland Schulz:
+
+I suggest not to use a version number. This is already a problem with
+the tpx version and branches. Instead I suggest to have a bitvector
+where each bit says whether a certain feature is present in this file.
+Given a central registry of meaning of the bits, this allows different
+groups/branches/software to add features. Which would be difficult with
+a version number approach which has an inherently linear ordering. The
+last bit probably should be reserved to signify whether the 64bit
+bitvector is extended by a another 64bit. The data should be stored in
+the order of the bitvectors. A reader which doesn't support a certain
+bit, cannot read any of the following data if the bit is on.
+
+[[c]](#cmnt_ref3)magnus.lundborg:
+
+We will have a problem if we want to add data to a frame set in a file.
+All subsequent frame sets will need to be rewritten. One alternative
+would be to have a list of pointers to each block of each block type in
+the frame set table of contents block. But we will have a problem adding
+rows to that block as well, which in turn could be fixed by having a
+pointer from the frame set block to the "current" table of contents
+block and just let the old one remain. We could actually have a flag in
+block headers to show if the block is "up-to-date". But there is a risk
+that these pointers will be slow - especially when it comes to writing.
+
+[[d]](#cmnt_ref4)Rossen Apostolov:
+
+somehow the name of the FF doesn't fit naturally with the rest of the
+info here :)
+
+How about including the simulation setup in the file in a separate
+block? That will be needed if the file can be used for restarts too.
+
+[[e]](#cmnt_ref5)magnus.lundborg:
+
+This introduces a bit of redundancy, but helps keeping track of the
+data.
+
+[[f]](#cmnt_ref6)Roland Schulz:
+
+might be good to make this optional. And if it isn't given then the
+numbering is consecutive. The would still give the flexibility that one
+can specify the first and no of particles which isn't possible without
+index block.
+
+* * * * *
+
+Daniel Spångberg:
+
+if this is made optional, the comment below the section can be removed.
+and particle mapping blocks required, since it will not cost much extra
+to have it.
+
+[[g]](#cmnt_ref7)Rossen Apostolov:
+
+We should think of a different name for the traj. group blcok, it's
+confusing
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#ifndef BWLZH_H
+#define BWLZH_H
+
+/* Compress the integers (positive, small integers are preferable)
+ using bwlzh compression. The unsigned char *output should be
+ allocated to be able to hold worst case. You can obtain this length
+ conveniently by calling comp_get_buflen()
+*/
+void DECLSPECDLLEXPORT bwlzh_compress(unsigned int *vals, int nvals,
+ unsigned char *output, int *output_len);
+
+void DECLSPECDLLEXPORT bwlzh_compress_no_lz77(unsigned int *vals, int nvals,
+ unsigned char *output, int *output_len);
+
+int DECLSPECDLLEXPORT bwlzh_get_buflen(int nvals);
+
+void DECLSPECDLLEXPORT bwlzh_decompress(unsigned char *input, int nvals,
+ unsigned int *vals);
+
+
+/* The routines below are mostly useful for testing, and for internal
+ use by the library. */
+
+void DECLSPECDLLEXPORT bwlzh_compress_verbose(unsigned int *vals, int nvals,
+ unsigned char *output, int *output_len);
+
+void DECLSPECDLLEXPORT bwlzh_compress_no_lz77_verbose(unsigned int *vals, int nvals,
+ unsigned char *output, int *output_len);
+
+void DECLSPECDLLEXPORT bwlzh_decompress_verbose(unsigned char *input, int nvals,
+ unsigned int *vals);
+
+/* Compress the integers (positive, small integers are preferable)
+ using huffman coding, with automatic selection of how to handle the
+ huffman dictionary. The unsigned char *huffman should be allocated
+ to be able to hold worst case. You can obtain this length
+ conveniently by calling comp_huff_buflen()
+*/
+void Ptngc_comp_huff_compress(unsigned int *vals, int nvals,
+ unsigned char *huffman, int *huffman_len);
+
+int Ptngc_comp_huff_buflen(int nvals);
+
+void Ptngc_comp_huff_decompress(unsigned char *huffman, int huffman_len,
+ unsigned int *vals);
+
+
+/* the value pointed to by chosen_algo should be
+ sent as -1 for autodetect. */
+void Ptngc_comp_huff_compress_verbose(unsigned int *vals, int nvals,
+ unsigned char *huffman, int *huffman_len,
+ int *huffdatalen,
+ int *huffman_lengths,int *chosen_algo,
+ int isvals16);
+
+#define N_HUFFMAN_ALGO 3
+char *Ptngc_comp_get_huff_algo_name(int algo);
+char *Ptngc_comp_get_algo_name(int algo);
+
+
+#endif
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#ifndef BWT_H
+#define BWT_H
+
+void Ptngc_comp_to_bwt(unsigned int *vals, int nvals,
+ unsigned int *output, int *index);
+
+void Ptngc_comp_from_bwt(unsigned int *input, int nvals, int index,
+ unsigned int *vals);
+
+void Ptngc_bwt_merge_sort_inner(int *indices, int nvals,unsigned int *vals,
+ int start, int end,
+ unsigned int *nrepeat,
+ int *workarray);
+
+#endif
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+#ifndef CODER_H
+#define CODER_H
+
+#ifndef DECLSPECDLLEXPORT
+#ifdef USE_WINDOWS
+#define DECLSPECDLLEXPORT __declspec(dllexport)
+#else /* USE_WINDOWS */
+#define DECLSPECDLLEXPORT
+#endif /* USE_WINDOWS */
+#endif /* DECLSPECDLLEXPORT */
+
+struct coder
+{
+ unsigned int pack_temporary;
+ int pack_temporary_bits;
+ int stat_overflow;
+ int stat_numval;
+};
+
+struct coder DECLSPECDLLEXPORT *Ptngc_coder_init(void);
+void DECLSPECDLLEXPORT Ptngc_coder_deinit(struct coder *coder);
+unsigned char DECLSPECDLLEXPORT *Ptngc_pack_array(struct coder *coder,int *input, int *length, int coding, int coding_parameter, int natoms, int speed);
+int DECLSPECDLLEXPORT Ptngc_unpack_array(struct coder *coder,unsigned char *packed,int *output, int length, int coding, int coding_parameter, int natoms);
+unsigned char DECLSPECDLLEXPORT *Ptngc_pack_array_xtc2(struct coder *coder,int *input, int *length);
+int DECLSPECDLLEXPORT Ptngc_unpack_array_xtc2(struct coder *coder,unsigned char *packed,int *output, int length);
+unsigned char DECLSPECDLLEXPORT *Ptngc_pack_array_xtc3(int *input, int *length, int natoms, int speed);
+int DECLSPECDLLEXPORT Ptngc_unpack_array_xtc3(unsigned char *packed,int *output, int length, int natoms);
+
+void DECLSPECDLLEXPORT Ptngc_out8bits(struct coder *coder, unsigned char **output);
+void DECLSPECDLLEXPORT Ptngc_pack_flush(struct coder *coder,unsigned char **output);
+void DECLSPECDLLEXPORT Ptngc_write_pattern(struct coder *coder,unsigned int pattern, int nbits, unsigned char **output);
+
+void DECLSPECDLLEXPORT Ptngc_writebits(struct coder *coder,unsigned int value,int nbits, unsigned char **output_ptr);
+void DECLSPECDLLEXPORT Ptngc_write32bits(struct coder *coder,unsigned int value,int nbits, unsigned char **output_ptr);
+void DECLSPECDLLEXPORT Ptngc_writemanybits(struct coder *coder,unsigned char *value,int nbits, unsigned char **output_ptr);
+
+
+#endif
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#ifndef DICT_H
+#define DICT_H
+
+void Ptngc_comp_canonical_dict(unsigned int *dict, int *ndict);
+
+void Ptngc_comp_make_dict_hist(unsigned int *vals, int nvals,
+ unsigned int *dict, int *ndict,
+ unsigned int *hist);
+
+#endif
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+#ifndef FIXPOINT_H
+#define FIXPOINT_H
+
+#include "../compression/my64bit.h"
+
+/* There are at least 32 bits available in a long. */
+typedef unsigned long fix_t;
+
+/* Positive double to 32 bit fixed point value */
+fix_t Ptngc_ud_to_fix_t(double d,double max);
+
+/* double to signed 32 bit fixed point value */
+fix_t Ptngc_d_to_fix_t(double d,double max);
+
+/* 32 bit fixed point value to positive double */
+double Ptngc_fix_t_to_ud(fix_t f, double max);
+
+/* signed 32 bit fixed point value to double */
+double Ptngc_fix_t_to_d(fix_t f, double max);
+
+/* Convert a floating point variable to two 32 bit integers with range
+ -2.1e9 to 2.1e9 and precision to somewhere around 1e-9. */
+void Ptngc_d_to_i32x2(double d, fix_t *hi, fix_t *lo);
+
+/* Convert two 32 bit integers to a floating point variable
+ -2.1e9 to 2.1e9 and precision to somewhere around 1e-9. */
+double Ptngc_i32x2_to_d(fix_t hi, fix_t lo);
+
+#endif
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#ifndef HUFFMAN_H
+#define HUFFMAN_H
+
+void Ptngc_comp_conv_to_huffman(unsigned int *vals, int nvals,
+ unsigned int *dict, int ndict,
+ unsigned int *prob,
+ unsigned char *huffman,
+ int *huffman_len,
+ unsigned char *huffman_dict,
+ int *huffman_dictlen,
+ unsigned int *huffman_dict_unpacked,
+ int *huffman_dict_unpackedlen);
+
+void Ptngc_comp_conv_from_huffman(unsigned char *huffman,
+ unsigned int *vals, int nvals,
+ int ndict,
+ unsigned char *huffman_dict,
+ int huffman_dictlen,
+ unsigned int *huffman_dict_unpacked,
+ int huffman_dict_unpackedlen);
+
+#endif
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#ifndef LZ77_H
+#define LZ77_H
+
+void Ptngc_comp_to_lz77(unsigned int *vals, int nvals,
+ unsigned int *data, int *ndata,
+ unsigned int *len, int *nlens,
+ unsigned int *offsets, int *noffsets);
+
+void Ptngc_comp_from_lz77(unsigned int *data, int ndata,
+ unsigned int *len, int nlens,
+ unsigned int *offsets, int noffsets,
+ unsigned int *vals, int nvals);
+
+#endif
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#ifndef MERGE_SORT_H
+#define MERGE_SORT_H
+
+void Ptngc_merge_sort(void *base, size_t nmemb, size_t size,
+ int (*compar)(const void *v1,const void *v2,const void *private),
+ void *private);
+
+
+#endif
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#ifndef MTF_H
+#define MTF_H
+
+void Ptngc_comp_conv_to_mtf(unsigned int *vals, int nvals,
+ unsigned int *dict, int ndict,
+ unsigned int *valsmtf);
+
+void Ptngc_comp_conv_from_mtf(unsigned int *valsmtf, int nvals,
+ unsigned int *dict, int ndict,
+ unsigned int *vals);
+
+void Ptngc_comp_conv_to_mtf_partial(unsigned int *vals, int nvals,
+ unsigned int *valsmtf);
+
+void Ptngc_comp_conv_from_mtf_partial(unsigned int *valsmtf, int nvals,
+ unsigned int *vals);
+
+void Ptngc_comp_conv_to_mtf_partial3(unsigned int *vals, int nvals,
+ unsigned char *valsmtf);
+
+void Ptngc_comp_conv_from_mtf_partial3(unsigned char *valsmtf, int nvals,
+ unsigned int *vals);
+
+#endif
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+#ifndef MY64BIT_H
+#define MY64BIT_H
+
+#ifdef USE_STD_INTTYPES_H
+#include <inttypes.h>
+typedef int64_t my_int64_t;
+typedef uint64_t my_uint64_t;
+#define HAVE64BIT
+#else /* USE_STD_INTTYPES */
+/* The USE_WINDOWS symbol should be automatically defined in tng_compress.h */
+#include "../compression/tng_compress.h"
+#ifdef USE_WINDOWS
+typedef __int64 my_int64_t;
+typedef unsigned __int64 my_uint64_t;
+#define HAVE64BIT
+#else /* USE_WINDOWS */
+/* Fall back to assume that we have unsigned long long */
+typedef unsigned long long my_uint64_t;
+#define HAVE64BIT
+#endif /* USE_WINDOWS */
+#endif /* USE_STD_INTTYPES */
+
+#endif
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#ifndef RLE_H
+#define RLE_H
+
+void Ptngc_comp_conv_to_rle(unsigned int *vals, int nvals,
+ unsigned int *rle, int *nrle,
+ int min_rle);
+
+void Ptngc_comp_conv_from_rle(unsigned int *rle,
+ unsigned int *vals, int nvals);
+
+#endif
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+#ifndef TNG_COMPRESS_H
+#define TNG_COMPRESS_H
+
+#ifndef USE_WINDOWS
+#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
+#define USE_WINDOWS
+#endif /* win32... */
+#endif /* not defined USE_WINDOWS */
+
+#ifndef DECLSPECDLLEXPORT
+#ifdef USE_WINDOWS
+#define DECLSPECDLLEXPORT __declspec(dllexport)
+#else /* USE_WINDOWS */
+#define DECLSPECDLLEXPORT
+#endif /* USE_WINDOWS */
+#endif /* DECLSPECDLLEXPORT */
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* tng_compress_pos expects positions to have the order:
+ first xyz, then sorted in atom order
+ then all the frames repeated, i.e.:
+ nframes * [
+ natoms* [
+ x, y, z
+ ]
+ ]
+ desired_precision what to round the numbers to, i.e. integers will be created as:
+ round(pos[]/desired_precision).
+
+ algo should first be determined by calling
+ tng_compress_pos_find_algo
+
+ The compressed data is returned in a malloced pointer (so free can
+ be called to free the memory), the number of chars in the compressed
+ data is put into *nitems.
+
+ If too large values are input (compared to the precision), NULL is returned.
+*/
+
+char DECLSPECDLLEXPORT *tng_compress_pos(double *pos, int natoms, int nframes,
+ double desired_precision,
+ int speed, int *algo,
+ int *nitems);
+
+char DECLSPECDLLEXPORT *tng_compress_pos_float(float *pos, int natoms, int nframes,
+ float desired_precision,
+ int speed, int *algo,
+ int *nitems);
+
+char DECLSPECDLLEXPORT *tng_compress_pos_int(int *pos, int natoms, int nframes,
+ unsigned long prec_hi, unsigned long prec_lo,
+ int speed,int *algo,
+ int *nitems);
+
+/* The tng_compress_pos_find_algo works the same as tng_compress_pos, but
+ it performs benchmarking to find the algorithms with the best
+ compression ratio.
+ The search is controlled by giving speed:
+ speed=1: Fast algorithms only. This excludes all BWLZH algorithms and
+ the XTC3 algorithm.
+ speed=2: Same as 1 and also includes the XTC3 algorithm using base compression
+ only.
+ speed=3: Same as 2 and also includes the XTC3 algorithm which will use BWLZH
+ compression when it seems likely to give better
+ compression. Also includes the interframe BWLZH algorithm for
+ coordinates and velocities.
+ speed=4: Enable the inter frame BWLZH algorithm for the coordinates.
+ The one-to-one BWLZH algorithm is enabled for velocities.
+ speed=5: Enable the LZ77 part of the BWLZH algorithm.
+ speed=6: Enable the intra frame BWLZH algorithm for the coordinates. Always try
+ the BWLZH compression in the XTC3 algorithm.
+
+ Set speed=0 to allow tng_compression to set the default speed (which is currently 2).
+ For very good compression it makes sense to choose speed=4 or speed=5
+
+ The number of items required in the algorithm array can be found
+ by calling tng_compress_nalgo
+*/
+
+char DECLSPECDLLEXPORT *tng_compress_pos_find_algo(double *pos, int natoms, int nframes,
+ double desired_precision,
+ int speed,
+ int *algo,
+ int *nitems);
+
+char DECLSPECDLLEXPORT *tng_compress_pos_float_find_algo(float *pos, int natoms, int nframes,
+ float desired_precision,
+ int speed,
+ int *algo,
+ int *nitems);
+
+char DECLSPECDLLEXPORT *tng_compress_pos_int_find_algo(int *pos, int natoms, int nframes,
+ unsigned long prec_hi, unsigned long prec_lo,
+ int speed,int *algo,
+ int *nitems);
+
+/* This returns the number of integers required for the storage of the algorithm
+ with the best compression ratio. */
+int DECLSPECDLLEXPORT tng_compress_nalgo(void);
+
+/* The following two routines does the same as the compression of the
+ positions, but compresses velocities instead. The algorithm
+ selection for velocities is different, so the position and
+ velocities routines should not be mixed. */
+
+char DECLSPECDLLEXPORT *tng_compress_vel(double *vel, int natoms, int nframes,
+ double desired_precision,
+ int speed, int *algo,
+ int *nitems);
+
+char DECLSPECDLLEXPORT *tng_compress_vel_float(float *vel, int natoms, int nframes,
+ float desired_precision,
+ int speed, int *algo,
+ int *nitems);
+
+char DECLSPECDLLEXPORT *tng_compress_vel_int(int *vel, int natoms, int nframes,
+ unsigned long prec_hi, unsigned long prec_lo,
+ int speed, int *algo,
+ int *nitems);
+
+char DECLSPECDLLEXPORT *tng_compress_vel_find_algo(double *vel, int natoms, int nframes,
+ double desired_precision,
+ int speed,
+ int *algo,
+ int *nitems);
+
+char DECLSPECDLLEXPORT *tng_compress_vel_float_find_algo(float *vel, int natoms, int nframes,
+ float desired_precision,
+ int speed,
+ int *algo,
+ int *nitems);
+
+char DECLSPECDLLEXPORT *tng_compress_vel_int_find_algo(int *vel, int natoms, int nframes,
+ unsigned long prec_hi, unsigned long prec_lo,
+ int speed,
+ int *algo,
+ int *nitems);
+
+/* From a compressed block, obtain information about
+ whether it is a position or velocity block:
+ *vel=1 means velocity block, *vel=0 means position block.
+ It also gives info about the number of atoms,
+ frames, and the precision used to compress the block, and the algorithms used to
+ compress the block. The return value=0 if the block looks like a tng compressed block,
+ and 1 otherwise. If the return value is 1 no information is returned. */
+int DECLSPECDLLEXPORT tng_compress_inquire(char *data,int *vel, int *natoms,
+ int *nframes, double *precision,
+ int *algo);
+
+/* Uncompresses any tng compress block, positions or velocities. It determines whether it is positions or velocities from the data buffer. The return value is 0 if ok, and 1 if not.
+*/
+int DECLSPECDLLEXPORT tng_compress_uncompress(char *data,double *posvel);
+
+int DECLSPECDLLEXPORT tng_compress_uncompress_float(char *data,float *posvel);
+
+int DECLSPECDLLEXPORT tng_compress_uncompress_int(char *data,int *posvel, unsigned long *prec_hi, unsigned long *prec_lo);
+
+/* This converts a block of integers, as obtained from tng_compress_uncompress_int, to floating point values
+ either double precision or single precision. */
+void DECLSPECDLLEXPORT tng_compress_int_to_double(int *posvel_int,unsigned long prec_hi, unsigned long prec_lo,
+ int natoms,int nframes,
+ double *posvel_double);
+
+void DECLSPECDLLEXPORT tng_compress_int_to_float(int *posvel_int,unsigned long prec_hi, unsigned long prec_lo,
+ int natoms,int nframes,
+ float *posvel_float);
+
+
+/* Compression algorithms (matching the original trajng
+ assignments) The compression backends require that some of the
+ algorithms must have the same value. */
+
+#define TNG_COMPRESS_ALGO_STOPBIT 1
+#define TNG_COMPRESS_ALGO_TRIPLET 2
+#define TNG_COMPRESS_ALGO_BWLZH1 8
+#define TNG_COMPRESS_ALGO_BWLZH2 9
+
+#define TNG_COMPRESS_ALGO_POS_STOPBIT_INTER TNG_COMPRESS_ALGO_STOPBIT
+#define TNG_COMPRESS_ALGO_POS_TRIPLET_INTER TNG_COMPRESS_ALGO_TRIPLET
+#define TNG_COMPRESS_ALGO_POS_TRIPLET_INTRA 3
+#define TNG_COMPRESS_ALGO_POS_XTC2 5
+#define TNG_COMPRESS_ALGO_POS_TRIPLET_ONETOONE 7
+#define TNG_COMPRESS_ALGO_POS_BWLZH_INTER TNG_COMPRESS_ALGO_BWLZH1
+#define TNG_COMPRESS_ALGO_POS_BWLZH_INTRA TNG_COMPRESS_ALGO_BWLZH2
+#define TNG_COMPRESS_ALGO_POS_XTC3 10
+#define TNG_COMPRESS_ALGO_VEL_STOPBIT_ONETOONE TNG_COMPRESS_ALGO_STOPBIT
+#define TNG_COMPRESS_ALGO_VEL_TRIPLET_INTER TNG_COMPRESS_ALGO_TRIPLET
+#define TNG_COMPRESS_ALGO_VEL_TRIPLET_ONETOONE 3
+#define TNG_COMPRESS_ALGO_VEL_STOPBIT_INTER 6
+#define TNG_COMPRESS_ALGO_VEL_BWLZH_INTER TNG_COMPRESS_ALGO_BWLZH1
+#define TNG_COMPRESS_ALGO_VEL_BWLZH_ONETOONE TNG_COMPRESS_ALGO_BWLZH2
+#define TNG_COMPRESS_ALGO_MAX 11
+
+
+
+/* Obtain strings describing the actual algorithms. These point to static memory, so should
+ not be freed. */
+char DECLSPECDLLEXPORT *tng_compress_initial_pos_algo(int *algo);
+char DECLSPECDLLEXPORT *tng_compress_pos_algo(int *algo);
+char DECLSPECDLLEXPORT *tng_compress_initial_vel_algo(int *algo);
+char DECLSPECDLLEXPORT *tng_compress_vel_algo(int *algo);
+
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+
+#endif
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#ifndef VALS16_H
+#define VALS16_H
+
+void Ptngc_comp_conv_to_vals16(unsigned int *vals,int nvals,
+ unsigned int *vals16, int *nvals16);
+
+void Ptngc_comp_conv_from_vals16(unsigned int *vals16,int nvals16,
+ unsigned int *vals, int *nvals);
+
+#endif
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#ifndef WARNMALLOC_H
+#define WARNMALLOC_H
+
+#include "../compression/tng_compress.h"
+
+void DECLSPECDLLEXPORT *Ptngc_warnmalloc_x(size_t size, char *file, int line);
+
+#define warnmalloc(size) Ptngc_warnmalloc_x(size,__FILE__,__LINE__)
+
+void DECLSPECDLLEXPORT *Ptngc_warnrealloc_x(void *old, size_t size, char *file, int line);
+
+#define warnrealloc(old,size) Ptngc_warnrealloc_x(old,size,__FILE__,__LINE__)
+
+
+#endif
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#ifndef WIDEMULDIV_H
+#define WIDEMULDIV_H
+
+/* Multiply two 32 bit unsigned integers returning a 64 bit unsigned value (in two integers) */
+void Ptngc_widemul(unsigned int i1, unsigned int i2, unsigned int *ohi, unsigned int *olo);
+
+/* Divide a 64 bit unsigned value in hi:lo with the 32 bit value i and
+ return the result in result and the remainder in remainder */
+void Ptngc_widediv(unsigned int hi, unsigned int lo, unsigned int i, unsigned int *result, unsigned int *remainder);
+
+/* Add a unsigned int to a largeint. */
+void Ptngc_largeint_add(unsigned int v1, unsigned int *largeint, int n);
+
+/* Multiply v1 with largeint_in and return result in largeint_out */
+void Ptngc_largeint_mul(unsigned int v1, unsigned int *largeint_in, unsigned int *largeint_out, int n);
+
+/* Return the remainder from dividing largeint_in with v1. Result of the division is returned in largeint_out */
+unsigned int Ptngc_largeint_div(unsigned int v1, unsigned int *largeint_in, unsigned int *largeint_out, int n);
+
+#endif
--- /dev/null
+
+/* This file has been modified in the TNG library distribution. Modifications
+ * are marked below. */
+
+/*
+ Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ ghost@aladdin.com
+
+ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.h is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Removed support for non-ANSI compilers; removed
+ references to Ghostscript; clarified derivation from RFC 1321;
+ now handles byte order either statically or dynamically.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
+ added conditionalization for C++ compilation from Martin
+ Purschke <purschke@bnl.gov>.
+ 1999-05-03 lpd Original version.
+ */
+
+#ifndef md5_INCLUDED
+# define md5_INCLUDED
+
+
+/*
+ * This package supports both compile-time and run-time determination of CPU
+ * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
+ * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
+ * defined as non-zero, the code will be compiled to run only on big-endian
+ * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
+ * run on either big- or little-endian CPUs, but will run slightly less
+ * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
+ */
+
+typedef unsigned char md5_byte_t; /* 8-bit byte */
+typedef unsigned int md5_word_t; /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct md5_state_s {
+ md5_word_t count[2]; /* message length in bits, lsw first */
+ md5_word_t abcd[4]; /* digest buffer */
+ md5_byte_t buf[64]; /* accumulate block */
+} md5_state_t;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* The USE_WINDOWS define below was added in TNG library distribution of this
+ * file in order to compile properly in MSVC */
+#ifndef USE_WINDOWS
+#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
+#define USE_WINDOWS
+#endif /* win32... */
+#endif /* not defined USE_WINDOWS */
+
+/* The DECLSPECDLLEXPORT define below was added in the TNG library distribution
+ * of this file. It is also used in the function declarations. */
+#ifndef DECLSPECDLLEXPORT
+#ifdef USE_WINDOWS
+#define DECLSPECDLLEXPORT __declspec(dllexport)
+#else /* USE_WINDOWS */
+#define DECLSPECDLLEXPORT
+#endif /* USE_WINDOWS */
+#endif /* DECLSPECDLLEXPORT */
+
+/* Initialize the algorithm. */
+void DECLSPECDLLEXPORT md5_init(md5_state_t *pms);
+
+/* Append a string to the message. */
+void DECLSPECDLLEXPORT md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
+
+/* Finish the message and return the digest. */
+void DECLSPECDLLEXPORT md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+#endif /* md5_INCLUDED */
--- /dev/null
+/* This code is part of the tng binary trajectory format.
+ *
+ * VERSION 1.4
+ *
+ * Written by Magnus Lundborg
+ * Copyright (c) 2012-2013, The GROMACS development team.
+ * Check out http://www.gromacs.org for more information.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+/** @file tng_io.h
+ * @brief API for input and output of tng trajectory files
+ * @mainpage TNG: A flexible binary trajectory format
+ * @section intro_sec Introduction
+ *
+ * The TNG format is developed as part of the ScalaLife EU project.
+ * It is flexible by design to allow parallel writing, custom data blocks,
+ * different output frequencies and different compression algorithms.
+ *
+ * Each block can contain MD5 hashes to verify data integrity and the file
+ * can be signed by the user to ensure that the origin is correct.
+ *
+ * This is version 1.4 of the TNG API. The intention is that this version of
+ * the API and ABI should be stable, but it is still possible that future
+ * changes might make that impossible, in which case that will be clarified.
+ *
+ * The API and all examples are released without any warranties. Use them at
+ * your own risk.
+ *
+ * @section authors_sec Authors
+ *
+ * The TNG trajectory format is developed by:
+ *
+ * Magnus Lundborg magnus.lundborg@scilifelab.se
+ *
+ * Daniel Spångberg daniels@mkem.uu.se
+ *
+ * Rossen Apostolov rossen@kth.se
+ *
+ * The API is implemented mainly by:
+ *
+ * Magnus Lundborg
+ *
+ * @section License
+ *
+ * Copyright (c) 2012, The GROMACS development team.
+ * check out http://www.gromacs.org for more information.
+ *
+ * The TNG API is released under the Revised BSD License and is free to
+ * redistribute according to that license.
+ *
+ * A license file (named COPYING) should be included with each copy of the API.
+ *
+ * @section install_sec Installation
+ *
+ * \code
+ * mkdir build
+ *
+ * cd build
+ *
+ * cmake ..
+ *
+ * make
+ *
+ * make install
+ * \endcode
+ * Test by running:
+ * \code
+ * bin/tests/tng_testing
+ * \endcode
+ *
+ * @section change_sec Change Log
+ *
+ * See git log for full revision history.
+ *
+ * Revisions
+ *
+ * v. 1.4 - Changed from LGPL to the Revised BSD License.
+ *
+ * - More flexible support for digital signatures in header.
+ * - Block ID numbers changed.
+ *
+ * v. 1.3 - Second stable release of the API.
+ *
+ * - Added multiplication factor for coordinate units to general info.
+ * - Added time stamps and time per frame in frame sets.
+ * - High-level API functions added (not for managing molecules yet)
+ * - Added functions for reading data blocks into 1D arrays.
+ * - TNG compression added.
+ * - C++ interface added.
+ * - Avoid memory allocation if no data is submitted when adding data
+ * blocks.
+ * - Added function tng_num_frames_per_frame_set_set
+ * - Added data block IDs for charges, b-factors and occupancy.
+ * - GZIP compression added.
+ * - Fixed bug when updating MD5 hashes of data blocks.
+ * - Fixed bug in chain_name_of_particle_get(...)
+ * - Update frame set pointers properly.
+ * - Moved fortran wrapper from header file to source file.
+ * - Write sparse data in mdrun examples.
+ * - Fixed bugs related to reading and writing sparse data.
+ * - Fixed memory leak for non-trajectory particle data blocks.
+ * - Fixed bug when writing data blocks.
+ * - Fixed wrong values in dependency constants
+ * - Write box shape, partial charges and annotation data in tng_testing
+ * - Bug fixes in tng_testing (frame sets not written before)
+ *
+ * v. 1.0 - First stable release of the API.
+ *
+ *
+ * @section examples_sec Examples
+ *
+ * There are some examples of how to use the library located in src/tests/
+ *
+ * @subsection tng_subsec TNG files
+ *
+ * The build directory contains an example_files directory, which in turn
+ * contains a very short example of a TNG file containing a few water molecules,
+ * a box shape description and positions in 10 frames.
+ *
+ * It is also possible to run the bin/examples/md_openmp_util
+ * (see src/tests/md_openmp_util.c)
+ * testing program, which will save MD simulations output to a new file
+ * (saved in the example_files directory).
+ *
+ * These files can be read using the bin/examples/tng_io_read_pos_util
+ * program.
+ *
+ * @subsection c_subsec C
+ *
+ * Example writing data to a TNG file (just an excerpt):
+ * \code
+ * for ( step = 1; step < step_num; step++ )
+ * {
+ * compute ( np, nd, pos, vel, mass, force, &potential, &kinetic );
+ *
+ * if(step % step_save == 0)
+ * {
+ * // Write positions, velocities and forces
+ * if(tng_util_pos_write(traj, step, pos) != TNG_SUCCESS)
+ * {
+ * printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ * break;
+ * }
+ * if(tng_util_vel_write(traj, step, vel) != TNG_SUCCESS)
+ * {
+ * printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ * break;
+ * }
+ * if(tng_util_force_write(traj, step, force) != TNG_SUCCESS)
+ * {
+ * printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ * break;
+ * }
+ * }
+ * update ( np, nd, pos, vel, force, acc, mass, dt );
+ * }
+ * \endcode
+ *
+ * Example reading positions from a TNG file:
+ * \code
+ * #include <stdlib.h>
+ * #include <stdio.h>
+ * #include "tng_io.h"
+ *
+ * int main(int argc, char **argv)
+ * {
+ * tng_trajectory_t traj;
+ * // Assume that the data is stored as floats. The data is placed in 1-D
+ * // arrays
+ * float *positions = 0, *box_shape = 0;
+ * int64_t n_particles, n_frames, tot_n_frames, stride_length, i, j;
+ * // Set a default frame range
+ * int64_t first_frame = 0, last_frame = 5000;
+ * int k;
+ *
+ * // A reference must be passed to allocate memory
+ * tng_util_trajectory_open(argv[1], 'r', &traj);
+ *
+ * if(tng_num_frames_get(traj, &tot_n_frames) != TNG_SUCCESS)
+ * {
+ * printf("Cannot determine the number of frames in the file\n");
+ * tng_util_trajectory_close(&traj);
+ * exit(1);
+ * }
+ *
+ * if(tng_num_particles_get(traj, &n_particles) != TNG_SUCCESS)
+ * {
+ * printf("Cannot determine the number of particles in the file\n");
+ * tng_util_trajectory_close(&traj);
+ * exit(1);
+ * }
+ *
+ * printf("%"PRId64" frames in file\n", tot_n_frames);
+ *
+ * if(last_frame > tot_n_frames - 1)
+ * {
+ * last_frame = tot_n_frames - 1;
+ * }
+ *
+ * if(tng_util_box_shape_read(traj, &box_shape, &stride_length) ==
+ * TNG_SUCCESS)
+ * {
+ * printf("Simulation box shape: ");
+ * for(i=0; i < 9; i++)
+ * {
+ * printf("%f ", box_shape[i]);
+ * }
+ * printf("\n");
+ * }
+ * else
+ * {
+ * printf("Simulation box shape not set in the file (or could not be read)\n");
+ * }
+ *
+ * n_frames = last_frame - first_frame + 1;
+ *
+ *
+ * // Get the positions of all particles in the requested frame range.
+ * // The positions are stored in the positions array.
+ * // N.B. No proper error checks.
+ * if(tng_util_pos_read_range(traj, 0, last_frame, &positions, &stride_length)
+ * == TNG_SUCCESS)
+ * {
+ * // Print the positions of the wanted particle (zero based)
+ * for(i=0; i < n_frames; i += stride_length)
+ * {
+ * printf("\nFrame %"PRId64":\n", first_frame + i);
+ * for(j=0; j < n_particles; j++)
+ * {
+ * printf("Atom nr: %"PRId64"", j);
+ * for(k=0; k < 3; k++)
+ * {
+ * printf("\t%f", positions[i/stride_length*n_particles*
+ * 3+j*3+k]);
+ * }
+ * printf("\n");
+ * }
+ * }
+ * }
+ * else
+ * {
+ * printf("Cannot read positions\n");
+ * }
+ *
+ * // Free memory
+ * if(positions)
+ * {
+ * free(positions);
+ * }
+ * tng_util_trajectory_close(&traj);
+ *
+ * return(0);
+ * }
+ *
+ * \endcode
+ *
+ * @subsection fortran_subsec Fortran
+ *
+ * The TNG library can be used from Fortran. It requires cray pointers, which
+ * are not part of the Fortran 77 standard, but available in most compilers.
+ *
+ * To compile the fortran example -DTNG_BUILD_FORTRAN=ON needs to be specified when
+ * running cmake.
+ *
+ */
+
+#ifndef TNG_IO_H
+#define TNG_IO_H 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "tng_io_fwd.h"
+
+#ifdef USE_STD_INTTYPES_H
+#include <inttypes.h>
+#else
+/* Visual Studio does not contain inttypes.h and stdint.h. Some defines and
+ * typedefs are used from the GNU C Library */
+#ifdef _MSC_VER
+
+typedef __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+#else
+#include <stdint.h>
+#endif /* _MSC_VER */
+
+/* This is from inttypes.h (GNU C Library) */
+/* The ISO C99 standard specifies that these macros must only be
+ defined if explicitly requested. */
+#if !defined __cplusplus || defined __STDC_FORMAT_MACROS
+
+# if __WORDSIZE == 64
+# define __PRI64_PREFIX "l"
+# define __PRIPTR_PREFIX "l"
+# else
+# define __PRI64_PREFIX "ll"
+# define __PRIPTR_PREFIX
+# endif
+
+/* From stdint.h (GNU C Library) */
+/* Macros for printing format specifiers. */
+/* Decimal notation. */
+#ifndef PRId64
+# define PRId64 __PRI64_PREFIX "d"
+#endif
+
+#endif
+
+#endif /* USE_STD_INTTYPES_H */
+
+
+#ifndef USE_WINDOWS
+#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
+#define USE_WINDOWS
+#endif /* win32... */
+#endif /* not defined USE_WINDOWS */
+
+#ifndef DECLSPECDLLEXPORT
+#ifdef USE_WINDOWS
+#define DECLSPECDLLEXPORT __declspec(dllexport)
+#else /* USE_WINDOWS */
+#define DECLSPECDLLEXPORT
+#endif /* USE_WINDOWS */
+#endif /* DECLSPECDLLEXPORT */
+
+
+/** The version of this TNG build */
+#define TNG_VERSION 4 /* TNG_VERSION 4 => Api version 1.4 */
+
+/** Flag to indicate frame dependent data. */
+#define TNG_FRAME_DEPENDENT 1
+/** Flag to indicate particle dependent data. */
+#define TNG_PARTICLE_DEPENDENT 2
+
+/** The maximum length of a date string */
+#define TNG_MAX_DATE_STR_LEN 24
+/** The length of an MD5 hash */
+#define TNG_MD5_HASH_LEN 16
+/** The maximum allowed length of a string */
+#define TNG_MAX_STR_LEN 1024
+
+#ifndef NDEBUG
+#define TNG_ASSERT(cnd, msg) if(!(cnd)) {printf("%s\n", msg); assert(cnd);}
+#else
+#define TNG_ASSERT(cnd, msg) (void)0;
+#endif
+
+/** Flag to specify the endianness of a TNG file */
+typedef enum {TNG_BIG_ENDIAN,
+ TNG_LITTLE_ENDIAN} tng_file_endianness;
+
+/** Flag to specify the endianness of 32 bit values of the current architecture. */
+typedef enum {TNG_BIG_ENDIAN_32,
+ TNG_LITTLE_ENDIAN_32,
+ TNG_BYTE_PAIR_SWAP_32} tng_endianness_32;
+
+/** Flag to specify the endianness of 64 bit values of the current architecture. */
+typedef enum {TNG_BIG_ENDIAN_64,
+ TNG_LITTLE_ENDIAN_64,
+ TNG_QUAD_SWAP_64,
+ TNG_BYTE_PAIR_SWAP_64,
+ TNG_BYTE_SWAP_64} tng_endianness_64;
+
+/** Compression mode is specified in each data block */
+typedef enum {TNG_UNCOMPRESSED,
+ TNG_XTC_COMPRESSION,
+ TNG_TNG_COMPRESSION,
+ TNG_GZIP_COMPRESSION} tng_compression;
+
+/** Hash types */
+typedef enum {TNG_NO_HASH,
+ TNG_MD5,
+ TNG_SHA256} tng_hash_type;
+
+/** Non trajectory blocks come before the first frame set block */
+typedef enum {TNG_NON_TRAJECTORY_BLOCK, TNG_TRAJECTORY_BLOCK} tng_block_type;
+
+/** @defgroup def1 Standard non-trajectory blocks
+ * Block IDs of standard non-trajectory blocks.
+ * @{
+ */
+#define TNG_GENERAL_INFO 0x0000000000000000LL
+#define TNG_MOLECULES 0x0000000000000001LL
+#define TNG_TRAJECTORY_FRAME_SET 0x0000000000000002LL
+#define TNG_PARTICLE_MAPPING 0x0000000000000003LL
+/** @} */
+
+/** @defgroup def2 Standard trajectory blocks
+ * Block IDs of standard trajectory blocks. Box shape and partial charges can
+ * be either trajectory blocks or non-trajectory blocks
+ * @{
+ */
+#define TNG_TRAJ_BOX_SHAPE 0x0000000010000000LL
+#define TNG_TRAJ_POSITIONS 0x0000000010000001LL
+#define TNG_TRAJ_VELOCITIES 0x0000000010000002LL
+#define TNG_TRAJ_FORCES 0x0000000010000003LL
+#define TNG_TRAJ_PARTIAL_CHARGES 0x0000000010000004LL
+#define TNG_TRAJ_FORMAL_CHARGES 0x0000000010000005LL
+#define TNG_TRAJ_B_FACTORS 0x0000000010000006LL
+#define TNG_TRAJ_ANISOTROPIC_B_FACTORS 0x0000000010000007LL
+#define TNG_TRAJ_OCCUPANCY 0x0000000010000008LL
+/** @} */
+
+
+/** @defgroup def3 GROMACS data block IDs
+ * Block IDs of data blocks specific to GROMACS.
+ * @{
+ */
+#define TNG_GMX_LAMBDA 0x1000000010000000LL
+#define TNG_GMX_ENERGY_ANGLE 0x1000000010000001LL
+#define TNG_GMX_ENERGY_RYCKAERT_BELL 0x1000000010000002LL
+#define TNG_GMX_ENERGY_LJ_14 0x1000000010000003LL
+#define TNG_GMX_ENERGY_COULOMB_14 0x1000000010000004LL
+#define TNG_GMX_ENERGY_LJ_(SR) 0x1000000010000005LL
+#define TNG_GMX_ENERGY_COULOMB_(SR) 0x1000000010000006LL
+#define TNG_GMX_ENERGY_COUL_RECIP 0x1000000010000007LL
+#define TNG_GMX_ENERGY_POTENTIAL 0x1000000010000008LL
+#define TNG_GMX_ENERGY_KINETIC_EN 0x1000000010000009LL
+#define TNG_GMX_ENERGY_TOTAL_ENERGY 0x1000000010000010LL
+#define TNG_GMX_ENERGY_TEMPERATURE 0x1000000010000011LL
+#define TNG_GMX_ENERGY_PRESSURE 0x1000000010000012LL
+#define TNG_GMX_ENERGY_CONSTR_RMSD 0x1000000010000013LL
+#define TNG_GMX_ENERGY_BOX_X 0x1000000010000014LL
+#define TNG_GMX_ENERGY_BOX_Y 0x1000000010000015LL
+#define TNG_GMX_ENERGY_BOX_Z 0x1000000010000016LL
+#define TNG_GMX_ENERGY_VOLUME 0x1000000010000017LL
+#define TNG_GMX_ENERGY_DENSITY 0x1000000010000018LL
+#define TNG_GMX_ENERGY_PV 0x1000000010000019LL
+#define TNG_GMX_ENERGY_ENTHALPY 0x1000000010000020LL
+#define TNG_GMX_ENERGY_VIR_XX 0x1000000010000021LL
+#define TNG_GMX_ENERGY_VIR_XY 0x1000000010000022LL
+#define TNG_GMX_ENERGY_VIR_XZ 0x1000000010000023LL
+#define TNG_GMX_ENERGY_VIR_YX 0x1000000010000024LL
+#define TNG_GMX_ENERGY_VIR_YY 0x1000000010000025LL
+#define TNG_GMX_ENERGY_VIR_YZ 0x1000000010000026LL
+#define TNG_GMX_ENERGY_VIR_ZX 0x1000000010000027LL
+#define TNG_GMX_ENERGY_VIR_ZY 0x1000000010000028LL
+#define TNG_GMX_ENERGY_VIR_ZZ 0x1000000010000029LL
+#define TNG_GMX_ENERGY_PRES_XX 0x1000000010000030LL
+#define TNG_GMX_ENERGY_PRES_XY 0x1000000010000031LL
+#define TNG_GMX_ENERGY_PRES_XZ 0x1000000010000032LL
+#define TNG_GMX_ENERGY_PRES_YX 0x1000000010000033LL
+#define TNG_GMX_ENERGY_PRES_YY 0x1000000010000034LL
+#define TNG_GMX_ENERGY_PRES_YZ 0x1000000010000035LL
+#define TNG_GMX_ENERGY_PRES_ZX 0x1000000010000036LL
+#define TNG_GMX_ENERGY_PRES_ZY 0x1000000010000037LL
+#define TNG_GMX_ENERGY_PRES_ZZ 0x1000000010000038LL
+#define TNG_GMX_ENERGY_SURFXSURFTEN 0x1000000010000039LL
+#define TNG_GMX_ENERGY_T_SYSTEM 0x1000000010000040LL
+#define TNG_GMX_ENERGY_LAMB_SYSTEM 0x1000000010000041LL
+#define TNG_GMX_SELECTION_GROUP_NAMES 0x1000000010000042LL
+#define TNG_GMX_ATOM_SELECTION_GROUP 0x1000000010000043LL
+/** @} */
+
+/** Flag to specify if a data block contains data related to particles or not.*/
+typedef enum {TNG_NON_PARTICLE_BLOCK_DATA,
+ TNG_PARTICLE_BLOCK_DATA} tng_particle_dependency;
+
+
+typedef enum {TNG_FALSE, TNG_TRUE} tng_bool;
+
+/** Flag to specify if the number of atoms change throughout the trajectory or
+ * if it is constant. */
+typedef enum {TNG_CONSTANT_N_ATOMS, TNG_VARIABLE_N_ATOMS}
+ tng_variable_n_atoms_flag;
+
+/** Return values of API functions. TNG_SUCCESS means that the operation
+ * was successful. TNG_FAILURE means that the operation failed for some
+ * reason, but it is possible to try to continue anyhow. TNG_CRITICAL
+ * means that the error is irrecoverable. */
+typedef enum {TNG_SUCCESS, TNG_FAILURE, TNG_CRITICAL} tng_function_status;
+
+/** If tng_hash_mode == TNG_USE_HASH md5 hashes will be written to output files
+ * and when reading a file the md5 hashes of the contents will be compared to
+ * those in the file (for each block) in order to ensure data integrity */
+typedef enum {TNG_SKIP_HASH, TNG_USE_HASH} tng_hash_mode;
+
+/** Possible formats of data block contents */
+typedef enum {TNG_CHAR_DATA,
+ TNG_INT_DATA,
+ TNG_FLOAT_DATA,
+ TNG_DOUBLE_DATA} tng_data_type;
+
+
+struct tng_trajectory;
+struct tng_molecule;
+struct tng_chain;
+struct tng_residue;
+struct tng_atom;
+struct tng_bond;
+struct tng_gen_block;
+struct tng_particle_mapping;
+struct tng_trajectory_frame_set;
+struct tng_particle_data;
+struct tng_non_particle_data;
+
+/** Data can be either double, float, int or a string */
+union data_values {
+ double d;
+ float f;
+ int64_t i;
+ char *c;
+};
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** @defgroup group1 Low-level API
+ * These functions give detailed control of the TNG data management. Most
+ * things can be done using the more convenient high-level API functions
+ * instead.
+ * @{
+ */
+
+/**
+ * @brief Setup a trajectory data container.
+ * @param tng_data_p a pointer to memory to initialise as a trajectory.
+ * @pre tng_data_p must not be pointing at a reserved memory block.
+ * @details Memory is allocated during initialisation.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_trajectory_init
+ (tng_trajectory_t *tng_data_p);
+
+/**
+ * @brief Clean up a trajectory data container.
+ * @param tng_data_p a pointer to the trajectory data to destroy.
+ * @details All allocated memory in the data structure is freed, as well as
+ * tng_data_p itself.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy
+ (tng_trajectory_t *tng_data_p);
+
+/**
+ * @brief Copy a trajectory data container (dest is setup as well).
+ * @details This initialises dest and copies only what is absolute necessary for
+ * parallel i/o. This can be used inside pragma omp for setting up a thread
+ * local copy of src. It can be freed (using tng_trajectory_destroy) at the
+ * end of the parallel block.
+ * @param src the original trajectory.
+ * @param dest_p a pointer to memory to initialise as a trajectory.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre tng_data_p must not be pointing at a reserved memory block.
+ * @details Memory is allocated during initialisation.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_from_src
+ (tng_trajectory_t src, tng_trajectory_t *dest_p);
+
+/**
+ * @brief Get the name of the input file.
+ * @param tng_data the trajectory of which to get the input file name.
+ * @param file_name the string to fill with the name of the input file,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for file_name. This includes \0 terminating character.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code file_name != 0 \endcode The pointer to the file name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+tng_function_status DECLSPECDLLEXPORT tng_input_file_get
+ (const tng_trajectory_t tng_data,
+ char *file_name, const int max_len);
+
+/**
+ * @brief Set the name of the input file.
+ * @param tng_data the trajectory of which to set the input file name.
+ * @param file_name the name of the input file.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code file_name != 0 \endcode The pointer to the file name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_input_file_set
+ (tng_trajectory_t tng_data,
+ const char *file_name);
+
+/**
+ * @brief Get the name of the output file.
+ * @param tng_data the trajectory of which to get the input file name.
+ * @param file_name the string to fill with the name of the output file,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for file_name. This includes \0 terminating character.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code file_name != 0 \endcode The pointer to the file name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+tng_function_status DECLSPECDLLEXPORT tng_output_file_get
+ (const tng_trajectory_t tng_data,
+ char *file_name, const int max_len);
+
+/**
+ * @brief Set the name of the output file.
+ * @param tng_data the trajectory of which to set the output file name.
+ * @param file_name the name of the output file.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code file_name != 0 \endcode The pointer to the file name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_output_file_set
+ (tng_trajectory_t tng_data,
+ const char *file_name);
+
+/**
+ * @brief Set the name of the output file for appending. The output file
+ * will not be overwritten.
+ * @param tng_data the trajectory of which to set the output file name.
+ * @param file_name the name of the output file to append to.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code file_name != 0 \endcode The pointer to the file name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_output_append_file_set
+ (tng_trajectory_t tng_data,
+ const char *file_name);
+
+/**
+ * @brief Get the endianness of the output file.
+ * @param tng_data the trajectory of which to get the endianness of the current
+ * output file.
+ * @param endianness will contain the enumeration of the endianness.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code endianness != 0 \endcode The pointer to the endianness container
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the endianness
+ * could not be retrieved.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_get
+ (tng_trajectory_t tng_data, tng_file_endianness *endianness);
+
+/**
+ * @brief Set the endianness of the output file.
+ * @param tng_data the trajectory of which to set the endianness of the current
+ * output file.
+ * @param endianness the enumeration of the endianness, can be either
+ * TNG_BIG_ENDIAN (0) or TNG_LITTLE_ENDIAN (1).
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @details The endianness cannot be changed after file output has started.
+ * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the endianness
+ * could not be set.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_set
+ (tng_trajectory_t tng_data,
+ const tng_file_endianness endianness);
+
+/**
+ * @brief Get the name of the program used when creating the trajectory.
+ * @param tng_data the trajectory of which to get the program name.
+ * @param name the string to fill with the name of the program,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for name. This includes \0 terminating character.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+tng_function_status DECLSPECDLLEXPORT tng_first_program_name_get
+ (const tng_trajectory_t tng_data,
+ char *name, const int max_len);
+
+/**
+ * @brief Set the name of the program used when creating the trajectory.
+ * @param tng_data the trajectory of which to set the program name.
+ * @param new_name is a string containing the wanted name.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code new_name != 0 \endcode The pointer to the new_name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_first_program_name_set
+ (tng_trajectory_t tng_data,
+ const char *new_name);
+
+/**
+ * @brief Get the name of the program used when last modifying the trajectory.
+ * @param tng_data the trajectory of which to get the program name.
+ * @param name the string to fill with the name of the program,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for name. This includes \0 terminating character.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+tng_function_status DECLSPECDLLEXPORT tng_last_program_name_get
+ (const tng_trajectory_t tng_data,
+ char *name, const int max_len);
+
+/**
+ * @brief Set the name of the program used when last modifying the trajectory.
+ * @param tng_data the trajectory of which to set the program name.
+ * @param new_name is a string containing the wanted name.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code new_name != 0 \endcode The pointer to the new_name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_last_program_name_set
+ (tng_trajectory_t tng_data,
+ const char *new_name);
+
+/**
+ * @brief Get the name of the user who created the trajectory.
+ * @param tng_data the trajectory of which to get the user name.
+ * @param name the string to fill with the name of the user,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for name. This includes \0 terminating character.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+tng_function_status DECLSPECDLLEXPORT tng_first_user_name_get
+ (const tng_trajectory_t tng_data,
+ char *name, const int max_len);
+
+/**
+ * @brief Set the name of the user who created the trajectory.
+ * @param tng_data the trajectory of which to set the user name.
+ * @param new_name is a string containing the wanted name.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code new_name != 0 \endcode The pointer to the new_name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_first_user_name_set
+ (tng_trajectory_t tng_data,
+ const char *new_name);
+
+/**
+ * @brief Get the name of the user who last modified the trajectory.
+ * @param tng_data the trajectory of which to get the user name.
+ * @param name the string to fill with the name of the user,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for name. This includes \0 terminating character.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+tng_function_status DECLSPECDLLEXPORT tng_last_user_name_get
+ (const tng_trajectory_t tng_data,
+ char *name, const int max_len);
+
+/**
+ * @brief Set the name of the user who last modified the trajectory.
+ * @param tng_data the trajectory of which to set the user name.
+ * @param new_name is a string containing the wanted name.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code new_name != 0 \endcode The pointer to the new_name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_last_user_name_set
+ (tng_trajectory_t tng_data,
+ const char *new_name);
+
+/**
+ * @brief Get the name of the computer used when creating the trajectory.
+ * @param tng_data the trajectory of which to get the computer name.
+ * @param name the string to fill with the name of the computer,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for name. This includes \0 terminating character.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_get
+ (const tng_trajectory_t tng_data,
+ char *name, const int max_len);
+
+/**
+ * @brief Set the name of the computer used when creating the trajectory.
+ * @param tng_data the trajectory of which to set the computer name.
+ * @param new_name is a string containing the wanted name.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code new_name != 0 \endcode The pointer to the new_name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_set
+ (tng_trajectory_t tng_data,
+ const char *new_name);
+
+/**
+ * @brief Get the name of the computer used when last modifying the trajectory.
+ * @param tng_data the trajectory of which to get the computer name.
+ * @param name the string to fill with the name of the computer,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for name. This includes \0 terminating character.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_get
+ (const tng_trajectory_t tng_data,
+ char *name, const int max_len);
+
+/**
+ * @brief Set the name of the computer used when last modifying the trajectory.
+ * @param tng_data the trajectory of which to set the computer name.
+ * @param new_name is a string containing the wanted name.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code new_name != 0 \endcode The pointer to the new_name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_set
+ (tng_trajectory_t tng_data,
+ const char *new_name);
+
+/**
+ * @brief Get the pgp_signature of the user creating the trajectory.
+ * @param tng_data the trajectory of which to get the computer name.
+ * @param signature the string to fill with the signature,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for name. This includes \0 terminating character.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code signature != 0 \endcode The pointer to the signature
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+tng_function_status DECLSPECDLLEXPORT tng_first_signature_get
+ (const tng_trajectory_t tng_data,
+ char *signature, const int max_len);
+
+/**
+ * @brief Set the pgp_signature of the user creating the trajectory.
+ * @param tng_data the trajectory of which to set the computer name.
+ * @param signature is a string containing the pgp_signature.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code signature != 0 \endcode The pointer to the signature
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_first_signature_set
+ (tng_trajectory_t tng_data,
+ const char *signature);
+
+/**
+ * @brief Get the pgp_signature of the user last modifying the trajectory.
+ * @param tng_data the trajectory of which to get the computer name.
+ * @param signature the string to fill with the signature,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for name. This includes \0 terminating character.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code signature != 0 \endcode The pointer to the signature
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+tng_function_status DECLSPECDLLEXPORT tng_last_signature_get
+ (const tng_trajectory_t tng_data,
+ char *signature, const int max_len);
+
+/**
+ * @brief Set the pgp_signature of the user last modifying the trajectory.
+ * @param tng_data the trajectory of which to set the computer name.
+ * @param signature is a string containing the pgp_signature.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code signature != 0 \endcode The pointer to the signature
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_last_signature_set
+ (tng_trajectory_t tng_data,
+ const char *signature);
+
+/**
+ * @brief Get the name of the forcefield used in the trajectory.
+ * @param tng_data the trajectory of which to get the forcefield name.
+ * @param name the string to fill with the name of the forcefield,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for name. This includes \0 terminating character.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_get
+ (const tng_trajectory_t tng_data,
+ char *name, const int max_len);
+
+/**
+ * @brief Set the name of the forcefield used in the trajectory.
+ * @param tng_data the trajectory of which to set the forcefield name.
+ * @param new_name is a string containing the wanted name.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code new_name != 0 \endcode The pointer to the new_name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_set
+ (tng_trajectory_t tng_data,
+ const char *new_name);
+
+/**
+ * @brief Get the medium stride length of the trajectory.
+ * @param tng_data is the trajectory from which to get the stride length.
+ * @param len is pointing to a value set to the stride length.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code len != 0 \endcode The pointer to len must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_get
+ (const tng_trajectory_t tng_data,
+ int64_t *len);
+
+/**
+ * @brief Set the medium stride length of the trajectory.
+ * @param tng_data is the trajectory of which to set the stride length.
+ * @param len is the wanted medium stride length.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_set
+ (tng_trajectory_t tng_data,
+ const int64_t len);
+
+/**
+ * @brief Get the long stride length of the trajectory.
+ * @param tng_data is the trajectory from which to get the stride length.
+ * @param len is pointing to a value set to the stride length.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code len != 0 \endcode The pointer to len must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_get
+ (const tng_trajectory_t tng_data,
+ int64_t *len);
+
+/**
+ * @brief Set the long stride length of the trajectory.
+ * @param tng_data is the trajectory of which to set the stride length.
+ * @param len is the wanted long stride length.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_set
+ (tng_trajectory_t tng_data,
+ const int64_t len);
+
+/**
+ * @brief Get the current time per frame of the trajectory.
+ * @param tng_data is the trajectory from which to get the time per frame.
+ * @param time is pointing to a value set to the time per frame.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code time != 0 \endcode The pointer to time must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_get
+ (const tng_trajectory_t tng_data,
+ double *time);
+
+/**
+ * @brief Set the time per frame of the trajectory.
+ * @param tng_data is the trajectory of which to set the time per frame.
+ * @param time is the new time per frame.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code time > 0 \endcode The time per frame must be >= 0.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_set
+ (tng_trajectory_t tng_data,
+ const double time);
+
+/**
+ * @brief Get the length of the input file.
+ * @param tng_data is the trajectory from which to get the input file length.
+ * @param len is pointing to a value set to the file length.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code len != 0 \endcode The pointer to len must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_input_file_len_get
+ (const tng_trajectory_t tng_data,
+ int64_t *len);
+
+/**
+ * @brief Get the number of frames in the trajectory
+ * @param tng_data is the trajectory of which to get the number of frames.
+ * @param n is pointing to a value set to the number of frames.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code tng_data->input_file != 0 \endcode An input file must be open
+ * to find the next frame set.
+ * @pre \code n != 0 \endcode The pointer to n must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (could not find last frame set).
+ */
+tng_function_status DECLSPECDLLEXPORT tng_num_frames_get
+ (const tng_trajectory_t tng_data,
+ int64_t *n);
+
+/**
+ * @brief Get the precision of lossy compression.
+ * @param tng_data is the trajectory of which to get the compression precision.
+ * @param precision will be pointing to the retrieved compression precision.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @details A compression precision of 0.001 (the default) means that the
+ * compressed values are accurate to the third decimal. This function does
+ * not check actual precision of compressed data, but just returns what has
+ * previously been set using tng_compression_precision_set().
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_compression_precision_get
+ (const tng_trajectory_t tng_data,
+ double *precision);
+
+/**
+ * @brief Set the precision of lossy compression.
+ * @param tng_data is the trajectory of which to set the compression precision.
+ * @param precision is the new compression precision.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @details A compression precision of 0.001 (the default) means that the
+ * compressed values are accurate to the third decimal.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_compression_precision_set
+ (tng_trajectory_t tng_data,
+ const double precision);
+
+/**
+ * @brief Set the number of particles, in the case no molecular system is used.
+ * @param tng_data is the trajectory of which to get the number of particles.
+ * @param n is the number of particles to use.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @details When creating a molecular system the number of particles are set
+ * automatically. This should only be used when there is no molecular system
+ * specified or if the number of atoms needs to be overridden for some reason.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_implicit_num_particles_set
+ (tng_trajectory_t tng_data,
+ const int64_t n);
+
+/**
+ * @brief Get the current number of particles.
+ * @param tng_data is the trajectory from which to get the number of particles.
+ * @param n is pointing to a value set to the number of particles.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code n != 0 \endcode The pointer to n must not be a NULL pointer.
+ * @details If variable number of particles are used this function will return
+ * the number of particles in the current frame set.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_num_particles_get
+ (const tng_trajectory_t tng_data,
+ int64_t *n);
+
+/**
+ * @brief Get if the number of particle can be varied during the simulation.
+ * @param tng_data is the trajectory from which to get the number of particles.
+ * @param variable is pointing to a value set to TNG_CONSTANT_N_ATOMS if the
+ * number of particles cannot change or TNG_VARIABLE_N_ATOMS if the number of
+ * particles can change.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code variable != 0 \endcode The pointer to variable must not be
+ * a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_num_particles_variable_get
+ (const tng_trajectory_t tng_data,
+ char *variable);
+
+/**
+ * @brief Get the number of molecule types (length of tng_data->molecules).
+ * @param tng_data is the trajectory from which to get the number of molecules.
+ * @param n is pointing to a value set to the number of molecule types.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code n != 0 \endcode The pointer to n must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_num_molecule_types_get
+ (const tng_trajectory_t tng_data,
+ int64_t *n);
+
+/**
+ * @brief Get the current total number of molecules.
+ * @param tng_data is the trajectory from which to get the number of molecules.
+ * @param n is pointing to a value set to the number of molecules.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code n != 0 \endcode The pointer to n must not be a NULL pointer.
+ * @details If variable number of particles are used this function will return
+ * the total number of molecules in the current frame set.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_num_molecules_get
+ (const tng_trajectory_t tng_data,
+ int64_t *n);
+
+/** @brief Get the list of the count of each molecule.
+ * @param tng_data is the trajectory from which to get the molecule count list.
+ * @param mol_cnt_list is a list of the count of each molecule in the
+ * mol system. This is a pointer to the list in the TNG container, which
+ * means that it should be handled carefully, e.g. not freed.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @return TNG_SUCCESS (0) if successful or TNG_FAILURE(1) if the list of
+ * molecule counts was not valid.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_list_get
+ (const tng_trajectory_t tng_data,
+ int64_t **mol_cnt_list);
+
+/**
+ * @brief Get the exponent used for distances in the trajectory.
+ * @param tng_data is the trajectory from which to get the information.
+ * @param exp is pointing to a value set to the distance unit exponent.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code exp != 0 \endcode The pointer to exp must not be a NULL pointer.
+ * @details Example: If the distances are specified in nm (default) exp is -9.
+ * If the distances are specified in Å exp is -10.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_get
+ (const tng_trajectory_t tng_data,
+ int64_t *exp);
+
+/**
+ * @brief Set the exponent used for distances in the trajectory.
+ * @param tng_data is the trajectory of which to set the unit exponent.
+ * @param exp is the distance unit exponent to use.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @details Example: If the distances are specified in nm (default) exp is -9.
+ * If the distances are specified in Å exp is -10.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_set
+ (const tng_trajectory_t tng_data,
+ const int64_t exp);
+
+/**
+ * @brief Get the number of frames per frame set.
+ * @param tng_data is the trajectory from which to get the number of frames
+ * per frame set.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code n != 0 \endcode The pointer to n must not be a NULL pointer.
+ * @param n is pointing to a value set to the number of frames per frame set.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_get
+ (const tng_trajectory_t tng_data,
+ int64_t *n);
+
+/**
+ * @brief Set the number of frames per frame set.
+ * @param tng_data is the trajectory of which to set the number of frames
+ * per frame set.
+ * @param n is the number of frames per frame set.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @details This does not affect already existing frame sets. For
+ * consistency the number of frames per frame set should be set
+ * betfore creating any frame sets.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_set
+ (const tng_trajectory_t tng_data,
+ const int64_t n);
+
+/**
+ * @brief Get the number of frame sets.
+ * @details This updates tng_data->n_trajectory_frame_sets before returning it.
+ * @param tng_data is the trajectory from which to get the number of frame sets.
+ * @param n is pointing to a value set to the number of frame sets.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code n != 0 \endcode The pointer to n must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_num_frame_sets_get
+ (const tng_trajectory_t tng_data,
+ int64_t *n);
+
+/**
+ * @brief Get the current trajectory frame set.
+ * @param tng_data is the trajectory from which to get the frame set.
+ * @param frame_set_p will be set to point at the memory position of
+ * the found frame set.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_current_frame_set_get
+ (tng_trajectory_t tng_data,
+ tng_trajectory_frame_set_t *frame_set_p);
+
+/**
+ * @brief Find the requested frame set number.
+ * @param tng_data is the trajectory from which to get the frame set.
+ * @param nr is the frame set number to search for.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code nr >= 0 \endcode The frame set number (nr) must be >= 0.
+ * @details tng_data->current_trajectory_frame_set will contain the
+ * found trajectory if successful.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
+ (tng_trajectory_t tng_data,
+ const int64_t nr);
+
+/**
+ * @brief Find the frame set containing a specific frame.
+ * @param tng_data is the trajectory from which to get the frame set.
+ * @param frame is the frame number to search for.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code frame >= 0 \endcode The frame number must be >= 0.
+ * @details tng_data->current_trajectory_frame_set will contain the
+ * found trajectory if successful.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
+ (tng_trajectory_t tng_data,
+ const int64_t frame);
+
+/**
+ * @brief Get the file position of the next frame set in the input file.
+ * @param tng_data is a trajectory data container.
+ * @param frame_set is the frame set of which to get the position of the
+ * following frame set.
+ * @param pos is pointing to a value set to the file position.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code pos != 0 \endcode The pointer to pos must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_next_frame_set_file_pos_get
+ (const tng_trajectory_t tng_data,
+ const tng_trajectory_frame_set_t frame_set,
+ int64_t *pos);
+
+/**
+ * @brief Get the file position of the previous frame set in the input file.
+ * @param tng_data is a trajectory data container.
+ * @param frame_set is the frame set of which to get the position of the
+ * previous frame set.
+ * @param pos is pointing to a value set to the file position.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code pos != 0 \endcode The pointer to pos must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_prev_frame_set_file_pos_get
+ (const tng_trajectory_t tng_data,
+ const tng_trajectory_frame_set_t frame_set,
+ int64_t *pos);
+
+/**
+ * @brief Get the first and last frames of the frame set.
+ * @param tng_data is a trajectory data container.
+ * @param frame_set is the frame set of which to get the frame range.
+ * @param first_frame is set to the first frame of the frame set.
+ * @param last_frame is set to the last frame of the frame set.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code first_frame != 0 \endcode The pointer to first_frame must
+ * not be a NULL pointer.
+ * @pre \code last_frame != 0 \endcode The pointer to last_frame must
+ * not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_frame_range_get
+ (const tng_trajectory_t tng_data,
+ const tng_trajectory_frame_set_t frame_set,
+ int64_t *first_frame,
+ int64_t *last_frame);
+
+/**
+ * @brief Allocate memory for and setup a molecule container.
+ * @param tng_data is a trajectory data container.
+ * @param molecule_p is a pointer to molecule to allocate and initialise.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_alloc(const tng_trajectory_t tng_data,
+ tng_molecule_t *molecule_p);
+
+/**
+ * @brief Clean up a molecule container and free its allocated memory.
+ * @param tng_data is a trajectory data container.
+ * @param molecule_p is the molecule to destroy.
+ * @details All allocated memory in the data structure is freed and also the memory
+ * of the molecule itself.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_free(const tng_trajectory_t tng_data,
+ tng_molecule_t *molecule_p);
+
+/**
+ * @brief Setup a molecule container.
+ * @param tng_data is a trajectory data container.
+ * @param molecule is the molecule to initialise. Memory must be preallocated.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_init
+ (const tng_trajectory_t tng_data,
+ tng_molecule_t molecule);
+
+/**
+ * @brief Clean up a molecule container.
+ * @param tng_data is a trajectory data container.
+ * @param molecule is the molecule to destroy.
+ * @details All allocated memory in the data structure is freed, but not the
+ * memory of molecule itself.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_destroy
+ (const tng_trajectory_t tng_data,
+ tng_molecule_t molecule);
+
+/**
+ * @brief Add a molecule to the trajectory.
+ * @param tng_data is the trajectory data container containing the block..
+ * @param name is a pointer to the string containing the name of the new molecule.
+ * @param molecule is a pointer to the newly created molecule.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the ID could
+ * not be set properly or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_add
+ (tng_trajectory_t tng_data,
+ const char *name,
+ tng_molecule_t *molecule);
+
+/**
+ * @brief Add a molecule with a specific ID to the trajectory.
+ * @param tng_data is the trajectory data container containing the block..
+ * @param name is a pointer to the string containing the name of the new molecule.
+ * @param id is the ID of the created molecule.
+ * @param molecule is a pointer to the newly created molecule.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the ID could
+ * not be set properly or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_w_id_add
+ (tng_trajectory_t tng_data,
+ const char *name,
+ const int64_t id,
+ tng_molecule_t *molecule);
+
+/**
+ * @brief Add an existing molecule (from a molecule container) to the trajectory.
+ * @param tng_data is the trajectory data container containing the block..
+ * @param molecule is a pointer to the molecule to add to the trajectory and will
+ * afterwards point to the molecule in the trajectory.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_existing_add
+ (tng_trajectory_t tng_data,
+ tng_molecule_t *molecule);
+
+/**
+ * @brief Get the name of a molecule.
+ * @param tng_data the trajectory containing the molecule.
+ * @param molecule the molecule of which to get the name.
+ * @param name the string to fill with the name of the molecule,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for name. This includes \0 terminating character.
+ * @pre \code molecule != 0 \endcode The molecule must not be NULL.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_name_get
+ (const tng_trajectory_t tng_data,
+ const tng_molecule_t molecule,
+ char *name,
+ const int max_len);
+
+/**
+ * @brief Set the name of a molecule.
+ * @param tng_data is the trajectory data container containing the molecule..
+ * @param molecule is the molecule to rename.
+ * @param new_name is a string containing the wanted name.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code new_name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_name_set
+ (tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ const char *new_name);
+
+/**
+ * @brief Get the count of a molecule.
+ * @param tng_data is the trajectory data container containing the molecule..
+ * @param molecule is the molecule of which to get the count.
+ * @param cnt is a pointer to the variable to be populated with the count.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code cnt != 0 \endcode The pointer to the molecule count
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_get
+ (tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ int64_t *cnt);
+
+/**
+ * @brief Set the count of a molecule.
+ * @param tng_data is the trajectory data container containing the molecule..
+ * @param molecule is the molecule of which to set the count.
+ * @param cnt is the number of instances of this molecule.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_set
+ (tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ const int64_t cnt);
+
+/**
+ * @brief Find a molecule.
+ * @param tng_data is the trajectory data container containing the molecule.
+ * @param name is a string containing the name of the molecule. If name is empty
+ * only id will be used for finding the molecule.
+ * @param id is the id of the molecule to look for. If id is -1 only the name of
+ * the molecule will be used for finding the molecule.
+ * @param molecule is a pointer to the molecule if it was found - otherwise 0.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if the molecule is found or TNG_FAILURE (1) if the
+ * molecule is not found.
+ * @details If name is an empty string and id == -1 the first residue will
+ * be found.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_find
+ (tng_trajectory_t tng_data,
+ const char *name,
+ int64_t id,
+ tng_molecule_t *molecule);
+
+/**
+ * @brief Retrieve the molecule with specified index in the list of molecules.
+ * @param tng_data is the trajectory data container containing the molecule.
+ * @param index is the index (in tng_data->molecules) of the molecule to return
+ * @param molecule is a pointer to the molecule if it was found - otherwise 0.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code molecule != 0 \endcode molecule must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if the molecule is found or TNG_FAILURE (1) if the
+ * molecule is not found.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_of_index_get
+ (tng_trajectory_t tng_data,
+ int64_t index,
+ tng_molecule_t *molecule);
+
+/**
+ * @brief Copy all molecules and the molecule counts from one TNG trajectory
+ * to another.
+ * @param tng_data_src is the source trajectory containing the molecular
+ * system to copy.
+ * @param tng_data_dest is the destination trajectory.
+ * @pre \code tng_data_src != 0 \endcode The trajectory container (tng_data_src)
+ * must be initialised before using it.
+ * @pre \code tng_data_dest != 0 \endcode The trajectory container (tng_data_dest)
+ * must be initialised before using it.
+ * @details The molecular system in tng_data_dest will be overwritten.
+ * @return TNG_SUCCESS(0) if the copying is successful, TNG_FAILURE if a minor
+ * error has occured or TNG_CRITICAL(2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_system_copy(tng_trajectory_t tng_data_src,
+ tng_trajectory_t tng_data_dest);
+
+/**
+ * @brief Get the number of chains in a molecule.
+ * @param tng_data is the trajectory containing the molecule.
+ * @param molecule is the molecule of which to get the number of chains.
+ * @param n is pointing to a value set to the number of chains.
+ * @pre \code molecule != 0 \endcode The molecule must not be NULL.
+ * @pre \code n != 0 \endcode The pointer to n must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_num_chains_get
+ (tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ int64_t *n);
+
+/**
+ * @brief Retrieve the chain of a molecule with specified index in the list
+ * of chains.
+ * @param tng_data is the trajectory data container containing the molecule.
+ * @param index is the index (in molecule->chains) of the chain to return
+ * @param molecule is the molecule from which to get the chain.
+ * @param chain is a pointer to the chain if it was found - otherwise 0.
+ * @pre \code molecule != 0 \endcode molecule must not be a NULL pointer.
+ * @pre \code chain != 0 \endcode chain must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if the chain is found or TNG_FAILURE (1) if the
+ * chain is not found.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_of_index_get
+ (tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ int64_t index,
+ tng_chain_t *chain);
+
+/**
+ * @brief Get the number of residues in a molecule.
+ * @param tng_data is the trajectory containing the molecule.
+ * @param molecule is the molecule of which to get the number residues.
+ * @param n is pointing to a value set to the number of residues.
+ * @pre \code molecule != 0 \endcode The molecule must not be NULL.
+ * @pre \code n != 0 \endcode The pointer to n must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_num_residues_get
+ (tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ int64_t *n);
+
+/**
+ * @brief Retrieve the residue of a molecule with specified index in the list
+ * of chains.
+ * @param tng_data is the trajectory data container containing the molecule.
+ * @param index is the index (in molecule->residues) of the residue to return
+ * @param molecule is the molecule from which to get the residue.
+ * @param residue is a pointer to the residue if it was found - otherwise 0.
+ * @pre \code molecule != 0 \endcode molecule must not be a NULL pointer.
+ * @pre \code residue != 0 \endcode residue must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if the residue is found or TNG_FAILURE (1) if the
+ * residue is not found.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_residue_of_index_get
+ (tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ int64_t index,
+ tng_residue_t *residue);
+
+/**
+ * @brief Get the number of atoms in a molecule.
+ * @param tng_data is the trajectory containing the molecule.
+ * @param molecule is the molecule of which to get the number of atoms.
+ * @param n is pointing to a value set to the number of atoms.
+ * @pre \code molecule != 0 \endcode The molecule must not be NULL.
+ * @pre \code n != 0 \endcode The pointer to n must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_num_atoms_get
+ (tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ int64_t *n);
+
+/**
+ * @brief Retrieve the atom of a molecule with specified index in the list
+ * of atoms.
+ * @param tng_data is the trajectory data container containing the molecule.
+ * @param index is the index (in molecule->atoms) of the atom to return
+ * @param molecule is the molecule from which to get the atom.
+ * @param atom is a pointer to the atom if it was found - otherwise 0.
+ * @pre \code molecule != 0 \endcode molecule must not be a NULL pointer.
+ * @pre \code atom != 0 \endcode atom must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if the atom is found or TNG_FAILURE (1) if the
+ * atom is not found.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_of_index_get
+ (tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ int64_t index,
+ tng_atom_t *atom);
+
+/**
+ * @brief Find a chain in a molecule.
+ * @param tng_data is the trajectory data container containing the molecule.
+ * @param molecule is the molecule in which to search for the chain.
+ * @param name is a string containing the name of the chain. If name is empty
+ * only id will be used for finding the chain.
+ * @param id is the id of the chain to look for. If id is -1 only the name of
+ * the chain will be used for finding the chain.
+ * @param chain is a pointer to the chain if it was found - otherwise 0.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if the chain is found or TNG_FAILURE (1) if the
+ * chain is not found.
+ * @details If name is an empty string and id == -1 the first residue will
+ * be found.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_find
+ (tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ const char *name,
+ int64_t id,
+ tng_chain_t *chain);
+
+/**
+ * @brief Add a chain to a molecule.
+ * @param tng_data is the trajectory data container containing the molecule..
+ * @param molecule is the molecule to add a chain to.
+ * @param name is a string containing the name of the chain.
+ * @param chain is a pointer to the newly created chain.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the ID could
+ * not be set properly or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_add
+ (tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ const char *name,
+ tng_chain_t *chain);
+
+/**
+ * @brief Add a chain with a specific id to a molecule.
+ * @param tng_data is the trajectory data container containing the molecule..
+ * @param molecule is the molecule to add a chain to.
+ * @param name is a string containing the name of the chain.
+ * @param id is the ID of the created chain.
+ * @param chain is a pointer to the newly created chain.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the ID could
+ * not be set properly or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_w_id_add
+ (tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ const char *name,
+ const int64_t id,
+ tng_chain_t *chain);
+
+/**
+ * @brief Add a bond between two atoms to a molecule.
+ * @param tng_data is the trajectory data container containing the molecule.
+ * @param molecule is the molecule containing the atoms to connect.
+ * @param from_atom_id is the id of one of the two atoms in the bond.
+ * @param to_atom_id is the id of the other atom in the bond.
+ * @param bond is a pointer to the newly created bond.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (!) if a minor error
+ * has occured or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_bond_add
+ (const tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ const int64_t from_atom_id,
+ const int64_t to_atom_id,
+ tng_bond_t *bond);
+
+/**
+ * @brief Find an atom in a molecule.
+ * @param tng_data is the trajectory data container containing the molecule.
+ * @param molecule is the molecule in which to search for the atom.
+ * @param name is a string containing the name of the atom. If name is an
+ * empty string only id will be used for searching.
+ * @param id is the id of the atom to find. If id == -1 the first atom
+ * that matches the specified name will be found.
+ * @param atom is a pointer to the atom if it was found - otherwise 0.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if the atom is found or TNG_FAILURE (1) if the
+ * atom is not found.
+ * @details If name is an empty string and id == -1 the first residue will
+ * be found.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_find
+ (tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ const char *name,
+ int64_t id,
+ tng_atom_t *atom);
+
+/**
+ * @brief Get the name of a chain.
+ * @param tng_data the trajectory containing the chain.
+ * @param chain the chain of which to get the name.
+ * @param name the string to fill with the name of the chain,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for name. This includes \0 terminating character.
+ * @pre \code chain != 0 \endcode The chain must not be NULL.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+tng_function_status DECLSPECDLLEXPORT tng_chain_name_get
+ (const tng_trajectory_t tng_data,
+ const tng_chain_t chain,
+ char *name,
+ const int max_len);
+
+/**
+ * @brief Set the name of a chain.
+ * @param tng_data is the trajectory data container containing the atom..
+ * @param chain is the chain to rename.
+ * @param new_name is a string containing the wanted name.
+ * @pre \code new_name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_chain_name_set
+ (tng_trajectory_t tng_data,
+ tng_chain_t chain,
+ const char *new_name);
+
+/**
+ * @brief Get the number of residues in a molecule chain.
+ * @param tng_data is the trajectory containing the chain.
+ * @param chain is the chain of which to get the number of residues.
+ * @param n is pointing to a value set to the number of residues.
+ * @pre \code chain != 0 \endcode The chain must not be NULL.
+ * @pre \code n != 0 \endcode The pointer to n must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_chain_num_residues_get
+ (const tng_trajectory_t tng_data,
+ const tng_chain_t chain,
+ int64_t *n);
+
+/**
+ * @brief Retrieve the residue of a chain with specified index in the list
+ * of residues.
+ * @param tng_data is the trajectory data container containing the chain.
+ * @param index is the index (in chain->residues) of the residue to return
+ * @param chain is the chain from which to get the residue.
+ * @param residue is a pointer to the residue if it was found - otherwise 0.
+ * @pre \code chain != 0 \endcode chain must not be a NULL pointer.
+ * @pre \code residue != 0 \endcode residue must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if the residue is found or TNG_FAILURE (1) if the
+ * residue is not found.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_chain_residue_of_index_get
+ (tng_trajectory_t tng_data,
+ tng_chain_t chain,
+ int64_t index,
+ tng_residue_t *residue);
+
+/**
+ * @brief Find a residue in a chain.
+ * @param tng_data is the trajectory data container containing the chain.
+ * @param chain is the chain in which to search for the residue.
+ * @param name is a string containing the name of the residue. If name is an
+ * empty string only id will be used for searching.
+ * @param id is the id of the residue to find. If id == -1 the first residue
+ * that matches the specified name will be found.
+ * @param residue is a pointer to the residue if it was found - otherwise 0.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if the residue is found or TNG_FAILURE (1) if the
+ * residue is not found.
+ * @details If name is an empty string and id == -1 the first residue will
+ * be found.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_chain_residue_find
+ (tng_trajectory_t tng_data,
+ tng_chain_t chain,
+ const char *name,
+ int64_t id,
+ tng_residue_t *residue);
+
+/**
+ * @brief Add a residue to a chain.
+ * @param tng_data is the trajectory data container containing the chain..
+ * @param chain is the chain to add a residue to.
+ * @param name is a string containing the name of the residue.
+ * @param residue is a pointer to the newly created residue.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the ID could
+ * not be set properly or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_chain_residue_add
+ (tng_trajectory_t tng_data,
+ tng_chain_t chain,
+ const char *name,
+ tng_residue_t *residue);
+
+/**
+ * @brief Add a residue with a specific ID to a chain.
+ * @param tng_data is the trajectory data container containing the chain..
+ * @param chain is the chain to add a residue to.
+ * @param name is a string containing the name of the residue.
+ * @param id is the ID of the created residue.
+ * @param residue is a pointer to the newly created residue.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the ID could
+ * not be set properly or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_chain_residue_w_id_add
+ (tng_trajectory_t tng_data,
+ tng_chain_t chain,
+ const char *name,
+ const int64_t id,
+ tng_residue_t *residue);
+
+/**
+ * @brief Get the name of a residue.
+ * @param tng_data the trajectory containing the residue.
+ * @param residue the residue of which to get the name.
+ * @param name the string to fill with the name of the residue,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for name. This includes \0 terminating character.
+ * @pre \code residue != 0 \endcode The residue must not be NULL.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+tng_function_status DECLSPECDLLEXPORT tng_residue_name_get
+ (const tng_trajectory_t tng_data,
+ const tng_residue_t residue,
+ char *name,
+ const int max_len);
+
+/**
+ * @brief Set the name of a residue.
+ * @param tng_data is the trajectory data container containing the residue.
+ * @param residue is the residue to rename.
+ * @param new_name is a string containing the wanted name.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code new_name != 0 \endcode The new name to set (new_name) must
+ * not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_residue_name_set
+ (tng_trajectory_t tng_data,
+ tng_residue_t residue,
+ const char *new_name);
+
+/**
+ * @brief Get the number of atoms in a residue.
+ * @param tng_data is the trajectory containing the residue.
+ * @param residue is the residue of which to get the number atoms.
+ * @param n is pointing to a value set to the number of atoms.
+ * @pre \code residue != 0 \endcode The residue must not be NULL.
+ * @pre \code n != 0 \endcode The pointer to n must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_residue_num_atoms_get
+ (const tng_trajectory_t tng_data,
+ const tng_residue_t residue,
+ int64_t *n);
+
+/**
+ * @brief Retrieve the atom of a residue with specified index in the list
+ * of atoms.
+ * @param tng_data is the trajectory data container containing the residue.
+ * @param index is the index (in residue->atoms) of the atom to return
+ * @param residue is the residue from which to get the atom.
+ * @param atom is a pointer to the atom if it was found - otherwise 0.
+ * @pre \code residue != 0 \endcode residue must not be a NULL pointer.
+ * @pre \code atom != 0 \endcode atom must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if the atom is found or TNG_FAILURE (1) if the
+ * atom is not found.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_residue_atom_of_index_get
+ (tng_trajectory_t tng_data,
+ tng_residue_t residue,
+ int64_t index,
+ tng_atom_t *atom);
+
+/**
+ * @brief Add an atom to a residue.
+ * @param tng_data is the trajectory containing the residue.
+ * @param residue is the residue to add an atom to.
+ * @param atom_name is a string containing the name of the atom.
+ * @param atom_type is a string containing the atom type of the atom.
+ * @param atom is a pointer to the newly created atom.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code atom_name != 0 \endcode The pointer to the atom name string
+ * must not be a NULL pointer.
+ * @pre \code atom_type != 0 \endcode The pointer to the atom_type string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the ID could
+ * not be set properly or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_residue_atom_add
+ (tng_trajectory_t tng_data,
+ tng_residue_t residue,
+ const char *atom_name,
+ const char *atom_type,
+ tng_atom_t *atom);
+
+/**
+ * @brief Add an atom with a specific ID to a residue.
+ * @param tng_data is the trajectory containing the residue.
+ * @param residue is the residue to add an atom to.
+ * @param atom_name is a string containing the name of the atom.
+ * @param atom_type is a string containing the atom type of the atom.
+ * @param id is the ID of the created atom.
+ * @param atom is a pointer to the newly created atom.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code atom_name != 0 \endcode The pointer to the atom name string
+ * must not be a NULL pointer.
+ * @pre \code atom_type != 0 \endcode The pointer to the atom_type string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the ID could
+ * not be set properly or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_residue_atom_w_id_add
+ (tng_trajectory_t tng_data,
+ tng_residue_t residue,
+ const char *atom_name,
+ const char *atom_type,
+ const int64_t id,
+ tng_atom_t *atom);
+
+/**
+ * @brief Get the residue of an atom.
+ * @param tng_data the trajectory containing the atom.
+ * @param atom the atom of which to get the name.
+ * @param residue is set to the residue of the atom.
+ * @pre \code atom != 0 \endcode The atom must not be NULL.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status tng_atom_residue_get(tng_trajectory_t tng_data,
+ const tng_atom_t atom,
+ tng_residue_t *residue);
+
+/**
+ * @brief Get the name of an atom.
+ * @param tng_data the trajectory containing the atom.
+ * @param atom the atom of which to get the name.
+ * @param name the string to fill with the name of the atom,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for name. This includes \0 terminating character.
+ * @pre \code atom != 0 \endcode The atom must not be NULL.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+tng_function_status DECLSPECDLLEXPORT tng_atom_name_get
+ (const tng_trajectory_t tng_data,
+ const tng_atom_t atom,
+ char *name,
+ const int max_len);
+
+/**
+ * @brief Set the name of an atom.
+ * @param tng_data is the trajectory data container containing the atom.
+ * @param atom is the atom to rename.
+ * @param new_name is a string containing the wanted name.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code new_name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_atom_name_set
+ (tng_trajectory_t tng_data,
+ tng_atom_t atom,
+ const char *new_name);
+
+/**
+ * @brief Get the type of an atom.
+ * @param tng_data the trajectory containing the atom.
+ * @param atom the atom of which to get the type.
+ * @param type the string to fill with the type of the atom,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for type. This includes \0 terminating character.
+ * @pre \code atom != 0 \endcode The atom must not be NULL.
+ * @pre \code type != 0 \endcode The pointer to the type string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+tng_function_status DECLSPECDLLEXPORT tng_atom_type_get
+ (const tng_trajectory_t tng_data,
+ const tng_atom_t atom,
+ char *type,
+ const int max_len);
+
+/**
+ * @brief Set the atom type of an atom.
+ * @param tng_data is the trajectory data container containing the atom.
+ * @param atom is the atom to change.
+ * @param new_type is a string containing the atom type.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code new_type != 0 \endcode The pointer to the atom type string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_atom_type_set
+ (tng_trajectory_t tng_data,
+ tng_atom_t atom,
+ const char *new_type);
+
+/**
+ * @brief Get the molecule name of real particle number (number in mol system).
+ * @param tng_data is the trajectory data container containing the atom.
+ * @param nr is the real number of the particle in the molecular system.
+ * @param name is a string, which is set to the name of the molecule. Memory
+ * must be reserved beforehand.
+ * @param max_len is the maximum length of name.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (!) if a minor error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_name_of_particle_nr_get
+ (const tng_trajectory_t tng_data,
+ const int64_t nr,
+ char *name,
+ int max_len);
+
+/**
+ * @brief Get the molecule id of real particle number (number in mol system).
+ * @param tng_data is the trajectory data container containing the atom.
+ * @param nr is the real number of the particle in the molecular system.
+ * @param id is will be set to the id of the molecule.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code id != 0 \endcode The pointer to id must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (!) if a minor error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molecule_id_of_particle_nr_get
+ (const tng_trajectory_t tng_data,
+ const int64_t nr,
+ int64_t *id);
+
+/**
+ * @brief Get the bonds of the current molecular system.
+ * @param tng_data is the trajectory data container containing the molecular
+ * system.
+ * @param n_bonds is set to the number of bonds in the molecular system and
+ * thereby also the lengths of the two lists: from_atoms and to_atoms.
+ * @param from_atoms is a list (memory reserved by this function) of atoms
+ * (number of atom in mol system) in bonds.
+ * @param to_atoms is a list (memory reserved by this function) of atoms
+ * (number of atom in mol system) in bonds.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code n_bonds != 0 \endcode The pointer to n_bonds must not be a
+ * NULL pointer.
+ * @pre \code from_atoms != 0 \endcode The pointer to from_atoms must not
+ * be a NULL pointer.
+ * @pre \code to_atoms != 0 \endcode The pointer to to_atoms must not
+ * be a NULL pointer.
+ * @details The two lists of atoms use the same index, i.e. from_atoms[0]
+ * and to_atoms[0] are linked with a bond. Since memory is reserved in
+ * this function it must be freed afterwards.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_molsystem_bonds_get
+ (const tng_trajectory_t tng_data,
+ int64_t *n_bonds,
+ int64_t **from_atoms,
+ int64_t **to_atoms);
+
+/**
+ * @brief Get the chain name of real particle number (number in mol system).
+ * @param tng_data is the trajectory data container containing the atom.
+ * @param nr is the real number of the particle in the molecular system.
+ * @param name is a string, which is set to the name of the chain. Memory
+ * must be reserved beforehand.
+ * @param max_len is the maximum length of name.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (!) if a minor error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_chain_name_of_particle_nr_get
+ (const tng_trajectory_t tng_data,
+ const int64_t nr,
+ char *name,
+ int max_len);
+
+/**
+ * @brief Get the residue name of real particle number (number in mol system).
+ * @param tng_data is the trajectory data container containing the atom.
+ * @param nr is the real number of the particle in the molecular system.
+ * @param name is a string, which is set to the name of the residue. Memory
+ * must be reserved beforehand.
+ * @param max_len is the maximum length of name.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (!) if a minor error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_residue_name_of_particle_nr_get
+ (const tng_trajectory_t tng_data,
+ const int64_t nr,
+ char *name,
+ int max_len);
+
+/**
+ * @brief Get the residue id (local to molecule) of real particle number
+ * (number in mol system).
+ * @param tng_data is the trajectory data container containing the atom.
+ * @param nr is the real number of the particle in the molecular system.
+ * @param id is a pointer to the variable, which will be set to the ID.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code id != 0 \endcode The pointer to id must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (!) if a minor error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_residue_id_of_particle_nr_get
+ (const tng_trajectory_t tng_data,
+ const int64_t nr,
+ int64_t *id);
+
+/**
+ * @brief Get the residue id (based on other molecules and molecule counts)
+ * of real particle number (number in mol system).
+ * @param tng_data is the trajectory data container containing the atom.
+ * @param nr is the real number of the particle in the molecular system.
+ * @param id is a pointer to the variable, which will be set to the ID.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code id != 0 \endcode The pointer to id must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (!) if a minor error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_global_residue_id_of_particle_nr_get
+ (const tng_trajectory_t tng_data,
+ const int64_t nr,
+ int64_t *id);
+
+/**
+ * @brief Get the atom name of real particle number (number in mol system).
+ * @param tng_data is the trajectory data container containing the atom.
+ * @param nr is the real number of the particle in the molecular system.
+ * @param name is a string, which is set to the name of the atom. Memory
+ * must be reserved beforehand.
+ * @param max_len is the maximum length of name.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (!) if a minor error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_atom_name_of_particle_nr_get
+ (const tng_trajectory_t tng_data,
+ const int64_t nr,
+ char *name,
+ int max_len);
+
+/**
+ * @brief Get the atom type of real particle number (number in mol system).
+ * @param tng_data is the trajectory data container containing the atom.
+ * @param nr is the real number of the particle in the molecular system.
+ * @param type is a string, which is set to the type of the atom. Memory
+ * must be reserved beforehand.
+ * @param max_len is the maximum length of type.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code type != 0 \endcode The pointer to the type string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (!) if a minor error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_atom_type_of_particle_nr_get
+ (const tng_trajectory_t tng_data,
+ const int64_t nr,
+ char *type,
+ int max_len);
+
+/**
+ * @brief Add a particle mapping table.
+ * @details Each particle mapping table will be written as a separate block,
+ * followed by the data blocks for the corresponding particles. In most cases
+ * there is one particle mapping block for each thread writing the trajectory.
+ * @param tng_data is the trajectory, with the frame set to which to add
+ * the mapping block.
+ * @details The mapping information is added to the currently active frame set
+ * of tng_data
+ * @param num_first_particle is the first particle number of this mapping
+ * block.
+ * @param n_particles is the number of particles in this mapping block.
+ * @param mapping_table is a list of the real particle numbers (i.e. the numbers
+ * used in the molecular system). The list is n_particles long.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @details mapping_table[0] is the real particle number of the first particle
+ * in the following data blocks.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_particle_mapping_add
+ (tng_trajectory_t tng_data,
+ const int64_t num_first_particle,
+ const int64_t n_particles,
+ const int64_t *mapping_table);
+
+/**
+ * @brief Remove all particle mappings (in memory) from the current frame set.
+ * @details Clears the currently setup particle mappings of the current frame
+ * set.
+ * @param tng_data is the trajectory, with the frame set of which to clear
+ * all particle mappings.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_particle_mapping_free
+ (tng_trajectory_t tng_data);
+
+/**
+ * @brief Read the header blocks from the input_file of tng_data.
+ * @details The trajectory blocks must be read separately and iteratively in chunks
+ * to fit in memory.
+ * @param tng_data is a trajectory data container.
+ * @details tng_data->input_file_path specifies
+ * which file to read from. If the file (input_file) is not open it will be
+ * opened.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_file_headers_read
+ (tng_trajectory_t tng_data,
+ const char hash_mode);
+
+/**
+ * @brief Write the header blocks to the output_file of tng_data.
+ * @details The trajectory blocks must be written separately and iteratively in chunks
+ * to fit in memory.
+ * @param tng_data is a trajectory data container.
+ * @details tng_data->output_file_path
+ * specifies which file to write to. If the file (output_file) is not open it
+ * will be opened.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH an md5 hash for each header block will be generated.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_file_headers_write
+ (tng_trajectory_t tng_data,
+ const char hash_mode);
+
+/**
+ * @brief Read one (the next) block (of any kind) from the input_file of tng_data.
+ * @param tng_data is a trajectory data container.
+ * @details tng_data->input_file_path specifies
+ * which file to read from. If the file (input_file) is not open it will be
+ * opened.
+ * @param block_data is a pointer to the struct which will be populated with the
+ * data.
+ * @details If block_data->input_file_pos > 0 it is the position from where the
+ * reading starts otherwise it starts from the current position.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code block != 0 \endcode The block container (block) must be
+ * initialised before using it.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_block_read_next
+ (tng_trajectory_t tng_data,
+ tng_gen_block_t block_data,
+ const char hash_mode);
+
+/**
+ * @brief Read one frame set, including all particle mapping blocks and data
+ * blocks, starting from the current file position.
+ * @param tng_data is a trajectory data container.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_read
+ (tng_trajectory_t tng_data,
+ const char hash_mode);
+
+/**
+ * @brief Read data from the current frame set from the input_file. Only read
+ * particle mapping and data blocks matching the specified block_id.
+ * @param tng_data is a trajectory data container.
+ * @details tng_data->input_file_path specifies
+ * which file to read from. If the file (input_file) is not open it will be
+ * opened.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @param block_id is the ID of the data block to read from file.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_current_only_data_from_block_id
+ (tng_trajectory_t tng_data,
+ const char hash_mode,
+ const int64_t block_id);
+
+/**
+ * @brief Read one (the next) frame set, including particle mapping and related data blocks
+ * from the input_file of tng_data.
+ * @param tng_data is a trajectory data container.
+ * @details tng_data->input_file_path specifies
+ * which file to read from. If the file (input_file) is not open it will be
+ * opened.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next
+ (tng_trajectory_t tng_data,
+ const char hash_mode);
+
+/**
+ * @brief Read one (the next) frame set, including particle mapping and data blocks with a
+ * specific block id from the input_file of tng_data.
+ * @param tng_data is a trajectory data container.
+ * @details tng_data->input_file_path specifies
+ * which file to read from. If the file (input_file) is not open it will be
+ * opened.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @param block_id is the ID number of the blocks that should be read from file.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next_only_data_from_block_id
+ (tng_trajectory_t tng_data,
+ const char hash_mode,
+ const int64_t block_id);
+
+/**
+ * @brief Write one frame set, including mapping and related data blocks
+ * to the output_file of tng_data.
+ * @param tng_data is a trajectory data container.
+ * @details tng_data->output_file_path specifies
+ * which file to write to. If the file (output_file) is not open it will be
+ * opened.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH an md5 hash for each header block will be generated.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_write
+ (tng_trajectory_t tng_data,
+ const char hash_mode);
+
+/**
+ * @brief Write one frame set even if it does not have as many frames as
+ * expected. The function also writes mapping and related data blocks
+ * to the output_file of tng_data.
+ * @param tng_data is a trajectory data container.
+ * @details tng_data->output_file_path specifies
+ * which file to write to. If the file (output_file) is not open it will be
+ * opened.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH an md5 hash for each header block will be generated.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @details The number of frames in the frame set is set to the number of
+ * frames of the data blocks before writing it to disk.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_premature_write
+ (tng_trajectory_t tng_data,
+ const char hash_mode);
+
+/**
+ * @brief Create and initialise a frame set.
+ * @details Particle mappings are retained from previous frame set (if any).
+ * To explicitly clear particle mappings use tng_frame_set_particle_mapping_free().
+ * @param tng_data is the trajectory data container in which to add the frame
+ * set.
+ * @param first_frame is the first frame of the frame set.
+ * @param n_frames is the number of frames in the frame set.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code first_frame >= 0 \endcode The first frame must not be negative.
+ * @pre \code n_frames >= 0 \endcode The number of frames must not be negative.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_new
+ (tng_trajectory_t tng_data,
+ const int64_t first_frame,
+ const int64_t n_frames);
+
+/**
+ * @brief Create and initialise a frame set with the time of the first frame
+ * specified.
+ * @param tng_data is the trajectory data container in which to add the frame
+ * set.
+ * @param first_frame is the first frame of the frame set.
+ * @param n_frames is the number of frames in the frame set.
+ * @param first_frame_time is the time stamp of the first frame (in seconds).
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code first_frame >= 0 \endcode The first frame must not be negative.
+ * @pre \code n_frames >= 0 \endcode The number of frames must not be negative.
+ * @pre \code first_frame_time >= 0 \endcode The time stamp of the first frame
+ * must not be negative.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_with_time_new
+ (tng_trajectory_t tng_data,
+ const int64_t first_frame,
+ const int64_t n_frames,
+ const double first_frame_time);
+
+/**
+ * @brief Set the time stamp of the first frame of the current frame set.
+ * @param tng_data is the trajectory containing the frame set.
+ * @param first_frame_time is the time stamp of the first frame in the
+ * frame set.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code first_frame_time >= 0 \endcode The time stamp of the first frame
+ * must not be negative.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_first_frame_time_set
+ (tng_trajectory_t tng_data,
+ const double first_frame_time);
+
+/**
+ * @brief Read the number of the first frame of the next frame set.
+ * @param tng_data is the trajectory containing the frame set.
+ * @param frame is set to the frame number of the first frame in the
+ * next frame set.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code tng_data->input_file != 0 \endcode An input file must be open
+ * to find the next frame set.
+ * @pre \code frame != 0 \endcode The pointer to the frame must not be a NULL
+ * pointer.
+ * @return TNG_SUCCESS(0) if successful, TNG_FAILURE(1) if there is no next
+ * frame set or TNG_CRITICAL(2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_first_frame_nr_of_next_frame_set_get
+ (tng_trajectory_t tng_data,
+ int64_t *frame);
+
+/**
+ * @brief Add a non-particle dependent data block.
+ * @param tng_data is the trajectory data container in which to add the data
+ * block
+ * @param id is the block ID of the block to add.
+ * @param block_name is a descriptive name of the block to add
+ * @param datatype is the datatype of the data in the block (e.g. int/float)
+ * @param block_type_flag indicates if this is a non-trajectory block (added
+ * directly to tng_data) or if it is a trajectory block (added to the
+ * frame set)
+ * @param n_frames is the number of frames of the data block (automatically
+ * set to 1 if adding a non-trajectory data block)
+ * @param n_values_per_frame is how many values a stored each frame (e.g. 9
+ * for a box shape block)
+ * @param stride_length is how many frames are between each entry in the
+ * data block
+ * @param codec_id is the ID of the codec to compress the data.
+ * @param new_data is an array of data values to add.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code block_name != 0 \endcode The pointer to the block name must
+ * not be a NULL pointer.
+ * @pre \code n_values_per_frame > 0 \endcode n_values_per_frame must be
+ * a positive integer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_data_block_add
+ (tng_trajectory_t tng_data,
+ const int64_t id,
+ const char *block_name,
+ const char datatype,
+ const char block_type_flag,
+ int64_t n_frames,
+ const int64_t n_values_per_frame,
+ int64_t stride_length,
+ const int64_t codec_id,
+ void *new_data);
+
+/**
+ * @brief Add a particle dependent data block.
+ * @param tng_data is the trajectory data container in which to add the data
+ * block
+ * @param id is the block ID of the block to add.
+ * @param block_name is a descriptive name of the block to add
+ * @param datatype is the datatype of the data in the block (e.g. int/float)
+ * @param block_type_flag indicates if this is a non-trajectory block (added
+ * directly to tng_data) or if it is a trajectory block (added to the
+ * frame set)
+ * @param n_frames is the number of frames of the data block (automatically
+ * set to 1 if adding a non-trajectory data block)
+ * @param n_values_per_frame is how many values a stored each frame (e.g. 9
+ * for a box shape block)
+ * @param stride_length is how many frames are between each entry in the
+ * data block
+ * @param num_first_particle is the number of the first particle stored
+ * in this data block
+ * @param n_particles is the number of particles stored in this data block
+ * @param codec_id is the ID of the codec to compress the data.
+ * @param new_data is an array of data values to add.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code block_name != 0 \endcode The pointer to the block name must
+ * not be a NULL pointer.
+ * @pre \code n_values_per_frame > 0 \endcode n_values_per_frame must be
+ * a positive integer.
+ * @pre \code num_first_particle >= 0 \endcode The number of the
+ * first particle must be >= 0.
+ * @pre \code n_particles >= 0 \endcode n_particles must be >= 0.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_particle_data_block_add
+ (tng_trajectory_t tng_data,
+ const int64_t id,
+ const char *block_name,
+ const char datatype,
+ const char block_type_flag,
+ int64_t n_frames,
+ const int64_t n_values_per_frame,
+ int64_t stride_length,
+ const int64_t num_first_particle,
+ const int64_t n_particles,
+ const int64_t codec_id,
+ void *new_data);
+
+/** @brief Get the name of a data block of a specific ID.
+ * @param tng_data is the trajectory data container.
+ * @param block_id is the ID of the data block of which to get the name.
+ * @param name is a string, which is set to the name of the data block.
+ * Memory must be reserved beforehand.
+ * @param max_len is the maximum length of name.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code name != 0 \endcode The pointer to the name string
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if the data block is found, TNG_FAILURE (1)
+ * if a minor error has occured or the data block is not found or
+ * TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_data_block_name_get
+ (tng_trajectory_t tng_data,
+ int64_t block_id,
+ char *name,
+ int max_len);
+
+/** @brief Get the dependency of a data block of a specific ID.
+ * @param tng_data is the trajectory data container.
+ * @param block_id is the ID of the data block of which to get the name.
+ * @param block_dependency is a pointer to the dependency of the data block.
+ * If the block is frame dependent it will be set to TNG_FRAME_DEPENDENT,
+ * if it is particle dependent it will be set to TNG_PARTICLE_DEPENDENT and
+ * if it is both it will be set to TNG_FRAME_DEPENDENT & TNG_PARTICLE_DEPENDENT.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code block_dependency != 0 \endcode The pointer to the block dependency
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if the data block is found, TNG_FAILURE (1)
+ * if a minor error has occured or the data block is not found or
+ * TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_data_block_dependency_get
+ (tng_trajectory_t tng_data,
+ int64_t block_id,
+ int *block_dependency);
+
+/** @brief Get the number of values per frame of a data block of a specific ID.
+ * @param tng_data is the trajectory data container.
+ * @param block_id is the ID of the data block of which to get the name.
+ * @param n_values_per_frame is a pointer set to the number of values per frame.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code n_values_per_frame != 0 \endcode The pointer to the number of values
+ * per frame must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if the data block is found, TNG_FAILURE (1)
+ * if a minor error has occured or the data block is not found or
+ * TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_data_block_num_values_per_frame_get
+ (tng_trajectory_t tng_data,
+ int64_t block_id,
+ int64_t *n_values_per_frame);
+
+/**
+ * @brief Write data of one trajectory frame to the output_file of tng_data.
+ * @param tng_data is a trajectory data container. tng_data->output_file_path
+ * specifies which file to write to. If the file (output_file) is not open it
+ * will be opened.
+ * @param frame_nr is the index number of the frame to write.
+ * @param block_id is the ID of the data block to write the data to.
+ * @param values is an array of data to write. The length of the array should
+ * equal n_values_per_frame.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0.
+ * @pre \code values != 0 \endcode The pointer to the values must not be a NULL
+ * pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_frame_data_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const int64_t block_id,
+ const void *values,
+ const char hash_mode);
+
+/**
+ * @brief Write particle data of one trajectory frame to the output_file of
+ * tng_data.
+ * @param tng_data is a trajectory data container. tng_data->output_file_path
+ * specifies which file to write to. If the file (output_file) is not open it
+ * will be opened.
+ * @param frame_nr is the index number of the frame to write.
+ * @param block_id is the ID of the data block to write the data to.
+ * @param val_first_particle is the number of the first particle in the data
+ * array.
+ * @param val_n_particles is the number of particles in the data array.
+ * @param values is a 1D-array of data to write. The length of the array should
+ * equal n_particles * n_values_per_frame.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0.
+ * @pre \code val_first_particle >= 0 \endcode The number of the
+ * first particle must be >= 0.
+ * @pre \code val_n_particles >= 0 \endcode The number of particles must be >= 0.
+ * @pre \code values != 0 \endcode The pointer to the values must not be a NULL
+ * pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_frame_particle_data_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const int64_t block_id,
+ const int64_t val_first_particle,
+ const int64_t val_n_particles,
+ const void *values,
+ const char hash_mode);
+
+/**
+ * @brief Free data of an array of values (2D).
+ * @param tng_data is a trajectory data container.
+ * @param values is the 2D array to free and will be set to 0 afterwards.
+ * @param n_frames is the number of frames in the data array.
+ * @param n_values_per_frame is the number of values per frame in the data array.
+ * @param type is the data type of the data in the array (e.g. int/float/char).
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_data_values_free
+ (const tng_trajectory_t tng_data,
+ union data_values **values,
+ const int64_t n_frames,
+ const int64_t n_values_per_frame,
+ const char type);
+
+/**
+ * @brief Free data of an array of values (3D).
+ * @param tng_data is a trajectory data container.
+ * @param values is the array to free and will be set to 0 afterwards.
+ * @param n_frames is the number of frames in the data array.
+ * @param n_particles is the number of particles in the data array.
+ * @param n_values_per_frame is the number of values per frame in the data array.
+ * @param type is the data type of the data in the array (e.g. int/float/char).
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_particle_data_values_free
+ (const tng_trajectory_t tng_data,
+ union data_values ***values,
+ const int64_t n_frames,
+ const int64_t n_particles,
+ const int64_t n_values_per_frame,
+ const char type);
+
+/**
+ * @brief Retrieve non-particle data, from the last read frame set. Obsolete!
+ * @param tng_data is a trajectory data container. tng_data->input_file_path specifies
+ * which file to read from. If the file (input_file) is not open it will be
+ * opened.
+ * @param block_id is the id number of the particle data block to read.
+ * @param values is a pointer to a 2-dimensional array (memory unallocated), which
+ * will be filled with data. The array will be sized
+ * (n_frames * n_values_per_frame).
+ * Since ***values is allocated in this function it is the callers
+ * responsibility to free the memory.
+ * @param n_frames is set to the number of frames in the returned data. This is
+ * needed to properly reach and/or free the data afterwards.
+ * @param n_values_per_frame is set to the number of values per frame in the data.
+ * This is needed to properly reach and/or free the data afterwards.
+ * @param type is set to the data type of the data in the array.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code n_frames != 0 \endcode The pointer to the number of frames
+ * must not be a NULL pointer.
+ * @pre \code n_values_per_frame != 0 \endcode The pointer to the number of
+ * values per frame must not be a NULL pointer.
+ * @pre \code type != 0 \endcode The pointer to the data type must not
+ * be a NULL pointer.
+ * @details This function is obsolete and only retained for compatibility. Use
+ * tng_data_vector_get() instead.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_data_get(tng_trajectory_t tng_data,
+ const int64_t block_id,
+ union data_values ***values,
+ int64_t *n_frames,
+ int64_t *n_values_per_frame,
+ char *type);
+
+/**
+ * @brief Retrieve a vector (1D array) of non-particle data, from the last read frame set.
+ * @param tng_data is a trajectory data container. tng_data->input_file_path specifies
+ * which file to read from. If the file (input_file) is not open it will be
+ * opened.
+ * @param block_id is the id number of the particle data block to read.
+ * @param values is a pointer to a 1-dimensional array (memory unallocated), which
+ * will be filled with data. The length of the array will be (n_frames * n_values_per_frame).
+ * Since **values is allocated in this function it is the callers
+ * responsibility to free the memory.
+ * @param n_frames is set to the number of particles in the returned data. This is
+ * needed to properly reach and/or free the data afterwards.
+ * @param stride_length is set to the stride length of the returned data.
+ * @param n_values_per_frame is set to the number of values per frame in the data.
+ * This is needed to properly reach and/or free the data afterwards.
+ * @param type is set to the data type of the data in the array.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code n_frames != 0 \endcode The pointer to the number of frames
+ * must not be a NULL pointer.
+ * @pre \code stride_length != 0 \endcode The pointer to the stride length
+ * must not be a NULL pointer.
+ * @pre \code n_values_per_frame != 0 \endcode The pointer to the number of
+ * values per frame must not be a NULL pointer.
+ * @pre \code type != 0 \endcode The pointer to the data type must not
+ * be a NULL pointer.
+ * @details This does only work for numerical (int, float, double) data.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_data_vector_get
+ (tng_trajectory_t tng_data,
+ const int64_t block_id,
+ void **values,
+ int64_t *n_frames,
+ int64_t *stride_length,
+ int64_t *n_values_per_frame,
+ char *type);
+
+/**
+ * @brief Read and retrieve non-particle data, in a specific interval. Obsolete!
+ * @param tng_data is a trajectory data container. tng_data->input_file_path specifies
+ * which file to read from. If the file (input_file) is not open it will be
+ * opened.
+ * @param block_id is the id number of the particle data block to read.
+ * @param start_frame_nr is the index number of the first frame to read.
+ * @param end_frame_nr is the index number of the last frame to read.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @param values is a pointer to a 2-dimensional array (memory unallocated), which
+ * will be filled with data. The array will be sized
+ * (n_frames * n_values_per_frame).
+ * Since ***values is allocated in this function it is the callers
+ * responsibility to free the memory.
+ * @param n_values_per_frame is set to the number of values per frame in the data.
+ * This is needed to properly reach and/or free the data afterwards.
+ * @param type is set to the data type of the data in the array.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code start_frame_nr <= end_frame_nr \endcode The first frame must be before
+ * the last frame.
+ * @pre \code n_values_per_frame != 0 \endcode The pointer to the number of
+ * values per frame must not be a NULL pointer.
+ * @pre \code type != 0 \endcode The pointer to the data type must not
+ * be a NULL pointer.
+ * @details This function is obsolete and only retained for compatibility. Use
+ * tng_data_vector_interval_get() instead.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_data_interval_get
+ (tng_trajectory_t tng_data,
+ const int64_t block_id,
+ const int64_t start_frame_nr,
+ const int64_t end_frame_nr,
+ const char hash_mode,
+ union data_values ***values,
+ int64_t *n_values_per_frame,
+ char *type);
+
+/**
+ * @brief Read and retrieve a vector (1D array) of non-particle data,
+ * in a specific interval.
+ * @param tng_data is a trajectory data container. tng_data->input_file_path specifies
+ * which file to read from. If the file (input_file) is not open it will be
+ * opened.
+ * @param block_id is the id number of the particle data block to read.
+ * @param start_frame_nr is the index number of the first frame to read.
+ * @param end_frame_nr is the index number of the last frame to read.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @param values is a pointer to a 1-dimensional array (memory unallocated), which
+ * will be filled with data. The length of the array will be (n_frames * n_values_per_frame).
+ * Since **values is allocated in this function it is the callers
+ * responsibility to free the memory.
+ * @param stride_length is set to the stride length (writing interval) of
+ * the data.
+ * @param n_values_per_frame is set to the number of values per frame in the data.
+ * This is needed to properly reach and/or free the data afterwards.
+ * @param type is set to the data type of the data in the array.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code start_frame_nr <= end_frame_nr \endcode The first frame must be before
+ * the last frame.
+ * @pre \code stride_length != 0 \endcode The pointer to the stride length
+ * must not be a NULL pointer.
+ * @pre \code n_values_per_frame != 0 \endcode The pointer to the number of
+ * values per frame must not be a NULL pointer.
+ * @pre \code type != 0 \endcode The pointer to the data type must not
+ * be a NULL pointer.
+ * @details This does only work for numerical (int, float, double) data.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_data_vector_interval_get
+ (tng_trajectory_t tng_data,
+ const int64_t block_id,
+ const int64_t start_frame_nr,
+ const int64_t end_frame_nr,
+ const char hash_mode,
+ void **values,
+ int64_t *stride_length,
+ int64_t *n_values_per_frame,
+ char *type);
+
+/**
+ * @brief Retrieve particle data, from the last read frame set. Obsolete!
+ * @details The particle dimension of the returned values array is translated
+ * to real particle numbering, i.e. the numbering of the actual molecular
+ * system.
+ * @param tng_data is a trajectory data container. tng_data->input_file_path
+ * specifies which file to read from. If the file (input_file) is not open it
+ * will be opened.
+ * @param block_id is the id number of the particle data block to read.
+ * @param values is a pointer to a 3-dimensional array (memory unallocated), which
+ * will be filled with data. The array will be sized
+ * (n_frames * n_particles * n_values_per_frame).
+ * Since ****values is allocated in this function it is the callers
+ * responsibility to free the memory.
+ * @param n_frames is set to the number of frames in the returned data. This is
+ * needed to properly reach and/or free the data afterwards.
+ * @param n_particles is set to the number of particles in the returned data. This is
+ * needed to properly reach and/or free the data afterwards.
+ * @param n_values_per_frame is set to the number of values per frame in the data.
+ * This is needed to properly reach and/or free the data afterwards.
+ * @param type is set to the data type of the data in the array.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code n_frames != 0 \endcode The pointer to the number of frames
+ * must not be a NULL pointer.
+ * @pre \code n_particles != 0 \endcode The pointer to the number of particles must
+ * not be a NULL pointer.
+ * @pre \code n_values_per_frame != 0 \endcode The pointer to the number of
+ * values per frame must not be a NULL pointer.
+ * @pre \code type != 0 \endcode The pointer to the data type must not
+ * be a NULL pointer.
+ * @details This function is obsolete and only retained for compatibility. Use
+ * tng_particle_data_vector_get() instead.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_particle_data_get
+ (tng_trajectory_t tng_data,
+ const int64_t block_id,
+ union data_values ****values,
+ int64_t *n_frames,
+ int64_t *n_particles,
+ int64_t *n_values_per_frame,
+ char *type);
+
+/**
+ * @brief Retrieve a vector (1D array) of particle data, from the last read frame set.
+ * @details The particle dimension of the returned values array is translated
+ * to real particle numbering, i.e. the numbering of the actual molecular
+ * system.
+ * @param tng_data is a trajectory data container. tng_data->input_file_path
+ * specifies which file to read from. If the file (input_file) is not open it
+ * will be opened.
+ * @param block_id is the id number of the particle data block to read.
+ * @param values is a pointer to a 1-dimensional array (memory unallocated), which
+ * will be filled with data. The length of the array will be
+ * (n_frames * n_particles * n_values_per_frame).
+ * Since **values is allocated in this function it is the callers
+ * responsibility to free the memory.
+ * @param n_frames is set to the number of frames in the returned data. This is
+ * needed to properly reach and/or free the data afterwards.
+ * @param stride_length is set to the stride length of the returned data.
+ * @param n_particles is set to the number of particles in the returned data. This is
+ * needed to properly reach and/or free the data afterwards.
+ * @param n_values_per_frame is set to the number of values per frame in the data.
+ * This is needed to properly reach and/or free the data afterwards.
+ * @param type is set to the data type of the data in the array.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code n_particles != 0 \endcode The pointer to the number of particles must
+ * not be a NULL pointer.
+ * @pre \code stride_length != 0 \endcode The pointer to the stride length
+ * must not be a NULL pointer.
+ * @pre \code n_values_per_frame != 0 \endcode The pointer to the number of
+ * values per frame must not be a NULL pointer.
+ * @pre \code type != 0 \endcode The pointer to the data type must not
+ * be a NULL pointer.
+ * @details This does only work for numerical (int, float, double) data.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_get
+ (tng_trajectory_t tng_data,
+ const int64_t block_id,
+ void **values,
+ int64_t *n_frames,
+ int64_t *stride_length,
+ int64_t *n_particles,
+ int64_t *n_values_per_frame,
+ char *type);
+
+/**
+ * @brief Read and retrieve particle data, in a specific interval. Obsolete!
+ * @details The particle dimension of the returned values array is translated
+ * to real particle numbering, i.e. the numbering of the actual molecular
+ * system.
+ * @param tng_data is a trajectory data container. tng_data->input_file_path specifies
+ * which file to read from. If the file (input_file) is not open it will be
+ * opened.
+ * @param block_id is the id number of the particle data block to read.
+ * @param start_frame_nr is the index number of the first frame to read.
+ * @param end_frame_nr is the index number of the last frame to read.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @param values is a pointer to a 3-dimensional array (memory unallocated), which
+ * will be filled with data. The array will be sized
+ * (n_frames * n_particles * n_values_per_frame).
+ * Since ****values is allocated in this function it is the callers
+ * responsibility to free the memory.
+ * @param n_particles is set to the number of particles in the returned data. This is
+ * needed to properly reach and/or free the data afterwards.
+ * @param n_values_per_frame is set to the number of values per frame in the data.
+ * This is needed to properly reach and/or free the data afterwards.
+ * @param type is set to the data type of the data in the array.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code n_frames != 0 \endcode The pointer to the number of frames
+ * must not be a NULL pointer.
+ * @pre \code start_frame_nr <= end_frame_nr \endcode The first frame must be before
+ * the last frame.
+ * @pre \code n_particles != 0 \endcode The pointer to the number of particles must
+ * not be a NULL pointer.
+ * @pre \code n_values_per_frame != 0 \endcode The pointer to the number of
+ * values per frame must not be a NULL pointer.
+ * @pre \code type != 0 \endcode The pointer to the data type must not
+ * be a NULL pointer.
+ * @details This function is obsolete and only retained for compatibility. Use
+ * tng_particle_data_vector_interval_get() instead.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get
+ (tng_trajectory_t tng_data,
+ const int64_t block_id,
+ const int64_t start_frame_nr,
+ const int64_t end_frame_nr,
+ const char hash_mode,
+ union data_values ****values,
+ int64_t *n_particles,
+ int64_t *n_values_per_frame,
+ char *type);
+
+/**
+ * @brief Read and retrieve a vector (1D array) particle data, in a
+ * specific interval.
+ * @details The particle dimension of the returned values array is translated
+ * to real particle numbering, i.e. the numbering of the actual molecular
+ * system.
+ * @param tng_data is a trajectory data container. tng_data->input_file_path specifies
+ * which file to read from. If the file (input_file) is not open it will be
+ * opened.
+ * @param block_id is the id number of the particle data block to read.
+ * @param start_frame_nr is the index number of the first frame to read.
+ * @param end_frame_nr is the index number of the last frame to read.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @param values is a pointer to a 1-dimensional array (memory unallocated), which
+ * will be filled with data. The length of the array will be
+ * (n_frames * n_particles * n_values_per_frame).
+ * Since **values is allocated in this function it is the callers
+ * responsibility to free the memory.
+ * @param stride_length is set to the stride length (writing interval) of
+ * the data.
+ * @param n_particles is set to the number of particles in the returned data. This is
+ * needed to properly reach and/or free the data afterwards.
+ * @param n_values_per_frame is set to the number of values per frame in the data.
+ * This is needed to properly reach and/or free the data afterwards.
+ * @param type is set to the data type of the data in the array.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code start_frame_nr <= end_frame_nr \endcode The first frame must be before
+ * the last frame.
+ * @pre \code n_particles != 0 \endcode The pointer to the number of particles must
+ * not be a NULL pointer.
+ * @pre \code stride_length != 0 \endcode The pointer to the stride length
+ * must not be a NULL pointer.
+ * @pre \code n_values_per_frame != 0 \endcode The pointer to the number of
+ * values per frame must not be a NULL pointer.
+ * @pre \code type != 0 \endcode The pointer to the data type must not
+ * be a NULL pointer.
+ * @details This does only work for numerical (int, float, double) data.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_interval_get
+ (tng_trajectory_t tng_data,
+ const int64_t block_id,
+ const int64_t start_frame_nr,
+ const int64_t end_frame_nr,
+ const char hash_mode,
+ void **values,
+ int64_t *n_particles,
+ int64_t *stride_length,
+ int64_t *n_values_per_frame,
+ char *type);
+
+/**
+ * @brief Get the stride length of a specific data (particle dependency does not matter)
+ * block, either in the current frame set or of a specific frame.
+ * @param tng_data is the trajectory data container.
+ * @param block_id is the block ID of the data block, of which to retrieve the
+ * stride length of the data.
+ * @param frame is the frame from which to get the stride length. If frame is set to -1
+ * no specific frame will be used, but instead the first frame, starting from the last read
+ * frame set, containing the data block will be used.
+ * @param stride_length is set to the value of the stride length of the data block.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_data_get_stride_length
+ (tng_trajectory_t tng_data,
+ const int64_t block_id,
+ int64_t frame,
+ int64_t *stride_length);
+
+/**
+ * @brief Get the date and time of initial file creation in ISO format (string).
+ * @param tng_data is a trajectory data container.
+ * @param time is a pointer to the string in which the date will be stored. Memory
+ * must be reserved beforehand.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code time != 0 \endcode The pointer to the time must not be a NULL
+ * pointer.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_time_get_str
+ (const tng_trajectory_t tng_data,
+ char *time);
+/** @} */ /* end of group1 */
+
+/** @defgroup group2 High-level API
+ * These functions make it easier to access and output TNG data. They
+ * are recommended unless there is a special reason to use the more
+ * detailed functions available in the low-level API.
+ * @{
+ */
+
+/**
+ * @brief High-level function for opening and initializing a TNG trajectory.
+ * @param filename is a string containing the name of the trajectory to open.
+ * @param mode specifies the file mode of the trajectory. Can be set to 'r',
+ * 'w' or 'a' for reading, writing or appending respectively.
+ * @param tng_data_p is a pointer to the opened trajectory. This will be
+ * allocated by the TNG library. The trajectory must be
+ * closed by the user, whereby memory is freed.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code filename != 0 \endcode The pointer to the filename must not be a
+ * NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_open
+ (const char *filename,
+ const char mode,
+ tng_trajectory_t *tng_data_p);
+
+/**
+ * @brief High-level function for closing a TNG trajectory.
+ * @param tng_data_p is a pointer to the trajectory to close. The memory
+ * will be freed after finalising the writing.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_close
+ (tng_trajectory_t *tng_data_p);
+
+/**
+ * @brief High-level function for getting the time (in seconds) of a frame.
+ * @param tng_data is the trajectory containing the frame.
+ * @param frame_nr is the frame number of which to get the time.
+ * @param time is set to the time (in seconds) of the specified frame.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code time != 0 \endcode The pointer to the time must not be a
+ * NULL pointer.
+ * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if a
+ * minor error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_time_of_frame_get
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ double *time);
+
+/*
+ * @brief High-level function for getting the molecules in the mol system.
+ * @param tng_data is the trajectory containing the mol system.
+ * @param n_mols is set to the number of molecules in the system.
+ * @param molecule_cnt_list will be pointing to the list of counts of each molecule
+ * in the mol system.
+ * @param mols pointing to the list of molecules in the mol system.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code n_mols != 0 \endcode The pointer to the number of molecules must
+ * not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+/*tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecules_get
+ (tng_trajectory_t tng_data,
+ int64_t *n_mols,
+ int64_t **molecule_cnt_list,
+ tng_molecule_t *mols);
+*/
+/*
+ * @brief High-level function for adding a molecule to the mol system.
+ * @param tng_data is the trajectory containing the mol system.
+ * @param name is the name of the molecule to add.
+ * @param cnt is the count of the molecule.
+ * @param mol is set to point to the newly created molecule.
+ * @pre \code name != 0 \endcode The pointer to the name must not be a
+ * NULL pointer.
+ * @pre \code cnt >= 0 \endcode The requested count must be >= 0.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured or TNG_CRITICAL (2) if a major error has occured.
+ */
+/*tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecule_add
+ (tng_trajectory_t tng_data,
+ const char *name,
+ const int64_t cnt,
+ tng_molecule_t *mol);
+*/
+/*
+// tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_get
+// (tng_trajectory_t tng_data,
+// const tng_molecule_t mol,
+// int64_t *n_particles,
+// char ***names,
+// char ***types,
+// char ***res_names,
+// int64_t **res_ids,
+// char ***chain_names,
+// int64_t **chain_ids);
+//
+// tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_set
+// (tng_trajectory_t tng_data,
+// tng_molecule_t mol,
+// const int64_t n_particles,
+// const char **names,
+// const char **types,
+// const char **res_names,
+// const int64_t *res_ids,
+// const char **chain_names,
+// const int64_t *chain_ids);
+*/
+/**
+ * @brief High-level function for reading the positions of all particles
+ * from all frames.
+ * @param tng_data is the trajectory to read from.
+ * @param positions will be set to point at a 1-dimensional array of floats,
+ * which will contain the positions. The data is stored sequentially in order
+ * of frames. For each frame the positions (x, y and z coordinates) are stored.
+ * The variable may point at already allocated memory or be a NULL pointer.
+ * The memory must be freed afterwards.
+ * @param stride_length will be set to the writing interval of the stored data.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code positions != 0 \endcode The pointer to the positions array
+ * must not be a NULL pointer.
+ * @pre \code stride_length != 0 \endcode The pointer to the stride length
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_pos_read
+ (tng_trajectory_t tng_data,
+ float **positions,
+ int64_t *stride_length);
+
+/**
+ * @brief High-level function for reading the velocities of all particles
+ * from all frames.
+ * @param tng_data is the trajectory to read from.
+ * @param velocities will be set to point at a 1-dimensional array of floats,
+ * which will contain the velocities. The data is stored sequentially in order
+ * of frames. For each frame the velocities (in x, y and z) are stored. The
+ * variable may point at already allocated memory or be a NULL pointer.
+ * The memory must be freed afterwards.
+ * @param stride_length will be set to the writing interval of the stored data.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code velocities != 0 \endcode The pointer to the velocities array
+ * must not be a NULL pointer.
+ * @pre \code stride_length != 0 \endcode The pointer to the stride length
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_vel_read
+ (tng_trajectory_t tng_data,
+ float **velocities,
+ int64_t *stride_length);
+
+/**
+ * @brief High-level function for reading the forces of all particles
+ * from all frames.
+ * @param tng_data is the trajectory to read from.
+ * @param forces will be set to point at a 1-dimensional array of floats,
+ * which will contain the forces. The data is stored sequentially in order
+ * of frames. For each frame the forces (in x, y and z) are stored. The
+ * variable may point at already allocated memory or be a NULL pointer.
+ * The memory must be freed afterwards.
+ * @param stride_length will be set to the writing interval of the stored data.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code forces != 0 \endcode The pointer to the forces array
+ * must not be a NULL pointer.
+ * @pre \code stride_length != 0 \endcode The pointer to the stride length
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_force_read
+ (tng_trajectory_t tng_data,
+ float **forces,
+ int64_t *stride_length);
+
+/**
+ * @brief High-level function for reading the box shape from all frames.
+ * @param tng_data is the trajectory to read from.
+ * @param box_shape will be set to point at a 1-dimensional array of floats,
+ * which will contain the box shape. The data is stored sequentially in order
+ * of frames. The variable may point at already allocated memory or be a NULL pointer.
+ * If the box shape is not modified during the trajectory, but as general data,
+ * that will be returned instead.
+ * @param stride_length will be set to the writing interval of the stored data.
+ * @details This function should only be used if number of values used to specify
+ * the box shape is known (by default TNG uses 9 values) since it does not
+ * return the number of values in the array. It is recommended to use
+ * tng_data_vector_interval_get() instead.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code box_shape != 0 \endcode The pointer to the box_shape array
+ * must not be a NULL pointer.
+ * @pre \code stride_length != 0 \endcode The pointer to the stride length
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read
+ (tng_trajectory_t tng_data,
+ float **box_shape,
+ int64_t *stride_length);
+
+/**
+ * @brief High-level function for reading the next frame of particle-dependent
+ * data of a specific type.
+ * @param tng_data is the trajectory to read from.
+ * @param block_id is the ID number of the block containing the data of interest.
+ * @param values will be set to point at a 1-dimensional array containing the
+ * requested data. The variable may point at already allocated memory or be a
+ * NULL pointer. The memory must be freed afterwards.
+ * @param data_type will be pointing to a character indicating the size of the
+ * data of the returned values, e.g. TNG_INT_DATA, TNG_FLOAT_DATA or TNG_DOUBLE_DATA.
+ * @param retrieved_frame_number will be pointing at the frame number of the
+ * returned frame.
+ * @param retrieved_time will be pointing at the time stamp of the returned
+ * frame.
+ * @details If no frame has been read before the first frame of the trajectory
+ * is read.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code values != 0 \endcode The pointer to the values array
+ * must not be a NULL pointer.
+ * @pre \code data_type != 0 \endcode The pointer to the data type of the
+ * returned data must not be a NULL pointer.
+ * @pre \code retrieved_frame_number != 0 \endcode The pointer to the frame
+ * number of the returned data must not be a NULL pointer.
+ * @pre \code retrieved_time != 0 \endcode The pointer to the time of the
+ * returned data must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_particle_data_next_frame_read
+ (tng_trajectory_t tng_data,
+ const int64_t block_id,
+ void **values,
+ char *data_type,
+ int64_t *retrieved_frame_number,
+ double *retrieved_time);
+
+/**
+ * @brief High-level function for reading the next frame of non-particle-dependent
+ * data of a specific type.
+ * @param tng_data is the trajectory to read from.
+ * @param block_id is the ID number of the block containing the data of interest.
+ * @param values will be set to point at a 1-dimensional array containing the
+ * requested data. The variable may point at already allocated memory or be a
+ * NULL pointer. The memory must be freed afterwards.
+ * @param data_type will be pointing to a character indicating the size of the
+ * data of the returned values, e.g. TNG_INT_DATA, TNG_FLOAT_DATA or TNG_DOUBLE_DATA.
+ * @param retrieved_frame_number will be pointing at the frame number of the
+ * returned frame.
+ * @param retrieved_time will be pointing at the time stamp of the returned
+ * frame.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code values != 0 \endcode The pointer to the values array
+ * must not be a NULL pointer.
+ * @pre \code data_type != 0 \endcode The pointer to the data type of the
+ * returned data must not be a NULL pointer.
+ * @pre \code retrieved_frame_number != 0 \endcode The pointer to the frame
+ * number of the returned data must not be a NULL pointer.
+ * @pre \code retrieved_time != 0 \endcode The pointer to the time of the
+ * returned data must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_non_particle_data_next_frame_read
+ (tng_trajectory_t tng_data,
+ const int64_t block_id,
+ void **values,
+ char *data_type,
+ int64_t *retrieved_frame_number,
+ double *retrieved_time);
+
+/**
+ * @brief High-level function for reading the positions of all particles
+ * from a specific range of frames.
+ * @param tng_data is the trajectory to read from.
+ * @param first_frame is the first frame to return position data from.
+ * @param last_frame is the last frame to return position data from.
+ * @param positions will be set to point at a 1-dimensional array of floats,
+ * which will contain the positions. The data is stored sequentially in order
+ * of frames. For each frame the positions (x, y and z coordinates) are stored.
+ * The variable may point at already allocated memory or be a NULL pointer.
+ * The memory must be freed afterwards.
+ * @param stride_length will be set to the writing interval of the stored data.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code start_frame_nr <= end_frame_nr \endcode The first frame must be before
+ * the last frame.
+ * @pre \code positions != 0 \endcode The pointer to the positions array
+ * must not be a NULL pointer.
+ * @pre \code stride_length != 0 \endcode The pointer to the stride length
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_pos_read_range
+ (tng_trajectory_t tng_data,
+ const int64_t first_frame,
+ const int64_t last_frame,
+ float **positions,
+ int64_t *stride_length);
+
+/**
+ * @brief High-level function for reading the velocities of all particles
+ * from a specific range of frames.
+ * @param tng_data is the trajectory to read from.
+ * @param first_frame is the first frame to return position data from.
+ * @param last_frame is the last frame to return position data from.
+ * @param velocities will be set to point at a 1-dimensional array of floats,
+ * which will contain the velocities. The data is stored sequentially in order
+ * of frames. For each frame the velocities (in x, y and z) are stored. The
+ * variable may point at already allocated memory or be a NULL pointer.
+ * The memory must be freed afterwards.
+ * @param stride_length will be set to the writing interval of the stored data.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code start_frame_nr <= end_frame_nr \endcode The first frame must be before
+ * the last frame.
+ * @pre \code velocities != 0 \endcode The pointer to the velocities array
+ * must not be a NULL pointer.
+ * @pre \code stride_length != 0 \endcode The pointer to the stride length
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_vel_read_range
+ (tng_trajectory_t tng_data,
+ const int64_t first_frame,
+ const int64_t last_frame,
+ float **velocities,
+ int64_t *stride_length);
+
+/**
+ * @brief High-level function for reading the forces of all particles
+ * from a specific range of frames.
+ * @param tng_data is the trajectory to read from.
+ * @param first_frame is the first frame to return position data from.
+ * @param last_frame is the last frame to return position data from.
+ * @param forces will be set to point at a 1-dimensional array of floats,
+ * which will contain the forces. The data is stored sequentially in order
+ * of frames. For each frame the forces (in x, y and z) are stored. The
+ * variable may point at already allocated memory or be a NULL pointer.
+ * The memory must be freed afterwards.
+ * @param stride_length will be set to the writing interval of the stored data.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code start_frame_nr <= end_frame_nr \endcode The first frame must be before
+ * the last frame.
+ * @pre \code forces != 0 \endcode The pointer to the forces array
+ * must not be a NULL pointer.
+ * @pre \code stride_length != 0 \endcode The pointer to the stride length
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_force_read_range
+ (tng_trajectory_t tng_data,
+ const int64_t first_frame,
+ const int64_t last_frame,
+ float **forces,
+ int64_t *stride_length);
+
+/**
+ * @brief High-level function for reading the box shape
+ * from a specific range of frames.
+ * @param tng_data is the trajectory to read from.
+ * @param first_frame is the first frame to return position data from.
+ * @param last_frame is the last frame to return position data from.
+ * @param box_shape will be set to point at a 1-dimensional array of floats,
+ * which will contain the box shape. The data is stored sequentially in order
+ * of frames.
+ * If the box shape is not modified during the trajectory, but as general data,
+ * that will be returned instead. The
+ * variable may point at already allocated memory or be a NULL pointer.
+ * The memory must be freed afterwards.
+ * @param stride_length will be set to the writing interval of the stored data.
+ * @details This function should only be used if number of values used to specify
+ * the box shape is known (by default TNG uses 9 values) since it does not
+ * return the number of values in the array. It is recommended to use
+ * tng_data_vector_interval_get() instead.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code start_frame_nr <= end_frame_nr \endcode The first frame must be before
+ * the last frame.
+ * @pre \code box_shape != 0 \endcode The pointer to the box_shape array
+ * must not be a NULL pointer.
+ * @pre \code stride_length != 0 \endcode The pointer to the stride length
+ * must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read_range
+ (tng_trajectory_t tng_data,
+ const int64_t first_frame,
+ const int64_t last_frame,
+ float **box_shape,
+ int64_t *stride_length);
+
+/**
+ * @brief High-level function for setting the writing interval of data blocks.
+ * @param tng_data is the trajectory to use.
+ * @param i is the output interval, i.e. i == 10 means data written every 10th
+ * frame.
+ * @param n_values_per_frame is the number of values to store per frame. If the
+ * data is particle dependent there will be n_values_per_frame stored per
+ * particle each frame.
+ * @param block_id is the ID of the block, of which to set the output interval.
+ * @param block_name is a string that will be used as name of the block. Only
+ * required if the block did not exist, i.e. a new block is created.
+ * @param particle_dependency should be TNG_NON_PARTICLE_BLOCK_DATA (0) if the
+ * data is not related to specific particles (e.g. box shape) or
+ * TNG_PARTICLE_BLOCK_DATA (1) is it is related to specific particles (e.g.
+ * positions). Only required if the block did not exist, i.e. a new block is
+ * created.
+ * @param compression is the compression routine to use when writing the data.
+ * Only required if the block did not exist, i.e. a new block is created.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code i >= 0 \endcode The writing interval must be >= 0.
+ * @details n_values_per_frame, block_name, particle_dependency and
+ * compression are only used if the data block did not exist before calling
+ * this function, in which case it is created.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_set
+ (tng_trajectory_t tng_data,
+ const int64_t i,
+ const int64_t n_values_per_frame,
+ const int64_t block_id,
+ const char *block_name,
+ const char particle_dependency,
+ const char compression);
+
+/**
+ * @brief High-level function for setting the writing interval of data blocks
+ * containing double precision data.
+ * @param tng_data is the trajectory to use.
+ * @param i is the output interval, i.e. i == 10 means data written every 10th
+ * frame.
+ * @param n_values_per_frame is the number of values to store per frame. If the
+ * data is particle dependent there will be n_values_per_frame stored per
+ * particle each frame.
+ * @param block_id is the ID of the block, of which to set the output interval.
+ * @param block_name is a string that will be used as name of the block. Only
+ * required if the block did not exist, i.e. a new block is created.
+ * @param particle_dependency should be TNG_NON_PARTICLE_BLOCK_DATA (0) if the
+ * data is not related to specific particles (e.g. box shape) or
+ * TNG_PARTICLE_BLOCK_DATA (1) is it is related to specific particles (e.g.
+ * positions). Only required if the block did not exist, i.e. a new block is
+ * created.
+ * @param compression is the compression routine to use when writing the data.
+ * Only required if the block did not exist, i.e. a new block is created.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code i >= 0 \endcode The writing interval must be >= 0.
+ * @details n_values_per_frame, block_name, particle_dependency and
+ * compression are only used if the data block did not exist before calling
+ * this function, in which case it is created.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_double_set
+ (tng_trajectory_t tng_data,
+ const int64_t i,
+ const int64_t n_values_per_frame,
+ const int64_t block_id,
+ const char *block_name,
+ const char particle_dependency,
+ const char compression);
+
+/**
+ * @brief High-level function for setting the writing interval of data blocks.
+ * Obsolete! Use tng_util_generic_write_interval_set()
+ * @param tng_data is the trajectory to use.
+ * @param i is the output interval, i.e. i == 10 means data written every 10th
+ * frame.
+ * @param n_values_per_frame is the number of values to store per frame. If the
+ * data is particle dependent there will be n_values_per_frame stored per
+ * particle each frame.
+ * @param block_id is the ID of the block, of which to set the output interval.
+ * @param block_name is a string that will be used as name of the block. Only
+ * required if the block did not exist, i.e. a new block is created.
+ * @param particle_dependency should be TNG_NON_PARTICLE_BLOCK_DATA (0) if the
+ * data is not related to specific particles (e.g. box shape) or
+ * TNG_PARTICLE_BLOCK_DATA (1) is it is related to specific particles (e.g.
+ * positions). Only required if the block did not exist, i.e. a new block is
+ * created.
+ * @param compression is the compression routine to use when writing the data.
+ * Only required if the block did not exist, i.e. a new block is created.
+ * @details n_values_per_frame, block_name, particle_dependency and
+ * compression are only used if the data block did not exist before calling
+ * this function, in which case it is created.
+ * This function is replaced by the more correcly named
+ * tng_util_generic_write_interval_set(), but is kept for compatibility.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_frequency_set
+ (tng_trajectory_t tng_data,
+ const int64_t i,
+ const int64_t n_values_per_frame,
+ const int64_t block_id,
+ const char *block_name,
+ const char particle_dependency,
+ const char compression);
+
+/**
+ * @brief High-level function for setting the writing interval of position
+ * data blocks.
+ * @param tng_data is the trajectory to use.
+ * @param i is the output interval, i.e. i == 10 means data written every 10th
+ * frame.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code i >= 0 \endcode The writing interval must be >= 0.
+ * @details This function uses tng_util_generic_write_interval_set() and will
+ * create a positions data block if none exists.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_set
+ (tng_trajectory_t tng_data,
+ const int64_t i);
+
+/**
+ * @brief High-level function for setting the writing interval of position
+ * data blocks containing double precision data.
+ * @param tng_data is the trajectory to use.
+ * @param i is the output interval, i.e. i == 10 means data written every 10th
+ * frame.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code i >= 0 \endcode The writing interval must be >= 0.
+ * @details This function uses tng_util_generic_write_interval_set() and will
+ * create a positions data block if none exists.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_double_set
+ (tng_trajectory_t tng_data,
+ const int64_t i);
+
+/**
+ * @brief High-level function for setting the writing interval of position
+ * data blocks. Obsolete! Use tng_util_pos_write_interval_set()
+ * @param tng_data is the trajectory to use.
+ * @param i is the output interval, i.e. i == 10 means data written every 10th
+ * frame.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code i >= 0 \endcode The writing interval must be >= 0.
+ * @details This function uses tng_util_generic_write_interval_set() and will
+ * create a positions data block if none exists.
+ * This function is replaced by the more correcly named
+ * tng_util_pos_write_interval_set(), but is kept for compatibility.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_frequency_set
+ (tng_trajectory_t tng_data,
+ const int64_t i);
+
+/**
+ * @brief High-level function for setting the writing interval of velocity
+ * data blocks.
+ * @param tng_data is the trajectory to use.
+ * @param i is the output interval, i.e. i == 10 means data written every 10th
+ * frame.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code i >= 0 \endcode The writing interval must be >= 0.
+ * @details This function uses tng_util_generic_write_interval_set() and will
+ * create a velocities data block if none exists.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_set
+ (tng_trajectory_t tng_data,
+ const int64_t i);
+
+/**
+ * @brief High-level function for setting the writing interval of velocity
+ * data blocks containing double precision data.
+ * @param tng_data is the trajectory to use.
+ * @param i is the output interval, i.e. i == 10 means data written every 10th
+ * frame.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code i >= 0 \endcode The writing interval must be >= 0.
+ * @details This function uses tng_util_generic_write_interval_set() and will
+ * create a velocities data block if none exists.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_double_set
+ (tng_trajectory_t tng_data,
+ const int64_t i);
+
+/**
+ * @brief High-level function for setting the writing interval of velocity
+ * data blocks. Obsolete! Use tng_util_vel_write_interval_set()
+ * @param tng_data is the trajectory to use.
+ * @param i is the output interval, i.e. i == 10 means data written every 10th
+ * frame.
+ * @details This function uses tng_util_generic_write_interval_set() and will
+ * create a velocities data block if none exists.
+ * This function is replaced by the more correcly named
+ * tng_util_vel_write_interval_set(), but is kept for compatibility.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_frequency_set
+ (tng_trajectory_t tng_data,
+ const int64_t i);
+
+/**
+ * @brief High-level function for setting the writing interval of force
+ * data blocks.
+ * @param tng_data is the trajectory to use.
+ * @param i is the output interval, i.e. i == 10 means data written every 10th
+ * frame.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code i >= 0 \endcode The writing interval must be >= 0.
+ * @details This function uses tng_util_generic_write_interval_set() and will
+ * create a forces data block if none exists.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_set
+ (tng_trajectory_t tng_data,
+ const int64_t i);
+
+/**
+ * @brief High-level function for setting the writing interval of force
+ * data blocks containing double precision data.
+ * @param tng_data is the trajectory to use.
+ * @param i is the output interval, i.e. i == 10 means data written every 10th
+ * frame.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code i >= 0 \endcode The writing interval must be >= 0.
+ * @details This function uses tng_util_generic_write_interval_set() and will
+ * create a forces data block if none exists.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_double_set
+ (tng_trajectory_t tng_data,
+ const int64_t i);
+
+/**
+ * @brief High-level function for setting the writing interval of force
+ * data blocks. Obsolete! Use tng_util_force_write_interval_set()
+ * @param tng_data is the trajectory to use.
+ * @param i is the output interval, i.e. i == 10 means data written every 10th
+ * frame.
+ * @details This function uses tng_util_generic_write_interval_set() and will
+ * create a forces data block if none exists.
+ * This function is replaced by the more correcly named
+ * tng_util_force_write_interval_set(), but is kept for compatibility.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_force_write_frequency_set
+ (tng_trajectory_t tng_data,
+ const int64_t i);
+
+/**
+ * @brief High-level function for setting the writing interval of box shape
+ * data blocks.
+ * @param tng_data is the trajectory to use.
+ * @param i is the output interval, i.e. i == 10 means data written every 10th
+ * frame.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code i >= 0 \endcode The writing interval must be >= 0.
+ * @details This function uses tng_util_generic_write_interval_set() and will
+ * create a box shape data block if none exists.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_set
+ (tng_trajectory_t tng_data,
+ const int64_t i);
+
+/**
+ * @brief High-level function for setting the writing interval of box shape
+ * data blocks containing double precision data.
+ * @param tng_data is the trajectory to use.
+ * @param i is the output interval, i.e. i == 10 means data written every 10th
+ * frame.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code i >= 0 \endcode The writing interval must be >= 0.
+ * @details This function uses tng_util_generic_write_interval_set() and will
+ * create a box shape data block if none exists.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_double_set
+ (tng_trajectory_t tng_data,
+ const int64_t i);
+
+/**
+ * @brief High-level function for setting the writing interval of velocity
+ * data blocks. Obsolete! Use tng_util_box_shape_write_interval_set()
+ * @param tng_data is the trajectory to use.
+ * @param i is the output interval, i.e. i == 10 means data written every 10th
+ * frame.
+ * @details This function uses tng_util_generic_write_interval_set() and will
+ * create a box shape data block if none exists.
+ * This function is replaced by the more correcly named
+ * tng_util_box_shape_write_interval_set(), but is kept for compatibility.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_frequency_set
+ (tng_trajectory_t tng_data,
+ const int64_t i);
+
+/**
+ * @brief High-level function for writing data of one frame to a data block.
+ * @param tng_data is the trajectory to use.
+ * @param frame_nr is the frame number of the data.
+ * @param values is a 1D array of data to add. The array should be of length
+ * n_particles * n_values_per_frame if writing particle related data, otherwise
+ * it should be n_values_per_frame.
+ * @param n_values_per_frame is the number of values to store per frame. If the
+ * data is particle dependent there will be n_values_per_frame stored per
+ * particle each frame.
+ * @param block_id is the ID of the block, of which to set the output interval.
+ * @param block_name is a string that will be used as name of the block. Only
+ * required if the block did not exist, i.e. a new block is created.
+ * @param particle_dependency should be TNG_NON_PARTICLE_BLOCK_DATA (0) if the
+ * data is not related to specific particles (e.g. box shape) or
+ * TNG_PARTICLE_BLOCK_DATA (1) is it is related to specific particles (e.g.
+ * positions). Only required if the block did not exist, i.e. a new block is
+ * created.
+ * @param compression is the compression routine to use when writing the data.
+ * Only required if the block did not exist, i.e. a new block is created.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0.
+ * @pre \code values != 0 \endcode The pointer to the values array must not
+ * be a NULL pointer.
+ * @details n_values_per_frame, block_name, particle_dependency and
+ * compression are only used if the data block did not exist before calling
+ * this function, in which case it is created.
+ * N.b. Data is written a whole block at a time. The data is not
+ * actually written to disk until the frame set is finished or the TNG
+ * trajectory is closed.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_generic_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const float *values,
+ const int64_t n_values_per_frame,
+ const int64_t block_id,
+ const char *block_name,
+ const char particle_dependency,
+ const char compression);
+
+/**
+ * @brief High-level function for writing data of one frame to a double precision
+ * data block.
+ * @param tng_data is the trajectory to use.
+ * @param frame_nr is the frame number of the data.
+ * @param values is a 1D array of data to add. The array should be of length
+ * n_particles * n_values_per_frame if writing particle related data, otherwise
+ * it should be n_values_per_frame.
+ * @param n_values_per_frame is the number of values to store per frame. If the
+ * data is particle dependent there will be n_values_per_frame stored per
+ * particle each frame.
+ * @param block_id is the ID of the block, of which to set the output interval.
+ * @param block_name is a string that will be used as name of the block. Only
+ * required if the block did not exist, i.e. a new block is created.
+ * @param particle_dependency should be TNG_NON_PARTICLE_BLOCK_DATA (0) if the
+ * data is not related to specific particles (e.g. box shape) or
+ * TNG_PARTICLE_BLOCK_DATA (1) is it is related to specific particles (e.g.
+ * positions). Only required if the block did not exist, i.e. a new block is
+ * created.
+ * @param compression is the compression routine to use when writing the data.
+ * Only required if the block did not exist, i.e. a new block is created.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0.
+ * @pre \code values != 0 \endcode The pointer to the values array must not
+ * be a NULL pointer.
+ * @details n_values_per_frame, block_name, particle_dependency and
+ * compression are only used if the data block did not exist before calling
+ * this function, in which case it is created.
+ * N.b. Data is written a whole block at a time. The data is not
+ * actually written to disk until the frame set is finished or the TNG
+ * trajectory is closed.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_generic_double_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double *values,
+ const int64_t n_values_per_frame,
+ const int64_t block_id,
+ const char *block_name,
+ const char particle_dependency,
+ const char compression);
+
+/**
+ * @brief High-level function for adding data to positions data blocks.
+ * @param tng_data is the trajectory to use.
+ * @param frame_nr is the frame number of the data.
+ * @param positions is a 1D array of data to add. The array should be of length
+ * n_particles * 3.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0.
+ * @pre \code positions != 0 \endcode The pointer to the positions array must not
+ * be a NULL pointer.
+ * @details This function uses tng_util_generic_write() and will
+ * create a positions data block if none exists. Positions are stored as three
+ * values per frame and compressed using TNG compression.
+ * N.b. Since compressed data is written a whole block at a time the data is not
+ * actually written to disk until the frame set is finished or the TNG
+ * trajectory is closed.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_pos_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const float *positions);
+
+/**
+ * @brief High-level function for adding data to positions data blocks at double
+ * precision.
+ * @param tng_data is the trajectory to use.
+ * @param frame_nr is the frame number of the data.
+ * @param positions is a 1D array of data to add. The array should be of length
+ * n_particles * 3.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0.
+ * @pre \code positions != 0 \endcode The pointer to the positions array must not
+ * be a NULL pointer.
+ * @details This function uses tng_util_generic_write() and will
+ * create a positions data block if none exists. Positions are stored as three
+ * values per frame and compressed using TNG compression.
+ * N.b. Since compressed data is written a whole block at a time the data is not
+ * actually written to disk until the frame set is finished or the TNG
+ * trajectory is closed.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_pos_double_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double *positions);
+
+/**
+ * @brief High-level function for adding data to velocities data blocks.
+ * @param tng_data is the trajectory to use.
+ * @param frame_nr is the frame number of the data.
+ * @param velocities is a 1D array of data to add. The array should be of length
+ * n_particles * 3.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0.
+ * @pre \code velocities != 0 \endcode The pointer to the velocities array must not
+ * be a NULL pointer.
+ * @details This function uses tng_util_generic_write() and will
+ * create a velocities data block if none exists. Velocities are stored as three
+ * values per frame and compressed using TNG compression.
+ * N.b. Since compressed data is written a whole block at a time the data is not
+ * actually written to disk until the frame set is finished or the TNG
+ * trajectory is closed.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_vel_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const float *velocities);
+
+/**
+ * @brief High-level function for adding data to velocities data blocks at double
+ * precision.
+ * @param tng_data is the trajectory to use.
+ * @param frame_nr is the frame number of the data.
+ * @param velocities is a 1D array of data to add. The array should be of length
+ * n_particles * 3.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0.
+ * @pre \code velocities != 0 \endcode The pointer to the velocities array must not
+ * be a NULL pointer.
+ * @details This function uses tng_util_generic_write() and will
+ * create a velocities data block if none exists. Velocities are stored as three
+ * values per frame and compressed using TNG compression.
+ * N.b. Since compressed data is written a whole block at a time the data is not
+ * actually written to disk until the frame set is finished or the TNG
+ * trajectory is closed.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_vel_double_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double *velocities);
+
+/**
+ * @brief High-level function for adding data to forces data blocks.
+ * @param tng_data is the trajectory to use.
+ * @param frame_nr is the frame number of the data.
+ * @param forces is a 1D array of data to add. The array should be of length
+ * n_particles * 3.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0.
+ * @pre \code forces != 0 \endcode The pointer to the forces array must not
+ * be a NULL pointer.
+ * @details This function uses tng_util_generic_write() and will
+ * create a forces data block if none exists. Forces are stored as three
+ * values per frame and compressed using gzip compression.
+ * N.b. Since compressed data is written a whole block at a time the data is not
+ * actually written to disk until the frame set is finished or the TNG
+ * trajectory is closed.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_force_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const float *forces);
+
+/**
+ * @brief High-level function for adding data to forces data blocks at double
+ * precision.
+ * @param tng_data is the trajectory to use.
+ * @param frame_nr is the frame number of the data.
+ * @param forces is a 1D array of data to add. The array should be of length
+ * n_particles * 3.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0.
+ * @pre \code forces != 0 \endcode The pointer to the forces array must not
+ * be a NULL pointer.
+ * @details This function uses tng_util_generic_write() and will
+ * create a forces data block if none exists. Forces are stored as three
+ * values per frame and compressed using gzip compression.
+ * N.b. Since compressed data is written a whole block at a time the data is not
+ * actually written to disk until the frame set is finished or the TNG
+ * trajectory is closed.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_force_double_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double *forces);
+
+/**
+ * @brief High-level function for adding data to box shape data blocks.
+ * @param tng_data is the trajectory to use.
+ * @param frame_nr is the frame number of the data.
+ * @param box_shape is a 1D array of data to add. The array should be of length 9.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0.
+ * @pre \code box_shape != 0 \endcode The pointer to the box_shape array must not
+ * be a NULL pointer.
+ * @details This function uses tng_util_generic_write() and will
+ * create a box shape data block if none exists. Box shapes are stored as 9
+ * values per frame and compressed using TNG compression.
+ * N.b. Since compressed data is written a whole block at a time the data is not
+ * actually written to disk until the frame set is finished or the TNG
+ * trajectory is closed.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const float *box_shape);
+
+/**
+ * @brief High-level function for adding data to box shape data blocks at double
+ * precision.
+ * @param tng_data is the trajectory to use.
+ * @param frame_nr is the frame number of the data.
+ * @param box_shape is a 1D array of data to add. The array should be of length 9.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0.
+ * @pre \code box_shape != 0 \endcode The pointer to the box_shape array must not
+ * be a NULL pointer.
+ * @details This function uses tng_util_generic_write() and will
+ * create a box shape data block if none exists. Box shapes are stored as 9
+ * values per frame and compressed using TNG compression.
+ * N.b. Since compressed data is written a whole block at a time the data is not
+ * actually written to disk until the frame set is finished or the TNG
+ * trajectory is closed.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_double_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double *box_shape);
+
+/**
+ * @brief High-level function for writing data of one frame to a data block.
+ * If the frame is at the beginning of a frame set the time stamp of the frame
+ * set is set.
+ * @param tng_data is the trajectory to use.
+ * @param frame_nr is the frame number of the data.
+ * @param time is the time stamp of the frame (in seconds).
+ * @param values is a 1D array of data to add. The array should be of length
+ * n_particles * n_values_per_frame if writing particle related data, otherwise
+ * it should be n_values_per_frame.
+ * @param n_values_per_frame is the number of values to store per frame. If the
+ * data is particle dependent there will be n_values_per_frame stored per
+ * particle each frame.
+ * @param block_id is the ID of the block, of which to set the output interval.
+ * @param block_name is a string that will be used as name of the block. Only
+ * required if the block did not exist, i.e. a new block is created.
+ * @param particle_dependency should be TNG_NON_PARTICLE_BLOCK_DATA (0) if the
+ * data is not related to specific particles (e.g. box shape) or
+ * TNG_PARTICLE_BLOCK_DATA (1) is it is related to specific particles (e.g.
+ * positions). Only required if the block did not exist, i.e. a new block is
+ * created.
+ * @param compression is the compression routine to use when writing the data.
+ * Only required if the block did not exist, i.e. a new block is created.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0.
+ * @pre \code time >= 0 \endcode The time stamp must be >= 0.
+ * @pre \code values != 0 \endcode The pointer to the values array must not
+ * be a NULL pointer.
+ * @details n_values_per_frame, block_name, particle_dependency and
+ * compression are only used if the data block did not exist before calling
+ * this function, in which case it is created.
+ * N.b. Data is written a whole block at a time. The data is not
+ * actually written to disk until the frame set is finished or the TNG
+ * trajectory is closed.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double time,
+ const float *values,
+ const int64_t n_values_per_frame,
+ const int64_t block_id,
+ const char *block_name,
+ const char particle_dependency,
+ const char compression);
+
+/**
+ * @brief High-level function for writing data of one frame to a double precision
+ * data block. If the frame is at the beginning of a frame set the time stamp of
+ * the frame set is set.
+ * @param tng_data is the trajectory to use.
+ * @param frame_nr is the frame number of the data.
+ * @param time is the time stamp of the frame (in seconds).
+ * @param values is a 1D array of data to add. The array should be of length
+ * n_particles * n_values_per_frame if writing particle related data, otherwise
+ * it should be n_values_per_frame.
+ * @param n_values_per_frame is the number of values to store per frame. If the
+ * data is particle dependent there will be n_values_per_frame stored per
+ * particle each frame.
+ * @param block_id is the ID of the block, of which to set the output interval.
+ * @param block_name is a string that will be used as name of the block. Only
+ * required if the block did not exist, i.e. a new block is created.
+ * @param particle_dependency should be TNG_NON_PARTICLE_BLOCK_DATA (0) if the
+ * data is not related to specific particles (e.g. box shape) or
+ * TNG_PARTICLE_BLOCK_DATA (1) is it is related to specific particles (e.g.
+ * positions). Only required if the block did not exist, i.e. a new block is
+ * created.
+ * @param compression is the compression routine to use when writing the data.
+ * Only required if the block did not exist, i.e. a new block is created.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0.
+ * @pre \code time >= 0 \endcode The time stamp must be >= 0.
+ * @pre \code values != 0 \endcode The pointer to the values array must not
+ * be a NULL pointer.
+ * @details n_values_per_frame, block_name, particle_dependency and
+ * compression are only used if the data block did not exist before calling
+ * this function, in which case it is created.
+ * N.b. Data is written a whole block at a time. The data is not
+ * actually written to disk until the frame set is finished or the TNG
+ * trajectory is closed.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_double_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double time,
+ const double *values,
+ const int64_t n_values_per_frame,
+ const int64_t block_id,
+ const char *block_name,
+ const char particle_dependency,
+ const char compression);
+
+/**
+ * @brief High-level function for adding data to positions data blocks. If the
+ * frame is at the beginning of a frame set the time stamp of the frame set
+ * is set.
+ * @param tng_data is the trajectory to use.
+ * @param frame_nr is the frame number of the data.
+ * @param time is the time stamp of the frame (in seconds).
+ * @param positions is a 1D array of data to add. The array should be of length
+ * n_particles * 3.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0.
+ * @pre \code time >= 0 \endcode The time stamp must be >= 0.
+ * @pre \code positions != 0 \endcode The pointer to the positions array must not
+ * be a NULL pointer.
+ * @details This function uses tng_util_generic_with_time_write() and will
+ * create a positions data block if none exists. Positions are stored as three
+ * values per frame and compressed using TNG compression.
+ * N.b. Since compressed data is written a whole block at a time the data is not
+ * actually written to disk until the frame set is finished or the TNG
+ * trajectory is closed.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double time,
+ const float *positions);
+
+/**
+ * @brief High-level function for adding data to positions data blocks at double
+ * precision. If the frame is at the beginning of a frame set the time stamp of
+ * the frame set is set.
+ * @param tng_data is the trajectory to use.
+ * @param frame_nr is the frame number of the data.
+ * @param time is the time stamp of the frame (in seconds).
+ * @param positions is a 1D array of data to add. The array should be of length
+ * n_particles * 3.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0.
+ * @pre \code time >= 0 \endcode The time stamp must be >= 0.
+ * @pre \code positions != 0 \endcode The pointer to the positions array must not
+ * be a NULL pointer.
+ * @details This function uses tng_util_generic_with_time_double_write() and will
+ * create a positions data block if none exists. Positions are stored as three
+ * values per frame and compressed using TNG compression.
+ * N.b. Since compressed data is written a whole block at a time the data is not
+ * actually written to disk until the frame set is finished or the TNG
+ * trajectory is closed.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_double_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double time,
+ const double *positions);
+
+/**
+ * @brief High-level function for adding data to velocities data blocks. If the
+ * frame is at the beginning of a frame set the time stamp of the frame set
+ * is set.
+ * @param tng_data is the trajectory to use.
+ * @param frame_nr is the frame number of the data.
+ * @param time is the time stamp of the frame (in seconds).
+ * @param velocities is a 1D array of data to add. The array should be of length
+ * n_particles * 3.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0.
+ * @pre \code time >= 0 \endcode The time stamp must be >= 0.
+ * @pre \code velocities != 0 \endcode The pointer to the velocities array must not
+ * be a NULL pointer.
+ * @details This function uses tng_util_generic_with_time_write() and will
+ * create a velocities data block if none exists. Velocities are stored as three
+ * values per frame and compressed using TNG compression.
+ * N.b. Since compressed data is written a whole block at a time the data is not
+ * actually written to disk until the frame set is finished or the TNG
+ * trajectory is closed.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double time,
+ const float *velocities);
+
+/**
+ * @brief High-level function for adding data to velocities data blocks at
+ * double precision. If the frame is at the beginning of a frame set the
+ * time stamp of the frame set is set.
+ * @param tng_data is the trajectory to use.
+ * @param frame_nr is the frame number of the data.
+ * @param time is the time stamp of the frame (in seconds).
+ * @param velocities is a 1D array of data to add. The array should be of length
+ * n_particles * 3.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0.
+ * @pre \code time >= 0 \endcode The time stamp must be >= 0.
+ * @pre \code velocities != 0 \endcode The pointer to the velocities array must not
+ * be a NULL pointer.
+ * @details This function uses tng_util_generic_with_time_double_write() and will
+ * create a velocities data block if none exists. Velocities are stored as three
+ * values per frame and compressed using TNG compression.
+ * N.b. Since compressed data is written a whole block at a time the data is not
+ * actually written to disk until the frame set is finished or the TNG
+ * trajectory is closed.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_double_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double time,
+ const double *velocities);
+
+/**
+ * @brief High-level function for adding data to forces data blocks. If the
+ * frame is at the beginning of a frame set the time stamp of the frame set
+ * is set.
+ * @param tng_data is the trajectory to use.
+ * @param frame_nr is the frame number of the data.
+ * @param time is the time stamp of the frame (in seconds).
+ * @param forces is a 1D array of data to add. The array should be of length
+ * n_particles * 3.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0.
+ * @pre \code time >= 0 \endcode The time stamp must be >= 0.
+ * @pre \code forces != 0 \endcode The pointer to the forces array must not
+ * be a NULL pointer.
+ * @details This function uses tng_util_generic_with_time_write() and will
+ * create a forces data block if none exists. Forces are stored as three
+ * values per frame and compressed using gzip compression.
+ * N.b. Since compressed data is written a whole block at a time the data is not
+ * actually written to disk until the frame set is finished or the TNG
+ * trajectory is closed.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double time,
+ const float *forces);
+
+/**
+ * @brief High-level function for adding data to forces data blocks at
+ * double precision. If the frame is at the beginning of a frame set
+ * the time stamp of the frame set is set.
+ * @param tng_data is the trajectory to use.
+ * @param frame_nr is the frame number of the data.
+ * @param time is the time stamp of the frame (in seconds).
+ * @param forces is a 1D array of data to add. The array should be of length
+ * n_particles * 3.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0.
+ * @pre \code time >= 0 \endcode The time stamp must be >= 0.
+ * @pre \code forces != 0 \endcode The pointer to the forces array must not
+ * be a NULL pointer.
+ * @details This function uses tng_util_generic_with_time_double_write() and will
+ * create a forces data block if none exists. Forces are stored as three
+ * values per frame and compressed using gzip compression.
+ * N.b. Since compressed data is written a whole block at a time the data is not
+ * actually written to disk until the frame set is finished or the TNG
+ * trajectory is closed.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_double_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double time,
+ const double *forces);
+
+/**
+ * @brief High-level function for adding data to box shape data blocks. If the
+ * frame is at the beginning of a frame set the time stamp of the frame set
+ * is set.
+ * @param tng_data is the trajectory to use.
+ * @param frame_nr is the frame number of the data.
+ * @param time is the time stamp of the frame (in seconds).
+ * @param box_shape is a 1D array of data to add. The array should be of length 9.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0.
+ * @pre \code time >= 0 \endcode The time stamp must be >= 0.
+ * @pre \code box_shape != 0 \endcode The pointer to the box_shape array must not
+ * be a NULL pointer.
+ * @details This function uses tng_util_generic_with_time_write() and will
+ * create a box shape data block if none exists. Box shapes are stored as 9
+ * values per frame and compressed using TNG compression.
+ * N.b. Since compressed data is written a whole block at a time the data is not
+ * actually written to disk until the frame set is finished or the TNG
+ * trajectory is closed.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double time,
+ const float *box_shape);
+
+/**
+ * @brief High-level function for adding data to box shape data blocks at
+ * double precision. If the frame is at the beginning of a frame set the
+ * time stamp of the frame set is set.
+ * @param tng_data is the trajectory to use.
+ * @param frame_nr is the frame number of the data.
+ * @param time is the time stamp of the frame (in seconds).
+ * @param box_shape is a 1D array of data to add. The array should be of length 9.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0.
+ * @pre \code time >= 0 \endcode The time stamp must be >= 0.
+ * @pre \code box_shape != 0 \endcode The pointer to the box_shape array must not
+ * be a NULL pointer.
+ * @details This function uses tng_util_generic_with_time_double_write() and will
+ * create a box shape data block if none exists. Box shapes are stored as 9
+ * values per frame and compressed using TNG compression.
+ * N.b. Since compressed data is written a whole block at a time the data is not
+ * actually written to disk until the frame set is finished or the TNG
+ * trajectory is closed.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_double_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double time,
+ const double *box_shape);
+
+/**
+ * @brief High-level function for getting the compression method and
+ * multiplication factor of the last read frame of a specific data block.
+ * @param tng_data is the trajectory to use.
+ * @param block_id is the ID number of the block containing the data of
+ * interest.
+ * @param codec_id will be set to the value of the codec_id of the
+ * compression of the data block. See tng_compression for more details.
+ * @param factor will be set to the multiplication factor applied to
+ * the values before compression, in order to get integers from them.
+ * factor is 1/precision.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code codec_id != 0 \endcode The pointer to the returned codec id
+ * must not be a NULL pointer.
+ * @pre \code factor != 0 \endcode The pointer to the returned multiplication
+ * factor must not be a NULL pointer.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_frame_current_compression_get
+ (tng_trajectory_t tng_data,
+ const int64_t block_id,
+ char *codec_id,
+ float *factor);
+
+/** @brief High-level function for determining the next frame with data and what
+ * data blocks have data for that frame. The search can be limited to certain
+ * data blocks.
+ * @param tng_data is the trajectory to use.
+ * @param current_frame is the frame that was last read, from where to start
+ * looking for data.
+ * @param n_requested_data_block_ids is the number of data blocks listed in
+ * requested_data_block_ids. If this is 0 all data blocks will be taken into
+ * account.
+ * @param requested_data_block_ids is an array of data blocks to look for.
+ * @param next_frame will be set to the next frame with data.
+ * @param n_data_blocks_in_next_frame is set to the number of data blocks with
+ * data for next_frame.
+ * @param data_block_ids_in_next_frame is set to an array (of length
+ * n_data_blocks_in_next_frame) that lists the data block IDs with data for
+ * next_frame. It must be pointing at NULL or previously allocated memory.
+ * Memory for the array is allocated by this function.
+ * The memory must be freed by the client afterwards or
+ * there will be a memory leak.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code next_frame != 0 \endcode The pointer to the next frame must not
+ * be NULL.
+ * @pre \code n_data_blocks_in_next_frame != 0 \endcode The pointer to
+ * n_data_blocks_in_next_frame must not be NULL.
+ * @pre \code *data_block_ids_in_next_frame != 0 \endcode The pointer to the
+ * list of data block IDs must not be NULL.
+ * @pre \code n_requested_data_block_ids == 0 || requested_data_block_ids != 0 \endcode
+ * If the number of requested data blocks != 0 then the array of data block IDs must not be NULL.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_next_frame_present_data_blocks_find
+ (tng_trajectory_t tng_data,
+ int64_t current_frame,
+ const int64_t n_requested_data_block_ids,
+ const int64_t *requested_data_block_ids,
+ int64_t *next_frame,
+ int64_t *n_data_blocks_in_next_frame,
+ int64_t **data_block_ids_in_next_frame);
+
+/* @brief High-level function for getting all data block ids and their names
+ * and stride lengths.
+ * @param tng_data is the trajectory to use.
+ * @param n_data_blocks is set to the number of data blocks in the trajectory.
+ * @param data_block_ids is set to an array (of length
+ * n_data_blocks) that lists the data block IDs in the trajectory.
+ * It must be pointing at NULL or previously allocated memory.
+ * Memory for the array is allocated by this function.
+ * The memory must be freed by the client afterwards or
+ * there will be a memory leak.
+ * @param data_block_names is set to an array (of length
+ * n_data_blocks) that contains the names of the data blocks.
+ * It must be pointing at NULL or previously allocated memory.
+ * Memory for the array is allocated by this function.
+ * The memory must be freed by the client afterwards or
+ * there will be a memory leak.
+ * @param stride_lengths is set to an array (of length
+ * n_data_blocks) that lists the stride lengths of the data blocks.
+ * It must be pointing at NULL or previously allocated memory.
+ * Memory for the array is allocated by this function.
+ * The memory must be freed by the client afterwards or
+ * there will be a memory leak.
+ * @param n_values_per_frame is set to an array (of length
+ * n_data_blocks) that lists the number of values per frame of the data blocks.
+ * It must be pointing at NULL or previously allocated memory.
+ * Memory for the array is allocated by this function.
+ * The memory must be freed by the client afterwards or
+ * there will be a memory leak.
+ * @param block_types is set to an array (of length
+ * n_data_blocks) that lists the block types of the data blocks.
+ * It must be pointing at NULL or previously allocated memory.
+ * Memory for the array is allocated by this function.
+ * The memory must be freed by the client afterwards or
+ * there will be a memory leak.
+ * @param dependencies is set to an array (of length
+ * n_data_blocks) that lists the dependencies of the data blocks.
+ * It must be pointing at NULL or previously allocated memory.
+ * Memory for the array is allocated by this function.
+ * The memory must be freed by the client afterwards or
+ * there will be a memory leak.
+ * @param compressions is set to an array (of length
+ * n_data_blocks) that lists the compressions of the data blocks.
+ * It must be pointing at NULL or previously allocated memory.
+ * Memory for the array is allocated by this function.
+ * The memory must be freed by the client afterwards or
+ * there will be a memory leak.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code n_data_blocks != 0 \endcode The pointer to
+ * n_data_blocks must not be NULL.
+ * @pre \code data_block_ids != 0 \endcode The pointer to the
+ * list of data block IDs must not be NULL.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured or TNG_CRITICAL (2) if a major error
+ * has occured.
+ */
+/*
+tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_all_data_block_types_get
+ (tng_trajectory_t tng_data,
+ int64_t *n_data_blocks,
+ int64_t **data_block_ids,
+ char ***data_block_names,
+ int64_t **stride_lengths,
+ int64_t **n_values_per_frame,
+ char **block_types,
+ char **dependencies,
+ char **compressions);
+*/
+
+/** @brief Finds the frame set of the specified frame in order to prepare for writing
+ * after it.
+ * @param tng_data is the trajectory to use.
+ * @param prev_frame is the frame after which to start appending.
+ * @pre \code tng_data != 0 \endcode The trajectory container (tng_data)
+ * must be initialised before using it.
+ * @pre \code prev_frame >= 0 \endcode The previous frame must not be negative.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occured (such as not finding the requested frame) or TNG_CRITICAL (2)
+ * if a major error has occured.
+ */
+tng_function_status DECLSPECDLLEXPORT tng_util_prepare_append_after_frame
+ (tng_trajectory_t tng_data,
+ const int64_t prev_frame);
+
+/** @} */ /* end of group2 */
+
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+#endif /* TNG_IO_H */
--- /dev/null
+/* This code is part of the tng binary trajectory format.
+ *
+ * VERSION 1.4
+ *
+ * Written by Anders Gärdenäs
+ * Copyright (c) 2012-2013, The GROMACS development team.
+ * Check out http://www.gromacs.org for more information.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+#ifndef TNG_IO_HPP
+#define TNG_IO_HPP
+
+#include "tng_io.h"
+
+namespace Tng
+{
+class Trajectory;
+class Atom;
+class Residue;
+class Chain;
+class Molecule;
+typedef class Molecule * Molecule_t;
+
+
+class Trajectory {
+private:
+ tng_trajectory_t traj;
+ tng_function_status status;
+public:
+ /**
+ * @brief Add a molecule to the trajectory.
+ * @param name is a pointer to the string containing the name of the new molecule.
+ * @param molecule is a pointer to the newly created molecule.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+
+ tng_function_status addMolecule(const char *, Molecule_t);
+ tng_function_status addMoleculeWithId(const char *, int64_t id, Molecule_t);
+ tng_function_status findMolecule(const char *name, int64_t id, Molecule_t molecule);
+ friend class Atom;
+ friend class Residue;
+ friend class Chain;
+ friend class Molecule;
+
+ //! Normal constructor
+ Trajectory()
+ { status = tng_trajectory_init(&traj); }
+
+ //! Copy constructor
+ Trajectory(Trajectory * src)
+ { status = tng_trajectory_init_from_src(traj,&src->traj); }
+
+ //! Detructor
+ ~Trajectory()
+ { status = tng_trajectory_destroy(&traj); }
+
+ //! Status
+ tng_function_status getStatus()
+ { return status; }
+
+
+ /**
+ * @brief Get the name of the input file.
+ * @param file_name the string to fill with the name of the input file,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for file_name. This includes \0 terminating character.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+ tng_function_status getInputFile (char *file_name, const int max_len)
+ {
+ return status = tng_input_file_get(traj, file_name, max_len);
+ }
+
+ /**
+ * @brief Set the name of the input file.
+ * @param file_name the name of the input file.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+ tng_function_status setInputFile(const char *file_name)
+ {
+ return status = tng_input_file_set(traj, file_name);
+ }
+
+
+ /**
+ * @brief Get the name of the output file.
+ * @param file_name the string to fill with the name of the output file,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for file_name. This includes \0 terminating character.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+ tng_function_status getOutputFile(char *file_name, const int max_len)
+ {
+ return status = tng_output_file_get(traj, file_name, max_len);
+ }
+
+
+ /**
+ * @brief Set the name of the output file.
+ * @param file_name the name of the output file.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+ tng_function_status setOutputFile(const char *file_name)
+ {
+ return status = tng_output_file_set(traj, file_name);
+ }
+
+ /**
+ * @brief Get the endianness of the output file.
+ * current output file.
+ * @param endianness will contain the enumeration of the endianness.
+ * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the endianness
+ * could not be retrieved.
+ */
+ tng_function_status getOutputFileEndianness
+ (tng_file_endianness *endianness)
+ {
+ return status = tng_output_file_endianness_get(traj, endianness);
+ }
+
+ /**
+ * @brief Set the endianness of the output file.
+ * @param endianness the enumeration of the endianness, can be either
+ * TNG_BIG_ENDIAN (0) or TNG_LITTLE_ENDIAN (1).
+ * @details The endianness cannot be changed after file output has started.
+ * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the endianness
+ * could not be set.
+ */
+ tng_function_status setOutputFileEndianness
+ (const tng_file_endianness endianness)
+ {
+ return status = tng_output_file_endianness_set(traj, endianness);
+ }
+
+ /**
+ * @brief Get the name of the program used when creating the trajectory.
+ * @param name the string to fill with the name of the program,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for name. This includes \0 terminating character.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+ tng_function_status getFirstProgramName(char *name, const int max_len)
+ {
+ return status = tng_first_program_name_get(traj,name,max_len);
+ }
+
+
+ /**
+ * @brief Set the name of the program used when creating the trajectory..
+ * @param new_name is a string containing the wanted name.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+ tng_function_status setFirstProgramName(const char *new_name)
+ {
+ return status = tng_first_program_name_set(traj, new_name);
+ }
+
+
+ /**
+ * @brief Get the name of the program used when last modifying the trajectory.
+ * @param name the string to fill with the name of the program,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for name. This includes \0 terminating character.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+ tng_function_status getLastProgramName(char *name, const int max_len)
+ {
+ return status = tng_last_program_name_get(traj, name, max_len);
+ }
+
+
+ /**
+ * @brief Set the name of the program used when last modifying the trajectory.
+ * @param new_name is a string containing the wanted name.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+ tng_function_status setLastProgramName(const char *new_name)
+ {
+ return status = tng_last_program_name_set(traj, new_name);
+ }
+
+
+ /**
+ * @brief Get the name of the user who created the trajectory.
+ * @param name the string to fill with the name of the user,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for name. This includes \0 terminating character.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+ tng_function_status getFirstUserName(char *name, const int max_len)
+ {
+ return status = tng_first_user_name_get(traj,name, max_len);
+ }
+
+
+ /**
+ * @brief Set the name of the user who created the trajectory.
+ * @param new_name is a string containing the wanted name.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+ tng_function_status setFirstUserName(const char *new_name)
+ {
+ return status = tng_first_user_name_set(traj, new_name);
+ }
+
+
+ /**
+ * @brief Get the name of the user who last modified the trajectory.
+ * @param name the string to fill with the name of the user,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for name. This includes \0 terminating character.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+ tng_function_status getLastUserName(char *name, const int max_len)
+ {
+ return status = tng_last_user_name_get(traj,name,max_len);
+ }
+
+
+ /**
+ * @brief Set the name of the user who last modified the trajectory.
+ * @param new_name is a string containing the wanted name.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+ tng_function_status setLastUserName(const char *new_name)
+ {
+ return status = tng_last_user_name_set(traj,new_name);
+ }
+
+
+
+ /**
+ * @brief Get the name of the computer used when creating the trajectory.
+ * @param name the string to fill with the name of the computer,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for name. This includes \0 terminating character.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+ tng_function_status getFirstComputerName(char *name, const int max_len)
+ {
+ return status = tng_first_computer_name_get(traj, name, max_len);
+ }
+
+
+ /**
+ * @brief Set the name of the computer used when creating the trajectory.
+ * @param new_name is a string containing the wanted name.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+ tng_function_status setFirstComputerName(const char *new_name)
+ {
+ return status = tng_first_computer_name_set(traj, new_name);
+ }
+
+
+ /**
+ * @brief Get the name of the computer used when last modifying the trajectory.
+ * @param name the string to fill with the name of the computer,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for name. This includes \0 terminating character.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+ tng_function_status getLastComputerName(char *name, const int max_len)
+ {
+ return status = tng_last_computer_name_get(traj,name,max_len);
+ }
+
+
+ /**
+ * @brief Set the name of the computer used when last modifying the trajectory.
+ * @param new_name is a string containing the wanted name.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+ tng_function_status setLastComputerName(const char *new_name)
+ {
+ return status = tng_last_computer_name_set(traj,new_name);
+ }
+
+
+ /**
+ * @brief Get the pgp_signature of the user creating the trajectory.
+ * @param signature the string to fill with the signature,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for name. This includes \0 terminating character.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+ tng_function_status getFirstSignature(char *signature, const int max_len)
+ {
+ return status = tng_last_computer_name_get(traj, signature,max_len);
+ }
+
+
+ /**
+ * @brief Set the pgp_signature of the user creating the trajectory.
+ * @param signature is a string containing the pgp_signature.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+ tng_function_status setFirstSignature(const char *signature)
+ {
+ return status = tng_first_signature_set(traj, signature);
+ }
+
+
+ /**
+ * @brief Get the pgp_signature of the user last modifying the trajectory.
+ * @param signature the string to fill with the signature,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for name. This includes \0 terminating character.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+ tng_function_status getLastSignature(char *signature, const int max_len)
+ {
+ return status = tng_first_signature_get(traj, signature, max_len);
+ }
+
+
+ /**
+ * @brief Set the pgp_signature of the user last modifying the trajectory.
+ * @param signature is a string containing the pgp_signature.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+ tng_function_status setLastSignature(const char *signature)
+ {
+ return status = tng_last_signature_set(traj, signature);
+ }
+
+
+ /**
+ * @brief Get the name of the forcefield used in the trajectory.
+ * @param name the string to fill with the name of the forcefield,
+ * memory must be allocated before.
+ * @param max_len maximum char length of the string, i.e. how much memory has
+ * been reserved for name. This includes \0 terminating character.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (source string longer than destination string).
+ */
+ tng_function_status getForcefieldName(char *name, const int max_len)
+ {
+ return status = tng_last_signature_get(traj,name,max_len);
+ }
+
+
+ /**
+ * @brief Set the name of the forcefield used in the trajectory.
+ * @param new_name is a string containing the wanted name.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+ tng_function_status setForcefieldName(const char *new_name)
+ {
+ return status = tng_forcefield_name_set(traj, new_name);
+ }
+
+
+ /**
+ * @brief Get the medium stride length of the trajectory.
+ * @param len is pointing to a value set to the stride length.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+ tng_function_status getMediumStrideLength(int64_t *len)
+ {
+ return status = tng_medium_stride_length_get(traj,len);
+ }
+
+
+ /**
+ * @brief Set the medium stride length of the trajectory.
+ * @param len is the wanted medium stride length.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred.
+ */
+ tng_function_status setMediumStrideLength(const int64_t len)
+ {
+ return status = tng_medium_stride_length_set(traj,len);
+ }
+
+
+ /**
+ * @brief Get the long stride length of the trajectory.
+ * @param len is pointing to a value set to the stride length.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+ tng_function_status getLongStrideLength(int64_t *len)
+ {
+ return status = tng_long_stride_length_get(traj, len);
+ }
+
+
+ /**
+ * @brief Set the long stride length of the trajectory.
+ * @param len is the wanted long stride length.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred.
+ */
+ tng_function_status setLongStrideLength(const int64_t len)
+ {
+ return status = tng_long_stride_length_set(traj,len);
+ }
+
+
+ /**
+ * @brief Get the current time per frame of the trajectory.
+ * @param len is pointing to a value set to the time per frame.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+ tng_function_status getTimePerFrame(double *time)
+ {
+ return status = tng_time_per_frame_get(traj, time);
+ }
+
+
+ /**
+ * @brief Set the time per frame of the trajectory.
+ * @param len is the new time per frame.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred.
+ */
+ tng_function_status setTimePerFrame(const double time)
+ {
+ return status = tng_time_per_frame_set(traj, time);
+ }
+
+
+ /**
+ * @brief Get the length of the input file.
+ * @param len is pointing to a value set to the file length.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+ tng_function_status getInputFileLen(int64_t *len)
+ {
+ return status = tng_input_file_len_get(traj, len);
+ }
+
+
+ /**
+ * @brief Get the number of frames in the trajectory
+ * @param n is pointing to a value set to the number of frames.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred (could not find last frame set).
+ */
+ tng_function_status getNumFrames(int64_t *n)
+ {
+ return status = tng_num_frames_get(traj, n);
+ }
+
+ /**
+ * @brief Get the current number of particles.
+ * @param n is pointing to a value set to the number of particles.
+ * @details If variable number of particles are used this function will return
+ * the number of particles in the current frame set.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+ tng_function_status getNumParticles(int64_t *n)
+ {
+ return status = tng_num_particles_get(traj, n);
+ }
+
+
+
+
+ /**
+ * @brief Get the current total number of molecules.
+ * @param n is pointing to a value set to the number of molecules.
+ * @details If variable number of particles are used this function will return
+ * the total number of molecules in the current frame set.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+ tng_function_status getNumMolecules(int64_t *n)
+ {
+ return status = tng_num_molecules_get(traj,n);
+ }
+
+ /**
+ * @brief Get the exponential used for distances in the trajectory.
+ * @param exp is pointing to a value set to the distance unit exponential.
+ * @details Example: If the distances are specified in nm (default) exp is -9.
+ * If the distances are specified in Å exp is -10.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+ tng_function_status getDistanceUnitExponential
+ (int64_t *exp)
+ {
+ return status = tng_distance_unit_exponential_get(traj, exp);
+ }
+
+ /**
+ * @brief Set the exponential used for distances in the trajectory.
+ * @param exp is the distance unit exponential to use.
+ * @details Example: If the distances are specified in nm (default) exp is -9.
+ * If the distances are specified in Å exp is -10.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+ tng_function_status setDistanceUnitExponential
+ (int64_t exp)
+ {
+ return status = tng_distance_unit_exponential_set(traj, exp);
+ }
+
+
+ /**
+ * @brief Get the number of frames per frame set.
+ * per frame set.
+ * @param n is pointing to a value set to the number of frames per frame set.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+ tng_function_status getNumFramesPerFrameSet(int64_t *n)
+ {
+ return status = tng_num_frames_per_frame_set_get(traj,n);
+ }
+
+ /**
+ * @brief Set the number of frames per frame set.
+ * @param n is the number of frames per frame set.
+ * @details This does not affect already existing frame sets. For
+ * consistency the number of frames per frame set should be set
+ * betfore creating any frame sets.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+ tng_function_status setNumFramesPerFrameSet(const int64_t n)
+ {
+ return status = tng_num_frames_per_frame_set_set(traj,n);
+ }
+
+ /**
+ * @brief Get the number of frame sets.
+ * @param n is pointing to a value set to the number of frame sets.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status getNumFrameSets(int64_t *n)
+ {
+ return status = tng_num_frame_sets_get(traj, n);
+ }
+
+
+ /**
+ * @brief Get the current trajectory frame set.
+ * @param frame_set_p will be set to point at the memory position of
+ * the found frame set.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+ tng_function_status getCurrentFrameSet(tng_trajectory_frame_set_t *frame_set_p)
+ {
+ return status = tng_current_frame_set_get(traj, frame_set_p);
+ }
+
+
+ /**
+ * @brief Find the requested frame set number.
+ * @param nr is the frame set number to search for.
+ * @details tng_data->current_trajectory_frame_set will contain the
+ * found trajectory if successful.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status findFrameSetNr(const int64_t nr)
+ {
+ return status = tng_frame_set_nr_find(traj,nr);
+ }
+
+
+ /**
+ * @brief Find the frame set containing a specific frame.
+ * @param frame is the frame number to search for.
+ * @details tng_data->current_trajectory_frame_set will contain the
+ * found trajectory if successful.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status findFrameSetOfFrame(const int64_t frame)
+ {
+ return status = tng_frame_set_of_frame_find(traj, frame);
+ }
+
+
+ /**
+ * @brief Get the file position of the next frame set in the input file.
+ * @param frame_set is the frame set of which to get the position of the
+ * following frame set.
+ * @param pos is pointing to a value set to the file position.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+ tng_function_status getNextFrameSetFilePos
+ (const tng_trajectory_frame_set_t frame_set,int64_t *pos)
+ {
+ return status = tng_frame_set_next_frame_set_file_pos_get(traj,frame_set,pos );
+ }
+
+ /**
+ * @brief Get the file position of the previous frame set in the input file.
+ * @param frame_set is the frame set of which to get the position of the
+ * previous frame set.
+ * @param pos is pointing to a value set to the file position.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+ tng_function_status getPrevFrameSetFilePos
+ (const tng_trajectory_frame_set_t frame_set,int64_t *pos)
+ {
+ return status = tng_frame_set_prev_frame_set_file_pos_get(traj, frame_set, pos);
+ }
+
+
+ /**
+ * @brief Get the first and last frames of the frame set.
+ * @param frame_set is the frame set of which to get the frame range.
+ * @param first_frame is set to the first frame of the frame set.
+ * @param last_frame is set to the last frame of the frame set.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+ tng_function_status getFrameSetFrameRange
+ (const tng_trajectory_frame_set_t frame_set,
+ int64_t *first_frame,
+ int64_t *last_frame)
+ {
+ return status = tng_frame_set_frame_range_get(traj,frame_set, first_frame, last_frame);
+ }
+
+
+ /**
+ * @brief Get the molecume name of real particle number (number in mol system).
+ * @param nr is the real number of the particle in the molecular system.
+ * @param name is a string, which is set to the name of the molecule. Memory
+ * must be reserved beforehand.
+ * @param max_len is the maximum length of name.
+ * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (!) if a minor error
+ * has occured.
+ */
+ tng_function_status getMoleculeNameOfParticleNr
+ (const int64_t nr,char *name,int max_len)
+ {
+ return status = tng_molecule_name_of_particle_nr_get(traj,nr,name,max_len);
+ }
+
+
+ /**
+ * @brief Get the chain name of real particle number (number in mol system).
+ * @param nr is the real number of the particle in the molecular system.
+ * @param name is a string, which is set to the name of the chain. Memory
+ * must be reserved beforehand.
+ * @param max_len is the maximum length of name.
+ * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (!) if a minor error
+ * has occured.
+ */
+ tng_function_status getChainNameOfParticleNr
+ (const int64_t nr,char *name,int max_len)
+ {
+ return status = tng_chain_name_of_particle_nr_get(traj, nr, name, max_len);
+ }
+
+
+ /**
+ * @brief Get the residue name of real particle number (number in mol system).
+ * @param nr is the real number of the particle in the molecular system.
+ * @param name is a string, which is set to the name of the residue. Memory
+ * must be reserved beforehand.
+ * @param max_len is the maximum length of name.
+ * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (!) if a minor error
+ * has occured.
+ */
+ tng_function_status getResidueNameOfParticleNr
+ (const int64_t nr,char *name,int max_len)
+ {
+ return status = tng_residue_name_of_particle_nr_get(traj,nr,name,max_len);
+ }
+
+
+ /**
+ * @brief Get the atom name of real particle number (number in mol system).
+ * @param nr is the real number of the particle in the molecular system.
+ * @param name is a string, which is set to the name of the atom. Memory
+ * must be reserved beforehand.
+ * @param max_len is the maximum length of name.
+ * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (!) if a minor error
+ * has occured.
+ */
+ tng_function_status getAtomNameOfParticleNr
+ (const int64_t nr,char *name,int max_len)
+ {
+ return status = tng_atom_name_of_particle_nr_get(traj, nr,name,max_len);
+ }
+
+
+ /**
+ * @brief Add a particle mapping table.
+ * @details Each particle mapping table will be written as a separate block,
+ * followed by the data blocks for the corresponding particles. In most cases
+ * there is one particle mapping block for each thread writing the trajectory.
+ * @details The mapping information is added to the currently active frame set
+ * of tng_data
+ * @param first_particle_number is the first particle number of this mapping
+ * block.
+ * @param n_particles is the number of particles in this mapping block.
+ * @param mapping_table is a list of the real particle numbers (i.e. the numbers
+ * used in the molecular system). The list is n_particles long.
+ * @details mapping_table[0] is the real particle number of the first particle
+ * in the following data blocks.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status addParticleMapping
+ (const int64_t first_particle_number,
+ const int64_t n_particles,
+ const int64_t *mapping_table)
+ {
+ return status = tng_particle_mapping_add(traj,first_particle_number,n_particles,mapping_table );
+ }
+
+
+ /**
+ * @brief Read the header blocks from the input_file of tng_data.
+ * @details The trajectory blocks must be read separately and iteratively in chunks
+ * to fit in memory.
+ * @details tng_data->input_file_path specifies
+ * which file to read from. If the file (input_file) is not open it will be
+ * opened.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+ tng_function_status readFileHeaders(const tng_hash_mode hash_mode)
+ {
+ return status = tng_file_headers_read(traj, hash_mode);
+ }
+
+
+ /**
+ * @brief Write the header blocks to the output_file of tng_data.
+ * @details The trajectory blocks must be written separately and iteratively in chunks
+ * to fit in memory.
+ * @details tng_data->output_file_path
+ * specifies which file to write to. If the file (output_file) is not open it
+ * will be opened.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH an md5 hash for each header block will be generated.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+ tng_function_status writeFileHeaders(const tng_hash_mode hash_mode)
+ {
+ return status = tng_file_headers_write(traj, hash_mode);
+ }
+
+
+
+ /**
+ * @brief Read one (the next) block (of any kind) from the input_file of tng_data.
+ * which file to read from. If the file (input_file) is not open it will be
+ * opened.
+ * @param block_data is a pointer to the struct which will be populated with the
+ * data.
+ * @details If block_data->input_file_pos > 0 it is the position from where the
+ * reading starts otherwise it starts from the current position.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status readNextBlock(const tng_hash_mode hash_mode, tng_gen_block_t block_data)
+ {
+ return status = tng_block_read_next(traj,block_data, hash_mode);
+ }
+
+
+
+ /**
+ * @brief Read one (the next) frame set, including mapping and related data blocks
+ * from the input_file of tng_data.
+ * which file to read from. If the file (input_file) is not open it will be
+ * opened.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status readNextFrameSet(const tng_hash_mode hash_mode)
+ {
+ return status = tng_frame_set_read_next(traj, hash_mode);
+ }
+
+
+ /**
+ * @brief Write one frame set, including mapping and related data blocks
+ * to the output_file of tng_data.
+ * @details tng_data->output_file_path specifies
+ * which file to write to. If the file (output_file) is not open it will be
+ * opened.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH an md5 hash for each header block will be generated.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status writeFrameSet(const tng_hash_mode hash_mode)
+ {
+ return status = tng_frame_set_write(traj, hash_mode);
+ }
+
+
+ /**
+ * @brief Create and initialise a frame set.
+ * @param first_frame is the first frame of the frame set.
+ * @param n_frames is the number of frames in the frame set.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status newFrameSet(const int64_t first_frame,
+ const int64_t n_frames)
+ {
+ return status = tng_frame_set_new(traj, first_frame, n_frames);
+ }
+
+
+ /**
+ * @brief Create and initialise a frame set with the time of the first frame
+ * specified.
+ * @param first_frame is the first frame of the frame set.
+ * @param n_frames is the number of frames in the frame set.
+ * @param first_frame_time is the time stamp of the first frame (in seconds).
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status newFrameSetWithTime
+ (const int64_t first_frame,
+ const int64_t n_frames,
+ const double first_frame_time)
+ {
+ return status = tng_frame_set_with_time_new(traj,
+ first_frame, n_frames,
+ first_frame_time);
+ }
+
+
+ /**
+ * @brief Set the time stamp of the first frame of the current frame set.
+ * @param first_frame_time is the time stamp of the first frame in the
+ * frame set.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+ tng_function_status setTimeOfFirstFrameOfFrameSet
+ (const double first_frame_time)
+ {
+ return status = tng_frame_set_first_frame_time_set(traj,
+ first_frame_time);
+ }
+
+ /**
+ * @brief Add a non-particle dependent data block.
+ * @param id is the block ID of the block to add.
+ * @param block_name is a descriptive name of the block to add
+ * @param datatype is the datatype of the data in the block (e.g. int/float)
+ * @param block_type_flag indicates if this is a non-trajectory block (added
+ * directly to tng_data) or if it is a trajectory block (added to the
+ * frame set)
+ * @param n_frames is the number of frames of the data block (automatically
+ * set to 1 if adding a non-trajectory data block)
+ * @param n_values_per_frame is how many values a stored each frame (e.g. 9
+ * for a box shape block)
+ * @param stride_length is how many frames are between each entry in the
+ * data block
+ * @param codec_id is the ID of the codec to compress the data.
+ * @param new_data is an array of data values to add.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status addDataBlock(const int64_t id,
+ const char *block_name,
+ const tng_data_type datatype,
+ const tng_block_type block_type_flag,
+ int64_t n_frames,
+ const int64_t n_values_per_frame,
+ const int64_t stride_length,
+ const int64_t codec_id,
+ void *new_data)
+ {
+ return status = tng_data_block_add(traj, id,block_name,
+ datatype,block_type_flag, n_frames,
+ n_values_per_frame, stride_length,
+ codec_id, new_data);
+ }
+
+
+ /**
+ * @brief Add a particle dependent data block.
+ * @param id is the block ID of the block to add.
+ * @param block_name is a descriptive name of the block to add
+ * @param datatype is the datatype of the data in the block (e.g. int/float)
+ * @param block_type_flag indicates if this is a non-trajectory block (added
+ * directly to tng_data) or if it is a trajectory block (added to the
+ * frame set)
+ * @param n_frames is the number of frames of the data block (automatically
+ * set to 1 if adding a non-trajectory data block)
+ * @param n_values_per_frame is how many values a stored each frame (e.g. 9
+ * for a box shape block)
+ * @param stride_length is how many frames are between each entry in the
+ * data block
+ * @param first_particle_number is the number of the first particle stored
+ * in this data block
+ * @param n_particles is the number of particles stored in this data block
+ * @param codec_id is the ID of the codec to compress the data.
+ * @param new_data is an array of data values to add.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status addParticleDataBlock(const int64_t id,
+ const char *block_name,
+ const tng_data_type datatype,
+ const tng_block_type block_type_flag,
+ int64_t n_frames,
+ const int64_t n_values_per_frame,
+ const int64_t stride_length,
+ const int64_t first_particle_number,
+ const int64_t n_particles,
+ const int64_t codec_id,
+ void *new_data)
+ {
+ return status = tng_particle_data_block_add(traj,id, block_name,
+ datatype, block_type_flag, n_frames,n_values_per_frame,
+ stride_length,first_particle_number,n_particles,
+ codec_id, new_data);
+ }
+
+
+ /**
+ * @brief Write data of one trajectory frame to the output_file of tng_data.
+ * @param frame_nr is the index number of the frame to write.
+ * @param block_id is the ID of the data block to write the data to.
+ * @param data is an array of data to write. The length of the array should
+ * equal n_values_per_frame.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status writeFrameData(const int64_t frame_nr,
+ const int64_t block_id,
+ const void *data,
+ const tng_hash_mode hash_mode)
+ {
+ return status = tng_frame_data_write(traj,frame_nr,block_id,data,hash_mode);
+ }
+
+
+ /**
+ * @brief Write particle data of one trajectory frame to the output_file of
+ * tng_data.
+ * @param frame_nr is the index number of the frame to write.
+ * @param block_id is the ID of the data block to write the data to.
+ * @param val_first_particle is the number of the first particle in the data
+ * array.
+ * @param val_n_particles is the number of particles in the data array.
+ * @param data is a 1D-array of data to write. The length of the array should
+ * equal n_particles * n_values_per_frame.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status writeFrameParticleData(const int64_t frame_nr,
+ const int64_t block_id,
+ const int64_t val_first_particle,
+ const int64_t val_n_particles,
+ const void *data,
+ const tng_hash_mode hash_mode)
+ {
+ return status = tng_frame_particle_data_write(traj,frame_nr,block_id,val_first_particle,val_n_particles,data,hash_mode);
+ }
+
+
+ /**
+ * @brief Free data is an array of values (2D).
+ * @param values is the 2D array to free and will be set to 0 afterwards.
+ * @param n_frames is the number of frames in the data array.
+ * @param n_values_per_frame is the number of values per frame in the data array.
+ * @param type is the data type of the data in the array (e.g. int/float/char).
+ * @return TNG_SUCCESS (0) if successful.
+ */
+ tng_function_status freeDataValues(union data_values **values,
+ const int64_t n_frames,
+ const int64_t n_values_per_frame,
+ const tng_data_type type)
+ {
+ return status = tng_data_values_free(traj, values, n_frames,n_values_per_frame,type);
+ }
+
+
+ /**
+ * @brief Free data is an array of values (3D).
+ * @param values is the array to free and will be set to 0 afterwards.
+ * @param n_frames is the number of frames in the data array.
+ * @param n_particles is the number of particles in the data array.
+ * @param n_values_per_frame is the number of values per frame in the data array.
+ * @param type is the data type of the data in the array (e.g. int/float/char).
+ * @return TNG_SUCCESS (0) if successful.
+ */
+ tng_function_status freeParticleDataValues(union data_values ***values,
+ const int64_t n_frames,
+ const int64_t n_particles,
+ const int64_t n_values_per_frame,
+ const tng_data_type type)
+ {
+ return status = tng_particle_data_values_free(traj, values,n_frames,n_particles,n_values_per_frame,type);
+ }
+
+
+ /**
+ * @brief Retrieve non-particle data, from the last read frame set. Obsolete!
+ * which file to read from. If the file (input_file) is not open it will be
+ * opened.
+ * @param block_id is the id number of the particle data block to read.
+ * @param values is a pointer to a 2-dimensional array (memory unallocated), which
+ * will be filled with data. The array will be sized
+ * (n_frames * n_values_per_frame).
+ * Since ***values is allocated in this function it is the callers
+ * responsibility to free the memory.
+ * @param n_frames is set to the number of particles in the returned data. This is
+ * needed to properly reach and/or free the data afterwards.
+ * @param n_values_per_frame is set to the number of values per frame in the data.
+ * This is needed to properly reach and/or free the data afterwards.
+ * @param type is set to the data type of the data in the array.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status getData(const int64_t block_id,
+ union data_values ***values,
+ int64_t *n_frames,
+ int64_t *n_values_per_frame,
+ char *type)
+ {
+ return status = tng_data_get(traj, block_id, values, n_frames,
+ n_values_per_frame, type);
+ }
+
+ /**
+ * @brief Retrieve a vector (1D array) of non-particle data, from the last read frame set.
+ * @param block_id is the id number of the particle data block to read.
+ * @param values is a pointer to a 1-dimensional array (memory unallocated), which
+ * will be filled with data. The length of the array will be (n_frames * n_values_per_frame).
+ * Since **values is allocated in this function it is the callers
+ * responsibility to free the memory.
+ * @param n_frames is set to the number of particles in the returned data. This is
+ * needed to properly reach and/or free the data afterwards.
+ * @param stride_length is set to the stride length of the returned data.
+ * @param n_values_per_frame is set to the number of values per frame in the data.
+ * This is needed to properly reach and/or free the data afterwards.
+ * @param type is set to the data type of the data in the array.
+ * @details This does only work for numerical (int, float, double) data.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status getDataVector
+ (const int64_t block_id,
+ void **values,
+ int64_t *n_frames,
+ int64_t *stride_length,
+ int64_t *n_values_per_frame,
+ char *type)
+ {
+ return status = tng_data_vector_get(traj, block_id, values, n_frames,
+ stride_length, n_values_per_frame,
+ type);
+ }
+
+ /**
+ * @brief Read and retrieve non-particle data, in a specific interval. Obsolete!
+ * which file to read from. If the file (input_file) is not open it will be
+ * opened.
+ * @param block_id is the id number of the particle data block to read.
+ * @param start_frame_nr is the index number of the first frame to read.
+ * @param end_frame_nr is the index number of the last frame to read.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @param values is a pointer to a 2-dimensional array (memory unallocated), which
+ * will be filled with data. The array will be sized
+ * (n_frames * n_values_per_frame).
+ * Since ***values is allocated in this function it is the callers
+ * responsibility to free the memory.
+ * @param n_values_per_frame is set to the number of values per frame in the data.
+ * This is needed to properly reach and/or free the data afterwards.
+ * @param type is set to the data type of the data in the array.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status getDataInterval(const int64_t block_id,
+ const int64_t start_frame_nr,
+ const int64_t end_frame_nr,
+ const tng_hash_mode hash_mode,
+ union data_values ***values,
+ int64_t *n_values_per_frame,
+ char *type)
+ {
+ return status = tng_data_interval_get(traj, block_id, start_frame_nr,
+ end_frame_nr, hash_mode, values,
+ n_values_per_frame, type);
+ }
+
+
+ /**
+ * @brief Read and retrieve a vector (1D array) of non-particle data,
+ * in a specific interval.
+ * @param block_id is the id number of the particle data block to read.
+ * @param start_frame_nr is the index number of the first frame to read.
+ * @param end_frame_nr is the index number of the last frame to read.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @param values is a pointer to a 1-dimensional array (memory unallocated), which
+ * will be filled with data. The length of the array will be (n_frames * n_values_per_frame).
+ * Since **values is allocated in this function it is the callers
+ * responsibility to free the memory.
+ * @param stride_length is set to the stride length (writing frequency) of
+ * the data.
+ * @param n_values_per_frame is set to the number of values per frame in the data.
+ * This is needed to properly reach and/or free the data afterwards.
+ * @param type is set to the data type of the data in the array.
+ * @details This does only work for numerical (int, float, double) data.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status getDataVectorInterval
+ (const int64_t block_id,
+ const int64_t start_frame_nr,
+ const int64_t end_frame_nr,
+ const char hash_mode,
+ void **values,
+ int64_t *stride_length,
+ int64_t *n_values_per_frame,
+ char *type)
+ {
+ return status = tng_data_vector_interval_get(traj, block_id,
+ start_frame_nr,
+ end_frame_nr,
+ hash_mode, values,
+ stride_length,
+ n_values_per_frame,
+ type);
+ }
+
+ /**
+ * @brief Retrieve particle data, from the last read frame set. Obsolete!
+ * @details The particle dimension of the returned values array is translated
+ * to real particle numbering, i.e. the numbering of the actual molecular
+ * system.
+ * specifies which file to read from. If the file (input_file) is not open it
+ * will be opened.
+ * @param block_id is the id number of the particle data block to read.
+ * @param values is a pointer to a 3-dimensional array (memory unallocated), which
+ * will be filled with data. The array will be sized
+ * (n_frames * n_particles * n_values_per_frame).
+ * Since ****values is allocated in this function it is the callers
+ * responsibility to free the memory.
+ * @param n_frames is set to the number of particles in the returned data. This is
+ * needed to properly reach and/or free the data afterwards.
+ * @param n_particles is set to the number of particles in the returned data. This is
+ * needed to properly reach and/or free the data afterwards.
+ * @param n_values_per_frame is set to the number of values per frame in the data.
+ * This is needed to properly reach and/or free the data afterwards.
+ * @param type is set to the data type of the data in the array.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status getParticleData(const int64_t block_id,
+ union data_values ****values,
+ int64_t *n_frames,
+ int64_t *n_particles,
+ int64_t *n_values_per_frame,
+ char *type)
+ {
+ return status = (tng_particle_data_get(traj, block_id, values, n_frames,
+ n_particles, n_values_per_frame, type));
+ }
+
+
+ /**
+ * @brief Retrieve a vector (1D array) of particle data, from the last read frame set.
+ * @details The particle dimension of the returned values array is translated
+ * to real particle numbering, i.e. the numbering of the actual molecular
+ * system.
+ * @param block_id is the id number of the particle data block to read.
+ * @param values is a pointer to a 1-dimensional array (memory unallocated), which
+ * will be filled with data. The length of the array will be
+ * (n_frames * n_particles * n_values_per_frame).
+ * Since **values is allocated in this function it is the callers
+ * responsibility to free the memory.
+ * @param n_frames is set to the number of frames in the returned data. This is
+ * needed to properly reach and/or free the data afterwards.
+ * @param stride_length is set to the stride length of the returned data.
+ * @param n_particles is set to the number of particles in the returned data. This is
+ * needed to properly reach and/or free the data afterwards.
+ * @param n_values_per_frame is set to the number of values per frame in the data.
+ * This is needed to properly reach and/or free the data afterwards.
+ * @param type is set to the data type of the data in the array.
+ * @details This does only work for numerical (int, float, double) data.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status getParticleDataVector
+ (const int64_t block_id,
+ void **values,
+ int64_t *n_frames,
+ int64_t *stride_length,
+ int64_t *n_particles,
+ int64_t *n_values_per_frame,
+ char *type)
+ {
+ return status = tng_particle_data_vector_get(traj, block_id,
+ values, n_frames,
+ stride_length,
+ n_particles,
+ n_values_per_frame, type);
+ }
+
+
+ /**
+ * @brief Read and retrieve particle data, in a specific interval. Obsolete!
+ * @details The particle dimension of the returned values array is translated
+ * to real particle numbering, i.e. the numbering of the actual molecular
+ * system.
+ * @param block_id is the id number of the particle data block to read.
+ * @param start_frame_nr is the index number of the first frame to read.
+ * @param end_frame_nr is the index number of the last frame to read.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @param values is a pointer to a 3-dimensional array (memory unallocated), which
+ * will be filled with data. The array will be sized
+ * (n_frames * n_particles * n_values_per_frame).
+ * Since ****values is allocated in this function it is the callers
+ * responsibility to free the memory.
+ * @param n_particles is set to the number of particles in the returned data. This is
+ * needed to properly reach and/or free the data afterwards.
+ * @param n_values_per_frame is set to the number of values per frame in the data.
+ * This is needed to properly reach and/or free the data afterwards.
+ * @param type is set to the data type of the data in the array.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status getParticleDataInterval(const int64_t block_id,
+ const int64_t start_frame_nr,
+ const int64_t end_frame_nr,
+ const tng_hash_mode hash_mode,
+ union data_values ****values,
+ int64_t *n_particles,
+ int64_t *n_values_per_frame,
+ char *type)
+ {
+ return status = (tng_particle_data_interval_get(traj, block_id, start_frame_nr,
+ end_frame_nr, hash_mode, values,
+ n_particles, n_values_per_frame,
+ type));
+ }
+
+
+ /**
+ * @brief Read and retrieve a vector (1D array) particle data, in a
+ * specific interval.
+ * @details The particle dimension of the returned values array is translated
+ * to real particle numbering, i.e. the numbering of the actual molecular
+ * system.
+ * @param block_id is the id number of the particle data block to read.
+ * @param start_frame_nr is the index number of the first frame to read.
+ * @param end_frame_nr is the index number of the last frame to read.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @param values is a pointer to a 1-dimensional array (memory unallocated), which
+ * will be filled with data. The length of the array will be
+ * (n_frames * n_particles * n_values_per_frame).
+ * Since **values is allocated in this function it is the callers
+ * responsibility to free the memory.
+ * @param stride_length is set to the stride length (writing frequency) of
+ * the data.
+ * @param n_particles is set to the number of particles in the returned data. This is
+ * needed to properly reach and/or free the data afterwards.
+ * @param n_values_per_frame is set to the number of values per frame in the data.
+ * This is needed to properly reach and/or free the data afterwards.
+ * @param type is set to the data type of the data in the array.
+ * @details This does only work for numerical (int, float, double) data.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status getParticleDataVectorInterval
+ (const int64_t block_id,
+ const int64_t start_frame_nr,
+ const int64_t end_frame_nr,
+ const tng_hash_mode hash_mode,
+ void **values,
+ int64_t *n_particles,
+ int64_t *stride_length,
+ int64_t *n_values_per_frame,
+ char *type)
+ {
+ return status = tng_particle_data_vector_interval_get(traj, block_id,
+ start_frame_nr,
+ end_frame_nr,
+ hash_mode,
+ values,
+ n_particles,
+ stride_length,
+ n_values_per_frame,
+ type);
+ }
+
+
+ /** @brief Get the date and time of initial file creation in ISO format (string).
+ * @param time is a pointer to the string in which the date will be stored. Memory
+ must be reserved beforehand.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+ tng_function_status getTimeStr(char *time)
+ {
+ return status = tng_time_get_str(traj, time);
+ }
+
+
+};
+
+
+
+
+
+class Molecule
+{
+private:
+
+ tng_molecule_t mol;
+ Trajectory * traj;
+ tng_function_status status;
+public:
+ tng_function_status addChain(const char *name, Chain *chain);
+ tng_function_status findChain(const char *name, int64_t id, Chain *chain);
+ friend class Trajectory;
+ //Constructor
+ Molecule(Trajectory * trajectory)
+ {
+ traj = trajectory;
+
+ //status = tng_molecule_init(traj->traj,mol);
+ }
+ /**
+ *@Dose nothing, use ~TngMolecule()
+ */
+ ~Molecule()
+ {
+ status = tng_molecule_destroy(traj->traj,mol);
+ }
+ //! Status
+ tng_function_status getStatus()
+ { return status; }
+
+
+ /**
+ * @brief Set the name of a molecule.
+ * @param new_name is a string containing the wanted name.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+ tng_function_status setName(const char *new_name)
+ {
+ return status = tng_molecule_name_set(traj->traj,mol,new_name);
+ }
+
+ /**
+ * @brief Get the count of a molecule.
+ * @param cnt is a pointer to the variable to be populated with the count.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status getCnt(int64_t *cnt)
+ {
+ return status = tng_molecule_cnt_get(traj->traj,mol,cnt);
+ }
+
+ /**
+ * @brief Set the count of a molecule.
+ * @param cnt is the number of instances of this molecule.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status setCnt(int64_t cnt)
+ {
+ return status = tng_molecule_cnt_set(traj->traj,mol,cnt);
+ }
+
+};
+
+ tng_function_status Trajectory::addMolecule(const char *name, Molecule_t molecule)
+{
+ return status = tng_molecule_add(traj,name, &molecule->mol);
+}
+
+ tng_function_status Trajectory::addMoleculeWithId
+ (const char *name,
+ const int64_t id,
+ Molecule_t molecule)
+{
+ return status = tng_molecule_w_id_add(traj, name, id, &molecule->mol);
+}
+
+/**
+* @brief Find a molecule.
+* @param tng_data is the trajectory data container containing the molecule.
+* @param name is a string containing the name of the molecule. If name is empty
+* only id will be used for finding the molecule.
+* @param id is the id of the molecule to look for. If id is -1 only the name of
+* the molecule will be used for finding the molecule.
+* @param molecule is a pointer to the molecule if it was found - otherwise 0.
+* @return TNG_SUCCESS (0) if the molecule is found or TNG_FAILURE (1) if the
+* molecule is not found.
+* @details If name is an empty string and id is -1 the first molecule will be
+* found.
+*/
+tng_function_status Trajectory::findMolecule
+ (const char *name,
+ int64_t id,
+ Molecule_t molecule)
+{
+ return status = tng_molecule_find(traj, name, id,
+ &molecule->mol);
+}
+
+
+class Atom
+{
+private:
+ tng_atom_t atom;
+ Trajectory * traj;
+ tng_function_status status;
+public:
+ friend class Residue;
+ //constructor
+ Atom(Trajectory * trajectory)
+ {
+ traj = trajectory;
+ }
+ //deonstructor
+ /**
+ *@Dose nothing, use ~TngMolecule()
+ */
+ ~Atom()
+ {
+ //delete atom;
+ }
+ //! Status
+ tng_function_status getStatus()
+ { return status; }
+ /**
+ * @brief Set the name of an atom.
+ * @param new_name is a string containing the wanted name.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+ tng_function_status setName(const char *new_name)
+ {
+ return status = tng_atom_name_set(traj->traj, atom , new_name);
+ }
+
+ /**
+ * @param new_type is a string containing the atom type.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+ tng_function_status setType(const char *new_type)
+ {
+ return status = tng_atom_type_set(traj->traj, atom, new_type);
+ }
+};
+
+class Residue
+{
+ private:
+ tng_residue_t residue;
+ Trajectory * traj;
+ tng_function_status status;
+public:
+ friend class Chain;
+ //constructor
+ Residue(Trajectory * trajectory)
+ {
+ traj = trajectory;
+ }
+ //deonstructor
+ /**
+ *@Dose nothing, use ~TngMolecule()
+ */
+ ~Residue()
+ {
+ //delete residue;
+ }
+ //! Status
+ tng_function_status getStatus()
+ { return status; }
+ /**
+ * @brief Set the name of a residue.
+ * @param residue is the residue to rename.
+ * @param new_name is a string containing the wanted name.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+ tng_function_status setName(const char *new_name)
+ {
+ return status = tng_residue_name_set(traj->traj, residue,new_name);
+ }
+
+ /**
+ * @brief Add an atom to a residue.
+ * @param atom_name is a string containing the name of the atom.
+ * @param atom_type is a string containing the atom type of the atom.
+ * @param atom is a pointer to the newly created atom.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+ tng_function_status addAtom(const char *atom_name,
+ const char *atom_type,
+ Atom * atom)
+ {
+ return status = tng_residue_atom_add(traj->traj, residue, atom_name,
+ atom_type, &atom->atom);
+ }
+
+
+ /**
+ * @brief Add an atom with a specific ID to a residue.
+ * @param atom_name is a string containing the name of the atom.
+ * @param atom_type is a string containing the atom type of the atom.
+ * @param id is the ID of the created atom.
+ * @param atom is a pointer to the newly created atom.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the ID could
+ * not be set properly or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status addAtomWithId
+ (const char *atom_name,
+ const char *atom_type,
+ const int64_t id,
+ Atom * atom)
+ {
+ return status = tng_residue_atom_w_id_add(traj->traj, residue,
+ atom_name, atom_type,
+ id, &atom->atom);
+ }
+
+};
+
+class Chain
+{
+ private:
+ tng_chain_t chain;
+ Trajectory * traj;
+ tng_function_status status;
+public:
+ friend class Molecule;
+ //constructor
+ Chain(Trajectory * trajectory)
+ {
+ traj = trajectory;
+ }
+ //deonstructor
+ /**
+ *@Dose nothing, use ~TngMolecule()
+ */
+ ~Chain()
+ {
+ //delete chain;
+ }
+ //! Status
+ tng_function_status getStatus()
+ { return status; }
+ /**
+ * @brief Set the name of a chain.
+ * @param new_name is a string containing the wanted name.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+ tng_function_status setName(const char *new_name)
+ {
+ return status = tng_chain_name_set(traj->traj, chain, new_name);
+ }
+
+
+ /**
+ * @brief Find a residue in a chain.
+ * @param name is a string containing the name of the residue.
+ * @param id is the id of the residue to find. If id == -1 the first residue
+ * that matches the specified name will be found.
+ * @param residue is a pointer to the residue if it was found - otherwise 0.
+ * @return TNG_SUCCESS (0) if the residue is found or TNG_FAILURE (1) if the
+ * residue is not found.
+ * @details If name is an empty string the first residue will be found.
+ */
+ tng_function_status findResidue
+ (const char *name,
+ int64_t id,
+ Residue *residue)
+ {
+ return status = tng_chain_residue_find(traj->traj, chain, name,
+ id, &residue->residue);
+ }
+
+ /**
+ * @brief Add a residue to a chain.
+ * @param name is a string containing the name of the residue.
+ * @param residue is a pointer to the newly created residue.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+ tng_function_status addResidue(const char *name,
+ Residue * residue)
+ {
+ return status = tng_chain_residue_add(traj->traj, chain,
+ name, &residue->residue);
+ }
+
+ /**
+ * @brief Add a residue with a specific ID to a chain.
+ * @param name is a string containing the name of the residue.
+ * @param id is the ID of the created residue.
+ * @param residue is a pointer to the newly created residue.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the ID could
+ * not be set properly or TNG_CRITICAL (2) if a major error has occured.
+ */
+ tng_function_status addResidueWithId
+ (const char *name,
+ const int64_t id,
+ Residue * residue)
+ {
+ return status = tng_chain_residue_w_id_add(traj->traj, chain,
+ name, id, &residue->residue);
+ }
+};
+
+/**
+* @brief Add a chain to a molecule.
+* @param name is a string containing the name of the chain.
+* @param chain s a pointer to the newly created chain.
+* @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+* error has occured.
+*/
+tng_function_status Molecule::addChain(const char *name, Chain *chain)
+{
+ return status = tng_molecule_chain_add(traj->traj,mol,name,&chain->chain);
+}
+
+/**
+* @brief Find a chain in a molecule.
+* @param name is a string containing the name of the chain. If name is empty
+* only id will be used for finding the chain.
+* @param id is the id of the chain to look for. If id is -1 only the name of
+* the chain will be used for finding the chain.
+* @param chain is a pointer to the chain if it was found - otherwise 0.
+* @return TNG_SUCCESS (0) if the chain is found or TNG_FAILURE (1) if the
+* chain is not found.
+* @details If name is an empty string and id is -1 the first chain will be
+* found.
+*/
+tng_function_status Molecule::findChain
+ (const char *name,
+ int64_t id,
+ Chain *chain)
+{
+ return status = tng_molecule_chain_find(traj->traj, mol, name, id,
+ &chain->chain);
+}
+
+}
+#endif
--- /dev/null
+/* This code is part of the tng binary trajectory format.
+ *
+ * VERSION 1.4
+ *
+ * Written by Magnus Lundborg
+ * Copyright (c) 2012-2013, The GROMACS development team.
+ * Check out http://www.gromacs.org for more information.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+#ifndef TNG_IO_FWD_H
+#define TNG_IO_FWD_H 1
+
+/** A pointer to the main trajectory data storage. */
+typedef struct tng_trajectory *tng_trajectory_t;
+/** A pointer to a molecule description. */
+typedef struct tng_molecule *tng_molecule_t;
+/** A pointer to a molecular chain description. */
+typedef struct tng_chain *tng_chain_t;
+/** A pointer to a molecular residue description. */
+typedef struct tng_residue *tng_residue_t;
+/** A pointer to a molecular atom description. */
+typedef struct tng_atom *tng_atom_t;
+/** A pointer to a bond between two atoms. */
+typedef struct tng_bond *tng_bond_t;
+/** A pointer to a structure containing data common to all trajectory blocks,
+ * such as header and contents. */
+typedef struct tng_gen_block *tng_gen_block_t;
+/** A pointer to particle mapping information. */
+typedef struct tng_particle_mapping *tng_particle_mapping_t;
+/** A pointer to a structure containing frame set information. */
+typedef struct tng_trajectory_frame_set *tng_trajectory_frame_set_t;
+/** A pointer to a particle data container. */
+typedef struct tng_particle_data *tng_particle_data_t;
+/** A pointer to a non-particle data container. */
+typedef struct tng_non_particle_data *tng_non_particle_data_t;
+
+#endif
--- /dev/null
+add_subdirectory(compression)
+add_subdirectory(lib)
+add_subdirectory(tests)
--- /dev/null
+add_library(tng_compress bwlzh.c bwt.c coder.c dict.c fixpoint.c huffman.c huffmem.c lz77.c merge_sort.c mtf.c rle.c tng_compress.c vals16.c warnmalloc.c widemuldiv.c xtc2.c xtc3.c)
+if(UNIX)
+target_link_libraries(tng_compress m)
+endif()
+
+set_property(TARGET tng_compress PROPERTY LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
+set_property(TARGET tng_compress PROPERTY ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
+
+install(TARGETS tng_compress
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib)
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "../../include/compression/warnmalloc.h"
+#include "../../include/compression/tng_compress.h"
+#include "../../include/compression/bwlzh.h"
+#include "../../include/compression/dict.h"
+#include "../../include/compression/vals16.h"
+#include "../../include/compression/rle.h"
+#include "../../include/compression/mtf.h"
+#include "../../include/compression/bwt.h"
+#include "../../include/compression/lz77.h"
+
+#if 0
+#define SHOWIT
+#endif
+
+#if 0
+#define SHOWTEST
+#endif
+
+#define MAX_VALS_PER_BLOCK 200000
+
+#if 1
+#define PARTIAL_MTF3
+#endif
+
+#if 0
+#define PARTIAL_MTF
+#endif
+
+int bwlzh_get_buflen(int nvals)
+{
+ return 132000+nvals*8+12*((nvals+MAX_VALS_PER_BLOCK)/MAX_VALS_PER_BLOCK);
+}
+
+#ifdef SHOWIT
+static void printvals(char *name, unsigned int *vals, int nvals)
+{
+ int i;
+ int nvalsmax=nvals;
+ if (nvalsmax>99)
+ nvalsmax=99;
+#if 0
+ for (i=0; i<nvalsmax; i++)
+ fprintf(stderr,"%s %d %u\n",name,i,vals[i]);
+#else
+ fprintf(stderr,"%s\n",name);
+ {
+ unsigned char *x=(unsigned char*)vals;
+ for (i=0; i<nvalsmax*4; i++)
+ fprintf(stderr,"%02x",(unsigned int)x[i]);
+ fprintf(stderr,"\n");
+ }
+#endif
+
+}
+#endif
+
+
+static void bwlzh_compress_gen(unsigned int *vals, int nvals,
+ unsigned char *output, int *output_len,
+ int enable_lz77,
+ int verbose)
+{
+ unsigned int *vals16;
+ int nvals16;
+ int huffdatalen;
+ int nhufflen[N_HUFFMAN_ALGO];
+ int huffalgo;
+ int bwt_index;
+ unsigned int *bwt=NULL;
+#ifdef PARTIAL_MTF3
+ unsigned char *mtf3=NULL;
+ int imtfinner;
+#endif
+ unsigned int *mtf=NULL;
+ unsigned int *rle=NULL;
+ unsigned int *offsets=NULL;
+ unsigned int *lens=NULL;
+ unsigned int *dict=warnmalloc(0x20004*sizeof *dict);
+ unsigned int *hist=warnmalloc(0x20004*sizeof *hist);
+ int nrle;
+ int noffsets;
+ int nlens;
+ unsigned char *bwlzhhuff=NULL;
+ int bwlzhhufflen;
+ int max_vals_per_block=MAX_VALS_PER_BLOCK;
+ int valsleft;
+ int thisvals;
+ int valstart;
+ int outdata=0;
+
+ unsigned int *tmpmem=warnmalloc(max_vals_per_block*18*sizeof *tmpmem);
+
+#if 0
+ verbose=1;
+#endif
+
+ bwlzhhuff=warnmalloc(Ptngc_comp_huff_buflen(3*nvals));
+ vals16=tmpmem;
+ bwt=tmpmem+max_vals_per_block*3;
+ mtf=tmpmem+max_vals_per_block*6;
+ rle=tmpmem+max_vals_per_block*9;
+ offsets=tmpmem+max_vals_per_block*12;
+ lens=tmpmem+max_vals_per_block*15;
+#ifdef PARTIAL_MTF3
+ mtf3=warnmalloc(max_vals_per_block*3*3*sizeof *mtf3); /* 3 due to expansion of 32 bit to 16 bit, 3 due to up to 3 bytes
+ per 16 value. */
+#endif
+ if (verbose)
+ {
+ fprintf(stderr,"Number of input values: %d\n",nvals);
+ }
+
+ /* Store the number of real values in the whole block. */
+ output[outdata++]=((unsigned int)nvals)&0xFFU;
+ output[outdata++]=(((unsigned int)nvals)>>8)&0xFFU;
+ output[outdata++]=(((unsigned int)nvals)>>16)&0xFFU;
+ output[outdata++]=(((unsigned int)nvals)>>24)&0xFFU;
+
+ valsleft=nvals;
+ valstart=0;
+ while (valsleft)
+ {
+ int reducealgo=1; /* Reduce algo is LZ77. */
+ if (!enable_lz77)
+ reducealgo=0;
+ thisvals=valsleft;
+ if (thisvals>max_vals_per_block)
+ thisvals=max_vals_per_block;
+ valsleft-=thisvals;
+ if (verbose)
+ fprintf(stderr,"Creating vals16 block from %d values.\n",thisvals);
+
+#ifdef SHOWIT
+ printvals("vals",vals+valstart,thisvals);
+#endif
+
+ Ptngc_comp_conv_to_vals16(vals+valstart,thisvals,vals16,&nvals16);
+ valstart+=thisvals;
+
+#ifdef SHOWTEST
+ nvals16=99;
+#endif
+
+#ifdef SHOWIT
+ printvals("vals16",vals16,nvals16);
+#endif
+
+ if (verbose)
+ {
+ fprintf(stderr,"Resulting vals16 values: %d\n",nvals16);
+ }
+ if (verbose)
+ {
+ fprintf(stderr,"BWT\n");
+ }
+ Ptngc_comp_to_bwt(vals16,nvals16,bwt,&bwt_index);
+
+#ifdef SHOWIT
+ printvals("bwt",bwt,nvals16);
+ fprintf(stderr,"BWT INDEX is %d\n",bwt_index);
+#endif
+
+ /* Store the number of real values in this block. */
+ output[outdata++]=((unsigned int)thisvals)&0xFFU;
+ output[outdata++]=(((unsigned int)thisvals)>>8)&0xFFU;
+ output[outdata++]=(((unsigned int)thisvals)>>16)&0xFFU;
+ output[outdata++]=(((unsigned int)thisvals)>>24)&0xFFU;
+
+ /* Store the number of nvals16 values in this block. */
+ output[outdata++]=((unsigned int)nvals16)&0xFFU;
+ output[outdata++]=(((unsigned int)nvals16)>>8)&0xFFU;
+ output[outdata++]=(((unsigned int)nvals16)>>16)&0xFFU;
+ output[outdata++]=(((unsigned int)nvals16)>>24)&0xFFU;
+
+ /* Store the BWT index. */
+ output[outdata++]=((unsigned int)bwt_index)&0xFFU;
+ output[outdata++]=(((unsigned int)bwt_index)>>8)&0xFFU;
+ output[outdata++]=(((unsigned int)bwt_index)>>16)&0xFFU;
+ output[outdata++]=(((unsigned int)bwt_index)>>24)&0xFFU;
+
+ if (verbose)
+ fprintf(stderr,"MTF\n");
+#ifdef PARTIAL_MTF3
+ Ptngc_comp_conv_to_mtf_partial3(bwt,nvals16,
+ mtf3);
+ for (imtfinner=0; imtfinner<3; imtfinner++)
+ {
+ int i;
+ if (verbose)
+ fprintf(stderr,"Doing partial MTF: %d\n",imtfinner);
+ for (i=0; i<nvals16; i++)
+ mtf[i]=(unsigned int)mtf3[imtfinner*nvals16+i];
+#else
+#ifdef PARTIAL_MTF
+ Ptngc_comp_conv_to_mtf_partial(bwt,nvals16,mtf);
+#else
+ int ndict;
+ Ptngc_comp_canonical_dict(dict,&ndict);
+ Ptngc_comp_conv_to_mtf(bwt,nvals16,
+ dict,ndict,mtf);
+#endif
+
+#ifdef SHOWIT
+ printvals("mtf",mtf,nvals16);
+#endif
+#endif
+
+
+ if (reducealgo==1)
+ {
+ if (verbose)
+ fprintf(stderr,"LZ77\n");
+ reducealgo=1;
+ Ptngc_comp_to_lz77(mtf,nvals16,rle,&nrle,lens,&nlens,offsets,&noffsets);
+
+ if (verbose)
+ {
+ fprintf(stderr,"Resulting LZ77 values: %d\n",nrle);
+ fprintf(stderr,"Resulting LZ77 lens: %d\n",nlens);
+ fprintf(stderr,"Resulting LZ77 offsets: %d\n",noffsets);
+ }
+#ifdef SHOWIT
+ printvals("lz77 table",rle,nrle);
+ printvals("lz77 lengths",lens,nlens);
+ printvals("lz77 offsets",offsets,noffsets);
+#endif
+
+#if 0
+ if (noffsets)
+ {
+ unsigned int thist[0x20004];
+ unsigned int coarse[17]={0,};
+ int jj;
+ Ptngc_comp_make_dict_hist(lens,nlens,dict,&ndict,thist);
+ for (jj=0; jj<ndict; jj++)
+ fprintf(stderr,"%d %u %u L\n",jj,dict[jj],thist[jj]);
+
+ Ptngc_comp_make_dict_hist(offsets,noffsets,dict,&ndict,thist);
+ for (jj=0; jj<ndict; jj++)
+ {
+ unsigned int v=dict[jj];
+ int numbits=0;
+ while (v)
+ {
+ numbits++;
+ v>>=1;
+ }
+ coarse[numbits-1]+=thist[jj];
+ }
+#if 1
+ for (jj=0; jj<ndict; jj++)
+ fprintf(stderr,"%d %u %u O\n",jj,dict[jj],thist[jj]);
+#else
+ for (jj=0; jj<17; jj++)
+ fprintf(stderr,"%d %u\n",jj+1,coarse[jj]);
+#endif
+
+ }
+ exit(0);
+#endif
+
+ if (nlens<2)
+ reducealgo=0;
+
+#ifdef SHOWTEST
+ reducealgo=1;
+#endif
+ }
+ if (reducealgo==0)
+ {
+ if (verbose)
+ fprintf(stderr,"RLE\n");
+ /* Do RLE. For any repetetitive characters. */
+ Ptngc_comp_conv_to_rle(mtf,nvals16,rle,&nrle,1);
+
+#ifdef SHOWIT
+ printvals("rle",rle,nrle);
+#endif
+ if (verbose)
+ fprintf(stderr,"Resulting RLE values: %d\n",nrle);
+ }
+
+ /* reducealgo: RLE == 0, LZ77 == 1 */
+ output[outdata++]=reducealgo;
+
+ if (verbose)
+ fprintf(stderr,"Huffman\n");
+
+ huffalgo=-1;
+ Ptngc_comp_huff_compress_verbose(rle,nrle,bwlzhhuff,&bwlzhhufflen,&huffdatalen,nhufflen,&huffalgo,1);
+#ifdef SHOWTEST
+ {
+ int i;
+ fprintf(stderr,"Huffman\n");
+ for (i=0; i<bwlzhhufflen; i++)
+ fprintf(stderr,"%02x",(unsigned int)bwlzhhuff[i]);
+ fprintf(stderr,"\n");
+ exit(0);
+ }
+#endif
+ if (verbose)
+ {
+ int i;
+ fprintf(stderr,"Huffman data length is %d B.\n",huffdatalen);
+ for (i=0; i<N_HUFFMAN_ALGO; i++)
+ fprintf(stderr,"Huffman dictionary for algorithm %s is %d B.\n",Ptngc_comp_get_huff_algo_name(i),nhufflen[i]-huffdatalen);
+ fprintf(stderr,"Resulting algorithm: %s. Size=%d B\n",Ptngc_comp_get_huff_algo_name(huffalgo),bwlzhhufflen);
+ }
+
+ /* Store the number of huffman values in this block. */
+ output[outdata++]=((unsigned int)nrle)&0xFFU;
+ output[outdata++]=(((unsigned int)nrle)>>8)&0xFFU;
+ output[outdata++]=(((unsigned int)nrle)>>16)&0xFFU;
+ output[outdata++]=(((unsigned int)nrle)>>24)&0xFFU;
+
+ /* Store the size of the huffman block. */
+ output[outdata++]=((unsigned int)bwlzhhufflen)&0xFFU;
+ output[outdata++]=(((unsigned int)bwlzhhufflen)>>8)&0xFFU;
+ output[outdata++]=(((unsigned int)bwlzhhufflen)>>16)&0xFFU;
+ output[outdata++]=(((unsigned int)bwlzhhufflen)>>24)&0xFFU;
+
+ /* Store the huffman block. */
+ memcpy(output+outdata,bwlzhhuff,bwlzhhufflen);
+ outdata+=bwlzhhufflen;
+
+ if (reducealgo==1)
+ {
+ /* Store the number of values in this block. */
+ output[outdata++]=((unsigned int)noffsets)&0xFFU;
+ output[outdata++]=(((unsigned int)noffsets)>>8)&0xFFU;
+ output[outdata++]=(((unsigned int)noffsets)>>16)&0xFFU;
+ output[outdata++]=(((unsigned int)noffsets)>>24)&0xFFU;
+
+ if (noffsets>0)
+ {
+ if (verbose)
+ fprintf(stderr,"Huffman for offsets\n");
+
+ huffalgo=-1;
+ Ptngc_comp_huff_compress_verbose(offsets,noffsets,bwlzhhuff,&bwlzhhufflen,&huffdatalen,nhufflen,&huffalgo,1);
+ if (verbose)
+ {
+ int i;
+ fprintf(stderr,"Huffman data length is %d B.\n",huffdatalen);
+ for (i=0; i<N_HUFFMAN_ALGO; i++)
+ fprintf(stderr,"Huffman dictionary for algorithm %s is %d B.\n",Ptngc_comp_get_huff_algo_name(i),nhufflen[i]-huffdatalen);
+ fprintf(stderr,"Resulting algorithm: %s. Size=%d B\n",Ptngc_comp_get_huff_algo_name(huffalgo),bwlzhhufflen);
+ }
+
+ /* If huffman was bad for these offsets, just store the offsets as pairs of bytes. */
+ if (bwlzhhufflen<noffsets*2)
+ {
+ output[outdata++]=0;
+
+ /* Store the size of the huffman block. */
+ output[outdata++]=((unsigned int)bwlzhhufflen)&0xFFU;
+ output[outdata++]=(((unsigned int)bwlzhhufflen)>>8)&0xFFU;
+ output[outdata++]=(((unsigned int)bwlzhhufflen)>>16)&0xFFU;
+ output[outdata++]=(((unsigned int)bwlzhhufflen)>>24)&0xFFU;
+
+ /* Store the huffman block. */
+ memcpy(output+outdata,bwlzhhuff,bwlzhhufflen);
+ outdata+=bwlzhhufflen;
+ }
+ else
+ {
+ int i;
+ output[outdata++]=1;
+ for (i=0; i<noffsets; i++)
+ {
+ output[outdata++]=((unsigned int)offsets[i])&0xFFU;
+ output[outdata++]=(((unsigned int)offsets[i])>>8)&0xFFU;
+ }
+ if (verbose)
+ fprintf(stderr,"Store raw offsets: %d B\n",noffsets*2);
+ }
+ }
+
+#if 0
+ {
+ int i,ndict;
+ FILE *f=fopen("len.dict","w");
+ Ptngc_comp_make_dict_hist(lens,nlens,dict,&ndict,hist);
+ for (i=0; i<ndict; i++)
+ fprintf(f,"%d %d %d\n",i,dict[i],hist[i]);
+ fclose(f);
+ f=fopen("off.dict","w");
+ Ptngc_comp_make_dict_hist(offsets,noffsets,dict,&ndict,hist);
+ for (i=0; i<ndict; i++)
+ fprintf(f,"%d %d %d\n",i,dict[i],hist[i]);
+ fclose(f);
+ f=fopen("len.time","w");
+ for (i=0; i<ndict; i++)
+ fprintf(f,"%d\n",lens[i]);
+ fclose(f);
+ f=fopen("off.time","w");
+ for (i=0; i<ndict; i++)
+ fprintf(f,"%d\n",offsets[i]);
+ fclose(f);
+ }
+#endif
+
+ if (verbose)
+ fprintf(stderr,"Huffman for lengths\n");
+
+ huffalgo=-1;
+ Ptngc_comp_huff_compress_verbose(lens,nlens,bwlzhhuff,&bwlzhhufflen,&huffdatalen,nhufflen,&huffalgo,1);
+ if (verbose)
+ {
+ int i;
+ fprintf(stderr,"Huffman data length is %d B.\n",huffdatalen);
+ for (i=0; i<N_HUFFMAN_ALGO; i++)
+ fprintf(stderr,"Huffman dictionary for algorithm %s is %d B.\n",Ptngc_comp_get_huff_algo_name(i),nhufflen[i]-huffdatalen);
+ fprintf(stderr,"Resulting algorithm: %s. Size=%d B\n",Ptngc_comp_get_huff_algo_name(huffalgo),bwlzhhufflen);
+ }
+
+ /* Store the number of values in this block. */
+ output[outdata++]=((unsigned int)nlens)&0xFFU;
+ output[outdata++]=(((unsigned int)nlens)>>8)&0xFFU;
+ output[outdata++]=(((unsigned int)nlens)>>16)&0xFFU;
+ output[outdata++]=(((unsigned int)nlens)>>24)&0xFFU;
+
+ /* Store the size of the huffman block. */
+ output[outdata++]=((unsigned int)bwlzhhufflen)&0xFFU;
+ output[outdata++]=(((unsigned int)bwlzhhufflen)>>8)&0xFFU;
+ output[outdata++]=(((unsigned int)bwlzhhufflen)>>16)&0xFFU;
+ output[outdata++]=(((unsigned int)bwlzhhufflen)>>24)&0xFFU;
+
+ /* Store the huffman block. */
+ memcpy(output+outdata,bwlzhhuff,bwlzhhufflen);
+ outdata+=bwlzhhufflen;
+ }
+#ifdef PARTIAL_MTF3
+ }
+#endif
+ }
+
+ *output_len=outdata;
+ free(hist);
+ free(dict);
+ free(bwlzhhuff);
+#ifdef PARTIAL_MTF3
+ free(mtf3);
+#endif
+ free(tmpmem);
+}
+
+
+void DECLSPECDLLEXPORT bwlzh_compress(unsigned int *vals, int nvals,
+ unsigned char *output, int *output_len)
+{
+ bwlzh_compress_gen(vals,nvals,output,output_len,1,0);
+}
+
+void DECLSPECDLLEXPORT bwlzh_compress_verbose(unsigned int *vals, int nvals,
+ unsigned char *output, int *output_len)
+{
+ bwlzh_compress_gen(vals,nvals,output,output_len,1,1);
+}
+
+
+void DECLSPECDLLEXPORT bwlzh_compress_no_lz77(unsigned int *vals, int nvals,
+ unsigned char *output, int *output_len)
+{
+ bwlzh_compress_gen(vals,nvals,output,output_len,0,0);
+}
+
+void DECLSPECDLLEXPORT bwlzh_compress_no_lz77_verbose(unsigned int *vals, int nvals,
+ unsigned char *output, int *output_len)
+{
+ bwlzh_compress_gen(vals,nvals,output,output_len,0,1);
+}
+
+
+static void bwlzh_decompress_gen(unsigned char *input, int nvals,
+ unsigned int *vals,
+ int verbose)
+{
+ unsigned int *vals16;
+ int nvals16;
+ int bwt_index;
+ unsigned int *bwt=NULL;
+ unsigned int *mtf=NULL;
+#ifdef PARTIAL_MTF3
+ unsigned char *mtf3=NULL;
+ int imtfinner;
+#endif
+ unsigned int *rle=NULL;
+ unsigned int *offsets=NULL;
+ unsigned int *lens=NULL;
+ unsigned int *dict=warnmalloc(0x20004*sizeof *dict);
+ unsigned int *hist=warnmalloc(0x20004*sizeof *hist);
+ int nrle, noffsets, nlens;
+ unsigned char *bwlzhhuff=NULL;
+ int bwlzhhufflen;
+ int max_vals_per_block=MAX_VALS_PER_BLOCK;
+ int valsleft;
+ int thisvals;
+ int valstart;
+ int inpdata=0;
+ int nvalsfile;
+
+ unsigned int *tmpmem=warnmalloc(max_vals_per_block*18*sizeof *tmpmem);
+
+#if 0
+ verbose=1;
+#endif
+
+
+ bwlzhhuff=warnmalloc(Ptngc_comp_huff_buflen(3*nvals));
+ vals16=tmpmem;
+ bwt=tmpmem+max_vals_per_block*3;
+ mtf=tmpmem+max_vals_per_block*6;
+ rle=tmpmem+max_vals_per_block*9;
+ offsets=tmpmem+max_vals_per_block*12;
+ lens=tmpmem+max_vals_per_block*15;
+#ifdef PARTIAL_MTF3
+ mtf3=warnmalloc(max_vals_per_block*3*3*sizeof *mtf3); /* 3 due to expansion of 32 bit to 16 bit, 3 due to up to 3 bytes
+ per 16 value. */
+#endif
+
+ if (verbose)
+ {
+ fprintf(stderr,"Number of input values: %d\n",nvals);
+ }
+
+ /* Read the number of real values in the whole block. */
+ nvalsfile=(int)(((unsigned int)input[inpdata]) |
+ (((unsigned int)input[inpdata+1])<<8) |
+ (((unsigned int)input[inpdata+2])<<16) |
+ (((unsigned int)input[inpdata+3])<<24));
+ inpdata+=4;
+
+ if (nvalsfile!=nvals)
+ {
+ fprintf(stderr,"BWLZH: The number of values found in the file is different from the number of values expected.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ valsleft=nvals;
+ valstart=0;
+ while (valsleft)
+ {
+ int valsnew;
+ int reducealgo;
+ /* Read the number of real values in this block. */
+ thisvals=(int)(((unsigned int)input[inpdata]) |
+ (((unsigned int)input[inpdata+1])<<8) |
+ (((unsigned int)input[inpdata+2])<<16) |
+ (((unsigned int)input[inpdata+3])<<24));
+ inpdata+=4;
+
+ valsleft-=thisvals;
+
+ /* Read the number of nvals16 values in this block. */
+ nvals16=(int)(((unsigned int)input[inpdata]) |
+ (((unsigned int)input[inpdata+1])<<8) |
+ (((unsigned int)input[inpdata+2])<<16) |
+ (((unsigned int)input[inpdata+3])<<24));
+ inpdata+=4;
+
+ /* Read the BWT index. */
+ bwt_index=(int)(((unsigned int)input[inpdata]) |
+ (((unsigned int)input[inpdata+1])<<8) |
+ (((unsigned int)input[inpdata+2])<<16) |
+ (((unsigned int)input[inpdata+3])<<24));
+ inpdata+=4;
+
+ if (thisvals>max_vals_per_block)
+ {
+ /* More memory must be allocated for decompression. */
+ max_vals_per_block=thisvals;
+ if (verbose)
+ fprintf(stderr,"Allocating more memory: %d B\n",(int)(max_vals_per_block*15*sizeof *tmpmem));
+ tmpmem=warnrealloc(tmpmem,max_vals_per_block*18*sizeof *tmpmem);
+ vals16=tmpmem;
+ bwt=tmpmem+max_vals_per_block*3;
+ mtf=tmpmem+max_vals_per_block*6;
+ rle=tmpmem+max_vals_per_block*9;
+ offsets=tmpmem+max_vals_per_block*12;
+ lens=tmpmem+max_vals_per_block*15;
+#ifdef PARTIAL_MTF3
+ mtf3=warnrealloc(mtf3,max_vals_per_block*3*3*sizeof *mtf3); /* 3 due to expansion of 32 bit to 16 bit, 3 due to up to 3 bytes
+ per 16 value. */
+#endif
+ }
+
+#ifdef PARTIAL_MTF3
+ for (imtfinner=0; imtfinner<3; imtfinner++)
+ {
+ int i;
+ if (verbose)
+ fprintf(stderr,"Doing partial MTF: %d\n",imtfinner);
+#endif
+
+ reducealgo=(int)input[inpdata];
+ inpdata++;
+
+ /* Read the number of huffman values in this block. */
+ nrle=(int)(((unsigned int)input[inpdata]) |
+ (((unsigned int)input[inpdata+1])<<8) |
+ (((unsigned int)input[inpdata+2])<<16) |
+ (((unsigned int)input[inpdata+3])<<24));
+ inpdata+=4;
+
+ /* Read the size of the huffman block. */
+ bwlzhhufflen=(int)(((unsigned int)input[inpdata]) |
+ (((unsigned int)input[inpdata+1])<<8) |
+ (((unsigned int)input[inpdata+2])<<16) |
+ (((unsigned int)input[inpdata+3])<<24));
+ inpdata+=4;
+
+ if (verbose)
+ fprintf(stderr,"Decompressing huffman block of length %d.\n",bwlzhhufflen);
+ /* Decompress the huffman block. */
+ Ptngc_comp_huff_decompress(input+inpdata,bwlzhhufflen,rle);
+ inpdata+=bwlzhhufflen;
+
+ if (reducealgo==1) /* LZ77 */
+ {
+ int offstore;
+ /* Read the number of huffman values in this block. */
+ noffsets=(int)(((unsigned int)input[inpdata]) |
+ (((unsigned int)input[inpdata+1])<<8) |
+ (((unsigned int)input[inpdata+2])<<16) |
+ (((unsigned int)input[inpdata+3])<<24));
+ inpdata+=4;
+
+ if (noffsets>0)
+ {
+ /* How are the offsets stored? */
+ offstore=(int)input[inpdata++];
+ if (offstore==0)
+ {
+ /* Read the size of the huffman block. */
+ bwlzhhufflen=(int)(((unsigned int)input[inpdata]) |
+ (((unsigned int)input[inpdata+1])<<8) |
+ (((unsigned int)input[inpdata+2])<<16) |
+ (((unsigned int)input[inpdata+3])<<24));
+ inpdata+=4;
+
+ if (verbose)
+ fprintf(stderr,"Decompressing offset huffman block.\n");
+
+ /* Decompress the huffman block. */
+ Ptngc_comp_huff_decompress(input+inpdata,bwlzhhufflen,offsets);
+ inpdata+=bwlzhhufflen;
+ }
+ else
+ {
+ int i;
+ if (verbose)
+ fprintf(stderr,"Reading offset block.\n");
+ for (i=0; i<noffsets; i++)
+ {
+ offsets[i]=(int)(((unsigned int)input[inpdata]) |
+ (((unsigned int)input[inpdata+1])<<8));
+ inpdata+=2;
+ }
+ }
+ }
+#if 0
+ {
+ int i;
+ for (i=0; i<nrle; i++)
+ fprintf(stderr,"RLE %d: %d\n",i,rle[i]);
+ for (i=0; i<noffsets; i++)
+ fprintf(stderr,"OFFSET %d: %d\n",i,offsets[i]);
+ }
+#endif
+
+
+ /* Read the number of huffman values in this block. */
+ nlens=(int)(((unsigned int)input[inpdata]) |
+ (((unsigned int)input[inpdata+1])<<8) |
+ (((unsigned int)input[inpdata+2])<<16) |
+ (((unsigned int)input[inpdata+3])<<24));
+ inpdata+=4;
+
+ /* Read the size of the huffman block. */
+ bwlzhhufflen=(int)(((unsigned int)input[inpdata]) |
+ (((unsigned int)input[inpdata+1])<<8) |
+ (((unsigned int)input[inpdata+2])<<16) |
+ (((unsigned int)input[inpdata+3])<<24));
+ inpdata+=4;
+
+ if (verbose)
+ fprintf(stderr,"Decompressing length huffman block.\n");
+
+ /* Decompress the huffman block. */
+ Ptngc_comp_huff_decompress(input+inpdata,bwlzhhufflen,lens);
+ inpdata+=bwlzhhufflen;
+
+ if (verbose)
+ fprintf(stderr,"Decompressing LZ77.\n");
+
+ Ptngc_comp_from_lz77(rle,nrle,lens,nlens,offsets,noffsets,mtf,nvals16);
+ }
+ else if (reducealgo==0) /* RLE */
+ {
+#ifdef SHOWIT
+ printvals("rle",rle,nrle);
+#endif
+
+ if (verbose)
+ fprintf(stderr,"Decompressing rle block.\n");
+ Ptngc_comp_conv_from_rle(rle,mtf,nvals16);
+ }
+
+#ifdef PARTIAL_MTF3
+ for (i=0; i<nvals16; i++)
+ mtf3[imtfinner*nvals16+i]=(unsigned char)mtf[i];
+ }
+#else
+#ifdef SHOWIT
+ printvals("mtf",mtf,nvals16);
+#endif
+
+#endif
+
+
+ if (verbose)
+ fprintf(stderr,"Inverse MTF.\n");
+#ifdef PARTIAL_MTF3
+ Ptngc_comp_conv_from_mtf_partial3(mtf3,nvals16,bwt);
+#else
+#ifdef PARTIAL_MTF
+ Ptngc_comp_conv_from_mtf_partial(mtf,nvals16,bwt);
+#else
+ int ndict;
+ Ptngc_comp_canonical_dict(dict,&ndict);
+ Ptngc_comp_conv_from_mtf(mtf,nvals16,dict,ndict,bwt);
+#endif
+#endif
+
+#ifdef SHOWIT
+ printvals("bwt",bwt,nvals16);
+ fprintf(stderr,"BWT INDEX is %d\n",bwt_index);
+#endif
+
+ if (verbose)
+ fprintf(stderr,"Inverse BWT.\n");
+ Ptngc_comp_from_bwt(bwt,nvals16,bwt_index,vals16);
+
+#ifdef SHOWIT
+ printvals("vals16",vals16,nvals16);
+#endif
+
+ if (verbose)
+ fprintf(stderr,"Decompressing vals16 block.\n");
+ Ptngc_comp_conv_from_vals16(vals16,nvals16,vals+valstart,&valsnew);
+
+#ifdef SHOWIT
+ printvals("vals",vals+valstart,thisvals);
+#endif
+
+ if (valsnew!=thisvals)
+ {
+ fprintf(stderr,"BWLZH: Block contained different number of values than expected.\n");
+ exit(EXIT_FAILURE);
+ }
+ valstart+=thisvals;
+ }
+ free(hist);
+ free(dict);
+ free(bwlzhhuff);
+#ifdef PARTIAL_MTF3
+ free(mtf3);
+#endif
+ free(tmpmem);
+}
+
+
+void DECLSPECDLLEXPORT bwlzh_decompress(unsigned char *input, int nvals,
+ unsigned int *vals)
+{
+ bwlzh_decompress_gen(input,nvals,vals,0);
+}
+
+void DECLSPECDLLEXPORT bwlzh_decompress_verbose(unsigned char *input, int nvals,
+ unsigned int *vals)
+{
+ bwlzh_decompress_gen(input,nvals,vals,1);
+}
+
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "../../include/compression/warnmalloc.h"
+#include "../../include/compression/bwt.h"
+
+#if 0
+#define SHOWIT
+#endif
+#if 0
+#define SHOWIT2
+#endif
+
+static int compare_index(int i1,int i2,int nvals,unsigned int *vals,unsigned int *nrepeat)
+{
+ int i,j;
+ for (i=0; i<nvals; i++)
+ {
+ /* If we have repeating patterns, we might be able to start the
+ comparison later in the string. */
+ /* Do we have a repeating pattern? If so are
+ the repeating patterns the same length? */
+ int repeat1=(int)(nrepeat[i1]>>8);
+ int k1=(int)(nrepeat[i1]&0xFFU);
+ int repeat2=(int)(nrepeat[i2]>>8);
+ int k2=(int)(nrepeat[i2]&0xFFU);
+
+ if ((repeat1>1) && (repeat2>1) && (k1==k2))
+ {
+ int maxskip=0;
+ /* Yes. Compare the repeating patterns. */
+ for (j=0; j<k1; j++)
+ {
+ unsigned int v1=vals[(i1+j)%nvals];
+ unsigned int v2=vals[(i2+j)%nvals];
+ if (v1<v2)
+ return -1;
+ else if (v1>v2)
+ return 1;
+ }
+ /* The repeating patterns are equal. Skip as far as we can
+ before continuing. */
+ maxskip=repeat1;
+ if (repeat2<repeat1)
+ maxskip=repeat2;
+ i1=(i1+maxskip)%nvals;
+ i2=(i2+maxskip)%nvals;
+ i+=maxskip-1;
+ }
+ else
+ {
+ if (vals[i1]<vals[i2])
+ return -1;
+ else if (vals[i1]>vals[i2])
+ return 1;
+ i1++;
+ if (i1>=nvals)
+ i1=0;
+ i2++;
+ if (i2>=nvals)
+ i2=0;
+ }
+ }
+ return 0;
+}
+
+void Ptngc_bwt_merge_sort_inner(int *indices, int nvals,unsigned int *vals,
+ int start, int end,
+ unsigned int *nrepeat,
+ int *workarray)
+{
+ int middle;
+ if ((end-start)>1)
+ {
+ middle=start+(end-start)/2;
+#if 0
+ printf("For start %d end %d obtained new middle: %d\n",start,end,middle);
+#endif
+ Ptngc_bwt_merge_sort_inner(indices,nvals,vals,
+ start,middle,
+ nrepeat,
+ workarray);
+ Ptngc_bwt_merge_sort_inner(indices,nvals,vals,
+ middle,end,
+ nrepeat,
+ workarray);
+#if 0
+ printf("For start %d end %d Before merge: Comparing element %d with %d\n",start,end,middle-1,middle);
+#endif
+ if (compare_index(indices[middle-1],indices[middle],nvals,vals,nrepeat)>0)
+ {
+ /* Merge to work array. */
+ int i, n=end-start;
+ int ileft=start;
+ int iright=middle;
+ for (i=0; i<n; i++)
+ {
+ if (ileft==middle)
+ {
+ workarray[i]=indices[iright];
+ iright++;
+ }
+ else if (iright==end)
+ {
+ workarray[i]=indices[ileft];
+ ileft++;
+ }
+ else
+ {
+#if 0
+ printf("For start %d end %d In merge: Comparing element %d with %d\n",start,end,ileft,iright);
+#endif
+ if (compare_index(indices[ileft],indices[iright],nvals,vals,nrepeat)>0)
+ {
+ workarray[i]=indices[iright];
+ iright++;
+ }
+ else
+ {
+ workarray[i]=indices[ileft];
+ ileft++;
+ }
+ }
+ }
+ /* Copy result back. */
+ memcpy(indices+start,workarray,(end-start)*sizeof(int));
+ }
+ }
+}
+
+/* Burrows-Wheeler transform. */
+void Ptngc_comp_to_bwt(unsigned int *vals, int nvals,
+ unsigned int *output, int *index)
+{
+ int i;
+ int *indices=warnmalloc(2*nvals*sizeof *indices);
+ unsigned int *nrepeat=warnmalloc(nvals*sizeof *nrepeat);
+ int *warr=indices+nvals;
+
+ if (nvals>0xFFFFFF)
+ {
+ fprintf(stderr,"BWT cannot pack more than %d values.\n",0xFFFFFF);
+ exit(1);
+ }
+
+ /* Also note that repeat pattern k (kmax) cannot be larger than 255. */
+#if 0
+ printf("Size of arrays is %.2f M\n",4*nvals*sizeof *indices/1024./1024.);
+#endif
+ for (i=0; i<nvals; i++)
+ indices[i]=i;
+ /* Find the length of the initial repeating pattern for the strings. */
+ /* First mark that the index does not have a found repeating string. */
+ for (i=0; i<nvals; i++)
+ nrepeat[i]=0U;
+#ifdef SHOWIT
+ printf("nvals is %d\n",nvals);
+#endif
+ for (i=0; i<nvals; i++)
+ {
+ /* If we have not already found a repeating string we must find
+ it. */
+ if (!nrepeat[i])
+ {
+ int maxrepeat=nvals*2;
+ int j,k,m;
+ int good_j=-1, good_k=0;
+ int kmax=16;
+ /* Track repeating patterns.
+ k=1 corresponds to AAAAA...
+ k=2 corresponds to ABABAB...
+ k=3 corresponds to ABCABCABCABC...
+ k=4 corresponds to ABCDABCDABCD...
+ etc. */
+ for (k=kmax; k>=1; k--)
+ {
+ try_next_k:
+ if (k>=1)
+ {
+#ifdef SHOWIT
+ printf("Trying k=%d at i=%d\n",k,i);
+#endif
+ for (j=k; j<maxrepeat; j+=k)
+ {
+ int is_equal=1;
+#ifdef SHOWIT
+ printf("Trying j=%d at i=%d for k %d\n",j,i,k);
+#endif
+ for (m=0; m<k; m++)
+ if (vals[(i+m)%nvals]!=vals[(i+j+m)%nvals])
+ {
+ is_equal=0;
+ break;
+ }
+ if (is_equal)
+ {
+ int new_j=j+k;
+ if (new_j>maxrepeat)
+ new_j=j;
+ if ((new_j>good_j) || ((new_j==good_j) && (k<good_k)))
+ {
+ good_j=new_j; /* We have found that
+ the strings repeat
+ for this length... */
+ good_k=k; /* ...and with this
+ length of the
+ repeating
+ pattern. */
+#ifdef SHOWIT
+ printf("Best j and k is now %d and %d\n",good_j,good_k);
+#endif
+ }
+ }
+ else
+ {
+ /* We know that it is no point in trying
+ with more than m */
+ if (j==0)
+ {
+ k=m;
+#ifdef SHOWIT
+ printf("Setting new k to m: %d\n",k);
+#endif
+ }
+ else
+ k--;
+#ifdef SHOWIT
+ printf("Trying next k\n");
+#endif
+ goto try_next_k;
+ }
+ }
+ }
+ }
+ /* From good_j and good_k we know the repeat for a large
+ number of strings. The very last repeat length should not
+ be assigned, since it can be much longer if a new test is
+ done. */
+ for (m=0; (m+good_k<good_j) && (i+m<nvals); m+=good_k)
+ {
+ int repeat=good_j-m;
+ if (repeat>nvals)
+ repeat=nvals;
+ nrepeat[i+m]=((unsigned int) (good_k)) | (((unsigned int) (repeat))<<8);
+ }
+ /* If no repetition was found for this value signal that here. */
+ if (!nrepeat[i])
+ nrepeat[i+m]=257U; /* This is 1<<8 | 1 */
+ }
+ }
+#ifdef SHOWIT
+ for (i=0; i<nvals; i++)
+ if ((nrepeat[i]>>8)!=1)
+ printf("String repeats at %d: %d %d\n",i,nrepeat[i]>>8,nrepeat[i]&0xFFU);
+#endif
+
+ /* Sort cyclic shift matrix. */
+ Ptngc_bwt_merge_sort_inner(indices,nvals,vals,0,nvals,nrepeat,warr);
+
+#if 0
+ /* Test that it really is sorted. */
+ for (i=0; i<nvals-1; i++)
+ if (compare_index(indices[i],indices[i+1],nvals,vals,nrepeat)!=-1)
+ fprintf(stderr,"SORTING NOT COMPLETED AT %d. Index %d against %d\n",i,indices[i],indices[i+1]);
+
+#endif
+
+
+#ifdef SHOWIT2
+ for (i=0; i<nvals; i++)
+ {
+ int j;
+ for (j=0; j<nvals; j++)
+ printf("%c",vals[(indices[i]+j)%nvals]);
+ printf("\n");
+ }
+#endif
+ /* Which one is the original string? */
+ for (i=0; i<nvals; i++)
+ if (indices[i]==0)
+ break;
+ *index=i;
+ /* Form output. */
+ for (i=0; i<nvals; i++)
+ {
+ int lastchar=indices[i]-1;
+ if (lastchar<0)
+ lastchar=nvals-1;
+ output[i]=vals[lastchar];
+ }
+ free(nrepeat);
+ free(indices);
+}
+
+/* Burrows-Wheeler inverse transform. */
+void Ptngc_comp_from_bwt(unsigned int *input, int nvals, int index,
+ unsigned int *vals)
+{
+ /* Straightforward from the Burrows-Wheeler paper (page 13). */
+ int i;
+ unsigned int *c=warnmalloc(0x10000*sizeof *c);
+ unsigned int *p=warnmalloc(nvals*sizeof *p);
+ unsigned int sum=0;
+ for (i=0; i<0x10000; i++)
+ c[i]=0;
+ for (i=0; i<nvals; i++)
+ {
+ p[i]=c[input[i]];
+ c[input[i]]++;
+ }
+ for (i=0; i<0x10000; i++)
+ {
+ sum+=c[i];
+ c[i]=sum-c[i];
+ }
+ for (i=nvals-1; i>=0; i--)
+ {
+ vals[i]=input[index];
+ index=p[index]+c[input[index]];
+ }
+ free(p);
+ free(c);
+}
+
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "../../include/compression/tng_compress.h"
+#include "../../include/compression/bwlzh.h"
+#include "../../include/compression/coder.h"
+#include "../../include/compression/warnmalloc.h"
+
+#ifndef USE_WINDOWS
+#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
+#define USE_WINDOWS
+#endif /* win32... */
+#endif /* not defined USE_WINDOWS */
+
+#ifdef USE_WINDOWS
+#define TNG_INLINE __inline
+#define TNG_SNPRINTF _snprintf
+#else
+#define TNG_INLINE inline
+#define TNG_SNPRINTF snprintf
+#endif
+
+struct coder DECLSPECDLLEXPORT *Ptngc_coder_init(void)
+{
+ struct coder *coder_inst=warnmalloc(sizeof *coder_inst);
+ coder_inst->pack_temporary_bits=0;
+ return coder_inst;
+}
+
+void DECLSPECDLLEXPORT Ptngc_coder_deinit(struct coder *coder_inst)
+{
+ free(coder_inst);
+}
+
+TNG_INLINE void DECLSPECDLLEXPORT Ptngc_out8bits(struct coder *coder_inst, unsigned char **output)
+{
+ int pack_temporary_bits=coder_inst->pack_temporary_bits;
+ unsigned int pack_temporary=coder_inst->pack_temporary;
+ while (pack_temporary_bits>=8)
+ {
+ unsigned int mask=~(0xFFU<<(pack_temporary_bits-8));
+ unsigned char out=(unsigned char)(pack_temporary>>(pack_temporary_bits-8));
+ **output=out;
+ (*output)++;
+ pack_temporary_bits-=8;
+ pack_temporary&=mask;
+ }
+ coder_inst->pack_temporary_bits=pack_temporary_bits;
+ coder_inst->pack_temporary=pack_temporary;
+}
+
+void DECLSPECDLLEXPORT Ptngc_write_pattern(struct coder *coder_inst, unsigned int pattern,
+ int nbits, unsigned char **output)
+{
+ unsigned int mask1,mask2;
+ mask1=1;
+ mask2=1<<(nbits-1);
+ coder_inst->pack_temporary<<=nbits; /* Make room for new data. */
+ coder_inst->pack_temporary_bits+=nbits;
+ while (nbits)
+ {
+ if (pattern & mask1)
+ coder_inst->pack_temporary|=mask2;
+ nbits--;
+ mask1<<=1;
+ mask2>>=1;
+ }
+ Ptngc_out8bits(coder_inst,output);
+}
+
+/* Write up to 24 bits */
+TNG_INLINE void DECLSPECDLLEXPORT Ptngc_writebits(struct coder *coder_inst,
+ unsigned int value, int nbits,
+ unsigned char **output_ptr)
+{
+ /* Make room for the bits. */
+ coder_inst->pack_temporary<<=nbits;
+ coder_inst->pack_temporary_bits+=nbits;
+ coder_inst->pack_temporary|=value;
+ Ptngc_out8bits(coder_inst,output_ptr);
+}
+
+/* Write up to 32 bits */
+void DECLSPECDLLEXPORT Ptngc_write32bits(struct coder *coder_inst,unsigned int value,
+ int nbits, unsigned char **output_ptr)
+{
+ unsigned int mask;
+ if (nbits>=8)
+ mask=0xFFU<<(nbits-8);
+ else
+ mask=0xFFU>>(8-nbits);
+ while (nbits>8)
+ {
+ /* Make room for the bits. */
+ coder_inst->pack_temporary<<=8;
+ coder_inst->pack_temporary_bits+=8;
+ coder_inst->pack_temporary|=(value&mask)>>(nbits-8);
+ Ptngc_out8bits(coder_inst,output_ptr);
+ nbits-=8;
+ mask>>=8;
+ }
+ if (nbits)
+ Ptngc_writebits(coder_inst,value&mask,nbits,output_ptr);
+}
+
+/* Write "arbitrary" number of bits */
+void DECLSPECDLLEXPORT Ptngc_writemanybits(struct coder *coder_inst, unsigned char *value,
+ int nbits, unsigned char **output_ptr)
+{
+ int vptr=0;
+ while (nbits>=24)
+ {
+ unsigned int v=((((unsigned int)value[vptr])<<16)|
+ (((unsigned int)value[vptr+1])<<8)|
+ (((unsigned int)value[vptr+2])));
+ Ptngc_writebits(coder_inst,v,24,output_ptr);
+ vptr+=3;
+ nbits-=24;
+ }
+ while (nbits>=8)
+ {
+ Ptngc_writebits(coder_inst,(unsigned int)value[vptr],8,output_ptr);
+ vptr++;
+ nbits-=8;
+ }
+ if (nbits)
+ {
+ Ptngc_writebits(coder_inst,(unsigned int)value[vptr],nbits,output_ptr);
+ }
+}
+
+static int write_stop_bit_code(struct coder *coder_inst, unsigned int s,
+ unsigned int coding_parameter,
+ unsigned char **output)
+{
+ do {
+ unsigned int extract=~(0xffffffffU<<coding_parameter);
+ unsigned int this=(s&extract)<<1;
+ s>>=coding_parameter;
+ if (s)
+ {
+ this|=1U;
+ coder_inst->stat_overflow++;
+ }
+ coder_inst->pack_temporary<<=(coding_parameter+1);
+ coder_inst->pack_temporary_bits+=coding_parameter+1;
+ coder_inst->pack_temporary|=this;
+ Ptngc_out8bits(coder_inst,output);
+ if (s)
+ {
+ coding_parameter>>=1;
+ if (coding_parameter<1)
+ coding_parameter=1;
+ }
+ } while (s);
+ coder_inst->stat_numval++;
+ return 0;
+}
+
+static int pack_stopbits_item(struct coder *coder_inst,int item,
+ unsigned char **output, int coding_parameter)
+{
+ /* Find this symbol in table. */
+ int s=0;
+ if (item>0)
+ s=1+(item-1)*2;
+ else if (item<0)
+ s=2+(-item-1)*2;
+ return write_stop_bit_code(coder_inst,s,coding_parameter,output);
+}
+
+static int pack_triplet(struct coder *coder_inst, unsigned int *s,
+ unsigned char **output, int coding_parameter,
+ unsigned int max_base, int maxbits)
+{
+ /* Determine base for this triplet. */
+ unsigned int min_base=1U<<coding_parameter;
+ unsigned int this_base=min_base;
+ int i;
+ unsigned int jbase=0;
+ unsigned int bits_per_value;
+ for (i=0; i<3; i++)
+ while (s[i]>=this_base)
+ {
+ this_base*=2;
+ jbase++;
+ }
+ bits_per_value=coding_parameter+jbase;
+ if (jbase>=3)
+ {
+ if (this_base>max_base)
+ return 1;
+ bits_per_value=maxbits;
+ jbase=3;
+ }
+ /* 2 bits selects the base */
+ coder_inst->pack_temporary<<=2;
+ coder_inst->pack_temporary_bits+=2;
+ coder_inst->pack_temporary|=jbase;
+ Ptngc_out8bits(coder_inst,output);
+ for (i=0; i<3; i++)
+ Ptngc_write32bits(coder_inst,s[i],bits_per_value,output);
+ return 0;
+}
+
+void DECLSPECDLLEXPORT Ptngc_pack_flush(struct coder *coder_inst,unsigned char **output)
+{
+ /* Zero-fill just enough. */
+ if (coder_inst->pack_temporary_bits>0)
+ Ptngc_write_pattern(coder_inst,0,8-coder_inst->pack_temporary_bits,output);
+}
+
+unsigned char DECLSPECDLLEXPORT *Ptngc_pack_array(struct coder *coder_inst,
+ int *input, int *length, int coding,
+ int coding_parameter, int natoms, int speed)
+{
+ if ((coding==TNG_COMPRESS_ALGO_BWLZH1) || (coding==TNG_COMPRESS_ALGO_BWLZH2))
+ {
+ unsigned char *output=warnmalloc(4+bwlzh_get_buflen(*length));
+ int i,j,k,n=*length;
+ unsigned int *pval=warnmalloc(n*sizeof *pval);
+ int nframes=n/natoms/3;
+ int cnt=0;
+ int most_negative=2147483647;
+ for (i=0; i<n; i++)
+ if (input[i]<most_negative)
+ most_negative=input[i];
+ most_negative=-most_negative;
+ output[0]=((unsigned int)most_negative)&0xFFU;
+ output[1]=(((unsigned int)most_negative)>>8)&0xFFU;
+ output[2]=(((unsigned int)most_negative)>>16)&0xFFU;
+ output[3]=(((unsigned int)most_negative)>>24)&0xFFU;
+ for (i=0; i<natoms; i++)
+ for (j=0; j<3; j++)
+ for (k=0; k<nframes; k++)
+ {
+ int item=input[k*3*natoms+i*3+j];
+ pval[cnt++]=(unsigned int)(item+most_negative);
+
+ }
+ if (speed>=5)
+ bwlzh_compress(pval,n,output+4,length);
+ else
+ bwlzh_compress_no_lz77(pval,n,output+4,length);
+ (*length)+=4;
+ free(pval);
+ return output;
+ }
+ else if (coding==TNG_COMPRESS_ALGO_POS_XTC3)
+ return Ptngc_pack_array_xtc3(input,length,natoms,speed);
+ else if (coding==TNG_COMPRESS_ALGO_POS_XTC2)
+ return Ptngc_pack_array_xtc2(coder_inst,input,length);
+ else
+ {
+ unsigned char *output=NULL;
+ unsigned char *output_ptr=NULL;
+ int i;
+ int output_length=0;
+
+ coder_inst->stat_numval=0;
+ coder_inst->stat_overflow=0;
+ /* Allocate enough memory for output */
+ output=warnmalloc(8* *length*sizeof *output);
+ output_ptr=output;
+ if ((coding==TNG_COMPRESS_ALGO_TRIPLET) ||
+ (coding==TNG_COMPRESS_ALGO_POS_TRIPLET_INTRA) ||
+ (coding==TNG_COMPRESS_ALGO_POS_TRIPLET_ONETOONE))
+ {
+ /* Pack triplets. */
+ int ntriplets=*length/3;
+ /* Determine max base and maxbits */
+ unsigned int max_base=1U<<coding_parameter;
+ unsigned int maxbits=coding_parameter;
+ unsigned int intmax=0;
+ for (i=0; i<*length; i++)
+ {
+ int item=input[i];
+ unsigned int s=0;
+ if (item>0)
+ s=1+(item-1)*2;
+ else if (item<0)
+ s=2+(-item-1)*2;
+ if (s>intmax)
+ intmax=s;
+ }
+ /* Store intmax */
+ coder_inst->pack_temporary_bits=32;
+ coder_inst->pack_temporary=intmax;
+ Ptngc_out8bits(coder_inst,&output_ptr);
+ while (intmax>=max_base)
+ {
+ max_base*=2;
+ maxbits++;
+ }
+ for (i=0; i<ntriplets; i++)
+ {
+ int j;
+ unsigned int s[3];
+ for (j=0; j<3; j++)
+ {
+ int item=input[i*3+j];
+ /* Find this symbol in table. */
+ s[j]=0;
+ if (item>0)
+ s[j]=1+(item-1)*2;
+ else if (item<0)
+ s[j]=2+(-item-1)*2;
+ }
+ if (pack_triplet(coder_inst, s, &output_ptr,
+ coding_parameter, max_base,maxbits))
+ {
+ free(output);
+ return NULL;
+ }
+ }
+ }
+ else
+ for (i=0; i<*length; i++)
+ if (pack_stopbits_item(coder_inst,input[i],&output_ptr,coding_parameter))
+ {
+ free(output);
+ return NULL;
+ }
+ Ptngc_pack_flush(coder_inst,&output_ptr);
+ output_length=(int)(output_ptr-output);
+ *length=output_length;
+ return output;
+ }
+}
+
+static int unpack_array_stop_bits(struct coder *coder_inst,
+ unsigned char *packed,int *output,
+ int length, int coding_parameter)
+{
+ int i,j;
+ unsigned int extract_mask=0x80;
+ unsigned char *ptr=packed;
+ (void) coder_inst;
+ for (i=0; i<length; i++)
+ {
+ unsigned int pattern=0;
+ int numbits=coding_parameter;
+ unsigned int bit;
+ int s;
+ unsigned int insert_mask=1U<<(numbits-1);
+ int inserted_bits=numbits;
+ do {
+ for (j=0; j<numbits; j++)
+ {
+ bit=*ptr & extract_mask;
+ if (bit)
+ pattern|=insert_mask;
+ insert_mask>>=1;
+ extract_mask>>=1;
+ if (!extract_mask)
+ {
+ extract_mask=0x80;
+ ptr++;
+ }
+ }
+ /* Check stop bit */
+ bit=*ptr & extract_mask;
+ extract_mask>>=1;
+ if (!extract_mask)
+ {
+ extract_mask=0x80;
+ ptr++;
+ }
+ if (bit)
+ {
+ numbits>>=1;
+ if (numbits<1)
+ numbits=1;
+ inserted_bits+=numbits;
+ insert_mask=1U<<(inserted_bits-1);
+ }
+ } while (bit);
+ s=(pattern+1)/2;
+ if ((pattern%2)==0)
+ s=-s;
+ output[i]=s;
+ }
+ return 0;
+}
+
+static int unpack_array_triplet(struct coder *coder_inst,
+ unsigned char *packed, int *output,
+ int length, int coding_parameter)
+{
+ int i,j;
+ unsigned int extract_mask=0x80;
+ unsigned char *ptr=packed;
+ /* Determine max base and maxbits */
+ unsigned int max_base=1U<<coding_parameter;
+ unsigned int maxbits=coding_parameter;
+ unsigned int intmax;
+ /* Get intmax */
+ (void) coder_inst;
+ intmax=((unsigned int)ptr[0])<<24|
+ ((unsigned int)ptr[1])<<16|
+ ((unsigned int)ptr[2])<<8|
+ ((unsigned int)ptr[3]);
+ ptr+=4;
+ while (intmax>=max_base)
+ {
+ max_base*=2;
+ maxbits++;
+ }
+ length/=3;
+ for (i=0; i<length; i++)
+ {
+ /* Find base */
+ unsigned int jbase=0;
+ unsigned int numbits;
+ unsigned int bit;
+ for (j=0; j<2; j++)
+ {
+ bit=*ptr & extract_mask;
+ jbase<<=1;
+ if (bit)
+ jbase|=1U;
+ extract_mask>>=1;
+ if (!extract_mask)
+ {
+ extract_mask=0x80;
+ ptr++;
+ }
+ }
+ if (jbase==3)
+ numbits=maxbits;
+ else
+ numbits=coding_parameter+jbase;
+ for (j=0; j<3; j++)
+ {
+ int s;
+ unsigned int jbit;
+ unsigned int pattern=0;
+ for (jbit=0; jbit<numbits; jbit++)
+ {
+ bit=*ptr & extract_mask;
+ pattern<<=1;
+ if (bit)
+ pattern|=1U;
+ extract_mask>>=1;
+ if (!extract_mask)
+ {
+ extract_mask=0x80;
+ ptr++;
+ }
+ }
+ s=(pattern+1)/2;
+ if ((pattern%2)==0)
+ s=-s;
+ output[i*3+j]=s;
+ }
+ }
+ return 0;
+}
+
+static int unpack_array_bwlzh(struct coder *coder_inst,
+ unsigned char *packed, int *output,
+ int length, int natoms)
+{
+ int i,j,k,n=length;
+ unsigned int *pval=warnmalloc(n*sizeof *pval);
+ int nframes=n/natoms/3;
+ int cnt=0;
+ int most_negative=(int)(((unsigned int)packed[0]) |
+ (((unsigned int)packed[1])<<8) |
+ (((unsigned int)packed[2])<<16) |
+ (((unsigned int)packed[3])<<24));
+ (void) coder_inst;
+ bwlzh_decompress(packed+4,length,pval);
+ for (i=0; i<natoms; i++)
+ for (j=0; j<3; j++)
+ for (k=0; k<nframes; k++)
+ {
+ unsigned int s=pval[cnt++];
+ output[k*3*natoms+i*3+j]=(int)s-most_negative;
+ }
+ free(pval);
+ return 0;
+}
+
+int DECLSPECDLLEXPORT Ptngc_unpack_array(struct coder *coder_inst,
+ unsigned char *packed, int *output,
+ int length, int coding, int coding_parameter,
+ int natoms)
+{
+ if ((coding==TNG_COMPRESS_ALGO_STOPBIT) ||
+ (coding==TNG_COMPRESS_ALGO_VEL_STOPBIT_INTER))
+ return unpack_array_stop_bits(coder_inst, packed, output, length, coding_parameter);
+ else if ((coding==TNG_COMPRESS_ALGO_TRIPLET) ||
+ (coding==TNG_COMPRESS_ALGO_POS_TRIPLET_INTRA) ||
+ (coding==TNG_COMPRESS_ALGO_POS_TRIPLET_ONETOONE))
+ return unpack_array_triplet(coder_inst, packed, output, length, coding_parameter);
+ else if (coding==TNG_COMPRESS_ALGO_POS_XTC2)
+ return Ptngc_unpack_array_xtc2(coder_inst, packed, output, length);
+ else if ((coding==TNG_COMPRESS_ALGO_BWLZH1) || (coding==TNG_COMPRESS_ALGO_BWLZH2))
+ return unpack_array_bwlzh(coder_inst, packed, output, length,natoms);
+ else if (coding==TNG_COMPRESS_ALGO_POS_XTC3)
+ return Ptngc_unpack_array_xtc3(packed, output, length,natoms);
+ return 1;
+}
+
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#include <string.h>
+#include "../../include/compression/dict.h"
+
+void Ptngc_comp_canonical_dict(unsigned int *dict, int *ndict)
+{
+ int i;
+ for (i=0; i<0x20004; i++)
+ dict[i]=i;
+ *ndict=0x20004;
+}
+
+void Ptngc_comp_make_dict_hist(unsigned int *vals, int nvals,
+ unsigned int *dict, int *ndict,
+ unsigned int *hist)
+{
+ int i;
+ int j=0;
+ for (i=0; i<0x20004; i++)
+ hist[i]=0;
+ for (i=0; i<0x20004; i++)
+ dict[i]=i;
+ for (i=0; i<nvals; i++)
+ hist[vals[i]]++;
+ for (i=0; i<0x20004; i++)
+ if (hist[i]!=0)
+ {
+ hist[j]=hist[i];
+ dict[j]=dict[i];
+ j++;
+ }
+ *ndict=j;
+}
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include "../../include/compression/fixpoint.h"
+
+#define MAX32BIT 4294967295UL
+#define MAX31BIT 2147483647UL
+#define SIGN32BIT 2147483648UL
+
+/* Conversion routines from / to double precision */
+
+/* Positive double to 32 bit fixed point value */
+fix_t Ptngc_ud_to_fix_t(double d,double max)
+{
+ fix_t val;
+ if (d<0.)
+ d=0.;
+ if (d>max)
+ d=max;
+ val=(fix_t)(MAX32BIT*(d/max));
+ if (val>MAX32BIT)
+ val=MAX32BIT;
+ return val;
+}
+
+/* double to signed 32 bit fixed point value */
+fix_t Ptngc_d_to_fix_t(double d,double max)
+{
+ fix_t val;
+ int sign=0;
+ if (d<0.)
+ {
+ sign=1;
+ d=-d;
+ }
+ if (d>max)
+ d=max;
+ val=(fix_t)(MAX31BIT*(d/max));
+ if (val>MAX31BIT)
+ val=MAX31BIT;
+ if (sign)
+ val|=SIGN32BIT;
+ return val;
+}
+
+
+/* 32 bit fixed point value to positive double */
+double Ptngc_fix_t_to_ud(fix_t f, double max)
+{
+ return (double)f*(max/MAX32BIT);
+}
+
+/* signed 32 bit fixed point value to double */
+double Ptngc_fix_t_to_d(fix_t f, double max)
+{
+ int sign=0;
+ double d;
+ if (f&SIGN32BIT)
+ {
+ sign=1;
+ f&=MAX31BIT;
+ }
+ d=(double)f*(max/MAX31BIT);
+ if (sign)
+ d=-d;
+ return d;
+}
+
+
+/* Convert a floating point variable to two 32 bit integers with range
+ -2.1e9 to 2.1e9 and precision to somewhere around 1e-9. */
+void Ptngc_d_to_i32x2(double d, fix_t *hi, fix_t *lo)
+{
+ int sign=0;
+ double frac;
+ double ent;
+ fix_t val,vallo;
+ if (d<0.)
+ {
+ sign=1;
+ d=-d;
+ }
+ /* First the integer part */
+ ent=floor(d);
+ /* Then the fractional part */
+ frac=d-ent;
+
+ val=(fix_t)ent;
+ if (sign)
+ val|=SIGN32BIT;
+
+ vallo=Ptngc_ud_to_fix_t(frac,1.);
+
+ *hi=val;
+ *lo=vallo;
+}
+
+/* Convert two 32 bit integers to a floating point variable
+ -2.1e9 to 2.1e9 and precision to somewhere around 1e-9. */
+double Ptngc_i32x2_to_d(fix_t hi, fix_t lo)
+{
+ double ent,frac=0.;
+ double val=0.;
+ int sign=0;
+ if (hi&SIGN32BIT)
+ {
+ sign=1;
+ hi&=MAX31BIT;
+ }
+ ent=(double)hi;
+ frac=Ptngc_fix_t_to_ud(lo,1.);
+ val=ent+frac;
+ if (sign)
+ val=-val;
+ return val;
+}
+
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "../../include/compression/warnmalloc.h"
+#include "../../include/compression/merge_sort.h"
+#include "../../include/compression/huffman.h"
+
+#define MAX_HUFFMAN_LEN 31
+
+enum htree_type { htree_leaf, htree_node };
+
+struct htree_leaf
+{
+ enum htree_type nodeleaf;
+ unsigned int idict; /* Index into input dictionary */
+ unsigned int prob;
+ unsigned int bit; /* One or zero */
+};
+
+struct htree_node
+{
+ enum htree_type nodeleaf;
+ union htree_nodeleaf *n1;
+ union htree_nodeleaf *n2;
+ unsigned int bit; /* One or zero */
+ unsigned int prob;
+};
+
+union htree_nodeleaf
+{
+ enum htree_type nodeleaf;
+ struct htree_node node;
+ struct htree_leaf leaf;
+};
+
+struct codelength
+{
+ unsigned int code;
+ int length;
+ unsigned int dict;
+ unsigned int prob;
+};
+
+static int comp_htree(const void *leafptr1, const void *leafptr2, const void *private)
+{
+ const union htree_nodeleaf *leaf1=(union htree_nodeleaf *)leafptr1;
+ const union htree_nodeleaf *leaf2=(union htree_nodeleaf *)leafptr2;
+ int rval=0;
+ (void)private;
+
+ if (leaf1->leaf.prob<leaf2->leaf.prob)
+ rval=1;
+ else if (leaf1->leaf.prob>leaf2->leaf.prob)
+ rval=-1;
+ return rval;
+}
+
+static void assign_codes(union htree_nodeleaf *htree,
+ struct codelength *codelength,
+ unsigned int code,
+ int length,
+ int top)
+{
+#if 0
+ printf("Assign codes called with code %d length %d\n",code,length);
+#endif
+ if (htree->nodeleaf==htree_leaf)
+ {
+ codelength[htree->leaf.idict].length=length+1;
+ codelength[htree->leaf.idict].code=(code<<1)|htree->leaf.bit;
+#if 0
+ printf("I am a leaf: %d %d\n",
+ codelength[htree->leaf.idict].length,
+ codelength[htree->leaf.idict].code);
+#endif
+ }
+ else
+ {
+ if (!top)
+ {
+ code<<=1;
+ code|=htree->node.bit;
+ length++;
+ }
+#if 0
+ printf("I am a node length: %d\n",length);
+ printf("I am a node code: %d\n",code);
+#endif
+ assign_codes(htree->node.n1,codelength,code,length,0);
+ assign_codes(htree->node.n2,codelength,code,length,0);
+ }
+}
+
+static void free_nodes(union htree_nodeleaf *htree, int top)
+{
+ if (htree->nodeleaf==htree_leaf)
+ {
+ if (!top)
+ free(htree);
+ }
+ else
+ {
+ free_nodes(htree->node.n1,0);
+ free_nodes(htree->node.n2,0);
+ if (!top)
+ free(htree);
+ }
+}
+
+static void flush_8bits(unsigned int *combine, unsigned char **output, int *bitptr)
+{
+ while ((*bitptr)>=8)
+ {
+ unsigned int mask=~(0xFFU<<((*bitptr)-8));
+ unsigned char out=(unsigned char)((*combine)>>((*bitptr)-8));
+ **output=out;
+ (*output)++;
+ (*bitptr)-=8;
+ (*combine)&=mask;
+ }
+}
+
+static void writebits(unsigned int value,int length, unsigned char **output, int *bitptr)
+{
+ unsigned int mask;
+ unsigned int combine=(unsigned int)**output;
+ if (length>=8)
+ mask=0xFFU<<(length-8);
+ else
+ mask=0xFFU>>(8-length);
+ while (length>8)
+ {
+ /* Make room for the bits. */
+ combine<<=8;
+ (*bitptr)+=8;
+ combine|=(value&mask)>>(length-8);
+ flush_8bits(&combine,output,bitptr);
+ length-=8;
+ mask>>=8;
+ }
+ if (length)
+ {
+ /* Make room for the bits. */
+ combine<<=length;
+ (*bitptr)+=length;
+ combine|=value;
+ flush_8bits(&combine,output,bitptr);
+ }
+ **output=(unsigned char)combine;
+}
+
+static unsigned int readbits(int length, unsigned char **input, int *bitptr)
+{
+ unsigned int val=0U;
+ unsigned int extract_mask=0x80U>>*bitptr;
+ unsigned char thisval=**input;
+ while (length--)
+ {
+ val<<=1;
+ val|=((extract_mask & thisval)!=0);
+ *bitptr=(*bitptr)+1;
+ extract_mask>>=1;
+ if (!extract_mask)
+ {
+ extract_mask=0x80U;
+ *input=(*input)+1;
+ *bitptr=0;
+ thisval=**input;
+ }
+ }
+ return val;
+}
+
+static int comp_codes(const void *codeptr1, const void *codeptr2, const void *private)
+{
+ const struct codelength *code1=(struct codelength *)codeptr1;
+ const struct codelength *code2=(struct codelength *)codeptr2;
+ int rval=0; /* It shouldn't be possible to get equal here, though. */
+ (void)private;
+ if (code1->length>code2->length)
+ rval=1;
+ else if (code1->length<code2->length)
+ rval=-1;
+ else if (code1->dict>code2->dict)
+ rval=1;
+ else
+ rval=-1;
+ return rval;
+}
+
+static int comp_codes_value(const void *codeptr1, const void *codeptr2, const void *private)
+{
+ const struct codelength *code1=(struct codelength *)codeptr1;
+ const struct codelength *code2=(struct codelength *)codeptr2;
+
+ int rval=0; /* It shouldn't be possible to get equal here, though. */
+ (void)private;
+ if (code1->dict>code2->dict)
+ rval=1;
+ else
+ rval=-1;
+ return rval;
+}
+
+/* The huffman_dict array should be 131077 (0x20005) long. The
+huffman_dict_unpacked array should be 131077 long (note five longer than
+0x20000) */
+void Ptngc_comp_conv_to_huffman(unsigned int *vals, int nvals,
+ unsigned int *dict, int ndict,
+ unsigned int *prob,
+ unsigned char *huffman,
+ int *huffman_len,
+ unsigned char *huffman_dict,
+ int *huffman_dictlen,
+ unsigned int *huffman_dict_unpacked,
+ int *huffman_dict_unpackedlen)
+{
+ int i;
+ int nleft;
+ union htree_nodeleaf *htree;
+ struct codelength *codelength;
+ int bitptr;
+ unsigned char *huffman_ptr;
+ int code;
+ int longcodes=1;
+ while (longcodes)
+ {
+ /* Create array of leafs (will be array of nodes/trees during
+ buildup of tree. */
+ htree=warnmalloc(ndict*sizeof *htree);
+ codelength=warnmalloc(ndict*sizeof *codelength);
+ bitptr=0;
+ huffman_ptr=huffman;
+ for (i=0; i<ndict; i++)
+ {
+ htree[i].nodeleaf=htree_leaf;
+ htree[i].leaf.idict=i;
+ htree[i].leaf.prob=prob[i];
+ }
+ /* Sort the leafs wrt probability. */
+ Ptngc_merge_sort(htree,ndict,sizeof *htree,comp_htree,NULL);
+
+#if 0
+ for (i=0; i<ndict; i++)
+ {
+ printf("%d %d\n",dict[htree[i].leaf.idict],htree[i].leaf.prob);
+ }
+#endif
+
+ /* Build tree. */
+ if (ndict==1)
+ {
+ codelength[0].code=1;
+ codelength[0].length=1;
+ }
+ else
+ {
+ /* Nodes and leafs left. */
+ nleft=ndict;
+
+ /* Take the two least probable symbols (which are at the end of the
+ array and combine them until there is nothing left. */
+ while (nleft>1)
+ {
+ union htree_nodeleaf *n1=warnmalloc(sizeof *n1);
+ union htree_nodeleaf *n2=warnmalloc(sizeof *n2);
+ int new_place;
+ int p1,p2, new_prob;
+ *n1=htree[nleft-1];
+ *n2=htree[nleft-2];
+ if (n1->nodeleaf==htree_leaf)
+ {
+ p1=n1->leaf.prob;
+ n1->leaf.bit=0;
+ }
+ else
+ {
+ p1=n1->node.prob;
+ n1->node.bit=0;
+ }
+ if (n2->nodeleaf==htree_leaf)
+ {
+ p2=n2->leaf.prob;
+ n2->leaf.bit=1;
+ }
+ else
+ {
+ p2=n2->node.prob;
+ n2->node.bit=1;
+ }
+ nleft--;
+ /* Create a new node */
+ htree[nleft-1].nodeleaf=htree_node;
+ htree[nleft-1].node.n1=n1;
+ htree[nleft-1].node.n2=n2;
+ new_prob=p1+p2;
+ htree[nleft-1].node.prob=new_prob;
+ /* Use insertion sort to place this in the correct place in the
+ array. */
+ /* Where should it be inserted? */
+ new_place=nleft;
+ while (new_place>0)
+ {
+ int pc;
+ if (htree[new_place-1].nodeleaf==htree_node)
+ pc=htree[new_place-1].node.prob;
+ else
+ pc=htree[new_place-1].leaf.prob;
+ if (new_prob<pc)
+ break;
+ else
+ new_place--;
+ }
+ if (new_place!=nleft)
+ {
+ /* Shift array (overlapping regions!) */
+ union htree_nodeleaf nodecopy=htree[nleft-1];
+ memmove(htree+new_place+1,
+ htree+new_place,
+ (nleft-1-new_place)*sizeof *htree);
+ htree[new_place]=nodecopy;
+ }
+ }
+ }
+ /* Create codes from tree */
+ assign_codes(htree,codelength,0,0,1);
+ /* Canonicalize */
+ /* First put values into to the codelength array for sorting. */
+ for (i=0; i<ndict; i++)
+ {
+ codelength[i].dict=dict[i];
+ codelength[i].prob=prob[i];
+ }
+ /* Sort codes wrt length/value */
+ Ptngc_merge_sort(codelength,ndict,sizeof *codelength,comp_codes,NULL);
+ /* Canonicalize codes. */
+ code=0;
+ for (i=0; i<ndict; i++)
+ {
+ codelength[i].code=code;
+ if (i<ndict-1)
+ code=(code+1)<<(codelength[i+1].length-codelength[i].length);
+ }
+ /* Free all nodes / leaves. */
+ free_nodes(htree,1);
+ /* Free array that held nodes/leaves. */
+ free(htree);
+
+ longcodes=0;
+ /* Check if there is a too long huffman code. */
+ for (i=0; i<ndict; i++)
+ if (codelength[i].length>MAX_HUFFMAN_LEN)
+ longcodes=1;
+
+ /* If the codes are too long alter the probabilities. */
+ if (longcodes)
+ {
+ for (i=0; i<ndict; i++)
+ {
+ prob[i]>>=1;
+ if (prob[i]==0)
+ prob[i]=1;
+ }
+
+ /* Free codelength. We will compute a new one. */
+ free(codelength);
+ }
+ }
+
+#if 0
+ {
+ for (i=0; i<ndict; i++)
+ {
+ printf("%d %d\t\t %d %d ",codelength[i].dict,codelength[i].prob,codelength[i].length,codelength[i].code);
+ {
+ unsigned int c=codelength[i].code;
+ int j;
+ unsigned int mask=1<<(codelength[i].length-1);
+ for (j=codelength[i].length-1; j>=0; j--)
+ {
+ int bit=c&mask;
+ if (bit)
+ printf("1");
+ else
+ printf("0");
+ mask>>=1;
+ }
+ printf("\n");
+ }
+ }
+ }
+#endif
+
+ /* Simply do compression by writing out the bits. */
+ for (i=0; i<nvals; i++)
+ {
+ int r;
+ for (r=0; r<ndict; r++)
+ if (codelength[r].dict==vals[i])
+ break;
+ writebits(codelength[r].code,codelength[r].length,&huffman_ptr,&bitptr);
+ }
+ if (bitptr)
+ writebits(0,8-bitptr,&huffman_ptr,&bitptr);
+ *huffman_len=(int)(huffman_ptr-huffman);
+ /* Output dictionary. */
+ /* First the largest symbol value is written in 16 bits. No bits are
+ encoded for symbols larger than this. Then one bit signifies if
+ there is a used symbol: 1 If unused entry: 0 If used symbol the 5
+ following bits encode the length of the symbol. Worst case is
+ thus 6*65538 bits used for the dictionary. That won't happen
+ unless there's really that many values in use. If that is so,
+ well, either we compress well, or we have many values anyway. */
+ /* First sort the dictionary wrt symbol */
+ Ptngc_merge_sort(codelength,ndict,sizeof *codelength,comp_codes_value,NULL);
+ bitptr=0;
+ huffman_ptr=huffman_dict;
+ *huffman_ptr++=(unsigned char)(codelength[ndict-1].dict&0xFFU);
+ *huffman_ptr++=(unsigned char)((codelength[ndict-1].dict>>8)&0xFFU);
+ *huffman_ptr++=(unsigned char)((codelength[ndict-1].dict>>16)&0xFFU);
+ huffman_dict_unpacked[0]=(unsigned char)(codelength[ndict-1].dict&0xFFU);
+ huffman_dict_unpacked[1]=(unsigned char)((codelength[ndict-1].dict>>8)&0xFFU);
+ huffman_dict_unpacked[2]=(unsigned char)((codelength[ndict-1].dict>>16)&0xFFU);
+ for (i=0; i<=(int)codelength[ndict-1].dict; i++)
+ {
+ /* Do I have this value? */
+ int ihave=0;
+ int j;
+ for (j=0; j<ndict; j++)
+ if (codelength[j].dict==(unsigned int)i)
+ {
+
+ ihave=1;
+ writebits(1,1,&huffman_ptr,&bitptr);
+ writebits(codelength[j].length,5,&huffman_ptr,&bitptr);
+ huffman_dict_unpacked[3+i]=codelength[j].length;
+ break;
+ }
+ if (!ihave)
+ {
+ writebits(0,1,&huffman_ptr,&bitptr);
+ huffman_dict_unpacked[3+i]=0;
+ }
+ }
+ if (bitptr)
+ writebits(0,8-bitptr,&huffman_ptr,&bitptr);
+ *huffman_dictlen=(int)(huffman_ptr-huffman_dict);
+ *huffman_dict_unpackedlen=3+codelength[ndict-1].dict+1;
+
+ /* Free info about codes and length. */
+ free(codelength);
+}
+
+void Ptngc_comp_conv_from_huffman(unsigned char *huffman,
+ unsigned int *vals, int nvals,
+ int ndict,
+ unsigned char *huffman_dict,
+ int huffman_dictlen,
+ unsigned int *huffman_dict_unpacked,
+ int huffman_dict_unpackedlen)
+{
+ struct codelength *codelength=warnmalloc(ndict*sizeof *codelength);
+ int i,j;
+ int maxdict;
+ int code;
+ unsigned char *huffman_ptr;
+ int bitptr;
+ (void)huffman_dictlen;
+ (void)huffman_dict_unpackedlen;
+ if (huffman_dict_unpacked)
+ {
+ maxdict=huffman_dict_unpacked[0]|(huffman_dict_unpacked[1]<<8)|(huffman_dict_unpacked[2]<<16);
+ j=0;
+ for(i=0; i<=maxdict; i++)
+ {
+ if (huffman_dict_unpacked[3+i]!=0)
+ {
+ codelength[j].length=huffman_dict_unpacked[3+i];
+ codelength[j].dict=i;
+#if 0
+ printf("%d %d\n",
+ codelength[j].length,
+ codelength[j].dict);
+#endif
+ j++;
+ }
+ }
+ }
+ else
+ {
+ huffman_ptr=huffman_dict;
+ maxdict=((unsigned int)huffman_ptr[0])|(((unsigned int)huffman_ptr[1])<<8)|(((unsigned int)huffman_ptr[2])<<16);
+ huffman_ptr+=3;
+ bitptr=0;
+ j=0;
+ for(i=0; i<=maxdict; i++)
+ {
+ int bit=readbits(1,&huffman_ptr,&bitptr);
+ if (bit)
+ {
+ codelength[j].length=readbits(5,&huffman_ptr,&bitptr);
+ codelength[j].dict=i;
+#if 0
+ printf("%d %d\n",
+ codelength[j].length,
+ codelength[j].dict);
+#endif
+ j++;
+ }
+ }
+ }
+ /* Sort codes wrt length/value. */
+ Ptngc_merge_sort(codelength,ndict,sizeof *codelength,comp_codes,NULL);
+ /* Canonicalize codes. */
+ code=0;
+ for (i=0; i<ndict; i++)
+ {
+ codelength[i].code=code;
+ if (i<ndict-1)
+ code=(code+1)<<(codelength[i+1].length-codelength[i].length);
+ }
+#if 0
+ {
+ for (i=0; i<ndict; i++)
+ {
+ printf("%d -\t\t %d %d ",codelength[i].dict,codelength[i].length,codelength[i].code);
+ {
+ unsigned int c=codelength[i].code;
+ int j;
+ unsigned int mask=1<<(codelength[i].length-1);
+ for (j=codelength[i].length-1; j>=0; j--)
+ {
+ int bit=c&mask;
+ if (bit)
+ printf("1");
+ else
+ printf("0");
+ mask>>=1;
+ }
+ printf("\n");
+ }
+ }
+ }
+#endif
+ /* Decompress data. */
+ huffman_ptr=huffman;
+ bitptr=0;
+ for (i=0; i<nvals; i++)
+ {
+ unsigned int symbol;
+ int len=codelength[0].length;
+ symbol=readbits(len,&huffman_ptr,&bitptr);
+ j=0;
+ while (symbol!=codelength[j].code)
+ {
+ int newlen;
+ j++;
+ newlen=codelength[j].length;
+ if (newlen!=len)
+ {
+ symbol<<=(newlen-len);
+ symbol|=readbits(newlen-len,&huffman_ptr,&bitptr);
+ len=newlen;
+ }
+ }
+ vals[i]=codelength[j].dict;
+ }
+ /* Free info about codes and length. */
+ free(codelength);
+}
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "../../include/compression/warnmalloc.h"
+#include "../../include/compression/tng_compress.h"
+#include "../../include/compression/bwlzh.h"
+#include "../../include/compression/huffman.h"
+#include "../../include/compression/dict.h"
+#include "../../include/compression/rle.h"
+#include "../../include/compression/vals16.h"
+
+int Ptngc_comp_huff_buflen(int nvals)
+{
+ return 132000+nvals*8;
+}
+
+/* the value pointed to by chosen_algo should be sent as -1 for autodetect. */
+void Ptngc_comp_huff_compress_verbose(unsigned int *vals, int nvals,
+ unsigned char *huffman, int *huffman_len,
+ int *huffdatalen,
+ int *huffman_lengths,int *chosen_algo,
+ int isvals16)
+{
+ unsigned int *dict=warnmalloc(0x20005*sizeof *dict);
+ unsigned int *hist=warnmalloc(0x20005*sizeof *hist);
+ unsigned int *vals16=NULL;
+ unsigned char *huffdict=warnmalloc(0x20005*sizeof *huffdict);
+ unsigned int *huffdictunpack=warnmalloc(0x20005*sizeof *huffdictunpack);
+ unsigned char *huffman1=warnmalloc(2*0x20005*sizeof *huffman1);
+ unsigned char *huffdict1=warnmalloc(0x20005*sizeof *huffdict1);
+ unsigned int *huffdictunpack1=warnmalloc(0x20005*sizeof *huffdictunpack1);
+ unsigned int *huffdictrle=warnmalloc((3*0x20005+3)*sizeof *huffdictrle);
+ unsigned char *huffman2=warnmalloc(6*0x20005*sizeof *huffman2);
+ unsigned char *huffdict2=warnmalloc(0x20005*sizeof *huffdict2);
+ unsigned int *huffdictunpack2=warnmalloc(0x20005*sizeof *huffdictunpack2);
+ int i;
+ int ndict,ndict1,ndict2;
+ int nhuff,nhuffdict,nhuffdictunpack;
+ int nhuff1,nhuffdict1,nhuffdictunpack1;
+ int nhuffrle,nhuff2,nhuffdict2,nhuffdictunpack2;
+ int nvals16;
+
+ /* Do I need to convert to vals16? */
+ if (!isvals16)
+ {
+ vals16=warnmalloc(nvals*3*sizeof *vals16);
+ Ptngc_comp_conv_to_vals16(vals,nvals,vals16,&nvals16);
+ nvals=nvals16;
+ vals=vals16;
+ }
+ else
+ nvals16=nvals;
+
+ /* Determine probabilities. */
+ Ptngc_comp_make_dict_hist(vals,nvals,dict,&ndict,hist);
+
+ /* First compress the data using huffman coding (place it ready for output at 14 (code for algorithm+length etc.). */
+ Ptngc_comp_conv_to_huffman(vals,nvals,dict,ndict,hist,
+ huffman+14,&nhuff,
+ huffdict,&nhuffdict,
+ huffdictunpack,&nhuffdictunpack);
+ *huffdatalen=nhuff;
+
+ /* Algorithm 0 stores the huffman dictionary directly (+ a code for
+ the algorithm) + lengths of the huffman buffer (4) and the huffman dictionary (3). */
+ huffman_lengths[0]=nhuff+nhuffdict+1*2+3*4+3+3;
+ /* Next we try to compress the huffman dictionary using huffman
+ coding ... (algorithm 1) */
+
+ /* Determine probabilities. */
+ Ptngc_comp_make_dict_hist(huffdictunpack,nhuffdictunpack,dict,&ndict1,hist);
+ /* Pack huffman dictionary */
+ Ptngc_comp_conv_to_huffman(huffdictunpack,nhuffdictunpack,
+ dict,ndict1,hist,
+ huffman1,&nhuff1,
+ huffdict1,&nhuffdict1,
+ huffdictunpack1,&nhuffdictunpack1);
+ huffman_lengths[1]=nhuff+nhuff1+nhuffdict1+1*2+3*4+3+3+3+3+3;
+
+ /* ... and rle + huffman coding ... (algorithm 2) Pack any repetetitive patterns. */
+ Ptngc_comp_conv_to_rle(huffdictunpack,nhuffdictunpack,
+ huffdictrle,&nhuffrle,1);
+
+ /* Determine probabilities. */
+ Ptngc_comp_make_dict_hist(huffdictrle,nhuffrle,dict,&ndict2,hist);
+ /* Pack huffman dictionary */
+ Ptngc_comp_conv_to_huffman(huffdictrle,nhuffrle,
+ dict,ndict2,hist,
+ huffman2,&nhuff2,
+ huffdict2,&nhuffdict2,
+ huffdictunpack2,&nhuffdictunpack2);
+ huffman_lengths[2]=nhuff+nhuff2+nhuffdict2+1*2+3*4+3+3+3+3+3+3;
+
+ /* Choose the best algorithm and output the data. */
+ if ((*chosen_algo==0) || ((*chosen_algo==-1) &&
+ (((huffman_lengths[0]<huffman_lengths[1]) &&
+ (huffman_lengths[0]<huffman_lengths[2])))))
+ {
+ *chosen_algo=0;
+ *huffman_len=huffman_lengths[0];
+ huffman[0]=isvals16;
+ huffman[1]=0;
+ huffman[2]=((unsigned int)nvals16)&0xFFU;
+ huffman[3]=(((unsigned int)nvals16)>>8)&0xFFU;
+ huffman[4]=(((unsigned int)nvals16)>>16)&0xFFU;
+ huffman[5]=(((unsigned int)nvals16)>>24)&0xFFU;
+ huffman[6]=((unsigned int)nvals)&0xFFU;
+ huffman[7]=(((unsigned int)nvals)>>8)&0xFFU;
+ huffman[8]=(((unsigned int)nvals)>>16)&0xFFU;
+ huffman[9]=(((unsigned int)nvals)>>24)&0xFFU;
+ huffman[10]=((unsigned int)nhuff)&0xFFU;
+ huffman[11]=(((unsigned int)nhuff)>>8)&0xFFU;
+ huffman[12]=(((unsigned int)nhuff)>>16)&0xFFU;
+ huffman[13]=(((unsigned int)nhuff)>>24)&0xFFU;
+ huffman[14+nhuff]=((unsigned int)nhuffdict)&0xFFU;
+ huffman[15+nhuff]=(((unsigned int)nhuffdict)>>8)&0xFFU;
+ huffman[16+nhuff]=(((unsigned int)nhuffdict)>>16)&0xFFU;
+ huffman[17+nhuff]=((unsigned int)ndict)&0xFFU;
+ huffman[18+nhuff]=(((unsigned int)ndict)>>8)&0xFFU;
+ huffman[19+nhuff]=(((unsigned int)ndict)>>16)&0xFFU;
+ for (i=0; i<nhuffdict; i++)
+ huffman[20+nhuff+i]=huffdict[i];
+ }
+ else if ((*chosen_algo==1) || ((*chosen_algo==-1) &&
+ ((huffman_lengths[1]<huffman_lengths[2]))))
+ {
+ *chosen_algo=1;
+ *huffman_len=huffman_lengths[1];
+ huffman[0]=isvals16;
+ huffman[1]=1;
+ huffman[2]=((unsigned int)nvals16)&0xFFU;
+ huffman[3]=(((unsigned int)nvals16)>>8)&0xFFU;
+ huffman[4]=(((unsigned int)nvals16)>>16)&0xFFU;
+ huffman[5]=(((unsigned int)nvals16)>>24)&0xFFU;
+ huffman[6]=((unsigned int)nvals)&0xFFU;
+ huffman[7]=(((unsigned int)nvals)>>8)&0xFFU;
+ huffman[8]=(((unsigned int)nvals)>>16)&0xFFU;
+ huffman[9]=(((unsigned int)nvals)>>24)&0xFFU;
+ huffman[10]=((unsigned int)nhuff)&0xFFU;
+ huffman[11]=(((unsigned int)nhuff)>>8)&0xFFU;
+ huffman[12]=(((unsigned int)nhuff)>>16)&0xFFU;
+ huffman[13]=(((unsigned int)nhuff)>>24)&0xFFU;
+ huffman[14+nhuff]=((unsigned int)nhuffdictunpack)&0xFFU;
+ huffman[15+nhuff]=(((unsigned int)nhuffdictunpack)>>8)&0xFFU;
+ huffman[16+nhuff]=(((unsigned int)nhuffdictunpack)>>16)&0xFFU;
+ huffman[17+nhuff]=((unsigned int)ndict)&0xFFU;
+ huffman[18+nhuff]=(((unsigned int)ndict)>>8)&0xFFU;
+ huffman[19+nhuff]=(((unsigned int)ndict)>>16)&0xFFU;
+ huffman[20+nhuff]=((unsigned int)nhuff1)&0xFFU;
+ huffman[21+nhuff]=(((unsigned int)nhuff1)>>8)&0xFFU;
+ huffman[22+nhuff]=(((unsigned int)nhuff1)>>16)&0xFFU;
+ huffman[23+nhuff]=((unsigned int)nhuffdict1)&0xFFU;
+ huffman[24+nhuff]=(((unsigned int)nhuffdict1)>>8)&0xFFU;
+ huffman[25+nhuff]=(((unsigned int)nhuffdict1)>>16)&0xFFU;
+ huffman[26+nhuff]=((unsigned int)ndict1)&0xFFU;
+ huffman[27+nhuff]=(((unsigned int)ndict1)>>8)&0xFFU;
+ huffman[28+nhuff]=(((unsigned int)ndict1)>>16)&0xFFU;
+ for (i=0; i<nhuff1; i++)
+ huffman[29+nhuff+i]=huffman1[i];
+ for (i=0; i<nhuffdict1; i++)
+ huffman[29+nhuff+nhuff1+i]=huffdict1[i];
+ }
+ else
+ {
+ *chosen_algo=2;
+ *huffman_len=huffman_lengths[2];
+ huffman[0]=isvals16;
+ huffman[1]=2;
+ huffman[2]=((unsigned int)nvals16)&0xFFU;
+ huffman[3]=(((unsigned int)nvals16)>>8)&0xFFU;
+ huffman[4]=(((unsigned int)nvals16)>>16)&0xFFU;
+ huffman[5]=(((unsigned int)nvals16)>>24)&0xFFU;
+ huffman[6]=((unsigned int)nvals)&0xFFU;
+ huffman[7]=(((unsigned int)nvals)>>8)&0xFFU;
+ huffman[8]=(((unsigned int)nvals)>>16)&0xFFU;
+ huffman[9]=(((unsigned int)nvals)>>24)&0xFFU;
+ huffman[10]=((unsigned int)nhuff)&0xFFU;
+ huffman[11]=(((unsigned int)nhuff)>>8)&0xFFU;
+ huffman[12]=(((unsigned int)nhuff)>>16)&0xFFU;
+ huffman[13]=(((unsigned int)nhuff)>>24)&0xFFU;
+ huffman[14+nhuff]=((unsigned int)nhuffdictunpack)&0xFFU;
+ huffman[15+nhuff]=(((unsigned int)nhuffdictunpack)>>8)&0xFFU;
+ huffman[16+nhuff]=(((unsigned int)nhuffdictunpack)>>16)&0xFFU;
+ huffman[17+nhuff]=((unsigned int)ndict)&0xFFU;
+ huffman[18+nhuff]=(((unsigned int)ndict)>>8)&0xFFU;
+ huffman[19+nhuff]=(((unsigned int)ndict)>>16)&0xFFU;
+ huffman[20+nhuff]=((unsigned int)nhuffrle)&0xFFU;
+ huffman[21+nhuff]=(((unsigned int)nhuffrle)>>8)&0xFFU;
+ huffman[22+nhuff]=(((unsigned int)nhuffrle)>>16)&0xFFU;
+ huffman[23+nhuff]=((unsigned int)nhuff2)&0xFFU;
+ huffman[24+nhuff]=(((unsigned int)nhuff2)>>8)&0xFFU;
+ huffman[25+nhuff]=(((unsigned int)nhuff2)>>16)&0xFFU;
+ huffman[26+nhuff]=((unsigned int)nhuffdict2)&0xFFU;
+ huffman[27+nhuff]=(((unsigned int)nhuffdict2)>>8)&0xFFU;
+ huffman[28+nhuff]=(((unsigned int)nhuffdict2)>>16)&0xFFU;
+ huffman[29+nhuff]=((unsigned int)ndict2)&0xFFU;
+ huffman[30+nhuff]=(((unsigned int)ndict2)>>8)&0xFFU;
+ huffman[31+nhuff]=(((unsigned int)ndict2)>>16)&0xFFU;
+ for (i=0; i<nhuff2; i++)
+ huffman[32+nhuff+i]=huffman2[i];
+ for (i=0; i<nhuffdict2; i++)
+ huffman[32+nhuff+nhuff2+i]=huffdict2[i];
+ }
+ if (!isvals16)
+ free(vals16);
+
+ free(huffdictunpack2);
+ free(huffdict2);
+ free(huffman2);
+ free(huffdictrle);
+ free(huffdictunpack1);
+ free(huffdict1);
+ free(huffman1);
+ free(huffdictunpack);
+ free(huffdict);
+ free(hist);
+ free(dict);
+}
+
+void Ptngc_comp_huff_compress(unsigned int *vals, int nvals,
+ unsigned char *huffman, int *huffman_len)
+{
+ int huffman_lengths[N_HUFFMAN_ALGO];
+ int algo=-1;
+ int huffdatalen;
+ Ptngc_comp_huff_compress_verbose(vals,nvals,huffman,huffman_len,&huffdatalen,
+ huffman_lengths,&algo,0);
+}
+
+void Ptngc_comp_huff_decompress(unsigned char *huffman, int huffman_len,
+ unsigned int *vals)
+{
+ int isvals16=(int)huffman[0];
+ unsigned int *vals16=NULL;
+ int algo=(int)huffman[1];
+ int nvals16=(int)((unsigned int)huffman[2]|
+ (((unsigned int)huffman[3])<<8)|
+ (((unsigned int)huffman[4])<<16)|
+ (((unsigned int)huffman[5])<<24));
+ int nvals=(int)((unsigned int)huffman[6]|
+ (((unsigned int)huffman[7])<<8)|
+ (((unsigned int)huffman[8])<<16)|
+ (((unsigned int)huffman[9])<<24));
+ int nhuff=(int)((unsigned int)huffman[10]|
+ (((unsigned int)huffman[11])<<8)|
+ (((unsigned int)huffman[12])<<16)|
+ (((unsigned int)huffman[13])<<24));
+ int ndict=(int)((unsigned int)huffman[17+nhuff]|
+ (((unsigned int)huffman[18+nhuff])<<8)|
+ (((unsigned int)huffman[19+nhuff])<<16));
+ (void)huffman_len;
+ if (!isvals16)
+ vals16=warnmalloc(nvals16*sizeof *vals16);
+ else
+ {
+ vals16=vals;
+ nvals16=nvals;
+ }
+ if (algo==0)
+ {
+ int nhuffdict=(int)((unsigned int)huffman[14+nhuff]|
+ (((unsigned int)huffman[15+nhuff])<<8)|
+ (((unsigned int)huffman[16+nhuff])<<16));
+ Ptngc_comp_conv_from_huffman(huffman+14,vals16,nvals16,ndict,
+ huffman+20+nhuff,nhuffdict,NULL,0);
+ }
+ else if (algo==1)
+ {
+ unsigned int *huffdictunpack=warnmalloc(0x20005*sizeof *huffdictunpack);
+ /* First the dictionary needs to be uncompressed. */
+ int nhuffdictunpack=(int)((unsigned int)huffman[14+nhuff]|
+ (((unsigned int)huffman[15+nhuff])<<8)|
+ (((unsigned int)huffman[16+nhuff])<<16));
+ int nhuff1=(int)((unsigned int)huffman[20+nhuff]|
+ (((unsigned int)huffman[21+nhuff])<<8)|
+ (((unsigned int)huffman[22+nhuff])<<16));
+ int nhuffdict1=(int)((unsigned int)huffman[23+nhuff]|
+ (((unsigned int)huffman[24+nhuff])<<8)|
+ (((unsigned int)huffman[25+nhuff])<<16));
+ int ndict1=(int)((unsigned int)huffman[26+nhuff]|
+ (((unsigned int)huffman[27+nhuff])<<8)|
+ (((unsigned int)huffman[28+nhuff])<<16));
+ Ptngc_comp_conv_from_huffman(huffman+29+nhuff,huffdictunpack,
+ nhuffdictunpack,ndict1,
+ huffman+29+nhuff+nhuff1,nhuffdict1,NULL,0);
+ /* Then decompress the "real" data. */
+ Ptngc_comp_conv_from_huffman(huffman+14,vals16,nvals16,ndict,
+ NULL,0,huffdictunpack,nhuffdictunpack);
+ free(huffdictunpack);
+ }
+ else if (algo==2)
+ {
+ unsigned int *huffdictunpack=warnmalloc(0x20005*sizeof *huffdictunpack);
+ unsigned int *huffdictrle=warnmalloc((3*0x20005+3)*sizeof *huffdictrle);
+ /* First the dictionary needs to be uncompressed. */
+ int nhuffdictunpack=(int)((unsigned int)huffman[14+nhuff]|
+ (((unsigned int)huffman[15+nhuff])<<8)|
+ (((unsigned int)huffman[16+nhuff])<<16));
+ int nhuffrle=(int)((unsigned int)huffman[20+nhuff]|
+ (((unsigned int)huffman[21+nhuff])<<8)|
+ (((unsigned int)huffman[22+nhuff])<<16));
+ int nhuff2=(int)((unsigned int)huffman[23+nhuff]|
+ (((unsigned int)huffman[24+nhuff])<<8)|
+ (((unsigned int)huffman[25+nhuff])<<16));
+ int nhuffdict2=(int)((unsigned int)huffman[26+nhuff]|
+ (((unsigned int)huffman[27+nhuff])<<8)|
+ (((unsigned int)huffman[28+nhuff])<<16));
+ int ndict2=(int)((unsigned int)huffman[29+nhuff]|
+ (((unsigned int)huffman[30+nhuff])<<8)|
+ (((unsigned int)huffman[31+nhuff])<<16));
+ Ptngc_comp_conv_from_huffman(huffman+32+nhuff,huffdictrle,
+ nhuffrle,ndict2,
+ huffman+32+nhuff+nhuff2,nhuffdict2,NULL,0);
+ /* Then uncompress the rle data */
+ Ptngc_comp_conv_from_rle(huffdictrle,huffdictunpack,nhuffdictunpack);
+ /* Then decompress the "real" data. */
+ Ptngc_comp_conv_from_huffman(huffman+14,vals16,nvals16,ndict,
+ NULL,0,huffdictunpack,nhuffdictunpack);
+ free(huffdictrle);
+ free(huffdictunpack);
+ }
+
+ /* Do I need to convert from vals16? */
+ if (!isvals16)
+ {
+ int nvalsx;
+ Ptngc_comp_conv_from_vals16(vals16,nvals16,vals,&nvalsx);
+ free(vals16);
+ }
+}
+
+static char *huff_algo_names[N_HUFFMAN_ALGO]=
+ {
+ "Huffman (dict=raw)",
+ "Huffman (dict=Huffman)",
+ "Huffman (dict=RLE+Huffman)"
+ };
+
+char *Ptngc_comp_get_huff_algo_name(int algo)
+{
+ if (algo<0)
+ return NULL;
+ else if (algo>=N_HUFFMAN_ALGO)
+ return NULL;
+ return huff_algo_names[algo];
+}
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "../../include/compression/warnmalloc.h"
+#include "../../include/compression/bwt.h"
+#include "../../include/compression/lz77.h"
+
+/* This is a simple Lempel-Ziv-77 compressor. It has not been set up
+ to remove every possible repeating pattern, but it might be better
+ than simple RLE.
+
+ Lempel-Ziv 77 with separate outputs for length, data, and offsets.
+ */
+
+#if 0
+/* Sort the strings (similar to BWT) to find similar patterns in the
+ input data. The output is an array with two values for each
+ input value. The sorted index value is the first in each doublet.
+ The second value is the "inverse" of the first value and can be
+ used to find the locations of similar strings. */
+static void sort_strings(unsigned int *vals, int nvals,
+ unsigned int *output)
+{
+ int i;
+ int *indices=warnmalloc(2*nvals*sizeof *indices);
+ unsigned int *nrepeat=warnmalloc(nvals*sizeof *nrepeat);
+ int *warr=indices+nvals;
+
+ if (nvals>0xFFFFFF)
+ {
+ fprintf(stderr,"BWT cannot pack more than %d values.\n",0xFFFFFF);
+ exit(1);
+ }
+
+ /* Also note that repeat pattern k (kmax) cannot be larger than 255. */
+ for (i=0; i<nvals; i++)
+ indices[i]=i;
+ /* Find the length of the initial repeating pattern for the strings. */
+ /* First mark that the index does not have a found repeating string. */
+ for (i=0; i<nvals; i++)
+ nrepeat[i]=0U;
+ for (i=0; i<nvals; i++)
+ {
+ /* If we have not already found a repeating string we must find
+ it. */
+ if (!nrepeat[i])
+ {
+ int maxrepeat=nvals*2;
+ int j,k,m;
+ int good_j=-1, good_k=0;
+ int kmax=16;
+ /* Track repeating patterns.
+ k=1 corresponds to AAAAA...
+ k=2 corresponds to ABABAB...
+ k=3 corresponds to ABCABCABCABC...
+ k=4 corresponds to ABCDABCDABCD...
+ etc. */
+ for (k=kmax; k>=1; k--)
+ {
+ try_next_k:
+ if (k>=1)
+ {
+ for (j=k; j<maxrepeat; j+=k)
+ {
+ int is_equal=1;
+ for (m=0; m<k; m++)
+ if (vals[(i+m)%nvals]!=vals[(i+j+m)%nvals])
+ {
+ is_equal=0;
+ break;
+ }
+ if (is_equal)
+ {
+ int new_j=j+k;
+ if (new_j>maxrepeat)
+ new_j=j;
+ if ((new_j>good_j) || ((new_j==good_j) && (k<good_k)))
+ {
+ good_j=new_j; /* We have found that
+ the strings repeat
+ for this length... */
+ good_k=k; /* ...and with this
+ length of the
+ repeating
+ pattern. */
+ }
+ }
+ else
+ {
+ /* We know that it is no point in trying
+ with more than m */
+ if (j==0)
+ {
+ k=m;
+ }
+ else
+ k--;
+ goto try_next_k;
+ }
+ }
+ }
+ }
+ /* From good_j and good_k we know the repeat for a large
+ number of strings. The very last repeat length should not
+ be assigned, since it can be much longer if a new test is
+ done. */
+ for (m=0; (m+good_k<good_j) && (i+m<nvals); m+=good_k)
+ {
+ int repeat=good_j-m;
+ if (repeat>nvals)
+ repeat=nvals;
+ nrepeat[i+m]=((unsigned int) (good_k)) | (((unsigned int) (repeat))<<8);
+ }
+ /* If no repetition was found for this value signal that here. */
+ if (!nrepeat[i])
+ nrepeat[i+m]=257U; /* This is 1<<8 | 1 */
+ }
+ }
+
+ /* Sort cyclic shift matrix. */
+ Ptngc_bwt_merge_sort_inner(indices,nvals,vals,0,nvals,nrepeat,warr);
+
+ /* Form output. */
+ for (i=0; i<nvals; i++)
+ {
+ output[i*2]=indices[i];
+ output[indices[i]*2+1]=i;
+ }
+ free(nrepeat);
+ free(indices);
+}
+#endif
+
+#define NUM_PREVIOUS 4
+#define MAX_LEN 0xFFFF
+#define MAX_OFFSET 0xFFFF
+#define MAX_STRING_SEARCH 8
+
+static void add_circular(int *previous,int v, int i)
+{
+ if (previous[(NUM_PREVIOUS+3)*v+2]!=i-1)
+ {
+ previous[(NUM_PREVIOUS+3)*v]++;
+ if (previous[(NUM_PREVIOUS+3)*v]>NUM_PREVIOUS)
+ previous[(NUM_PREVIOUS+3)*v]=NUM_PREVIOUS;
+ previous[(NUM_PREVIOUS+3)*v+3+previous[(NUM_PREVIOUS+3)*v+1]]=i;
+ previous[(NUM_PREVIOUS+3)*v+1]++;
+ if (previous[(NUM_PREVIOUS+3)*v+1]>=NUM_PREVIOUS)
+ previous[(NUM_PREVIOUS+3)*v+1]=0;
+ }
+ previous[(NUM_PREVIOUS+3)*v+2]=i;
+}
+
+void Ptngc_comp_to_lz77(unsigned int *vals, int nvals,
+ unsigned int *data, int *ndata,
+ unsigned int *len, int *nlens,
+ unsigned int *offsets, int *noffsets)
+{
+ int noff=0;
+ int ndat=0;
+ int nlen=0;
+ int i,j;
+ int *previous=warnmalloc(0x20000*(NUM_PREVIOUS+3)*sizeof *previous);
+#if 0
+ unsigned int *info=warnmalloc(2*nvals*sizeof *info);
+ sort_strings(vals,nvals,info);
+#endif
+ for (i=0; i<0x20000; i++)
+ {
+ previous[(NUM_PREVIOUS+3)*i]=0; /* Number of items in a circular buffer */
+ previous[(NUM_PREVIOUS+3)*i+1]=0; /* Pointer to beginning of circular buffer. */
+ previous[(NUM_PREVIOUS+3)*i+2]=-2; /* Last offset that had this value. -2 is really never... */
+ }
+ for (i=0; i<nvals; i++)
+ {
+ int k;
+#if 0
+ int kmin,kmax;
+#endif
+ int firstoffset=i-MAX_OFFSET;
+ if (firstoffset<0)
+ firstoffset=0;
+ if (i!=0)
+ {
+ int largest_len=0;
+ int largest_offset=0;
+ int icirc, ncirc;
+ /* Is this identical to a previous offset? Prefer close
+ values for offset. Search through circular buffer for the
+ possible values for the start of this string. */
+ ncirc=previous[(NUM_PREVIOUS+3)*vals[i]];
+ for (icirc=0; icirc<ncirc; icirc++)
+ {
+ int iptr=previous[(NUM_PREVIOUS+3)*vals[i]+1]-icirc-1;
+ if (iptr<0)
+ iptr+=NUM_PREVIOUS;
+ j=previous[(NUM_PREVIOUS+3)*vals[i]+3+iptr];
+ if (j<firstoffset)
+ break;
+#if 0
+ fprintf(stderr,"Starting search for %d at %d. Found %d\n",vals[i],j,vals[j]);
+#endif
+ while ((j<i) && (vals[j]==vals[i]))
+ {
+ if (j>=firstoffset)
+ {
+ for (k=0; i+k<nvals; k++)
+ if (vals[j+k]!=vals[i+k])
+ break;
+ if ((k>largest_len) && ((k>=(i-j)+16) || ((k>4) && (i-j==1))))
+ {
+ largest_len=k;
+ largest_offset=j;
+ }
+ }
+ j++;
+ }
+ }
+#if 0
+ /* Search in sorted string buffer too. */
+ kmin=info[i*2+1]-MAX_STRING_SEARCH;
+ kmax=info[i*2+1]+MAX_STRING_SEARCH;
+ if (kmin<0)
+ kmin=0;
+ if (kmax>=nvals)
+ kmax=nvals;
+ for (k=kmin; k<kmax; k++)
+ {
+ int m;
+ int s=info[k*2];
+ if ((s<i) && (s+MAX_OFFSET>=i))
+ {
+ for (m=0; i+m<nvals; m++)
+ if (vals[i+m]!=vals[(s+m)%nvals])
+ break;
+ if ((m>largest_len) && (m>4) && (m+2>=(i-s)))
+ {
+ largest_len=m;
+ largest_offset=s;
+#if 0
+ fprintf(stderr,"Offset: %d %d\n",m,i-s);
+#endif
+ }
+ }
+ }
+#endif
+ /* Check how to write this info. */
+ if (largest_len>MAX_LEN)
+ largest_len=MAX_LEN;
+ if (largest_len)
+ {
+ if (i-largest_offset==1)
+ {
+ data[ndat++]=0;
+ }
+ else
+ {
+ data[ndat++]=1;
+ offsets[noff++]=i-largest_offset;
+ }
+ len[nlen++]=largest_len;
+#if 0
+ fprintf(stderr,"l:o: %d:%d data=%d i=%d\n",largest_len,i-largest_offset,ndat,i);
+ fflush(stderr);
+#endif
+
+#if 0
+ fprintf(stderr,"Found largest len %d at %d.\n",largest_len,i-largest_offset);
+#endif
+ /* Add these values to the circular buffer. */
+ for (k=0; k<largest_len; k++)
+ add_circular(previous,vals[i+k],i+k);
+ i+=largest_len-1;
+ }
+ else
+ {
+ data[ndat++]=vals[i]+2;
+ /* Add this value to circular buffer. */
+ add_circular(previous,vals[i],i);
+ }
+ }
+ else
+ {
+ data[ndat++]=vals[i]+2;
+ /* Add this value to circular buffer. */
+ add_circular(previous,vals[i],i);
+ }
+ }
+ *noffsets=noff;
+ *ndata=ndat;
+ *nlens=nlen;
+#if 0
+ free(info);
+#endif
+ free(previous);
+}
+
+void Ptngc_comp_from_lz77(unsigned int *data, int ndata,
+ unsigned int *len, int nlens,
+ unsigned int *offsets, int noffsets,
+ unsigned int *vals, int nvals)
+{
+ int i=0;
+ int joff=0;
+ int jdat=0;
+ int jlen=0;
+ (void)ndata;
+ (void)nlens;
+ (void)noffsets;
+ while (i<nvals)
+ {
+ unsigned int v=data[jdat++];
+ if (v<2)
+ {
+ int offset=1;
+ int k;
+ int length=(int)len[jlen++];
+#if 0
+ fprintf(stderr,"len=%d off=%d i=%d\n",length,offset,i);
+#endif
+ if (v==1)
+ offset=offsets[joff++];
+ for (k=0; k<length; k++)
+ {
+ vals[i]=vals[i-offset];
+ if (i>=nvals)
+ {
+ fprintf(stderr,"too many vals.\n");
+ exit(EXIT_FAILURE);
+ }
+ i++;
+ }
+ }
+ else
+ vals[i++]=v-2;
+ }
+}
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "../../include/compression/warnmalloc.h"
+#include "../../include/compression/merge_sort.h"
+
+static void ms_inner(void *base, size_t size,
+ size_t start, size_t end,
+ int (*compar)(const void *v1,const void *v2,const void *private),
+ const void *private,
+ char *workarray)
+{
+ size_t middle;
+ if ((end-start)>1)
+ {
+ char *cbase=(char *)base;
+ middle=start+(end-start)/2;
+#if 0
+ printf("For start %d end %d obtained new middle: %d\n",start,end,middle);
+#endif
+ ms_inner(base,size,
+ start,middle,
+ compar,private,workarray);
+ ms_inner(base,size,
+ middle,end,
+ compar,private,workarray);
+#if 0
+ printf("For start %d end %d Before merge: Comparing element %d with %d\n",start,end,middle-1,middle);
+#endif
+ if (compar(cbase+(middle-1)*size,cbase+middle*size,private)>0)
+ {
+ /* Merge to work array. */
+ size_t i, n=end-start;
+ size_t ileft=start;
+ size_t iright=middle;
+ for (i=0; i<n; i++)
+ {
+ if (ileft==middle)
+ {
+ memcpy(workarray+i*size,cbase+iright*size,size);
+ iright++;
+ }
+ else if (iright==end)
+ {
+ memcpy(workarray+i*size,cbase+ileft*size,size);
+ ileft++;
+ }
+ else
+ {
+ #if 0
+ printf("For start %d end %d In merge: Comparing element %d with %d\n",start,end,ileft,iright);
+ #endif
+ if (compar(cbase+ileft*size,cbase+iright*size,private)>0)
+ {
+ memcpy(workarray+i*size,cbase+iright*size,size);
+ iright++;
+ }
+ else
+ {
+ memcpy(workarray+i*size,cbase+ileft*size,size);
+ ileft++;
+ }
+ }
+ }
+ /* Copy result back. */
+ memcpy(cbase+start*size,workarray,(end-start)*size);
+ }
+ }
+}
+
+
+void Ptngc_merge_sort(void *base, size_t nmemb, size_t size,
+ int (*compar)(const void *v1,const void *v2,const void *private),
+ void *private)
+{
+ char *warr=warnmalloc(nmemb*size);
+ ms_inner(base,size,0,nmemb,compar,private,warr);
+ free(warr);
+}
+
+
+#ifdef TEST
+
+static int compint(const void *v1, const void *v2,const void *private)
+{
+ const int *i1=(const int *)v1;
+ const int *i2=(const int *)v2;
+ if (*i1<*i2)
+ return -1;
+ else if (*i1>*i2)
+ return 1;
+ else
+ return 0;
+}
+
+static int qcompint(const void *v1, const void *v2)
+{
+ return compint(v1,v2,NULL);
+}
+
+#define N 1000000
+int main()
+{
+ int *arr=warnmalloc(N*sizeof *arr);
+ int i;
+ for (i=0; i<N; i++)
+ scanf("%d",arr+i);
+#if 1
+ merge_sort(arr,N,sizeof *arr,compint,NULL);
+#else
+ qsort(arr,N,sizeof *arr,qcompint);
+#endif
+ for (i=0; i<N; i++)
+ printf("%d %d\n",i,arr[i]);
+ return 0;
+}
+#endif
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#include <stdlib.h>
+#include "../../include/compression/warnmalloc.h"
+#include "../../include/compression/mtf.h"
+
+/* "Partial" MTF. Byte based. */
+/* Move to front coding.
+ Acceptable inputs are max 8 bits (0-0xFF) */
+static void comp_conv_to_mtf_byte(unsigned char *vals, int nvals,
+ unsigned char *valsmtf)
+{
+ int i;
+ /* Indices into a linked list */
+ int list[256];
+ int dict[256];
+ /* Head of the linked list */
+ int head;
+ for (i=0; i<256; i++)
+ dict[i]=i;
+ for (i=0; i<255; i++)
+ list[i]=i+1;
+ list[255]=-1; /* end. */
+ head=0;
+ for (i=0; i<nvals; i++)
+ {
+ int v=(int)vals[i];
+ /* Find how early in the dict the value is */
+ int ptr=head;
+ int oldptr=-1;
+ int r=0;
+ while (dict[ptr]!=v)
+ {
+ oldptr=ptr;
+ ptr=list[ptr];
+ r++;
+ }
+ valsmtf[i]=(unsigned char)r;
+ /* Move it to front in list */
+ /* Is it the head? Then it is already at the front. */
+ if (oldptr!=-1)
+ {
+ /* Remove it from inside the list */
+ list[oldptr]=list[ptr];
+ /* Move it to the front. */
+ list[ptr]=head;
+ head=ptr;
+ }
+ }
+}
+
+void Ptngc_comp_conv_to_mtf_partial(unsigned int *vals, int nvals,
+ unsigned int *valsmtf)
+{
+ unsigned char *tmp=warnmalloc(nvals*2);
+ int i, j;
+ for (i=0; i<nvals; i++)
+ valsmtf[i]=0U;
+ for (j=0; j<3; j++)
+ {
+ for (i=0; i<nvals; i++)
+ tmp[i]=(unsigned char)((vals[i]>>(8*j))&0xFF);
+ comp_conv_to_mtf_byte(tmp,nvals,tmp+nvals);
+ for (i=0; i<nvals; i++)
+ valsmtf[i]|=(((unsigned int)(tmp[nvals+i]))<<(8*j));
+ }
+ free(tmp);
+}
+
+void Ptngc_comp_conv_to_mtf_partial3(unsigned int *vals, int nvals,
+ unsigned char *valsmtf)
+{
+ unsigned char *tmp=warnmalloc(nvals);
+ int i, j;
+ for (j=0; j<3; j++)
+ {
+ for (i=0; i<nvals; i++)
+ tmp[i]=(unsigned char)((vals[i]>>(8*j))&0xFF);
+ comp_conv_to_mtf_byte(tmp,nvals,valsmtf+j*nvals);
+ }
+ free(tmp);
+}
+
+/* Move to front decoding */
+static void comp_conv_from_mtf_byte(unsigned char *valsmtf, int nvals,
+ unsigned char *vals)
+{
+ int i;
+ /* Indices into a linked list */
+ int list[256];
+ int dict[256];
+ /* Head of the linked list */
+ int head;
+ for (i=0; i<256; i++)
+ dict[i]=i;
+ for (i=0; i<255; i++)
+ list[i]=i+1;
+ list[255]=-1; /* end. */
+ head=0;
+ for (i=0; i<nvals; i++)
+ {
+ int r=(int)valsmtf[i];
+ /* Find value at position r in the list */
+ int ptr=head;
+ int oldptr=-1;
+ int cnt=0;
+ while (cnt<r)
+ {
+ oldptr=ptr;
+ ptr=list[ptr];
+ cnt++;
+ }
+ vals[i]=(unsigned int)dict[ptr];
+ /* Move it to front in list */
+ /* Is it the head? Then it is already at the front. */
+ if (oldptr!=-1)
+ {
+ /* Remove it from inside the list */
+ list[oldptr]=list[ptr];
+ /* Move it to the front. */
+ list[ptr]=head;
+ head=ptr;
+ }
+ }
+}
+
+void Ptngc_comp_conv_from_mtf_partial(unsigned int *valsmtf, int nvals,
+ unsigned int *vals)
+{
+ unsigned char *tmp=warnmalloc(nvals*2);
+ int i, j;
+ for (i=0; i<nvals; i++)
+ vals[i]=0U;
+ for (j=0; j<3; j++)
+ {
+ for (i=0; i<nvals; i++)
+ tmp[i]=(unsigned char)((valsmtf[i]>>(8*j))&0xFF);
+ comp_conv_from_mtf_byte(tmp,nvals,tmp+nvals);
+ for (i=0; i<nvals; i++)
+ vals[i]|=(((unsigned int)(tmp[nvals+i]))<<(8*j));
+ }
+ free(tmp);
+}
+
+void Ptngc_comp_conv_from_mtf_partial3(unsigned char *valsmtf, int nvals,
+ unsigned int *vals)
+{
+ unsigned char *tmp=warnmalloc(nvals);
+ int i, j;
+ for (i=0; i<nvals; i++)
+ vals[i]=0U;
+ for (j=0; j<3; j++)
+ {
+ comp_conv_from_mtf_byte(valsmtf+j*nvals,nvals,tmp);
+ for (i=0; i<nvals; i++)
+ vals[i]|=(((unsigned int)(tmp[i]))<<(8*j));
+ }
+ free(tmp);
+}
+
+/* Move to front coding.
+ Acceptable inputs are max 24 bits (0-0xFFFFFF) */
+void Ptngc_comp_conv_to_mtf(unsigned int *vals, int nvals,
+ unsigned int *dict, int ndict,
+ unsigned int *valsmtf)
+{
+ int i;
+ /* Indices into a linked list */
+ int *list=warnmalloc(ndict*sizeof *list);
+ /* Head of the linked list */
+ int head;
+ for (i=0; i<ndict-1; i++)
+ list[i]=i+1;
+ list[ndict-1]=-1; /* end. */
+ head=0;
+ for (i=0; i<nvals; i++)
+ {
+ int v=vals[i];
+ /* Find how early in the dict the value is */
+ int ptr=head;
+ int oldptr=-1;
+ int r=0;
+ while (dict[ptr]!=v)
+ {
+ oldptr=ptr;
+ ptr=list[ptr];
+ r++;
+ }
+ valsmtf[i]=r;
+ /* Move it to front in list */
+ /* Is it the head? Then it is already at the front. */
+ if (oldptr!=-1)
+ {
+ /* Remove it from inside the list */
+ list[oldptr]=list[ptr];
+ /* Move it to the front. */
+ list[ptr]=head;
+ head=ptr;
+ }
+ }
+ free(list);
+}
+
+/* Move to front decoding */
+void Ptngc_comp_conv_from_mtf(unsigned int *valsmtf, int nvals,
+ unsigned int *dict, int ndict,
+ unsigned int *vals)
+{
+ int i;
+ /* Indices into a linked list */
+ int *list=warnmalloc(ndict*sizeof *list);
+ /* Head of the linked list */
+ int head;
+ for (i=0; i<ndict-1; i++)
+ list[i]=i+1;
+ list[ndict-1]=-1; /* end. */
+ head=0;
+ for (i=0; i<nvals; i++)
+ {
+ int r=valsmtf[i];
+ /* Find value at position r in the list */
+ int ptr=head;
+ int oldptr=-1;
+ int cnt=0;
+ while (cnt<r)
+ {
+ oldptr=ptr;
+ ptr=list[ptr];
+ cnt++;
+ }
+ vals[i]=dict[ptr];
+ /* Move it to front in list */
+ /* Is it the head? Then it is already at the front. */
+ if (oldptr!=-1)
+ {
+ /* Remove it from inside the list */
+ list[oldptr]=list[ptr];
+ /* Move it to the front. */
+ list[ptr]=head;
+ head=ptr;
+ }
+ }
+ free(list);
+}
+
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#include "../../include/compression/rle.h"
+
+static void add_rle(unsigned int *rle,
+ int v,int nsim,
+ int *j,int min_rle)
+{
+ if (nsim>min_rle)
+ {
+ /* Insert run-length */
+ unsigned int run=((unsigned int)nsim);
+ while (run>1)
+ {
+ if (run&0x1U)
+ rle[(*j)++]=1;
+ else
+ rle[(*j)++]=0;
+ run>>=1;
+ }
+ nsim=1;
+ }
+ while (nsim--)
+ rle[(*j)++]=v+2;
+}
+
+/* Run length encoding.
+ Acceptable inputs are about 16 bits (0-0xFFFF)
+ If input is 0-N output will be be values of 0-(N+2) */
+void Ptngc_comp_conv_to_rle(unsigned int *vals, int nvals,
+ unsigned int *rle, int *nrle,
+ int min_rle)
+{
+ int i;
+ int j=0;
+ int nsim=0;
+ int v=-1;
+ for (i=0; i<nvals; i++)
+ {
+ if (!nsim)
+ {
+ v=vals[i];
+ nsim=1;
+ }
+ else
+ {
+ if (v==vals[i])
+ nsim++;
+ else
+ {
+ add_rle(rle,v,nsim,&j,min_rle);
+ nsim=1;
+ v=vals[i];
+ }
+ }
+ }
+ if (nsim!=0)
+ add_rle(rle,v,nsim,&j,min_rle);
+ *nrle=j;
+}
+
+void Ptngc_comp_conv_from_rle(unsigned int *rle,
+ unsigned int *vals, int nvals)
+{
+ int i=0;
+ int j=0;
+ while (i<nvals)
+ {
+ int k;
+ unsigned int len=0;
+ unsigned int mask=0x1;
+ unsigned int v=rle[j++];
+ unsigned int hasrle=0;
+ while (v<2)
+ {
+ if (v)
+ len|=mask;
+ mask<<=1;
+ hasrle=1;
+ v=rle[j++];
+ }
+ if (!hasrle)
+ len=1;
+ else
+ len|=mask;
+ for (k=0; k<(int)len; k++)
+ vals[i++]=v-2;
+ }
+}
+
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "../../include/compression/tng_compress.h"
+#include "../../include/compression/coder.h"
+#include "../../include/compression/fixpoint.h"
+
+/* Please see tng_compress.h for info on how to call these routines. */
+
+/* This becomes TNGP for positions (little endian) and TNGV for velocities. In ASCII. */
+#define MAGIC_INT_POS 0x50474E54
+#define MAGIC_INT_VEL 0x56474E54
+
+#define SPEED_DEFAULT 2 /* Default to relatively fast compression. For very good compression it makes sense to
+ choose speed=4 or speed=5 */
+
+#define PRECISION(hi,lo) (Ptngc_i32x2_to_d(hi,lo))
+
+#define MAX_FVAL 2147483647.
+
+static int verify_input_data(double *x, int natoms, int nframes, double precision)
+{
+ int iframe, i, j;
+ for (iframe=0; iframe<nframes; iframe++)
+ for (i=0; i<natoms; i++)
+ for (j=0; j<3; j++)
+ if (fabs(x[iframe*natoms*3+i*3+j]/precision+0.5)>=MAX_FVAL)
+ goto error;
+ return 0;
+ error:
+#if 0
+ for (iframe=0; iframe<nframes; iframe++)
+ for (i=0; i<natoms; i++)
+ for (j=0; j<3; j++)
+ if (fabs(x[iframe*natoms*3+i*3+j]/precision+0.5)>=MAX_FVAL)
+ printf("ERROR. Too large value: %d %d %d: %g %g %g\n",iframe,i,j,x[iframe*natoms*3+i*3+j],precision,x[iframe*natoms*3+i*3+j]/precision/MAX_FVAL);
+#endif
+ return 1;
+}
+
+static int verify_input_data_float(float *x, int natoms, int nframes, float precision)
+{
+ int iframe, i, j;
+ for (iframe=0; iframe<nframes; iframe++)
+ for (i=0; i<natoms; i++)
+ for (j=0; j<3; j++)
+ if (fabs(x[iframe*natoms*3+i*3+j]/precision+0.5)>=MAX_FVAL)
+ goto error;
+ return 0;
+ error:
+#if 0
+ for (iframe=0; iframe<nframes; iframe++)
+ for (i=0; i<natoms; i++)
+ for (j=0; j<3; j++)
+ if (fabs(x[iframe*natoms*3+i*3+j]/precision+0.5)>=MAX_FVAL)
+ printf("ERROR. Too large value: %d %d %d: %g %g %g\n",iframe,i,j,x[iframe*natoms*3+i*3+j],precision,x[iframe*natoms*3+i*3+j]/precision/MAX_FVAL);
+#endif
+ return 1;
+}
+
+static int quantize(double *x, int natoms, int nframes,
+ double precision,
+ int *quant)
+{
+ int iframe, i, j;
+ for (iframe=0; iframe<nframes; iframe++)
+ for (i=0; i<natoms; i++)
+ for (j=0; j<3; j++)
+ quant[iframe*natoms*3+i*3+j]=(int)floor((x[iframe*natoms*3+i*3+j]/precision)+0.5);
+ return verify_input_data(x,natoms,nframes,precision);
+}
+
+static int quantize_float(float *x, int natoms, int nframes,
+ float precision,
+ int *quant)
+{
+ int iframe, i, j;
+ for (iframe=0; iframe<nframes; iframe++)
+ for (i=0; i<natoms; i++)
+ for (j=0; j<3; j++)
+ quant[iframe*natoms*3+i*3+j]=(int)floor((x[iframe*natoms*3+i*3+j]/precision)+0.5);
+ return verify_input_data_float(x,natoms,nframes,precision);
+}
+
+static void quant_inter_differences(int *quant, int natoms, int nframes,
+ int *quant_inter)
+{
+ int iframe, i, j;
+ /* The first frame is used for absolute positions. */
+ for (i=0; i<natoms; i++)
+ for (j=0; j<3; j++)
+ quant_inter[i*3+j]=quant[i*3+j];
+ /* For all other frames, the difference to the previous frame is used. */
+ for (iframe=1; iframe<nframes; iframe++)
+ for (i=0; i<natoms; i++)
+ for (j=0; j<3; j++)
+ quant_inter[iframe*natoms*3+i*3+j]=quant[iframe*natoms*3+i*3+j]-quant[(iframe-1)*natoms*3+i*3+j];
+}
+
+static void quant_intra_differences(int *quant, int natoms, int nframes,
+ int *quant_intra)
+{
+ int iframe, i, j;
+ for (iframe=0; iframe<nframes; iframe++)
+ {
+ /* The first atom is used with its absolute position. */
+ for (j=0; j<3; j++)
+ quant_intra[iframe*natoms*3+j]=quant[iframe*natoms*3+j];
+ /* For all other atoms the intraframe differences are computed. */
+ for (i=1; i<natoms; i++)
+ for (j=0; j<3; j++)
+ quant_intra[iframe*natoms*3+i*3+j]=quant[iframe*natoms*3+i*3+j]-quant[iframe*natoms*3+(i-1)*3+j];
+ }
+}
+
+static void unquantize(double *x, int natoms, int nframes,
+ double precision,
+ int *quant)
+{
+ int iframe, i, j;
+ for (iframe=0; iframe<nframes; iframe++)
+ for (i=0; i<natoms; i++)
+ for (j=0; j<3; j++)
+ x[iframe*natoms*3+i*3+j]=(double)quant[iframe*natoms*3+i*3+j]*precision;
+}
+
+static void unquantize_float(float *x, int natoms, int nframes,
+ float precision,
+ int *quant)
+{
+ int iframe, i, j;
+ for (iframe=0; iframe<nframes; iframe++)
+ for (i=0; i<natoms; i++)
+ for (j=0; j<3; j++)
+ x[iframe*natoms*3+i*3+j]=(float)quant[iframe*natoms*3+i*3+j]*precision;
+}
+
+static void unquantize_inter_differences(double *x, int natoms, int nframes,
+ double precision,
+ int *quant)
+{
+ int iframe, i, j;
+ for (i=0; i<natoms; i++)
+ for (j=0; j<3; j++)
+ {
+ int q=quant[i*3+j]; /* First value. */
+ x[i*3+j]=(double)q*precision;
+ for (iframe=1; iframe<nframes; iframe++)
+ {
+ q+=quant[iframe*natoms*3+i*3+j];
+ x[iframe*natoms*3+i*3+j]=(double)q*precision;
+ }
+ }
+}
+
+static void unquantize_inter_differences_float(float *x, int natoms, int nframes,
+ float precision,
+ int *quant)
+{
+ int iframe, i, j;
+ for (i=0; i<natoms; i++)
+ for (j=0; j<3; j++)
+ {
+ int q=quant[i*3+j]; /* First value. */
+ x[i*3+j]=(float)q*precision;
+ for (iframe=1; iframe<nframes; iframe++)
+ {
+ q+=quant[iframe*natoms*3+i*3+j];
+ x[iframe*natoms*3+i*3+j]=(float)q*precision;
+ }
+ }
+}
+
+static void unquantize_inter_differences_int(int *x, int natoms, int nframes,
+ int *quant)
+{
+ int iframe, i, j;
+ for (i=0; i<natoms; i++)
+ for (j=0; j<3; j++)
+ {
+ int q=quant[i*3+j]; /* First value. */
+ x[i*3+j]=q;
+ for (iframe=1; iframe<nframes; iframe++)
+ {
+ q+=quant[iframe*natoms*3+i*3+j];
+ x[iframe*natoms*3+i*3+j]=q;
+ }
+ }
+}
+
+/* In frame update required for the initial frame if intra-frame
+ compression was used. */
+static void unquant_intra_differences_first_frame(int *quant, int natoms)
+{
+ int i,j;
+ for (j=0; j<3; j++)
+ {
+ int q=quant[j];
+ for (i=1; i<natoms; i++)
+ {
+ q+=quant[i*3+j];
+ quant[i*3+j]=q;
+ }
+ }
+#if 0
+ for (j=0; j<3; j++)
+ for (i=0; i<natoms; i++)
+ {
+ printf("UQ: %d %d %d: %d\n",0,j,i,quant[i*3+j]);
+ }
+#endif
+}
+
+static void unquantize_intra_differences(double *x, int natoms, int nframes,
+ double precision,
+ int *quant)
+{
+ int iframe, i, j;
+#if 0
+ printf("UQ precision=%g\n",precision);
+#endif
+ for (iframe=0; iframe<nframes; iframe++)
+ for (j=0; j<3; j++)
+ {
+ int q=quant[iframe*natoms*3+j];
+ x[iframe*natoms*3+j]=(double)q*precision;
+ for (i=1; i<natoms; i++)
+ {
+ q+=quant[iframe*natoms*3+i*3+j];
+ x[iframe*natoms*3+i*3+j]=(double)q*precision;
+ }
+ }
+}
+
+static void unquantize_intra_differences_float(float *x, int natoms, int nframes,
+ float precision,
+ int *quant)
+{
+ int iframe, i, j;
+ for (iframe=0; iframe<nframes; iframe++)
+ for (j=0; j<3; j++)
+ {
+ int q=quant[iframe*natoms*3+j];
+ x[iframe*natoms*3+j]=(float)q*precision;
+ for (i=1; i<natoms; i++)
+ {
+ q+=quant[iframe*natoms*3+i*3+j];
+ x[iframe*natoms*3+i*3+j]=(float)q*precision;
+ }
+ }
+}
+
+static void unquantize_intra_differences_int(int *x, int natoms, int nframes,
+ int *quant)
+{
+ int iframe, i, j;
+ for (iframe=0; iframe<nframes; iframe++)
+ for (j=0; j<3; j++)
+ {
+ int q=quant[iframe*natoms*3+j];
+ x[iframe*natoms*3+j]=q;
+ for (i=1; i<natoms; i++)
+ {
+ q+=quant[iframe*natoms*3+i*3+j];
+ x[iframe*natoms*3+i*3+j]=q;
+ }
+ }
+}
+
+/* Buffer num 8 bit bytes into buffer location buf */
+static void bufferfix(unsigned char *buf, fix_t v, int num)
+{
+ /* Store in little endian format. */
+ unsigned char c; /* at least 8 bits. */
+ c=(unsigned char)(v & 0xFFU);
+ while (num--)
+ {
+ *buf++=c;
+ v >>= 8;
+ c=(unsigned char)(v & 0xFFU);
+ }
+}
+
+static fix_t readbufferfix(unsigned char *buf, int num)
+{
+ unsigned char b;
+ int shift=0;
+ fix_t f=0UL;
+ int cnt=0;
+ do
+ {
+ b=buf[cnt++];
+ f |= ((fix_t)b & 0xFF)<<shift;
+ shift+=8;
+ } while (--num);
+ return f;
+}
+
+/* Perform position compression from the quantized data. */
+static void compress_quantized_pos(int *quant, int *quant_inter, int *quant_intra,
+ int natoms, int nframes,
+ int speed,
+ int initial_coding, int initial_coding_parameter,
+ int coding, int coding_parameter,
+ fix_t prec_hi, fix_t prec_lo,
+ int *nitems,
+ char *data)
+{
+ int bufloc=0;
+ char *datablock=NULL;
+ int length=0;
+ /* Information needed for decompression. */
+ if (data)
+ bufferfix((unsigned char*)data+bufloc,(fix_t)MAGIC_INT_POS,4);
+ bufloc+=4;
+ /* Number of atoms. */
+ if (data)
+ bufferfix((unsigned char*)data+bufloc,(fix_t)natoms,4);
+ bufloc+=4;
+ /* Number of frames. */
+ if (data)
+ bufferfix((unsigned char*)data+bufloc,(fix_t)nframes,4);
+ bufloc+=4;
+ /* Initial coding. */
+ if (data)
+ bufferfix((unsigned char*)data+bufloc,(fix_t)initial_coding,4);
+ bufloc+=4;
+ /* Initial coding parameter. */
+ if (data)
+ bufferfix((unsigned char*)data+bufloc,(fix_t)initial_coding_parameter,4);
+ bufloc+=4;
+ /* Coding. */
+ if (data)
+ bufferfix((unsigned char*)data+bufloc,(fix_t)coding,4);
+ bufloc+=4;
+ /* Coding parameter. */
+ if (data)
+ bufferfix((unsigned char*)data+bufloc,(fix_t)coding_parameter,4);
+ bufloc+=4;
+ /* Precision. */
+ if (data)
+ bufferfix((unsigned char*)data+bufloc,prec_lo,4);
+ bufloc+=4;
+ if (data)
+ bufferfix((unsigned char*)data+bufloc,prec_hi,4);
+ bufloc+=4;
+ /* The initial frame */
+ if ((initial_coding==TNG_COMPRESS_ALGO_POS_XTC2) ||
+ (initial_coding==TNG_COMPRESS_ALGO_POS_TRIPLET_ONETOONE) ||
+ (initial_coding==TNG_COMPRESS_ALGO_POS_XTC3))
+ {
+ struct coder *coder=Ptngc_coder_init();
+ length=natoms*3;
+ datablock=(char*)Ptngc_pack_array(coder,quant,&length,
+ initial_coding,initial_coding_parameter,natoms,speed);
+ Ptngc_coder_deinit(coder);
+ }
+ else if ((initial_coding==TNG_COMPRESS_ALGO_POS_TRIPLET_INTRA) ||
+ (initial_coding==TNG_COMPRESS_ALGO_POS_BWLZH_INTRA))
+ {
+ struct coder *coder=Ptngc_coder_init();
+ length=natoms*3;
+ datablock=(char*)Ptngc_pack_array(coder,quant_intra,&length,
+ initial_coding,initial_coding_parameter,natoms,speed);
+ Ptngc_coder_deinit(coder);
+ }
+ /* Block length. */
+ if (data)
+ bufferfix((unsigned char*)data+bufloc,(fix_t)length,4);
+ bufloc+=4;
+ /* The actual data block. */
+ if (data)
+ memcpy(data+bufloc,datablock,length);
+ free(datablock);
+ bufloc+=length;
+ /* The remaining frames */
+ if (nframes>1)
+ {
+ datablock=NULL;
+ /* Inter-frame compression? */
+ if ((coding==TNG_COMPRESS_ALGO_POS_STOPBIT_INTER) ||
+ (coding==TNG_COMPRESS_ALGO_POS_TRIPLET_INTER) ||
+ (coding==TNG_COMPRESS_ALGO_POS_BWLZH_INTER))
+ {
+ struct coder *coder=Ptngc_coder_init();
+ length=natoms*3*(nframes-1);
+ datablock=(char*)Ptngc_pack_array(coder,quant_inter+natoms*3,&length,
+ coding,coding_parameter,natoms,speed);
+ Ptngc_coder_deinit(coder);
+ }
+ /* One-to-one compression? */
+ else if ((coding==TNG_COMPRESS_ALGO_POS_XTC2) ||
+ (coding==TNG_COMPRESS_ALGO_POS_XTC3) ||
+ (coding==TNG_COMPRESS_ALGO_POS_TRIPLET_ONETOONE))
+ {
+ struct coder *coder=Ptngc_coder_init();
+ length=natoms*3*(nframes-1);
+ datablock=(char*)Ptngc_pack_array(coder,quant+natoms*3,&length,
+ coding,coding_parameter,natoms,speed);
+ Ptngc_coder_deinit(coder);
+ }
+ /* Intra-frame compression? */
+ else if ((coding==TNG_COMPRESS_ALGO_POS_TRIPLET_INTRA) ||
+ (coding==TNG_COMPRESS_ALGO_POS_BWLZH_INTRA))
+ {
+ struct coder *coder=Ptngc_coder_init();
+ length=natoms*3*(nframes-1);
+ datablock=(char*)Ptngc_pack_array(coder,quant_intra+natoms*3,&length,
+ coding,coding_parameter,natoms,speed);
+ Ptngc_coder_deinit(coder);
+ }
+ /* Block length. */
+ if (data)
+ bufferfix((unsigned char*)data+bufloc,(fix_t)length,4);
+ bufloc+=4;
+ if (data)
+ memcpy(data+bufloc,datablock,length);
+ free(datablock);
+ bufloc+=length;
+ }
+ *nitems=bufloc;
+}
+
+/* Perform velocity compression from vel into the data block */
+static void compress_quantized_vel(int *quant, int *quant_inter,
+ int natoms, int nframes,
+ int speed,
+ int initial_coding, int initial_coding_parameter,
+ int coding, int coding_parameter,
+ fix_t prec_hi, fix_t prec_lo,
+ int *nitems,
+ char *data)
+{
+ int bufloc=0;
+ char *datablock=NULL;
+ int length;
+ /* Information needed for decompression. */
+ if (data)
+ bufferfix((unsigned char*)data+bufloc,(fix_t)MAGIC_INT_VEL,4);
+ bufloc+=4;
+ /* Number of atoms. */
+ if (data)
+ bufferfix((unsigned char*)data+bufloc,(fix_t)natoms,4);
+ bufloc+=4;
+ /* Number of frames. */
+ if (data)
+ bufferfix((unsigned char*)data+bufloc,(fix_t)nframes,4);
+ bufloc+=4;
+ /* Initial coding. */
+ if (data)
+ bufferfix((unsigned char*)data+bufloc,(fix_t)initial_coding,4);
+ bufloc+=4;
+ /* Initial coding parameter. */
+ if (data)
+ bufferfix((unsigned char*)data+bufloc,(fix_t)initial_coding_parameter,4);
+ bufloc+=4;
+ /* Coding. */
+ if (data)
+ bufferfix((unsigned char*)data+bufloc,(fix_t)coding,4);
+ bufloc+=4;
+ /* Coding parameter. */
+ if (data)
+ bufferfix((unsigned char*)data+bufloc,(fix_t)coding_parameter,4);
+ bufloc+=4;
+ /* Precision. */
+ if (data)
+ bufferfix((unsigned char*)data+bufloc,prec_lo,4);
+ bufloc+=4;
+ if (data)
+ bufferfix((unsigned char*)data+bufloc,prec_hi,4);
+ bufloc+=4;
+
+ length=natoms*3;
+ /* The initial frame */
+ if ((initial_coding==TNG_COMPRESS_ALGO_VEL_STOPBIT_ONETOONE) ||
+ (initial_coding==TNG_COMPRESS_ALGO_VEL_TRIPLET_ONETOONE) ||
+ (initial_coding==TNG_COMPRESS_ALGO_VEL_BWLZH_ONETOONE))
+ {
+ struct coder *coder=Ptngc_coder_init();
+ datablock=(char*)Ptngc_pack_array(coder,quant,&length,
+ initial_coding,initial_coding_parameter,natoms,speed);
+ Ptngc_coder_deinit(coder);
+ }
+ /* Block length. */
+ if (data)
+ bufferfix((unsigned char*)data+bufloc,(fix_t)length,4);
+ bufloc+=4;
+ /* The actual data block. */
+ if (data && datablock)
+ {
+ memcpy(data+bufloc,datablock,length);
+ free(datablock);
+ bufloc+=length;
+ }
+ /* The remaining frames */
+ if (nframes>1)
+ {
+ datablock=NULL;
+ /* Inter-frame compression? */
+ if ((coding==TNG_COMPRESS_ALGO_VEL_TRIPLET_INTER) ||
+ (coding==TNG_COMPRESS_ALGO_VEL_STOPBIT_INTER) ||
+ (coding==TNG_COMPRESS_ALGO_VEL_BWLZH_INTER))
+ {
+ struct coder *coder=Ptngc_coder_init();
+ length=natoms*3*(nframes-1);
+ datablock=(char*)Ptngc_pack_array(coder,quant_inter+natoms*3,&length,
+ coding,coding_parameter,natoms,speed);
+ Ptngc_coder_deinit(coder);
+ }
+ /* One-to-one compression? */
+ else if ((coding==TNG_COMPRESS_ALGO_VEL_STOPBIT_ONETOONE) ||
+ (coding==TNG_COMPRESS_ALGO_VEL_TRIPLET_ONETOONE) ||
+ (coding==TNG_COMPRESS_ALGO_VEL_BWLZH_ONETOONE))
+ {
+ struct coder *coder=Ptngc_coder_init();
+ length=natoms*3*(nframes-1);
+ datablock=(char*)Ptngc_pack_array(coder,quant+natoms*3,&length,
+ coding,coding_parameter,natoms,speed);
+ Ptngc_coder_deinit(coder);
+ }
+ /* Block length. */
+ if (data)
+ bufferfix((unsigned char*)data+bufloc,(fix_t)length,4);
+ bufloc+=4;
+ if (data)
+ memcpy(data+bufloc,datablock,length);
+ free(datablock);
+ bufloc+=length;
+ }
+ *nitems=bufloc;
+}
+
+static int determine_best_coding_stop_bits(struct coder *coder,int *input, int *length,
+ int *coding_parameter, int natoms)
+{
+ int bits;
+ unsigned char *packed;
+ int best_length=0;
+ int new_parameter=-1;
+ int io_length;
+ for (bits=1; bits<20; bits++)
+ {
+ io_length=*length;
+ packed=Ptngc_pack_array(coder,input,&io_length,
+ TNG_COMPRESS_ALGO_STOPBIT,bits,natoms,0);
+ if (packed)
+ {
+ if ((new_parameter==-1) || (io_length<best_length))
+ {
+ new_parameter=bits;
+ best_length=io_length;
+ }
+ free(packed);
+ }
+ }
+ if (new_parameter==-1)
+ return 1;
+
+ *coding_parameter=new_parameter;
+ *length=best_length;
+ return 0;
+}
+
+static int determine_best_coding_triple(struct coder *coder,int *input, int *length,
+ int *coding_parameter, int natoms)
+{
+ int bits;
+ unsigned char *packed;
+ int best_length=0;
+ int new_parameter=-1;
+ int io_length;
+ for (bits=1; bits<20; bits++)
+ {
+ io_length=*length;
+ packed=Ptngc_pack_array(coder,input,&io_length,
+ TNG_COMPRESS_ALGO_TRIPLET,bits,natoms,0);
+ if (packed)
+ {
+ if ((new_parameter==-1) || (io_length<best_length))
+ {
+ new_parameter=bits;
+ best_length=io_length;
+ }
+ free(packed);
+ }
+ }
+ if (new_parameter==-1)
+ return 1;
+
+ *coding_parameter=new_parameter;
+ *length=best_length;
+ return 0;
+}
+
+static void determine_best_pos_initial_coding(int *quant, int *quant_intra, int natoms, int speed,
+ fix_t prec_hi, fix_t prec_lo,
+ int *initial_coding, int *initial_coding_parameter)
+{
+ if (*initial_coding==-1)
+ {
+ /* Determine all parameters automatically */
+ int best_coding;
+ int best_coding_parameter;
+ int best_code_size;
+ int current_coding;
+ int current_coding_parameter;
+ int current_code_size;
+ struct coder *coder;
+ /* Start with XTC2, it should always work. */
+ current_coding=TNG_COMPRESS_ALGO_POS_XTC2;
+ current_coding_parameter=0;
+ compress_quantized_pos(quant,NULL,quant_intra,natoms,1,speed,
+ current_coding,current_coding_parameter,
+ 0,0,prec_hi,prec_lo,¤t_code_size,NULL);
+ best_coding=current_coding;
+ best_coding_parameter=current_coding_parameter;
+ best_code_size=current_code_size;
+
+ /* Determine best parameter for triplet intra. */
+ current_coding=TNG_COMPRESS_ALGO_POS_TRIPLET_INTRA;
+ coder=Ptngc_coder_init();
+ current_code_size=natoms*3;
+ current_coding_parameter=0;
+ if (!determine_best_coding_triple(coder,quant_intra,¤t_code_size,¤t_coding_parameter,natoms))
+ {
+ if (current_code_size<best_code_size)
+ {
+ best_coding=current_coding;
+ best_coding_parameter=current_coding_parameter;
+ best_code_size=current_code_size;
+ }
+ }
+ Ptngc_coder_deinit(coder);
+
+ /* Determine best parameter for triplet one-to-one. */
+ current_coding=TNG_COMPRESS_ALGO_POS_TRIPLET_ONETOONE;
+ coder=Ptngc_coder_init();
+ current_code_size=natoms*3;
+ current_coding_parameter=0;
+ if (!determine_best_coding_triple(coder,quant,¤t_code_size,¤t_coding_parameter,natoms))
+ {
+ if (current_code_size<best_code_size)
+ {
+ best_coding=current_coding;
+ best_coding_parameter=current_coding_parameter;
+ best_code_size=current_code_size;
+ }
+ }
+ Ptngc_coder_deinit(coder);
+
+ if (speed>=2)
+ {
+ current_coding=TNG_COMPRESS_ALGO_POS_XTC3;
+ current_coding_parameter=0;
+ compress_quantized_pos(quant,NULL,quant_intra,natoms,1,speed,
+ current_coding,current_coding_parameter,
+ 0,0,prec_hi,prec_lo,¤t_code_size,NULL);
+ if (current_code_size<best_code_size)
+ {
+ best_coding=current_coding;
+ best_coding_parameter=current_coding_parameter;
+ best_code_size=current_code_size;
+ }
+ }
+ /* Test BWLZH intra */
+ if (speed>=6)
+ {
+ current_coding=TNG_COMPRESS_ALGO_POS_BWLZH_INTRA;
+ current_coding_parameter=0;
+ compress_quantized_pos(quant,NULL,quant_intra,natoms,1,speed,
+ current_coding,current_coding_parameter,
+ 0,0,prec_hi,prec_lo,¤t_code_size,NULL);
+ if (current_code_size<best_code_size)
+ {
+ best_coding=current_coding;
+ best_coding_parameter=current_coding_parameter;
+ }
+ }
+ *initial_coding=best_coding;
+ *initial_coding_parameter=best_coding_parameter;
+ }
+ else
+ {
+ if (*initial_coding_parameter==-1)
+ {
+ if ((*initial_coding==TNG_COMPRESS_ALGO_POS_XTC2) ||
+ (*initial_coding==TNG_COMPRESS_ALGO_POS_XTC3) ||
+ (*initial_coding==TNG_COMPRESS_ALGO_POS_BWLZH_INTRA))
+ *initial_coding_parameter=0;
+ else if (*initial_coding==TNG_COMPRESS_ALGO_POS_TRIPLET_INTRA)
+ {
+ struct coder *coder=Ptngc_coder_init();
+ int current_code_size=natoms*3;
+ determine_best_coding_triple(coder,quant_intra,¤t_code_size,initial_coding_parameter,natoms);
+ Ptngc_coder_deinit(coder);
+ }
+ else if (*initial_coding==TNG_COMPRESS_ALGO_POS_TRIPLET_ONETOONE)
+ {
+ struct coder *coder=Ptngc_coder_init();
+ int current_code_size=natoms*3;
+ determine_best_coding_triple(coder,quant,¤t_code_size,initial_coding_parameter,natoms);
+ Ptngc_coder_deinit(coder);
+ }
+ }
+ }
+}
+
+static void determine_best_pos_coding(int *quant, int *quant_inter, int *quant_intra, int natoms, int nframes, int speed,
+ fix_t prec_hi, fix_t prec_lo,
+ int *coding, int *coding_parameter)
+{
+ if (*coding==-1)
+ {
+ /* Determine all parameters automatically */
+ int best_coding;
+ int best_coding_parameter;
+ int best_code_size;
+ int current_coding;
+ int current_coding_parameter;
+ int current_code_size;
+ int initial_code_size;
+ struct coder *coder;
+ /* Always use XTC2 for the initial coding. */
+ compress_quantized_pos(quant,quant_inter,quant_intra,natoms,1,speed,
+ TNG_COMPRESS_ALGO_POS_XTC2,0,
+ 0,0,
+ prec_hi,prec_lo,&initial_code_size,NULL);
+ /* Start with XTC2, it should always work. */
+ current_coding=TNG_COMPRESS_ALGO_POS_XTC2;
+ current_coding_parameter=0;
+ compress_quantized_pos(quant,quant_inter,quant_intra,natoms,nframes,speed,
+ TNG_COMPRESS_ALGO_POS_XTC2,0,
+ current_coding,current_coding_parameter,
+ prec_hi,prec_lo,¤t_code_size,NULL);
+ best_coding=current_coding;
+ best_coding_parameter=current_coding_parameter;
+ best_code_size=current_code_size-initial_code_size; /* Correct for the use of XTC2 for the first frame. */
+
+ /* Determine best parameter for stopbit interframe coding. */
+ current_coding=TNG_COMPRESS_ALGO_POS_STOPBIT_INTER;
+ coder=Ptngc_coder_init();
+ current_code_size=natoms*3*(nframes-1);
+ current_coding_parameter=0;
+ if (!determine_best_coding_stop_bits(coder,quant_inter+natoms*3,¤t_code_size,
+ ¤t_coding_parameter,natoms))
+ {
+ if (current_code_size<best_code_size)
+ {
+ best_coding=current_coding;
+ best_coding_parameter=current_coding_parameter;
+ best_code_size=current_code_size;
+ }
+ }
+ Ptngc_coder_deinit(coder);
+
+ /* Determine best parameter for triplet interframe coding. */
+ current_coding=TNG_COMPRESS_ALGO_POS_TRIPLET_INTER;
+ coder=Ptngc_coder_init();
+ current_code_size=natoms*3*(nframes-1);
+ current_coding_parameter=0;
+ if (!determine_best_coding_triple(coder,quant_inter+natoms*3,¤t_code_size,
+ ¤t_coding_parameter,natoms))
+ {
+ if (current_code_size<best_code_size)
+ {
+ best_coding=current_coding;
+ best_coding_parameter=current_coding_parameter;
+ best_code_size=current_code_size;
+ }
+ }
+ Ptngc_coder_deinit(coder);
+
+ /* Determine best parameter for triplet intraframe coding. */
+ current_coding=TNG_COMPRESS_ALGO_POS_TRIPLET_INTRA;
+ coder=Ptngc_coder_init();
+ current_code_size=natoms*3*(nframes-1);
+ current_coding_parameter=0;
+ if (!determine_best_coding_triple(coder,quant_intra+natoms*3,¤t_code_size,
+ ¤t_coding_parameter,natoms))
+ {
+ if (current_code_size<best_code_size)
+ {
+ best_coding=current_coding;
+ best_coding_parameter=current_coding_parameter;
+ best_code_size=current_code_size;
+ }
+ }
+ Ptngc_coder_deinit(coder);
+
+ /* Determine best parameter for triplet one-to-one coding. */
+ current_coding=TNG_COMPRESS_ALGO_POS_TRIPLET_ONETOONE;
+ coder=Ptngc_coder_init();
+ current_code_size=natoms*3*(nframes-1);
+ current_coding_parameter=0;
+ if (!determine_best_coding_triple(coder,quant+natoms*3,¤t_code_size,
+ ¤t_coding_parameter,natoms))
+ {
+ if (current_code_size<best_code_size)
+ {
+ best_coding=current_coding;
+ best_coding_parameter=current_coding_parameter;
+ best_code_size=current_code_size;
+ }
+ }
+ Ptngc_coder_deinit(coder);
+
+ /* Test BWLZH inter */
+ if (speed>=4)
+ {
+ current_coding=TNG_COMPRESS_ALGO_POS_BWLZH_INTER;
+ current_coding_parameter=0;
+ compress_quantized_pos(quant,quant_inter,quant_intra,natoms,nframes,speed,
+ TNG_COMPRESS_ALGO_POS_XTC2,0,
+ current_coding,current_coding_parameter,
+ prec_hi,prec_lo,¤t_code_size,NULL);
+ current_code_size-=initial_code_size; /* Correct for the use of XTC2 for the first frame. */
+ if (current_code_size<best_code_size)
+ {
+ best_coding=current_coding;
+ best_coding_parameter=current_coding_parameter;
+ best_code_size=current_code_size;
+ }
+ }
+
+ /* Test BWLZH intra */
+ if (speed>=6)
+ {
+ current_coding=TNG_COMPRESS_ALGO_POS_BWLZH_INTRA;
+ current_coding_parameter=0;
+ compress_quantized_pos(quant,quant_inter,quant_intra,natoms,nframes,speed,
+ TNG_COMPRESS_ALGO_POS_XTC2,0,
+ current_coding,current_coding_parameter,
+ prec_hi,prec_lo,¤t_code_size,NULL);
+ current_code_size-=initial_code_size; /* Correct for the use of XTC2 for the first frame. */
+ if (current_code_size<best_code_size)
+ {
+ best_coding=current_coding;
+ best_coding_parameter=current_coding_parameter;
+ }
+ }
+ *coding=best_coding;
+ *coding_parameter=best_coding_parameter;
+ }
+ else if (*coding_parameter==-1)
+ {
+ if ((*coding==TNG_COMPRESS_ALGO_POS_XTC2) ||
+ (*coding==TNG_COMPRESS_ALGO_POS_XTC3) ||
+ (*coding==TNG_COMPRESS_ALGO_POS_BWLZH_INTER) ||
+ (*coding==TNG_COMPRESS_ALGO_POS_BWLZH_INTRA))
+ *coding_parameter=0;
+ else if (*coding==TNG_COMPRESS_ALGO_POS_STOPBIT_INTER)
+ {
+ struct coder *coder=Ptngc_coder_init();
+ int current_code_size=natoms*3*(nframes-1);
+ determine_best_coding_stop_bits(coder,quant_inter+natoms*3,¤t_code_size,
+ coding_parameter,natoms);
+ Ptngc_coder_deinit(coder);
+ }
+ else if (*coding==TNG_COMPRESS_ALGO_POS_TRIPLET_INTER)
+ {
+ struct coder *coder=Ptngc_coder_init();
+ int current_code_size=natoms*3*(nframes-1);
+ determine_best_coding_triple(coder,quant_inter+natoms*3,¤t_code_size,
+ coding_parameter,natoms);
+ Ptngc_coder_deinit(coder);
+ }
+ else if (*coding==TNG_COMPRESS_ALGO_POS_TRIPLET_INTRA)
+ {
+ struct coder *coder=Ptngc_coder_init();
+ int current_code_size=natoms*3*(nframes-1);
+ determine_best_coding_triple(coder,quant_intra+natoms*3,¤t_code_size,
+ coding_parameter,natoms);
+ Ptngc_coder_deinit(coder);
+ }
+ else if (*coding==TNG_COMPRESS_ALGO_POS_TRIPLET_ONETOONE)
+ {
+ struct coder *coder=Ptngc_coder_init();
+ int current_code_size=natoms*3*(nframes-1);
+ determine_best_coding_triple(coder,quant+natoms*3,¤t_code_size,
+ coding_parameter,natoms);
+ Ptngc_coder_deinit(coder);
+ }
+ }
+}
+
+static void determine_best_vel_initial_coding(int *quant, int natoms, int speed,
+ fix_t prec_hi, fix_t prec_lo,
+ int *initial_coding, int *initial_coding_parameter)
+{
+ if (*initial_coding==-1)
+ {
+ /* Determine all parameters automatically */
+ int best_coding=-1;
+ int best_coding_parameter=-1;
+ int best_code_size=-1;
+ int current_coding;
+ int current_coding_parameter;
+ int current_code_size;
+ struct coder *coder;
+ /* Start to determine best parameter for stopbit one-to-one. */
+ current_coding=TNG_COMPRESS_ALGO_VEL_STOPBIT_ONETOONE;
+ current_code_size=natoms*3;
+ current_coding_parameter=0;
+ coder=Ptngc_coder_init();
+ if (!determine_best_coding_stop_bits(coder,quant,¤t_code_size,
+ ¤t_coding_parameter,natoms))
+ {
+ best_coding=current_coding;
+ best_coding_parameter=current_coding_parameter;
+ best_code_size=current_code_size;
+ }
+ Ptngc_coder_deinit(coder);
+
+ /* Determine best parameter for triplet one-to-one. */
+ current_coding=TNG_COMPRESS_ALGO_VEL_TRIPLET_ONETOONE;
+ coder=Ptngc_coder_init();
+ current_code_size=natoms*3;
+ current_coding_parameter=0;
+ if (!determine_best_coding_triple(coder,quant,¤t_code_size,¤t_coding_parameter,natoms))
+ {
+ if ((best_coding==-1) || (current_code_size<best_code_size))
+ {
+ best_coding=current_coding;
+ best_coding_parameter=current_coding_parameter;
+ best_code_size=current_code_size;
+ }
+ }
+ Ptngc_coder_deinit(coder);
+
+ /* Test BWLZH one-to-one */
+ if (speed>=4)
+ {
+ current_coding=TNG_COMPRESS_ALGO_VEL_BWLZH_ONETOONE;
+ current_coding_parameter=0;
+ compress_quantized_vel(quant,NULL,natoms,1,speed,
+ current_coding,current_coding_parameter,
+ 0,0,prec_hi,prec_lo,¤t_code_size,NULL);
+ if ((best_coding==-1) || (current_code_size<best_code_size))
+ {
+ best_coding=current_coding;
+ best_coding_parameter=current_coding_parameter;
+ }
+ }
+ *initial_coding=best_coding;
+ *initial_coding_parameter=best_coding_parameter;
+ }
+ else if (*initial_coding_parameter==-1)
+ {
+ if (*initial_coding==TNG_COMPRESS_ALGO_VEL_BWLZH_ONETOONE)
+ *initial_coding_parameter=0;
+ else if (*initial_coding==TNG_COMPRESS_ALGO_VEL_STOPBIT_ONETOONE)
+ {
+ struct coder *coder=Ptngc_coder_init();
+ int current_code_size=natoms*3;
+ determine_best_coding_stop_bits(coder,quant,¤t_code_size,
+ initial_coding_parameter,natoms);
+ Ptngc_coder_deinit(coder);
+ }
+ else if (*initial_coding==TNG_COMPRESS_ALGO_VEL_TRIPLET_ONETOONE)
+ {
+ struct coder *coder=Ptngc_coder_init();
+ int current_code_size=natoms*3;
+ determine_best_coding_triple(coder,quant,¤t_code_size,initial_coding_parameter,natoms);
+ Ptngc_coder_deinit(coder);
+ }
+ }
+}
+
+static void determine_best_vel_coding(int *quant, int *quant_inter, int natoms, int nframes, int speed,
+ fix_t prec_hi, fix_t prec_lo,
+ int *coding, int *coding_parameter)
+{
+ if (*coding==-1)
+ {
+ /* Determine all parameters automatically */
+ int best_coding;
+ int best_coding_parameter;
+ int best_code_size;
+ int current_coding;
+ int current_coding_parameter;
+ int current_code_size;
+ int initial_code_size;
+ int initial_numbits=5;
+ struct coder *coder;
+ /* Use stopbits one-to-one coding for the initial coding. */
+ compress_quantized_vel(quant,NULL,natoms,1,speed,
+ TNG_COMPRESS_ALGO_VEL_STOPBIT_ONETOONE,initial_numbits,
+ 0,0,prec_hi,prec_lo,&initial_code_size,NULL);
+
+ /* Test stopbit one-to-one */
+ current_coding=TNG_COMPRESS_ALGO_VEL_STOPBIT_ONETOONE;
+ current_code_size=natoms*3*(nframes-1);
+ current_coding_parameter=0;
+ coder=Ptngc_coder_init();
+ determine_best_coding_stop_bits(coder,quant+natoms*3,¤t_code_size,
+ ¤t_coding_parameter,natoms);
+ Ptngc_coder_deinit(coder);
+ best_coding=current_coding;
+ best_code_size=current_code_size;
+ best_coding_parameter=current_coding_parameter;
+
+ /* Test triplet interframe */
+ current_coding=TNG_COMPRESS_ALGO_VEL_TRIPLET_INTER;
+ current_code_size=natoms*3*(nframes-1);
+ current_coding_parameter=0;
+ coder=Ptngc_coder_init();
+ if (!determine_best_coding_triple(coder,quant_inter+natoms*3,¤t_code_size,
+ ¤t_coding_parameter,natoms))
+ {
+ if (current_code_size<best_code_size)
+ {
+ best_coding=current_coding;
+ best_code_size=current_code_size;
+ best_coding_parameter=current_coding_parameter;
+ }
+ }
+ Ptngc_coder_deinit(coder);
+
+ /* Test triplet one-to-one */
+ current_coding=TNG_COMPRESS_ALGO_VEL_TRIPLET_ONETOONE;
+ current_code_size=natoms*3*(nframes-1);
+ current_coding_parameter=0;
+ coder=Ptngc_coder_init();
+ if (!determine_best_coding_triple(coder,quant+natoms*3,¤t_code_size,
+ ¤t_coding_parameter,natoms))
+ {
+ if (current_code_size<best_code_size)
+ {
+ best_coding=current_coding;
+ best_code_size=current_code_size;
+ best_coding_parameter=current_coding_parameter;
+ }
+ }
+ Ptngc_coder_deinit(coder);
+
+ /* Test stopbit interframe */
+ current_coding=TNG_COMPRESS_ALGO_VEL_STOPBIT_INTER;
+ current_code_size=natoms*3*(nframes-1);
+ current_coding_parameter=0;
+ coder=Ptngc_coder_init();
+ if (!determine_best_coding_stop_bits(coder,quant_inter+natoms*3,¤t_code_size,
+ ¤t_coding_parameter,natoms))
+ {
+ if (current_code_size<best_code_size)
+ {
+ best_coding=current_coding;
+ best_code_size=current_code_size;
+ best_coding_parameter=current_coding_parameter;
+ }
+ }
+ Ptngc_coder_deinit(coder);
+
+ if (speed>=4)
+ {
+ /* Test BWLZH inter */
+ current_coding=TNG_COMPRESS_ALGO_VEL_BWLZH_INTER;
+ current_coding_parameter=0;
+ compress_quantized_vel(quant,quant_inter,natoms,nframes,speed,
+ TNG_COMPRESS_ALGO_VEL_STOPBIT_ONETOONE,initial_numbits,
+ current_coding,current_coding_parameter,
+ prec_hi,prec_lo,¤t_code_size,NULL);
+ current_code_size-=initial_code_size; /* Correct for the initial frame */
+ if (current_code_size<best_code_size)
+ {
+ best_coding=current_coding;
+ best_code_size=current_code_size;
+ best_coding_parameter=current_coding_parameter;
+ }
+
+ /* Test BWLZH one-to-one */
+ current_coding=TNG_COMPRESS_ALGO_VEL_BWLZH_ONETOONE;
+ current_coding_parameter=0;
+ compress_quantized_vel(quant,quant_inter,natoms,nframes,speed,
+ TNG_COMPRESS_ALGO_VEL_STOPBIT_ONETOONE,initial_numbits,
+ current_coding,current_coding_parameter,
+ prec_hi,prec_lo,¤t_code_size,NULL);
+ current_code_size-=initial_code_size; /* Correct for the initial frame */
+ if (current_code_size<best_code_size)
+ {
+ best_coding=current_coding;
+ best_coding_parameter=current_coding_parameter;
+ }
+ }
+ *coding=best_coding;
+ *coding_parameter=best_coding_parameter;
+ }
+ else if (*coding_parameter==-1)
+ {
+ if ((*coding==TNG_COMPRESS_ALGO_VEL_BWLZH_INTER) ||
+ (*coding==TNG_COMPRESS_ALGO_VEL_BWLZH_ONETOONE))
+ *coding_parameter=0;
+ else if (*coding==TNG_COMPRESS_ALGO_VEL_STOPBIT_ONETOONE)
+ {
+ struct coder *coder=Ptngc_coder_init();
+ int current_code_size=natoms*3*(nframes-1);
+ determine_best_coding_stop_bits(coder,quant+natoms*3,¤t_code_size,
+ coding_parameter,natoms);
+ Ptngc_coder_deinit(coder);
+ }
+ else if (*coding==TNG_COMPRESS_ALGO_VEL_TRIPLET_INTER)
+ {
+ struct coder *coder=Ptngc_coder_init();
+ int current_code_size=natoms*3*(nframes-1);
+ determine_best_coding_triple(coder,quant_inter+natoms*3,¤t_code_size,
+ coding_parameter,natoms);
+ Ptngc_coder_deinit(coder);
+ }
+ else if (*coding==TNG_COMPRESS_ALGO_VEL_TRIPLET_ONETOONE)
+ {
+ struct coder *coder=Ptngc_coder_init();
+ int current_code_size=natoms*3*(nframes-1);
+ determine_best_coding_triple(coder,quant+natoms*3,¤t_code_size,
+ coding_parameter,natoms);
+ Ptngc_coder_deinit(coder);
+ }
+ else if (*coding==TNG_COMPRESS_ALGO_VEL_STOPBIT_INTER)
+ {
+ struct coder *coder=Ptngc_coder_init();
+ int current_code_size=natoms*3*(nframes-1);
+ determine_best_coding_stop_bits(coder,quant_inter+natoms*3,¤t_code_size,
+ coding_parameter,natoms);
+ Ptngc_coder_deinit(coder);
+ }
+ }
+}
+
+char DECLSPECDLLEXPORT *tng_compress_pos_int(int *pos, int natoms, int nframes,
+ unsigned long prec_hi, unsigned long prec_lo,
+ int speed,int *algo,
+ int *nitems)
+{
+ char *data=malloc(natoms*nframes*14+11*4); /* 12 bytes are required to store 4 32 bit integers
+ This is 17% extra. The final 11*4 is to store information
+ needed for decompression. */
+ int *quant=pos; /* Already quantized positions. */
+ int *quant_intra=malloc(natoms*nframes*3*sizeof *quant_intra);
+ int *quant_inter=malloc(natoms*nframes*3*sizeof *quant_inter);
+
+ int initial_coding, initial_coding_parameter;
+ int coding, coding_parameter;
+ if (speed==0)
+ speed=SPEED_DEFAULT; /* Set the default speed. */
+ /* Boundaries of speed. */
+ if (speed<1)
+ speed=1;
+ if (speed>6)
+ speed=6;
+ initial_coding=algo[0];
+ initial_coding_parameter=algo[1];
+ coding=algo[2];
+ coding_parameter=algo[3];
+
+ quant_inter_differences(quant,natoms,nframes,quant_inter);
+ quant_intra_differences(quant,natoms,nframes,quant_intra);
+
+ /* If any of the above codings / coding parameters are == -1, the optimal parameters must be found */
+ if (initial_coding==-1)
+ {
+ initial_coding_parameter=-1;
+ determine_best_pos_initial_coding(quant,quant_intra,natoms,speed,prec_hi,prec_lo,
+ &initial_coding,&initial_coding_parameter);
+ }
+ else if (initial_coding_parameter==-1)
+ {
+ determine_best_pos_initial_coding(quant,quant_intra,natoms,speed,prec_hi,prec_lo,
+ &initial_coding,&initial_coding_parameter);
+ }
+
+ if (nframes==1)
+ {
+ coding=0;
+ coding_parameter=0;
+ }
+
+ if (nframes>1)
+ {
+ if (coding==-1)
+ {
+ coding_parameter=-1;
+ determine_best_pos_coding(quant,quant_inter,quant_intra,natoms,nframes,speed,prec_hi,prec_lo,
+ &coding,&coding_parameter);
+ }
+ else if (coding_parameter==-1)
+ {
+ determine_best_pos_coding(quant,quant_inter,quant_intra,natoms,nframes,speed,prec_hi,prec_lo,
+ &coding,&coding_parameter);
+ }
+ }
+
+ compress_quantized_pos(quant,quant_inter,quant_intra,natoms,nframes,speed,
+ initial_coding,initial_coding_parameter,
+ coding,coding_parameter,
+ prec_hi,prec_lo,nitems,data);
+ free(quant_inter);
+ free(quant_intra);
+ if (algo[0]==-1)
+ algo[0]=initial_coding;
+ if (algo[1]==-1)
+ algo[1]=initial_coding_parameter;
+ if (algo[2]==-1)
+ algo[2]=coding;
+ if (algo[3]==-1)
+ algo[3]=coding_parameter;
+ return data;
+}
+
+char DECLSPECDLLEXPORT *tng_compress_pos(double *pos, int natoms, int nframes,
+ double desired_precision,
+ int speed,int *algo,
+ int *nitems)
+{
+ int *quant=malloc(natoms*nframes*3*sizeof *quant);
+ char *data;
+ fix_t prec_hi, prec_lo;
+ Ptngc_d_to_i32x2(desired_precision,&prec_hi,&prec_lo);
+
+ if (quantize(pos,natoms,nframes,PRECISION(prec_hi,prec_lo),quant))
+ data=NULL; /* Error occured. Too large input values. */
+ else
+ data=tng_compress_pos_int(quant,natoms,nframes,prec_hi,prec_lo,speed,algo,nitems);
+ free(quant);
+ return data;
+}
+
+char DECLSPECDLLEXPORT *tng_compress_pos_float(float *pos, int natoms, int nframes,
+ float desired_precision,
+ int speed,int *algo,
+ int *nitems)
+{
+ int *quant=malloc(natoms*nframes*3*sizeof *quant);
+ char *data;
+ fix_t prec_hi, prec_lo;
+ Ptngc_d_to_i32x2((double)desired_precision,&prec_hi,&prec_lo);
+
+ if (quantize_float(pos,natoms,nframes,(float)PRECISION(prec_hi,prec_lo),quant))
+ data=NULL; /* Error occured. Too large input values. */
+ else
+ data=tng_compress_pos_int(quant,natoms,nframes,prec_hi,prec_lo,speed,algo,nitems);
+ free(quant);
+ return data;
+}
+
+char DECLSPECDLLEXPORT *tng_compress_pos_find_algo(double *pos, int natoms, int nframes,
+ double desired_precision,
+ int speed,
+ int *algo,
+ int *nitems)
+{
+ algo[0]=-1;
+ algo[1]=-1;
+ algo[2]=-1;
+ algo[3]=-1;
+ return tng_compress_pos(pos,natoms,nframes,desired_precision,speed,algo,nitems);
+}
+
+char DECLSPECDLLEXPORT *tng_compress_pos_float_find_algo(float *pos, int natoms, int nframes,
+ float desired_precision,
+ int speed,
+ int *algo,
+ int *nitems)
+{
+ algo[0]=-1;
+ algo[1]=-1;
+ algo[2]=-1;
+ algo[3]=-1;
+ return tng_compress_pos_float(pos,natoms,nframes,desired_precision,speed,algo,nitems);
+}
+
+char DECLSPECDLLEXPORT *tng_compress_pos_int_find_algo(int *pos, int natoms, int nframes,
+ unsigned long prec_hi, unsigned long prec_lo,
+ int speed,int *algo,
+ int *nitems)
+{
+ algo[0]=-1;
+ algo[1]=-1;
+ algo[2]=-1;
+ algo[3]=-1;
+ return tng_compress_pos_int(pos,natoms,nframes,prec_hi,prec_lo,speed,algo,nitems);
+}
+
+
+
+int DECLSPECDLLEXPORT tng_compress_nalgo(void)
+{
+ return 4; /* There are currently four parameters required:
+
+ 1) The compression algorithm for the first frame (initial_coding).
+ 2) One parameter to the algorithm for the first frame (the initial coding parameter).
+ 3) The compression algorithm for the remaining frames (coding).
+ 4) One parameter to the algorithm for the remaining frames (the coding parameter). */
+}
+
+char DECLSPECDLLEXPORT *tng_compress_vel_int(int *vel, int natoms, int nframes,
+ unsigned long prec_hi, unsigned long prec_lo,
+ int speed, int *algo,
+ int *nitems)
+{
+ char *data=malloc(natoms*nframes*14+11*4); /* 12 bytes are required to store 4 32 bit integers
+ This is 17% extra. The final 11*4 is to store information
+ needed for decompression. */
+ int *quant=vel;
+ int *quant_inter=malloc(natoms*nframes*3*sizeof *quant_inter);
+
+ int initial_coding, initial_coding_parameter;
+ int coding, coding_parameter;
+ if (speed==0)
+ speed=SPEED_DEFAULT; /* Set the default speed. */
+ /* Boundaries of speed. */
+ if (speed<1)
+ speed=1;
+ if (speed>6)
+ speed=6;
+ initial_coding=algo[0];
+ initial_coding_parameter=algo[1];
+ coding=algo[2];
+ coding_parameter=algo[3];
+
+ quant_inter_differences(quant,natoms,nframes,quant_inter);
+
+ /* If any of the above codings / coding parameters are == -1, the optimal parameters must be found */
+ if (initial_coding==-1)
+ {
+ initial_coding_parameter=-1;
+ determine_best_vel_initial_coding(quant,natoms,speed,prec_hi,prec_lo,
+ &initial_coding,&initial_coding_parameter);
+ }
+ else if (initial_coding_parameter==-1)
+ {
+ determine_best_vel_initial_coding(quant,natoms,speed,prec_hi,prec_lo,
+ &initial_coding,&initial_coding_parameter);
+ }
+
+ if (nframes==1)
+ {
+ coding=0;
+ coding_parameter=0;
+ }
+
+ if (nframes>1)
+ {
+ if (coding==-1)
+ {
+ coding_parameter=-1;
+ determine_best_vel_coding(quant,quant_inter,natoms,nframes,speed,prec_hi,prec_lo,
+ &coding,&coding_parameter);
+ }
+ else if (coding_parameter==-1)
+ {
+ determine_best_vel_coding(quant,quant_inter,natoms,nframes,speed,prec_hi,prec_lo,
+ &coding,&coding_parameter);
+ }
+ }
+
+ compress_quantized_vel(quant,quant_inter,natoms,nframes,speed,
+ initial_coding,initial_coding_parameter,
+ coding,coding_parameter,
+ prec_hi,prec_lo,nitems,data);
+ free(quant_inter);
+ if (algo[0]==-1)
+ algo[0]=initial_coding;
+ if (algo[1]==-1)
+ algo[1]=initial_coding_parameter;
+ if (algo[2]==-1)
+ algo[2]=coding;
+ if (algo[3]==-1)
+ algo[3]=coding_parameter;
+ return data;
+}
+
+char DECLSPECDLLEXPORT *tng_compress_vel(double *vel, int natoms, int nframes,
+ double desired_precision,
+ int speed, int *algo,
+ int *nitems)
+{
+ int *quant=malloc(natoms*nframes*3*sizeof *quant);
+ char *data;
+ fix_t prec_hi, prec_lo;
+ Ptngc_d_to_i32x2(desired_precision,&prec_hi,&prec_lo);
+ if (quantize(vel,natoms,nframes,PRECISION(prec_hi,prec_lo),quant))
+ data=NULL; /* Error occured. Too large input values. */
+ else
+ data=tng_compress_vel_int(quant,natoms,nframes,prec_hi,prec_lo,speed,algo,nitems);
+ free(quant);
+ return data;
+}
+
+char DECLSPECDLLEXPORT *tng_compress_vel_float(float *vel, int natoms, int nframes,
+ float desired_precision,
+ int speed, int *algo,
+ int *nitems)
+{
+ int *quant=malloc(natoms*nframes*3*sizeof *quant);
+ char *data;
+ fix_t prec_hi, prec_lo;
+ Ptngc_d_to_i32x2((double)desired_precision,&prec_hi,&prec_lo);
+ if (quantize_float(vel,natoms,nframes,(float)PRECISION(prec_hi,prec_lo),quant))
+ data=NULL; /* Error occured. Too large input values. */
+ else
+ data=tng_compress_vel_int(quant,natoms,nframes,prec_hi,prec_lo,speed,algo,nitems);
+ free(quant);
+ return data;
+}
+
+char DECLSPECDLLEXPORT *tng_compress_vel_find_algo(double *vel, int natoms, int nframes,
+ double desired_precision,
+ int speed,
+ int *algo,
+ int *nitems)
+{
+ algo[0]=-1;
+ algo[1]=-1;
+ algo[2]=-1;
+ algo[3]=-1;
+ return tng_compress_vel(vel,natoms,nframes,desired_precision,speed,algo,nitems);
+}
+
+char DECLSPECDLLEXPORT *tng_compress_vel_float_find_algo(float *vel, int natoms, int nframes,
+ float desired_precision,
+ int speed,
+ int *algo,
+ int *nitems)
+{
+ algo[0]=-1;
+ algo[1]=-1;
+ algo[2]=-1;
+ algo[3]=-1;
+ return tng_compress_vel_float(vel,natoms,nframes,desired_precision,speed,algo,nitems);
+}
+
+char DECLSPECDLLEXPORT *tng_compress_vel_int_find_algo(int *vel, int natoms, int nframes,
+ unsigned long prec_hi, unsigned long prec_lo,
+ int speed,
+ int *algo,
+ int *nitems)
+{
+ algo[0]=-1;
+ algo[1]=-1;
+ algo[2]=-1;
+ algo[3]=-1;
+ return tng_compress_vel_int(vel,natoms,nframes,prec_hi,prec_lo,speed,algo,nitems);
+}
+
+int DECLSPECDLLEXPORT tng_compress_inquire(char *data,int *vel, int *natoms,
+ int *nframes, double *precision,
+ int *algo)
+{
+ int bufloc=0;
+ fix_t prec_hi, prec_lo;
+ int initial_coding, initial_coding_parameter;
+ int coding, coding_parameter;
+ int magic_int;
+ magic_int=(int)readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ if (magic_int==MAGIC_INT_POS)
+ *vel=0;
+ else if (magic_int==MAGIC_INT_VEL)
+ *vel=1;
+ else
+ return 1;
+ /* Number of atoms. */
+ *natoms=(int)readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ /* Number of frames. */
+ *nframes=(int)readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ /* Initial coding. */
+ initial_coding=(int)readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ /* Initial coding parameter. */
+ initial_coding_parameter=(int)readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ /* Coding. */
+ coding=(int)readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ /* Coding parameter. */
+ coding_parameter=(int)readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ /* Precision. */
+ prec_lo=readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ prec_hi=readbufferfix((unsigned char *)data+bufloc,4);
+ *precision=PRECISION(prec_hi, prec_lo);
+ algo[0]=initial_coding;
+ algo[1]=initial_coding_parameter;
+ algo[2]=coding;
+ algo[3]=coding_parameter;
+ return 0;
+}
+
+static int tng_compress_uncompress_pos_gen(char *data,double *posd,float *posf,int *posi,unsigned long *prec_hi, unsigned long *prec_lo)
+{
+ int bufloc=0;
+ int length;
+ int natoms, nframes;
+ int initial_coding, initial_coding_parameter;
+ int coding, coding_parameter;
+ int *quant=NULL;
+ struct coder *coder=NULL;
+ int rval=0;
+ int magic_int;
+ /* Magic integer for positions */
+ magic_int=(int)readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ if (magic_int!=MAGIC_INT_POS)
+ {
+ rval=1;
+ goto error;
+ }
+ /* Number of atoms. */
+ natoms=(int)readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ /* Number of frames. */
+ nframes=(int)readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ /* Initial coding. */
+ initial_coding=(int)readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ /* Initial coding parameter. */
+ initial_coding_parameter=(int)readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ /* Coding. */
+ coding=(int)readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ /* Coding parameter. */
+ coding_parameter=(int)readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ /* Precision. */
+ *prec_lo=readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ *prec_hi=readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ /* Allocate the memory for the quantized positions */
+ quant=malloc(natoms*nframes*3*sizeof *quant);
+ /* The data block length. */
+ length=(int)readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ /* The initial frame */
+ coder=Ptngc_coder_init();
+ rval=Ptngc_unpack_array(coder,(unsigned char*)data+bufloc,quant,natoms*3,
+ initial_coding,initial_coding_parameter,natoms);
+ Ptngc_coder_deinit(coder);
+ if (rval)
+ goto error;
+ /* Skip past the actual data block. */
+ bufloc+=length;
+ /* Obtain the actual positions for the initial block. */
+ if ((initial_coding==TNG_COMPRESS_ALGO_POS_XTC2) ||
+ (initial_coding==TNG_COMPRESS_ALGO_POS_TRIPLET_ONETOONE) ||
+ (initial_coding==TNG_COMPRESS_ALGO_POS_XTC3))
+ {
+ if (posd)
+ unquantize(posd,natoms,1,PRECISION(*prec_hi,*prec_lo),quant);
+ else if (posf)
+ unquantize_float(posf,natoms,1,(float)PRECISION(*prec_hi,*prec_lo),quant);
+ else if (posi)
+ memcpy(posi,quant,natoms*3*sizeof *posi);
+ }
+ else if ((initial_coding==TNG_COMPRESS_ALGO_POS_TRIPLET_INTRA) ||
+ (initial_coding==TNG_COMPRESS_ALGO_POS_BWLZH_INTRA))
+ {
+ if (posd)
+ unquantize_intra_differences(posd,natoms,1,PRECISION(*prec_hi,*prec_lo),quant);
+ else if (posf)
+ unquantize_intra_differences_float(posf,natoms,1,(float)PRECISION(*prec_hi,*prec_lo),quant);
+ else if (posi)
+ unquantize_intra_differences_int(posi,natoms,1,quant);
+ unquant_intra_differences_first_frame(quant,natoms);
+ }
+ /* The remaining frames. */
+ if (nframes>1)
+ {
+ bufloc+=4;
+ coder=Ptngc_coder_init();
+ rval=Ptngc_unpack_array(coder,(unsigned char *)data+bufloc,quant+natoms*3,(nframes-1)*natoms*3,
+ coding,coding_parameter,natoms);
+ Ptngc_coder_deinit(coder);
+ if (rval)
+ goto error;
+ if ((coding==TNG_COMPRESS_ALGO_POS_STOPBIT_INTER) ||
+ (coding==TNG_COMPRESS_ALGO_POS_TRIPLET_INTER) ||
+ (coding==TNG_COMPRESS_ALGO_POS_BWLZH_INTER))
+ {
+ /* This requires that the first frame is already in one-to-one format, even if intra-frame
+ compression was done there. Therefore the unquant_intra_differences_first_frame should be called
+ before to convert it correctly. */
+ if (posd)
+ unquantize_inter_differences(posd,natoms,nframes,PRECISION(*prec_hi,*prec_lo),quant);
+ else if (posf)
+ unquantize_inter_differences_float(posf,natoms,nframes,(float)PRECISION(*prec_hi,*prec_lo),quant);
+ else if (posi)
+ unquantize_inter_differences_int(posi,natoms,nframes,quant);
+ }
+ else if ((coding==TNG_COMPRESS_ALGO_POS_XTC2) ||
+ (coding==TNG_COMPRESS_ALGO_POS_XTC3) ||
+ (coding==TNG_COMPRESS_ALGO_POS_TRIPLET_ONETOONE))
+ {
+ if (posd)
+ unquantize(posd+natoms*3,natoms,nframes-1,PRECISION(*prec_hi,*prec_lo),quant+natoms*3);
+ else if (posf)
+ unquantize_float(posf+natoms*3,natoms,nframes-1,(float)PRECISION(*prec_hi,*prec_lo),quant+natoms*3);
+ else if (posi)
+ memcpy(posi+natoms*3,quant+natoms*3,natoms*3*(nframes-1)*sizeof *posi);
+ }
+ else if ((coding==TNG_COMPRESS_ALGO_POS_TRIPLET_INTRA) ||
+ (coding==TNG_COMPRESS_ALGO_POS_BWLZH_INTRA))
+ {
+ if (posd)
+ unquantize_intra_differences(posd+natoms*3,natoms,nframes-1,PRECISION(*prec_hi,*prec_lo),quant+natoms*3);
+ else if (posf)
+ unquantize_intra_differences_float(posf+natoms*3,natoms,nframes-1,(float)PRECISION(*prec_hi,*prec_lo),quant+natoms*3);
+ else if (posi)
+ unquantize_intra_differences_int(posi+natoms*3,natoms,nframes-1,quant+natoms*3);
+ }
+ }
+ error:
+ free(quant);
+ return rval;
+}
+
+static int tng_compress_uncompress_pos(char *data,double *pos)
+{
+ unsigned long prec_hi, prec_lo;
+ return tng_compress_uncompress_pos_gen(data,pos,NULL,NULL,&prec_hi,&prec_lo);
+}
+
+static int tng_compress_uncompress_pos_float(char *data,float *pos)
+{
+ unsigned long prec_hi, prec_lo;
+ return tng_compress_uncompress_pos_gen(data,NULL,pos,NULL,&prec_hi,&prec_lo);
+}
+
+static int tng_compress_uncompress_pos_int(char *data,int *pos, unsigned long *prec_hi, unsigned long *prec_lo)
+{
+ return tng_compress_uncompress_pos_gen(data,NULL,NULL,pos,prec_hi,prec_lo);
+}
+
+static int tng_compress_uncompress_vel_gen(char *data,double *veld,float *velf,int *veli,unsigned long *prec_hi, unsigned long *prec_lo)
+{
+ int bufloc=0;
+ int length;
+ int natoms, nframes;
+ int initial_coding, initial_coding_parameter;
+ int coding, coding_parameter;
+ int *quant=NULL;
+ struct coder *coder=NULL;
+ int rval=0;
+ int magic_int;
+ /* Magic integer for velocities */
+ magic_int=(int)readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ if (magic_int!=MAGIC_INT_VEL)
+ {
+ rval=1;
+ goto error;
+ }
+ /* Number of atoms. */
+ natoms=(int)readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ /* Number of frames. */
+ nframes=(int)readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ /* Initial coding. */
+ initial_coding=(int)readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ /* Initial coding parameter. */
+ initial_coding_parameter=(int)readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ /* Coding. */
+ coding=(int)readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ /* Coding parameter. */
+ coding_parameter=(int)readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ /* Precision. */
+ *prec_lo=readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ *prec_hi=readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ /* Allocate the memory for the quantized positions */
+ quant=malloc(natoms*nframes*3*sizeof *quant);
+ /* The data block length. */
+ length=(int)readbufferfix((unsigned char *)data+bufloc,4);
+ bufloc+=4;
+ /* The initial frame */
+ coder=Ptngc_coder_init();
+ rval=Ptngc_unpack_array(coder,(unsigned char*)data+bufloc,quant,natoms*3,
+ initial_coding,initial_coding_parameter,natoms);
+ Ptngc_coder_deinit(coder);
+ if (rval)
+ goto error;
+ /* Skip past the actual data block. */
+ bufloc+=length;
+ /* Obtain the actual positions for the initial block. */
+ if ((initial_coding==TNG_COMPRESS_ALGO_VEL_STOPBIT_ONETOONE) ||
+ (initial_coding==TNG_COMPRESS_ALGO_VEL_TRIPLET_ONETOONE) ||
+ (initial_coding==TNG_COMPRESS_ALGO_VEL_BWLZH_ONETOONE))
+ {
+ if (veld)
+ unquantize(veld,natoms,1,PRECISION(*prec_hi,*prec_lo),quant);
+ else if (velf)
+ unquantize_float(velf,natoms,1,(float)PRECISION(*prec_hi,*prec_lo),quant);
+ else if (veli)
+ memcpy(veli,quant,natoms*3*sizeof *veli);
+ }
+ /* The remaining frames. */
+ if (nframes>1)
+ {
+ bufloc+=4;
+ coder=Ptngc_coder_init();
+ rval=Ptngc_unpack_array(coder,(unsigned char *)data+bufloc,quant+natoms*3,(nframes-1)*natoms*3,
+ coding,coding_parameter,natoms);
+ Ptngc_coder_deinit(coder);
+ if (rval)
+ goto error;
+ /* Inter-frame compression? */
+ if ((coding==TNG_COMPRESS_ALGO_VEL_TRIPLET_INTER) ||
+ (coding==TNG_COMPRESS_ALGO_VEL_STOPBIT_INTER) ||
+ (coding==TNG_COMPRESS_ALGO_VEL_BWLZH_INTER))
+ {
+ /* This requires that the first frame is already in one-to-one format. */
+ if (veld)
+ unquantize_inter_differences(veld,natoms,nframes,PRECISION(*prec_hi,*prec_lo),quant);
+ else if (velf)
+ unquantize_inter_differences_float(velf,natoms,nframes,(float)PRECISION(*prec_hi,*prec_lo),quant);
+ else if (veli)
+ unquantize_inter_differences_int(veli,natoms,nframes,quant);
+ }
+ /* One-to-one compression? */
+ else if ((coding==TNG_COMPRESS_ALGO_VEL_STOPBIT_ONETOONE) ||
+ (coding==TNG_COMPRESS_ALGO_VEL_TRIPLET_ONETOONE) ||
+ (coding==TNG_COMPRESS_ALGO_VEL_BWLZH_ONETOONE))
+ {
+ if (veld)
+ unquantize(veld+natoms*3,natoms,nframes-1,PRECISION(*prec_hi,*prec_lo),quant+natoms*3);
+ else if (velf)
+ unquantize_float(velf+natoms*3,natoms,nframes-1,(float)PRECISION(*prec_hi,*prec_lo),quant+natoms*3);
+ else if (veli)
+ memcpy(veli+natoms*3,quant+natoms*3,natoms*3*(nframes-1)*sizeof *veli);
+ }
+ }
+ error:
+ free(quant);
+ return rval;
+}
+
+static int tng_compress_uncompress_vel(char *data,double *vel)
+{
+ unsigned long prec_hi, prec_lo;
+ return tng_compress_uncompress_vel_gen(data,vel,NULL,NULL,&prec_hi,&prec_lo);
+}
+
+static int tng_compress_uncompress_vel_float(char *data,float *vel)
+{
+ unsigned long prec_hi, prec_lo;
+ return tng_compress_uncompress_vel_gen(data,NULL,vel,NULL,&prec_hi,&prec_lo);
+}
+
+static int tng_compress_uncompress_vel_int(char *data,int *vel, unsigned long *prec_hi, unsigned long *prec_lo)
+{
+ return tng_compress_uncompress_vel_gen(data,NULL,NULL,vel,prec_hi,prec_lo);
+}
+
+/* Uncompresses any tng compress block, positions or velocities. It determines whether it is positions or velocities from the data buffer. The return value is 0 if ok, and 1 if not.
+*/
+int DECLSPECDLLEXPORT tng_compress_uncompress(char *data,double *posvel)
+{
+ int magic_int;
+ magic_int=(int)readbufferfix((unsigned char *)data,4);
+ if (magic_int==MAGIC_INT_POS)
+ return tng_compress_uncompress_pos(data,posvel);
+ else if (magic_int==MAGIC_INT_VEL)
+ return tng_compress_uncompress_vel(data,posvel);
+ else
+ return 1;
+}
+
+int DECLSPECDLLEXPORT tng_compress_uncompress_float(char *data,float *posvel)
+{
+ int magic_int;
+ magic_int=(int)readbufferfix((unsigned char *)data,4);
+ if (magic_int==MAGIC_INT_POS)
+ return tng_compress_uncompress_pos_float(data,posvel);
+ else if (magic_int==MAGIC_INT_VEL)
+ return tng_compress_uncompress_vel_float(data,posvel);
+ else
+ return 1;
+}
+
+int DECLSPECDLLEXPORT tng_compress_uncompress_int(char *data,int *posvel, unsigned long *prec_hi, unsigned long *prec_lo)
+{
+ int magic_int;
+ magic_int=(int)readbufferfix((unsigned char *)data,4);
+ if (magic_int==MAGIC_INT_POS)
+ return tng_compress_uncompress_pos_int(data,posvel,prec_hi,prec_lo);
+ else if (magic_int==MAGIC_INT_VEL)
+ return tng_compress_uncompress_vel_int(data,posvel,prec_hi,prec_lo);
+ else
+ return 1;
+}
+
+void DECLSPECDLLEXPORT tng_compress_int_to_double(int *posvel_int,unsigned long prec_hi, unsigned long prec_lo,
+ int natoms,int nframes,
+ double *posvel_double)
+{
+ unquantize(posvel_double,natoms,nframes,PRECISION(prec_hi,prec_lo),posvel_int);
+}
+
+void DECLSPECDLLEXPORT tng_compress_int_to_float(int *posvel_int,unsigned long prec_hi, unsigned long prec_lo,
+ int natoms,int nframes,
+ float *posvel_float)
+{
+ unquantize_float(posvel_float,natoms,nframes,(float)PRECISION(prec_hi,prec_lo),posvel_int);
+}
+
+static char *compress_algo_pos[TNG_COMPRESS_ALGO_MAX]={
+ "Positions invalid algorithm",
+ "Positions stopbits interframe",
+ "Positions triplet interframe",
+ "Positions triplet intraframe",
+ "Positions invalid algorithm",
+ "Positions XTC2",
+ "Positions invalid algorithm",
+ "Positions triplet one to one",
+ "Positions BWLZH interframe",
+ "Positions BWLZH intraframe",
+ "Positions XTC3"
+};
+
+static char *compress_algo_vel[TNG_COMPRESS_ALGO_MAX]={
+ "Velocities invalid algorithm",
+ "Velocities stopbits one to one",
+ "Velocities triplet interframe",
+ "Velocities triplet one to one",
+ "Velocities invalid algorithm",
+ "Velocities invalid algorithm",
+ "Velocities stopbits interframe",
+ "Velocities invalid algorithm",
+ "Velocities BWLZH interframe",
+ "Velocities BWLZH one to one",
+ "Velocities invalid algorithm"
+};
+
+char DECLSPECDLLEXPORT *tng_compress_initial_pos_algo(int *algo)
+{
+ int i=algo[0];
+ if (i<0)
+ i=0;
+ if (i>=TNG_COMPRESS_ALGO_MAX)
+ i=0;
+ return compress_algo_pos[i];
+}
+
+char DECLSPECDLLEXPORT *tng_compress_pos_algo(int *algo)
+{
+ int i=algo[2];
+ if (i<0)
+ i=0;
+ if (i>=TNG_COMPRESS_ALGO_MAX)
+ i=0;
+ return compress_algo_pos[i];
+}
+
+char DECLSPECDLLEXPORT *tng_compress_initial_vel_algo(int *algo)
+{
+ int i=algo[0];
+ if (i<0)
+ i=0;
+ if (i>=TNG_COMPRESS_ALGO_MAX)
+ i=0;
+ return compress_algo_vel[i];
+}
+
+char DECLSPECDLLEXPORT *tng_compress_vel_algo(int *algo)
+{
+ int i=algo[2];
+ if (i<0)
+ i=0;
+ if (i>=TNG_COMPRESS_ALGO_MAX)
+ i=0;
+ return compress_algo_vel[i];
+}
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#include "../../include/compression/vals16.h"
+
+/* Coding 32 bit ints in sequences of 16 bit ints. Worst case
+ the output is 3*nvals long. */
+void Ptngc_comp_conv_to_vals16(unsigned int *vals,int nvals,
+ unsigned int *vals16, int *nvals16)
+{
+ int i;
+ int j=0;
+ for (i=0; i<nvals; i++)
+ {
+ if (vals[i]<=0x7FFFU)
+ vals16[j++]=vals[i];
+ else
+ {
+ unsigned int lo=(vals[i]&0x7FFFU)|0x8000U;
+ unsigned int hi=vals[i]>>15;
+ vals16[j++]=lo;
+ if (hi<=0x7FFFU)
+ vals16[j++]=hi;
+ else
+ {
+ unsigned int lohi=(hi&0x7FFFU)|0x8000U;
+ unsigned int hihi=hi>>15;
+ vals16[j++]=lohi;
+ vals16[j++]=hihi;
+ }
+ }
+ }
+#if 0
+ /* Test that things that detect that this is bad really works. */
+ vals16[0]=0;
+#endif
+ *nvals16=j;
+}
+
+void Ptngc_comp_conv_from_vals16(unsigned int *vals16,int nvals16,
+ unsigned int *vals, int *nvals)
+{
+ int i=0;
+ int j=0;
+ while (i<nvals16)
+ {
+ if (vals16[i]<=0x7FFFU)
+ vals[j++]=vals16[i++];
+ else
+ {
+ unsigned int lo=vals16[i++];
+ unsigned int hi=vals16[i++];
+ if (hi<=0x7FFFU)
+ vals[j++]=(lo&0x7FFFU)|(hi<<15);
+ else
+ {
+ unsigned int hihi=vals16[i++];
+ vals[j++]=(lo&0x7FFFU)|((hi&0x7FFFU)<<15)|(hihi<<30);
+ }
+ }
+ }
+ *nvals=j;
+}
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "../../include/compression/tng_compress.h"
+#include "../../include/compression/warnmalloc.h"
+
+void DECLSPECDLLEXPORT *Ptngc_warnmalloc_x(size_t size, char *file, int line)
+{
+ void *mem=malloc(size);
+ if (!mem)
+ {
+ fprintf(stderr,"TRAJNG ERROR: Could not allocate memory of size %lu at %s:%d\n",(unsigned long) size,file,line);
+ exit(EXIT_FAILURE);
+ }
+ return mem;
+}
+
+void DECLSPECDLLEXPORT *Ptngc_warnrealloc_x(void *old, size_t size, char *file, int line)
+{
+ void *mem=realloc(old,size);
+ if (!mem)
+ {
+ fprintf(stderr,"TRAJNG ERROR: Could not allocate memory of size %lu at %s:%d\n",(unsigned long) size,file,line);
+ exit(EXIT_FAILURE);
+ }
+ return mem;
+}
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "../../include/compression/tng_compress.h"
+
+/* 64 bit integers are not required in this part of the program. But
+ they improve the running speed if present. If 64 bit integers are
+ available define the symbol HAVE64BIT. It should get automatically
+ defined by the defines in my64bit.h */
+#include "../../include/compression/my64bit.h"
+
+#include "../../include/compression/widemuldiv.h"
+
+#ifndef TRAJNG_X86_GCC_INLINE_MULDIV
+#if defined(__GNUC__) && defined(__i386__)
+#define TRAJNG_X86_GCC_INLINE_MULDIV
+#endif /* gcc & i386 */
+#if defined(__GNUC__) && defined(__x86_64__)
+#define TRAJNG_X86_GCC_INLINE_MULDIV
+#endif /* gcc & x86_64 */
+#endif /* TRAJNG X86 GCC INLINE MULDIV */
+
+/* Multiply two 32 bit unsigned integers returning a 64 bit unsigned value (in two integers) */
+void Ptngc_widemul(unsigned int i1, unsigned int i2, unsigned int *ohi, unsigned int *olo)
+{
+#if defined(TRAJNG_X86_GCC_INLINE_MULDIV)
+ __asm__ __volatile__ ("mull %%edx\n\t"
+ : "=a" (i1), "=d" (i2)
+ : "a" (i1),"d" (i2)
+ : "cc");
+ *ohi=i2;
+ *olo=i1;
+#else /* TRAJNG X86 GCC INLINE MULDIV */
+
+#ifdef HAVE64BIT
+ my_uint64_t res= ((my_uint64_t)i1) * ((my_uint64_t)i2);
+ *olo=res & 0xFFFFFFFFU;
+ *ohi=(res>>32) & 0xFFFFFFFFU;
+#else /* HAVE64BIT */
+
+ unsigned int bits=16;
+ unsigned int L_m=(1<<bits)-1; /* Lower bits mask. */
+
+ unsigned int a_U,a_L; /* upper and lower half of a */
+ unsigned int b_U,b_L; /* upper and lower half of b */
+
+ unsigned int x_UU,x_UL,x_LU,x_LL; /* temporary storage. */
+ unsigned int x,x_U,x_L; /* temporary storage. */
+
+ /* Extract partial ints */
+ a_L=i1 & L_m;
+ a_U=i1>>bits;
+ b_L=i2 & L_m;
+ b_U=i2>>bits;
+
+ /* Do a*a=>2a multiply where a is half number of bits in an int */
+ x=a_L*b_L;
+ x_LL=x & L_m;
+ x_LU=x>>bits;
+
+ x=a_U*b_L;
+ x_LU+=x & L_m;
+ x_UL=x>>bits;
+
+ x=a_L*b_U;
+ x_LU+=x & L_m;
+ x_UL+=x>>bits;
+
+ x=a_U*b_U;
+ x_UL+=x & L_m;
+ x_UU=x>>bits;
+
+ /* Combine results */
+ x_UL+=x_LU>>bits;
+ x_LU&=L_m;
+ x_UU+=x_UL>>bits;
+ x_UL&=L_m;
+
+ x_U=(x_UU<<bits)|x_UL;
+ x_L=(x_LU<<bits)|x_LL;
+
+ /* Write back results */
+ *ohi=x_U;
+ *olo=x_L;
+#endif /* HAVE64BIT */
+#endif /* TRAJNG X86 GCC INLINE MULDIV */
+}
+
+/* Divide a 64 bit unsigned value in hi:lo with the 32 bit value i and
+ return the result in result and the remainder in remainder */
+void Ptngc_widediv(unsigned int hi, unsigned int lo, unsigned int i, unsigned int *result, unsigned int *remainder)
+{
+#if defined(TRAJNG_X86_GCC_INLINE_MULDIV)
+ __asm__ __volatile__ ("divl %%ecx\n\t"
+ : "=a" (lo), "=d" (hi)
+ : "a" (lo),"d" (hi), "c" (i)
+ : "cc");
+ *result=lo;
+ *remainder=hi;
+#else /* TRAJNG X86 GCC INLINE MULDIV */
+#ifdef HAVE64BIT
+ my_uint64_t v= (((my_uint64_t)hi)<<32) | ((my_uint64_t)lo);
+ my_uint64_t res=v/((my_uint64_t)i);
+ my_uint64_t rem=v-res*((my_uint64_t)i);
+ *result=(unsigned int)res;
+ *remainder=(unsigned int)rem;
+#else /* HAVE64BIT */
+ unsigned int res;
+ unsigned int rmask;
+ unsigned int s_U,s_L;
+ unsigned int bits=16U;
+ unsigned int bits2=bits*2U;
+ unsigned int hibit=bits2-1U;
+ unsigned int hibit_mask=1U<<hibit;
+ unsigned int allbits=(hibit_mask-1U)|hibit_mask;
+
+ /* Do division. */
+ rmask=hibit_mask;
+ res=0;
+ s_U=i>>(bits2-hibit);
+ s_L=(i<<hibit)&0xFFFFFFFFU;
+ while (rmask)
+ {
+ if ((s_U<hi) || ((s_U==hi) && (s_L<=lo)))
+ {
+ /* Subtract */
+ hi-=s_U;
+ if (s_L>lo)
+ {
+ unsigned int t;
+ hi--; /* Borrow */
+ t=allbits-s_L;
+ lo+=t+1;
+ }
+ else
+ lo-=s_L;
+
+ /* Set bit. */
+ res|=rmask;
+ }
+ rmask>>=1;
+ s_L>>=1;
+ if (s_U & 1U)
+ s_L|=hibit_mask;
+ s_U>>=1;
+ }
+ *remainder=lo;
+ *result=res;
+#endif /* HAVE64BIT */
+#endif /* TRAJNG X86 GCC INLINE MULDIV */
+}
+
+/* Add a unsigned int to a largeint. j determines which value in the
+ largeint to add v1 to. */
+static void largeint_add_gen(unsigned int v1, unsigned int *largeint, int n, int j)
+{
+ /* Add with carry. unsigned ints in C wrap modulo 2**bits when "overflowed". */
+ unsigned int v2=(v1+largeint[j])&0xFFFFFFFFU; /* Add and cap at 32 bits */
+ unsigned int carry=0;
+ if ((((unsigned int)-1)&0xFFFFFFFFU) -v1<largeint[j])
+ carry=1;
+ largeint[j]=v2;
+ j++;
+ while ((j<n) && carry)
+ {
+ v2=(largeint[j]+carry)&0xFFFFFFFFU;
+ carry=0;
+ if ((((unsigned int)-1)&0xFFFFFFFFU) -1<largeint[j])
+ carry=1;
+ largeint[j]=v2;
+ j++;
+ }
+}
+
+/* Add a unsigned int to a largeint. */
+void Ptngc_largeint_add(unsigned int v1, unsigned int *largeint, int n)
+{
+ largeint_add_gen(v1,largeint,n,0);
+}
+
+/* Multiply v1 with largeint_in and return result in largeint_out */
+void Ptngc_largeint_mul(unsigned int v1, unsigned int *largeint_in, unsigned int *largeint_out, int n)
+{
+ int i;
+ for (i=0; i<n; i++)
+ largeint_out[i]=0U;
+ for (i=0; i<n; i++)
+ {
+ if (largeint_in[i]!=0U)
+ {
+ unsigned int lo,hi;
+ Ptngc_widemul(v1,largeint_in[i],&hi,&lo); /* 32x32->64 mul */
+ largeint_add_gen(lo,largeint_out,n,i);
+ if (i+1<n)
+ largeint_add_gen(hi,largeint_out,n,i+1);
+ }
+ }
+}
+
+/* Return the remainder from dividing largeint_in with v1. Result of the division is returned in largeint_out */
+unsigned int Ptngc_largeint_div(unsigned int v1, unsigned int *largeint_in, unsigned int *largeint_out, int n)
+{
+ unsigned int result,remainder=0;
+ int i;
+ unsigned int hi, lo;
+ /* Boot */
+ hi=0U;
+ i=n;
+ while (i)
+ {
+ lo=largeint_in[i-1];
+ Ptngc_widediv(hi,lo,v1,&result,&remainder);
+ largeint_out[i-1]=result;
+ hi=remainder;
+ i--;
+ }
+ return remainder;
+}
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+/* This code is heavily influenced by
+ http://hpcv100.rc.rug.nl/xdrf.html
+ Based on coordinate compression (c) by Frans van Hoesel.
+ and GROMACS xtc files (http://www.gromacs.org)
+ (c) Copyright (c) Erik Lindahl, David van der Spoel
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "../../include/compression/coder.h"
+#include "../../include/compression/widemuldiv.h"
+#include "../../include/compression/warnmalloc.h"
+
+/* Generated by gen_magic.py */
+#define MAX_MAGIC 92
+
+static unsigned int magic[MAX_MAGIC]={
+2U, 3U, 4U, 5U,
+6U, 8U, 10U, 12U,
+16U, 20U, 25U, 32U,
+40U, 50U, 64U, 80U,
+101U, 128U, 161U, 203U,
+256U, 322U, 406U, 512U,
+645U, 812U, 1024U, 1290U,
+1625U, 2048U, 2580U, 3250U,
+4096U, 5160U, 6501U, 8192U,
+10321U, 13003U, 16384U, 20642U,
+26007U, 32768U, 41285U, 52015U,
+65536U, 82570U, 104031U, 131072U,
+165140U, 208063U, 262144U, 330280U,
+416127U, 524288U, 660561U, 832255U,
+1048576U, 1321122U, 1664510U, 2097152U,
+2642245U, 3329021U, 4194304U, 5284491U,
+6658042U, 8388608U, 10568983U, 13316085U,
+16777216U, 21137967U, 26632170U, 33554432U,
+42275935U, 53264340U, 67108864U, 84551870U,
+106528681U, 134217728U, 169103740U, 213057362U,
+268435456U, 338207481U, 426114725U, 536870912U,
+676414963U, 852229450U, 1073741824U, 1352829926U,
+1704458900U, 2147483648U, 2705659852U, 3408917801U,
+};
+
+static unsigned int magic_bits[MAX_MAGIC][8]={
+{ 3, 6, 9, 12, 15, 18, 21, 24, },
+{ 5, 10, 15, 20, 24, 29, 34, 39, },
+{ 6, 12, 18, 24, 30, 36, 42, 48, },
+{ 7, 14, 21, 28, 35, 42, 49, 56, },
+{ 8, 16, 24, 32, 39, 47, 55, 63, },
+{ 9, 18, 27, 36, 45, 54, 63, 72, },
+{ 10, 20, 30, 40, 50, 60, 70, 80, },
+{ 11, 22, 33, 44, 54, 65, 76, 87, },
+{ 12, 24, 36, 48, 60, 72, 84, 97, },
+{ 13, 26, 39, 52, 65, 78, 91, 104, },
+{ 14, 28, 42, 56, 70, 84, 98, 112, },
+{ 15, 30, 45, 60, 75, 90, 105, 120, },
+{ 16, 32, 48, 64, 80, 96, 112, 128, },
+{ 17, 34, 51, 68, 85, 102, 119, 136, },
+{ 18, 36, 54, 72, 90, 108, 127, 144, },
+{ 19, 38, 57, 76, 95, 114, 133, 152, },
+{ 20, 40, 60, 80, 100, 120, 140, 160, },
+{ 21, 42, 63, 84, 105, 127, 147, 168, },
+{ 22, 44, 66, 88, 110, 132, 154, 176, },
+{ 23, 46, 69, 92, 115, 138, 161, 184, },
+{ 24, 48, 72, 97, 120, 144, 168, 192, },
+{ 25, 50, 75, 100, 125, 150, 175, 200, },
+{ 26, 52, 78, 104, 130, 156, 182, 208, },
+{ 27, 54, 81, 108, 135, 162, 190, 216, },
+{ 28, 56, 84, 112, 140, 168, 196, 224, },
+{ 29, 58, 87, 116, 145, 174, 203, 232, },
+{ 30, 60, 90, 120, 150, 180, 210, 240, },
+{ 31, 62, 93, 124, 155, 186, 217, 248, },
+{ 32, 64, 96, 128, 160, 192, 224, 256, },
+{ 33, 66, 99, 132, 165, 198, 231, 264, },
+{ 34, 68, 102, 136, 170, 204, 238, 272, },
+{ 35, 70, 105, 140, 175, 210, 245, 280, },
+{ 36, 72, 108, 144, 180, 216, 252, 288, },
+{ 37, 74, 111, 148, 185, 222, 259, 296, },
+{ 38, 76, 114, 152, 190, 228, 266, 304, },
+{ 39, 78, 117, 157, 195, 234, 273, 312, },
+{ 40, 80, 120, 160, 200, 240, 280, 320, },
+{ 41, 82, 123, 164, 205, 246, 287, 328, },
+{ 42, 84, 127, 168, 210, 252, 294, 336, },
+{ 43, 86, 129, 172, 215, 258, 301, 344, },
+{ 44, 88, 132, 176, 220, 264, 308, 352, },
+{ 45, 90, 135, 180, 225, 270, 315, 360, },
+{ 46, 92, 138, 184, 230, 276, 322, 368, },
+{ 47, 94, 141, 188, 235, 282, 329, 376, },
+{ 48, 97, 144, 192, 240, 288, 336, 384, },
+{ 49, 98, 147, 196, 245, 294, 343, 392, },
+{ 50, 100, 150, 200, 250, 300, 350, 400, },
+{ 52, 102, 153, 204, 255, 306, 357, 408, },
+{ 52, 104, 156, 208, 260, 312, 364, 416, },
+{ 53, 106, 159, 212, 265, 318, 371, 424, },
+{ 54, 108, 162, 216, 270, 324, 378, 432, },
+{ 55, 110, 165, 220, 275, 330, 385, 440, },
+{ 56, 112, 168, 224, 280, 336, 392, 448, },
+{ 57, 114, 172, 228, 285, 342, 399, 456, },
+{ 58, 116, 174, 232, 290, 348, 406, 464, },
+{ 59, 118, 177, 236, 295, 354, 413, 472, },
+{ 60, 120, 180, 240, 300, 360, 420, 480, },
+{ 61, 122, 183, 244, 305, 366, 427, 488, },
+{ 62, 124, 186, 248, 310, 372, 434, 496, },
+{ 63, 127, 190, 252, 315, 378, 442, 505, },
+{ 64, 128, 192, 256, 320, 384, 448, 512, },
+{ 65, 130, 195, 260, 325, 390, 455, 520, },
+{ 66, 132, 198, 264, 330, 396, 462, 528, },
+{ 67, 134, 201, 268, 335, 402, 469, 536, },
+{ 68, 136, 204, 272, 340, 408, 476, 544, },
+{ 69, 138, 207, 276, 345, 414, 483, 552, },
+{ 70, 140, 210, 280, 350, 420, 490, 560, },
+{ 71, 142, 213, 284, 355, 426, 497, 568, },
+{ 72, 144, 216, 288, 360, 432, 505, 576, },
+{ 73, 146, 219, 292, 365, 438, 511, 584, },
+{ 74, 148, 222, 296, 370, 444, 518, 592, },
+{ 75, 150, 225, 300, 375, 451, 525, 600, },
+{ 76, 152, 228, 304, 380, 456, 532, 608, },
+{ 77, 154, 231, 308, 385, 462, 539, 616, },
+{ 78, 157, 234, 312, 390, 469, 546, 625, },
+{ 79, 158, 237, 316, 395, 474, 553, 632, },
+{ 80, 160, 240, 320, 400, 480, 560, 640, },
+{ 81, 162, 243, 324, 406, 486, 568, 648, },
+{ 82, 164, 246, 328, 410, 492, 574, 656, },
+{ 83, 166, 249, 332, 415, 498, 581, 664, },
+{ 84, 168, 252, 336, 420, 505, 588, 672, },
+{ 85, 170, 255, 340, 425, 510, 595, 680, },
+{ 86, 172, 258, 344, 430, 516, 602, 688, },
+{ 87, 174, 261, 348, 435, 522, 609, 696, },
+{ 88, 176, 264, 352, 440, 528, 616, 704, },
+{ 89, 178, 267, 356, 445, 534, 623, 712, },
+{ 90, 180, 270, 360, 451, 540, 631, 720, },
+{ 91, 182, 273, 364, 455, 546, 637, 728, },
+{ 92, 184, 276, 368, 460, 552, 644, 736, },
+{ 94, 187, 279, 373, 466, 558, 651, 745, },
+{ 94, 188, 282, 376, 470, 564, 658, 752, },
+{ 95, 190, 285, 380, 475, 570, 665, 760, },
+};
+
+
+static const double iflipgaincheck=0.89089871814033927; /* 1./(2**(1./6)) */
+
+
+/* Difference in indices used for determining whether to store as large or small */
+#define QUITE_LARGE 3
+#define IS_LARGE 6
+
+#if 0
+#define SHOWIT
+#endif
+
+int Ptngc_magic(unsigned int i)
+{
+ return magic[i];
+}
+
+int Ptngc_find_magic_index(unsigned int maxval)
+{
+ int i=0;
+ while (magic[i]<=maxval)
+ i++;
+ return i;
+}
+
+static unsigned int positive_int(int item)
+{
+ int s=0;
+ if (item>0)
+ s=1+(item-1)*2;
+ else if (item<0)
+ s=2+(-item-1)*2;
+ return s;
+}
+
+static int unpositive_int(int val)
+{
+ int s=(val+1)/2;
+ if ((val%2)==0)
+ s=-s;
+ return s;
+}
+
+
+/* Sequence instructions */
+#define INSTR_DEFAULT 0
+#define INSTR_BASE_RUNLENGTH 1
+#define INSTR_ONLY_LARGE 2
+#define INSTR_ONLY_SMALL 3
+#define INSTR_LARGE_BASE_CHANGE 4
+#define INSTR_FLIP 5
+#define INSTR_LARGE_RLE 6
+
+#define MAXINSTR 7
+
+#ifdef SHOWIT
+static char *instrnames[MAXINSTR]={
+ "large+small",
+ "base+run",
+ "large",
+ "small",
+ "large base change",
+ "flip",
+ "large rle",
+};
+#endif
+
+/* Bit patterns in the compressed code stream: */
+
+static const int seq_instr[MAXINSTR][2]=
+ {
+ { 1,1 }, /* 1 : one large atom + runlength encoded small integers. Use same settings as before. */
+ { 0,2 }, /* 00 : set base and runlength in next four bits (x). base (increase/keep/decrease)=x%3-1. runlength=1+x/3.
+ The special value 1111 in the four bits means runlength=6 and base change=0 */
+ { 4,4 }, /* 0100 : next only a large atom comes. */
+ { 5,4 }, /* 0101 : next only runlength encoded small integers. Use same settings as before. */
+ { 6,4 }, /* 0110 : Large change in base. Change is encoded in the
+ following 2 bits. change direction (sign) is the first
+ bit. The next bit +1 is the actual change. This
+ allows the change of up to +/- 2 indices. */
+ { 14,5 }, /* 01110 : flip whether integers should be modified to compress water better */
+ { 15,5 }, /* 01111 : Large rle. The next 4 bits encode how many
+ large atoms are in the following sequence: 3-18. (2 is
+ more efficiently coded with two large instructions. */
+ };
+
+static void write_instruction(struct coder *coder,int instr,unsigned char **output_ptr)
+{
+ Ptngc_writebits(coder,seq_instr[instr][0],seq_instr[instr][1],output_ptr);
+#ifdef SHOWIT
+ fprintf(stderr,"INSTR: %s (%d bits)\n",instrnames[instr],seq_instr[instr][1]);
+#endif
+}
+
+static unsigned int readbits(unsigned char **ptr, int *bitptr, int nbits)
+{
+ unsigned int val=0U;
+ unsigned int extract_mask=0x80U>>*bitptr;
+ unsigned char thisval=**ptr;
+#ifdef SHOWIT
+ fprintf(stderr,"Read nbits=%d val=",nbits);
+#endif
+ while (nbits--)
+ {
+ val<<=1;
+ val|=((extract_mask & thisval)!=0);
+ *bitptr=(*bitptr)+1;
+ extract_mask>>=1;
+ if (!extract_mask)
+ {
+ extract_mask=0x80U;
+ *ptr=(*ptr)+1;
+ *bitptr=0;
+ if (nbits)
+ thisval=**ptr;
+ }
+ }
+#ifdef SHOWIT
+ fprintf(stderr,"%x\n",val);
+#endif
+ return val;
+}
+
+static void readmanybits(unsigned char **ptr, int *bitptr, int nbits, unsigned char *buffer)
+{
+ while (nbits>=8)
+ {
+ *buffer++=readbits(ptr,bitptr,8);
+ nbits-=8;
+#ifdef SHOWIT
+ fprintf(stderr,"Read value %02x\n",buffer[-1]);
+#endif
+ }
+ if (nbits)
+ {
+ *buffer++=readbits(ptr,bitptr,nbits);
+#ifdef SHOWIT
+ fprintf(stderr,"Read value %02x\n",buffer[-1]);
+#endif
+ }
+}
+
+static int read_instruction(unsigned char **ptr, int *bitptr)
+{
+ int instr=-1;
+ unsigned int bits=readbits(ptr,bitptr,1);
+ if (bits)
+ instr=INSTR_DEFAULT;
+ else
+ {
+ bits=readbits(ptr,bitptr,1);
+ if (!bits)
+ instr=INSTR_BASE_RUNLENGTH;
+ else
+ {
+ bits=readbits(ptr,bitptr,2);
+ if (bits==0)
+ instr=INSTR_ONLY_LARGE;
+ else if (bits==1)
+ instr=INSTR_ONLY_SMALL;
+ else if (bits==2)
+ instr=INSTR_LARGE_BASE_CHANGE;
+ else if (bits==3)
+ {
+ bits=readbits(ptr,bitptr,1);
+ if (bits==0)
+ instr=INSTR_FLIP;
+ else
+ instr=INSTR_LARGE_RLE;
+ }
+ }
+ }
+ return instr;
+}
+
+/* Modifies three integer values for better compression of water */
+static void swap_ints(int *in, int *out)
+{
+ out[0]=in[0]+in[1];
+ out[1]=-in[1];
+ out[2]=in[1]+in[2];
+}
+
+static void swap_is_better(int *input, int *minint, int *sum_normal, int *sum_swapped)
+{
+ int normal_max=0;
+ int swapped_max=0;
+ int i,j;
+ int normal[3];
+ int swapped[3];
+ for (i=0; i<3; i++)
+ {
+ normal[0]=input[i]-minint[i];
+ normal[1]=input[3+i]-input[i]; /* minint[i]-minint[i] cancels out */
+ normal[2]=input[6+i]-input[3+i]; /* minint[i]-minint[i] cancels out */
+ swap_ints(normal,swapped);
+ for (j=1; j<3; j++)
+ {
+ if (positive_int(normal[j])>(unsigned int)normal_max)
+ normal_max=positive_int(normal[j]);
+ if (positive_int(swapped[j])>(unsigned int)swapped_max)
+ swapped_max=positive_int(swapped[j]);
+ }
+ }
+ if (normal_max==0)
+ normal_max=1;
+ if (swapped_max==0)
+ swapped_max=1;
+ *sum_normal=normal_max;
+ *sum_swapped=swapped_max;
+}
+
+static void swapdecide(struct coder *coder, int *input,int *swapatoms, int *large_index, int *minint, unsigned char **output_ptr)
+{
+ int didswap=0;
+ int normal,swapped;
+ (void)large_index;
+ swap_is_better(input,minint,&normal,&swapped);
+ /* We have to determine if it is worth to change the behaviour.
+ If diff is positive it means that it is worth something to
+ swap. But it costs 4 bits to do the change. If we assume that
+ we gain 0.17 bit by the swap per value, and the runlength>2
+ for four molecules in a row, we gain something. So check if we
+ gain at least 0.17 bits to even attempt the swap.
+ */
+#ifdef SHOWIT
+ fprintf(stderr,"Trying Flip: %g %g\n",(double)swapped/normal, (double)normal/swapped);
+#endif
+ if (((swapped<normal) && (fabs((double)swapped/normal)<iflipgaincheck)) ||
+ ((normal<swapped) && (fabs((double)normal/swapped)<iflipgaincheck)))
+ {
+ if (swapped<normal)
+ {
+ if (!*swapatoms)
+ {
+ *swapatoms=1;
+ didswap=1;
+ }
+ }
+ else
+ {
+ if (*swapatoms)
+ {
+ *swapatoms=0;
+ didswap=1;
+ }
+ }
+ }
+ if (didswap)
+ {
+#ifdef SHOWIT
+ fprintf(stderr,"Flip. Swapatoms is now %d\n",*swapatoms);
+#endif
+ write_instruction(coder,INSTR_FLIP,output_ptr);
+ }
+}
+
+/* Compute number of bits required to store values using three different bases in the index array */
+static int compute_magic_bits(int *index)
+{
+ unsigned int largeint[4];
+ unsigned int largeint_tmp[4];
+ int i,j,onebit;
+ for (i=0; i<4; i++)
+ largeint[i]=0U;
+ for (i=0; i<3; i++)
+ {
+ if (i!=0)
+ {
+ /* We must do the multiplication of the largeint with the integer base */
+ Ptngc_largeint_mul(magic[index[i]],largeint,largeint_tmp,4);
+ for (j=0; j<4; j++)
+ largeint[j]=largeint_tmp[j];
+ }
+ Ptngc_largeint_add(magic[index[i]]-1,largeint,4);
+ }
+ /* Find last bit. */
+#if 0
+ printf("Largeint is %u %u %u\n",largeint[0],largeint[1],largeint[2]);
+#endif
+ onebit=0;
+ for (i=0; i<3; i++)
+ for (j=0; j<32; j++)
+ if (largeint[i]&(1U<<j))
+ onebit=i*32+j+1;
+ return onebit;
+}
+
+/* Convert a sequence of (hopefully) small positive integers
+ using the base pointed to by index (x base, y base and z base can be different).
+ The largest number of integers supported is 18 (29 to handle/detect overflow) */
+static void trajcoder_base_compress(int *input, int n, int *index, unsigned char *result)
+{
+ unsigned int largeint[19];
+ unsigned int largeint_tmp[19];
+ int i,j;
+ for (i=0; i<19; i++)
+ largeint[i]=0U;
+
+ for (i=0; i<n; i++)
+ {
+ if (i!=0)
+ {
+ /* We must do the multiplication of the largeint with the integer base */
+ Ptngc_largeint_mul(magic[index[i%3]],largeint,largeint_tmp,19);
+ for (j=0; j<19; j++)
+ largeint[j]=largeint_tmp[j];
+ }
+ Ptngc_largeint_add(input[i],largeint,19);
+ }
+ if (largeint[18])
+ {
+ fprintf(stderr,"TRAJNG: BUG! Overflow in compression detected.\n");
+ exit(EXIT_FAILURE);
+ }
+#if 0
+#ifdef SHOWIT
+ for (i=0; i<19; i++)
+ fprintf(stderr,"Largeint[%d]=0x%x\n",i,largeint[i]);
+#endif
+#endif
+ /* Convert the largeint to a sequence of bytes. */
+ for (i=0; i<18; i++)
+ {
+ int shift=0;
+ for (j=0; j<4; j++)
+ {
+ result[i*4+j]=(largeint[i]>>shift) & 0xFFU;
+ shift+=8;
+ }
+ }
+}
+
+/* The opposite of base_compress. */
+static void trajcoder_base_decompress(unsigned char *input, int n, int *index, int *output)
+{
+ unsigned int largeint[19];
+ unsigned int largeint_tmp[19];
+ int i,j;
+ /* Convert the sequence of bytes to a largeint. */
+ for (i=0; i<18; i++)
+ {
+ int shift=0;
+ largeint[i]=0U;
+ for (j=0; j<4; j++)
+ {
+ largeint[i]|=((unsigned int)input[i*4+j])<<shift;
+ shift+=8;
+ }
+ }
+ largeint[18]=0U;
+#if 0
+#ifdef SHOWIT
+ for (i=0; i<19; i++)
+ fprintf(stderr,"Largeint[%d]=0x%x\n",i,largeint[i]);
+#endif
+#endif
+ for (i=n-1; i>=0; i--)
+ {
+ unsigned int remainder=Ptngc_largeint_div(magic[index[i%3]],largeint,largeint_tmp,19);
+#if 0
+#ifdef SHOWIT
+ fprintf(stderr,"Remainder: %u\n",remainder);
+#endif
+#endif
+#if 0
+ for (j=0; j<19; j++)
+ largeint[j]=largeint_tmp[j];
+#endif
+ memcpy(largeint,largeint_tmp,19*sizeof *largeint);
+ output[i]=remainder;
+ }
+}
+
+/* It is "large" if we have to increase the small index quite a
+ bit. Not so much to be rejected by the not very large check
+ later. */
+static int is_quite_large(int *input, int small_index, int max_large_index)
+{
+ int is=0;
+ int i;
+ if (small_index+QUITE_LARGE>=max_large_index)
+ is=1;
+ else
+ {
+ for (i=0; i<3; i++)
+ if (positive_int(input[i])>magic[small_index+QUITE_LARGE])
+ {
+ is=1;
+ break;
+ }
+ }
+ return is;
+}
+
+#ifdef SHOWIT
+int nbits_sum;
+int nvalues_sum;
+#endif
+
+static void write_three_large(struct coder *coder, int *encode_ints, int *large_index, int nbits, unsigned char *compress_buffer, unsigned char **output_ptr)
+{
+ trajcoder_base_compress(encode_ints,3,large_index,compress_buffer);
+ Ptngc_writemanybits(coder,compress_buffer,nbits,output_ptr);
+#ifdef SHOWIT
+ fprintf(stderr,"nbits=%d (%g)\n",nbits,nbits/3.);
+ nbits_sum+=nbits;
+ nvalues_sum+=3;
+ fprintf(stderr,"Large: %d %d %d\n",encode_ints[0],encode_ints[1],encode_ints[2]);
+#endif
+}
+
+static void insert_batch(int *input_ptr, int ntriplets_left, int *prevcoord,int *minint, int *encode_ints, int startenc, int *nenc)
+{
+ int nencode=startenc*3;
+ int tmp_prevcoord[3];
+
+ tmp_prevcoord[0]=prevcoord[0];
+ tmp_prevcoord[1]=prevcoord[1];
+ tmp_prevcoord[2]=prevcoord[2];
+
+ if (startenc)
+ {
+ int i;
+ for (i=0; i<startenc; i++)
+ {
+ tmp_prevcoord[0]+=encode_ints[i*3];
+ tmp_prevcoord[1]+=encode_ints[i*3+1];
+ tmp_prevcoord[2]+=encode_ints[i*3+2];
+#ifdef SHOWIT
+ fprintf(stderr,"%6d: %6d %6d %6d\t\t%6d %6d %6d\t\t%6d %6d %6d\n",i*3,
+ tmp_prevcoord[0],tmp_prevcoord[1],tmp_prevcoord[2],
+ encode_ints[i*3],
+ encode_ints[i*3+1],
+ encode_ints[i*3+2],
+ positive_int(encode_ints[i*3]),
+ positive_int(encode_ints[i*3+1]),
+ positive_int(encode_ints[i*3+2]));
+#endif
+ }
+ }
+
+#ifdef SHOWIT
+ fprintf(stderr,"New batch\n");
+#endif
+ while ((nencode<21) && (nencode<ntriplets_left*3))
+ {
+ encode_ints[nencode]=input_ptr[nencode]-minint[0]-tmp_prevcoord[0];
+ encode_ints[nencode+1]=input_ptr[nencode+1]-minint[1]-tmp_prevcoord[1];
+ encode_ints[nencode+2]=input_ptr[nencode+2]-minint[2]-tmp_prevcoord[2];
+#ifdef SHOWIT
+ fprintf(stderr,"%6d: %6d %6d %6d\t\t%6d %6d %6d\t\t%6d %6d %6d\n",nencode,
+ input_ptr[nencode]-minint[0],
+ input_ptr[nencode+1]-minint[1],
+ input_ptr[nencode+2]-minint[2],
+ encode_ints[nencode],
+ encode_ints[nencode+1],
+ encode_ints[nencode+2],
+ positive_int(encode_ints[nencode]),
+ positive_int(encode_ints[nencode+1]),
+ positive_int(encode_ints[nencode+2]));
+#endif
+ tmp_prevcoord[0]=input_ptr[nencode]-minint[0];
+ tmp_prevcoord[1]=input_ptr[nencode+1]-minint[1];
+ tmp_prevcoord[2]=input_ptr[nencode+2]-minint[2];
+ nencode+=3;
+ }
+ *nenc=nencode;
+}
+
+static void flush_large(struct coder *coder, int *has_large, int *has_large_ints, int n,
+ int *large_index, int large_nbits, unsigned char *compress_buffer,
+ unsigned char **output_ptr)
+{
+ int i;
+ if (n<3)
+ {
+ for (i=0; i<n; i++)
+ {
+ write_instruction(coder,INSTR_ONLY_LARGE,output_ptr);
+ write_three_large(coder,has_large_ints+i*3,large_index,large_nbits,compress_buffer,output_ptr);
+ }
+ }
+ else
+ {
+#if 0
+ printf("CODING RLE: %d\n",n);
+#endif
+ write_instruction(coder,INSTR_LARGE_RLE,output_ptr);
+ Ptngc_writebits(coder,n-3,4,output_ptr); /* Number of large atoms in this sequence: 3 to 18 */
+ for (i=0; i<n; i++)
+ write_three_large(coder,has_large_ints+i*3,large_index,large_nbits,compress_buffer,output_ptr);
+ }
+ if (((*has_large)-n)!=0)
+ {
+ int j;
+ for (i=0; i<(*has_large)-n; i++)
+ for (j=0; j<3; j++)
+ has_large_ints[i*3+j]=has_large_ints[(i+n)*3+j];
+ }
+ *has_large=(*has_large)-n; /* Number of remaining large atoms in buffer */
+}
+
+static void buffer_large(struct coder *coder, int *has_large, int *has_large_ints, int *new_large_ints,
+ int *large_index, int large_nbits, unsigned char *compress_buffer,
+ unsigned char **output_ptr)
+{
+ /* If it is full we must write them all. */
+ if (*has_large==18)
+ flush_large(coder,has_large,has_large_ints, *has_large,
+ large_index,large_nbits,compress_buffer,output_ptr); /* Flush them all. */
+ has_large_ints[(*has_large)*3]=new_large_ints[0];
+ has_large_ints[(*has_large)*3+1]=new_large_ints[1];
+ has_large_ints[(*has_large)*3+2]=new_large_ints[2];
+ *has_large=(*has_large)+1;
+}
+
+
+unsigned char *Ptngc_pack_array_xtc2(struct coder *coder,int *input, int *length)
+{
+ unsigned char *output=NULL;
+ unsigned char *output_ptr=NULL;
+ int i,ienc,j;
+ int output_length=0;
+ /* Pack triplets. */
+ int ntriplets=*length/3;
+ int intmax;
+ int max_small;
+ int large_index[3];
+ int max_large_index;
+ int large_nbits;
+ int small_index;
+ int small_idx[3];
+ int minint[3],maxint[3];
+ int has_large=0;
+ int has_large_ints[54]; /* Large cache. Up to 18 large atoms. */
+ int prevcoord[3];
+ int runlength=0; /* Initial runlength. "Stupidly" set to zero for
+ simplicity and explicity */
+ int swapatoms=0; /* Initial guess is that we should not swap the
+ first two atoms in each large+small
+ transition */
+ int didswap; /* Whether swapping was actually done. */
+ int *input_ptr=input;
+ int encode_ints[21]; /* Up to 3 large + 18 small ints can be encoded at once */
+ int nencode;
+ unsigned char compress_buffer[18*4]; /* Holds compressed result for 3 large ints or up to 18 small ints. */
+ int ntriplets_left=ntriplets;
+ int refused=0;
+#ifdef SHOWIT
+ nbits_sum=0;
+ nvalues_sum=0;
+#endif
+ /* Allocate enough memory for output */
+ output=warnmalloc(8* *length*sizeof *output);
+ output_ptr=output;
+
+ maxint[0]=minint[0]=input[0];
+ maxint[1]=minint[1]=input[1];
+ maxint[2]=minint[2]=input[2];
+
+ for (i=1; i<ntriplets; i++)
+ for (j=0; j<3; j++)
+ {
+ if (input[i*3+j]>maxint[j])
+ maxint[j]=input[i*3+j];
+ if (input[i*3+j]<minint[j])
+ minint[j]=input[i*3+j];
+ }
+
+ large_index[0]=Ptngc_find_magic_index(maxint[0]-minint[0]+1);
+ large_index[1]=Ptngc_find_magic_index(maxint[1]-minint[1]+1);
+ large_index[2]=Ptngc_find_magic_index(maxint[2]-minint[2]+1);
+ large_nbits=compute_magic_bits(large_index);
+ max_large_index=large_index[0];
+ if (large_index[1]>max_large_index)
+ max_large_index=large_index[1];
+ if (large_index[2]>max_large_index)
+ max_large_index=large_index[2];
+
+#ifdef SHOWIT
+ for (j=0; j<3; j++)
+ fprintf(stderr,"minint[%d]=%d. maxint[%d]=%d large_index[%d]=%d value=%d\n",j,minint[j],j,maxint[j],
+ j,large_index[j],magic[large_index[j]]);
+ fprintf(stderr,"large_nbits=%d\n",large_nbits);
+#endif
+
+
+ /* Guess initial small index */
+ small_index=max_large_index/2;
+
+ /* Find the largest value that is not large. Not large is half index of
+ large. */
+ max_small=magic[small_index];
+ intmax=0;
+ for (i=0; i<*length; i++)
+ {
+ int item=input[i];
+ int s=positive_int(item);
+ if (s>intmax)
+ if (s<max_small)
+ intmax=s;
+ }
+ /* This value is not critical, since if I guess wrong, the code will
+ just insert instructions to increase this value. */
+ small_index=Ptngc_find_magic_index(intmax);
+#ifdef SHOWIT
+ fprintf(stderr,"initial_small intmax=%d. small_index=%d value=%d\n",intmax,small_index,magic[small_index]);
+#endif
+
+ /* Store min integers */
+ coder->pack_temporary_bits=32;
+ coder->pack_temporary=positive_int(minint[0]);
+ Ptngc_out8bits(coder,&output_ptr);
+ coder->pack_temporary_bits=32;
+ coder->pack_temporary=positive_int(minint[1]);
+ Ptngc_out8bits(coder,&output_ptr);
+ coder->pack_temporary_bits=32;
+ coder->pack_temporary=positive_int(minint[2]);
+ Ptngc_out8bits(coder,&output_ptr);
+ /* Store max indices */
+ coder->pack_temporary_bits=8;
+ coder->pack_temporary=large_index[0];
+ Ptngc_out8bits(coder,&output_ptr);
+ coder->pack_temporary_bits=8;
+ coder->pack_temporary=large_index[1];
+ Ptngc_out8bits(coder,&output_ptr);
+ coder->pack_temporary_bits=8;
+ coder->pack_temporary=large_index[2];
+ Ptngc_out8bits(coder,&output_ptr);
+ /* Store initial small index */
+ coder->pack_temporary_bits=8;
+ coder->pack_temporary=small_index;
+ Ptngc_out8bits(coder,&output_ptr);
+
+#if 0
+#ifdef SHOWIT
+ for (i=0; i<ntriplets_left; i++)
+ fprintf(stderr,"VALUE:%d %6d %6d %6d\n",
+ i,
+ input_ptr[i*3],
+ input_ptr[i*3+1],
+ input_ptr[i*3+2]);
+#endif
+#endif
+
+ /* Initial prevcoord is the minimum integers. */
+ prevcoord[0]=minint[0];
+ prevcoord[1]=minint[1];
+ prevcoord[2]=minint[2];
+
+ while (ntriplets_left)
+ {
+ if (ntriplets_left<0)
+ {
+ fprintf(stderr,"TRAJNG: BUG! ntriplets_left<0!\n");
+ exit(EXIT_FAILURE);
+ }
+ /* If only less than three atoms left we just write them all as large integers. Here no swapping is done! */
+ if (ntriplets_left<3)
+ {
+ for (ienc=0; ienc<ntriplets_left; ienc++)
+ {
+ int jenc;
+ for (jenc=0; jenc<3; jenc++)
+ encode_ints[jenc]=input_ptr[ienc*3+jenc]-minint[jenc];
+ buffer_large(coder,&has_large,has_large_ints,encode_ints,large_index,large_nbits,compress_buffer,&output_ptr);
+ input_ptr+=3;
+ ntriplets_left--;
+ }
+ flush_large(coder,&has_large,has_large_ints,has_large,large_index,large_nbits,compress_buffer,&output_ptr);
+ }
+ else
+ {
+ int min_runlength=0;
+ int largest_required_base;
+ int largest_runlength_base;
+ int largest_required_index;
+ int largest_runlength_index;
+ int new_runlength;
+ int new_small_index;
+ int iter_runlength;
+ int iter_small_index;
+ int rle_index_dep;
+ didswap=0;
+ /* Insert the next batch of integers to be encoded into the buffer */
+#ifdef SHOWIT
+ fprintf(stderr,"Initial batch\n");
+#endif
+ insert_batch(input_ptr,ntriplets_left,prevcoord,minint,encode_ints,0,&nencode);
+
+ /* First we must decide if the next value is large (does not reasonably fit in current small encoding)
+ Also, if we have not written any values yet, we must begin by writing a large atom. */
+ if ((input_ptr==input) || (is_quite_large(encode_ints,small_index,max_large_index)) || (refused))
+ {
+ /* If any of the next two atoms are large we should probably write them as large and not swap them */
+ int no_swap=0;
+ if ((is_quite_large(encode_ints+3,small_index,max_large_index)) || (is_quite_large(encode_ints+6,small_index,max_large_index)))
+ no_swap=1;
+ if (!no_swap)
+ {
+ /* Next we must decide if we should swap the first
+ two values. */
+#if 1
+ swapdecide(coder,input_ptr,&swapatoms,large_index,minint,&output_ptr);
+#else
+ swapatoms=0;
+#endif
+ /* If we should do the integer swapping manipulation we should do it now */
+ if (swapatoms)
+ {
+ didswap=1;
+ for (i=0; i<3; i++)
+ {
+ int in[3], out[3];
+ in[0]=input_ptr[i]-minint[i];
+ in[1]=input_ptr[3+i]-input_ptr[i]; /* minint[i]-minint[i] cancels out */
+ in[2]=input_ptr[6+i]-input_ptr[3+i]; /* minint[i]-minint[i] cancels out */
+ swap_ints(in,out);
+ encode_ints[i]=out[0];
+ encode_ints[3+i]=out[1];
+ encode_ints[6+i]=out[2];
+ }
+ /* We have swapped atoms, so the minimum run-length is 2 */
+#ifdef SHOWIT
+ fprintf(stderr,"Swap atoms results in:\n");
+ for (i=0; i<3; i++)
+ fprintf(stderr,"%d: %6d %6d %6d\t\t%6d %6d %6d\n",i*3,
+ encode_ints[i*3],
+ encode_ints[i*3+1],
+ encode_ints[i*3+2],
+ positive_int(encode_ints[i*3]),
+ positive_int(encode_ints[i*3+1]),
+ positive_int(encode_ints[i*3+2]));
+
+#endif
+ min_runlength=2;
+ }
+ }
+ if ((swapatoms) && (didswap))
+ {
+ for (ienc=0; ienc<3; ienc++)
+ prevcoord[ienc]=encode_ints[ienc];
+ }
+ else
+ {
+ for (ienc=0; ienc<3; ienc++)
+ prevcoord[ienc]=input_ptr[ienc]-minint[ienc];
+ }
+ /* Cache large value for later possible combination with
+ a sequence of small integers. */
+ buffer_large(coder,&has_large,has_large_ints,prevcoord,large_index,large_nbits,compress_buffer,&output_ptr);
+#ifdef SHOWIT
+ fprintf(stderr,"Prevcoord after packing of large: %d %d %d\n",
+ prevcoord[0],prevcoord[1],prevcoord[2]);
+#endif
+
+ /* We have written a large integer so we have one less atoms to worry about */
+ input_ptr+=3;
+ ntriplets_left--;
+
+ refused=0;
+
+ /* Insert the next batch of integers to be encoded into the buffer */
+#ifdef SHOWIT
+ fprintf(stderr,"Update batch due to large int.\n");
+#endif
+ if ((swapatoms) && (didswap))
+ {
+ /* Keep swapped values. */
+ for (i=0; i<2; i++)
+ for (ienc=0; ienc<3; ienc++)
+ encode_ints[i*3+ienc]=encode_ints[(i+1)*3+ienc];
+ }
+ insert_batch(input_ptr,ntriplets_left,prevcoord,minint,encode_ints,min_runlength,&nencode);
+ }
+ /* Here we should only have differences for the atom coordinates. */
+ /* Convert the ints to positive ints */
+ for (ienc=0; ienc<nencode; ienc++)
+ {
+ int pint=positive_int(encode_ints[ienc]);
+ encode_ints[ienc]=pint;
+ }
+ /* Now we must decide what base and runlength to do. If we have swapped atoms it will be at least 2.
+ If even the next atom is large, we will not do anything. */
+ largest_required_base=0;
+ /* Determine required base */
+ for (ienc=0; ienc<min_runlength*3; ienc++)
+ if (encode_ints[ienc]>largest_required_base)
+ largest_required_base=encode_ints[ienc];
+ /* Also compute what the largest base is for the current runlength setting! */
+ largest_runlength_base=0;
+ for (ienc=0; (ienc<runlength*3) && (ienc<nencode); ienc++)
+ if (encode_ints[ienc]>largest_runlength_base)
+ largest_runlength_base=encode_ints[ienc];
+
+ largest_required_index=Ptngc_find_magic_index(largest_required_base);
+ largest_runlength_index=Ptngc_find_magic_index(largest_runlength_base);
+
+ if (largest_required_index<largest_runlength_index)
+ {
+ new_runlength=min_runlength;
+ new_small_index=largest_required_index;
+ }
+ else
+ {
+ new_runlength=runlength;
+ new_small_index=largest_runlength_index;
+ }
+
+ /* Only allow increase of runlength wrt min_runlength */
+ if (new_runlength<min_runlength)
+ new_runlength=min_runlength;
+
+ /* If the current runlength is longer than the number of
+ triplets left stop it from being so. */
+ if (new_runlength>ntriplets_left)
+ new_runlength=ntriplets_left;
+
+ /* We must at least try to get some small integers going. */
+ if (new_runlength==0)
+ {
+ new_runlength=1;
+ new_small_index=small_index;
+ }
+
+ iter_runlength=new_runlength;
+ iter_small_index=new_small_index;
+
+ /* Iterate to find optimal encoding and runlength */
+#ifdef SHOWIT
+ fprintf(stderr,"Entering iterative loop.\n");
+ fflush(stderr);
+#endif
+
+ do {
+ new_runlength=iter_runlength;
+ new_small_index=iter_small_index;
+
+#ifdef SHOWIT
+ fprintf(stderr,"Test new_small_index=%d Base=%d\n",new_small_index,magic[new_small_index]);
+#endif
+ /* What is the largest runlength
+ we can do with the currently
+ selected encoding? Also the max supported runlength is 6 triplets! */
+ for (ienc=0; ienc<nencode && ienc<18; ienc++)
+ {
+ int test_index=Ptngc_find_magic_index(encode_ints[ienc]);
+ if (test_index>new_small_index)
+ break;
+ }
+ if (ienc/3>new_runlength)
+ {
+ iter_runlength=ienc/3;
+#ifdef SHOWIT
+ fprintf(stderr,"I found a new possible runlength: %d\n",iter_runlength);
+#endif
+ }
+
+ /* How large encoding do we have to use? */
+ largest_runlength_base=0;
+ for (ienc=0; ienc<iter_runlength*3; ienc++)
+ if (encode_ints[ienc]>largest_runlength_base)
+ largest_runlength_base=encode_ints[ienc];
+ largest_runlength_index=Ptngc_find_magic_index(largest_runlength_base);
+ if (largest_runlength_index!=new_small_index)
+ {
+ iter_small_index=largest_runlength_index;
+#ifdef SHOWIT
+ fprintf(stderr,"I found a new possible small index: %d Base=%d\n",iter_small_index,magic[iter_small_index]);
+#endif
+ }
+ } while ((new_runlength!=iter_runlength) ||
+ (new_small_index!=iter_small_index));
+
+#ifdef SHOWIT
+ fprintf(stderr,"Exit iterative loop.\n");
+ fflush(stderr);
+#endif
+
+ /* Verify that we got something good. We may have caught a
+ substantially larger atom. If so we should just bail
+ out and let the loop get on another lap. We may have a
+ minimum runlength though and then we have to fulfill
+ the request to write out these atoms! */
+ rle_index_dep=0;
+ if (new_runlength<3)
+ rle_index_dep=IS_LARGE;
+ else if (new_runlength<6)
+ rle_index_dep=QUITE_LARGE;
+ if ((min_runlength)
+ || ((new_small_index<small_index+IS_LARGE) && (new_small_index+rle_index_dep<max_large_index))
+#if 1
+ || (new_small_index+IS_LARGE<max_large_index)
+#endif
+)
+ {
+ int nbits;
+ if ((new_runlength!=runlength) || (new_small_index!=small_index))
+ {
+ int change=new_small_index-small_index;
+
+ if (new_small_index<=0)
+ change=0;
+
+ if (change<0)
+ {
+ int ixx;
+ for (ixx=0; ixx<new_runlength; ixx++)
+ {
+ int rejected;
+ do {
+ int ixyz;
+ double isum=0.; /* ints can be almost 32 bit so multiplication will overflow. So do doubles. */
+ for (ixyz=0; ixyz<3; ixyz++)
+ {
+ /* encode_ints is already positive (and multiplied by 2 versus the original, just as magic ints) */
+ double id=encode_ints[ixx*3+ixyz];
+ isum+=id*id;
+ }
+ rejected=0;
+#ifdef SHOWIT
+ fprintf(stderr,"Tested decrease %d of index: %g>=%g?\n",change,isum,(double)magic[small_index+change]*(double)magic[small_index+change]);
+#endif
+ if (isum>(double)magic[small_index+change]*(double)magic[small_index+change])
+ {
+#ifdef SHOWIT
+ fprintf(stderr,"Rejected decrease %d of index due to length of vector: %g>=%g\n",change,isum,(double)magic[small_index+change]*(double)magic[small_index+change]);
+#endif
+ rejected=1;
+ change++;
+ }
+ } while ((change<0) && (rejected));
+ if (change==0)
+ break;
+ }
+ }
+
+ /* If the only thing to do is to change the base by
+ only one -1 it is probably not worth it. */
+ if (!((change==-1) && (runlength==new_runlength)))
+ {
+ /* If we have a very short runlength we do not
+ want to do large base changes. It costs 6
+ extra bits to do -2. We gain 2/3
+ bits per value to decrease the index by -2,
+ ie 2 bits, so to any changes down we must
+ have a runlength of 3 or more to do it for
+ one molecule! If we have several molecules we
+ will gain of course, so not be so strict. */
+ if ((change==-2) && (new_runlength<3))
+ {
+ if (runlength==new_runlength)
+ change=0;
+ else
+ change=-1;
+#ifdef SHOWIT
+ fprintf(stderr,"Rejected change by -2 due to too short runlenght. Change set to %d\n",change);
+#endif
+ }
+
+ /* First adjust base using large base change instruction (if necessary) */
+ while ((change>1) || (change<-1) || ((new_runlength==6) && (change)))
+ {
+ unsigned int code=0U;
+ int this_change=change;
+ if (this_change>2)
+ this_change=2;
+ if (this_change<-2)
+ this_change=-2;
+ change-=this_change;
+#ifdef SHOWIT
+ fprintf(stderr,"Large base change: %d.\n",this_change);
+#endif
+ small_index+=this_change;
+ if (this_change<0)
+ {
+ code|=2U;
+ this_change=-this_change;
+ }
+ code|=(unsigned int)(this_change-1);
+ write_instruction(coder,INSTR_LARGE_BASE_CHANGE,&output_ptr);
+ Ptngc_writebits(coder,code,2,&output_ptr);
+ }
+ /* If there is still base change or runlength changes to do, we do them now. */
+ if ((new_runlength!=runlength) || (change))
+ {
+ unsigned int ichange=(unsigned int)(change+1);
+ unsigned int code=0U;
+ unsigned int irun=(unsigned int)((new_runlength-1)*3);
+ if (new_runlength==6)
+ ichange=0; /* Means no change. The change has been taken care of explicitly by a large
+ base change instruction above. */
+ code=ichange+irun;
+#ifdef SHOWIT
+ fprintf(stderr,"Small base change: %d Runlength change: %d\n",change,new_runlength);
+#endif
+ small_index+=change;
+ write_instruction(coder,INSTR_BASE_RUNLENGTH,&output_ptr);
+ Ptngc_writebits(coder,code,4,&output_ptr);
+ runlength=new_runlength;
+ }
+ }
+#ifdef SHOWIT
+ else
+ fprintf(stderr,"Rejected base change due to only change==-1\n");
+#endif
+#ifdef SHOWIT
+ fprintf(stderr,"Current small index: %d Base=%d\n",small_index,magic[small_index]);
+#endif
+ }
+ /* If we have a large previous integer we can combine it with a sequence of small ints. */
+ if (has_large)
+ {
+ /* If swapatoms is set to 1 but we did actually not
+ do any swapping, we must first write out the
+ large atom and then the small. If swapatoms is 1
+ and we did swapping we can use the efficient
+ encoding. */
+ if ((swapatoms) && (!didswap))
+ {
+#ifdef SHOWIT
+ fprintf(stderr,"Swapatoms was set to 1 but we did not do swapping!\n");
+ fprintf(stderr,"Only one large integer.\n");
+#endif
+ /* Flush all large atoms. */
+ flush_large(coder,&has_large,has_large_ints,has_large,large_index,large_nbits,compress_buffer,&output_ptr);
+#ifdef SHOWIT
+ fprintf(stderr,"Sequence of only small integers.\n");
+#endif
+ write_instruction(coder,INSTR_ONLY_SMALL,&output_ptr);
+ }
+ else
+ {
+
+#ifdef SHOWIT
+ fprintf(stderr,"Sequence of one large and small integers (good compression).\n");
+#endif
+ /* Flush all large atoms but one! */
+ if (has_large>1)
+ flush_large(coder,&has_large,has_large_ints,has_large-1,large_index,large_nbits,compress_buffer,&output_ptr);
+ write_instruction(coder,INSTR_DEFAULT,&output_ptr);
+ write_three_large(coder,has_large_ints,large_index,large_nbits,compress_buffer,&output_ptr);
+ has_large=0;
+ }
+ }
+ else
+ {
+#ifdef SHOWIT
+ fprintf(stderr,"Sequence of only small integers.\n");
+#endif
+ write_instruction(coder,INSTR_ONLY_SMALL,&output_ptr);
+ }
+ /* Base compress small integers using the current parameters. */
+ nbits=magic_bits[small_index][runlength-1];
+ /* The same base is used for the small changes. */
+ small_idx[0]=small_index;
+ small_idx[1]=small_index;
+ small_idx[2]=small_index;
+ trajcoder_base_compress(encode_ints,runlength*3,small_idx,compress_buffer);
+#ifdef SHOWIT
+ fprintf(stderr,"nbits=%d (%g)\n",nbits,nbits/(runlength*3.));
+ nbits_sum+=nbits;
+ nvalues_sum+=runlength*3;
+ fprintf(stderr,"Runlength encoded small integers. runlength=%d\n",runlength);
+#endif
+ /* write out base compressed small integers */
+ Ptngc_writemanybits(coder,compress_buffer,nbits,&output_ptr);
+#ifdef SHOWIT
+ for (ienc=0; ienc<runlength; ienc++)
+ fprintf(stderr,"Small: %d %d %d\n",
+ encode_ints[ienc*3],
+ encode_ints[ienc*3+1],
+ encode_ints[ienc*3+2]);
+#endif
+ /* Update prevcoord. */
+ for (ienc=0; ienc<runlength; ienc++)
+ {
+#ifdef SHOWIT
+ fprintf(stderr,"Prevcoord in packing: %d %d %d\n",
+ prevcoord[0],prevcoord[1],prevcoord[2]);
+#endif
+ prevcoord[0]+=unpositive_int(encode_ints[ienc*3]);
+ prevcoord[1]+=unpositive_int(encode_ints[ienc*3+1]);
+ prevcoord[2]+=unpositive_int(encode_ints[ienc*3+2]);
+ }
+#ifdef SHOWIT
+ fprintf(stderr,"Prevcoord in packing: %d %d %d\n",
+ prevcoord[0],prevcoord[1],prevcoord[2]);
+#endif
+
+ input_ptr+=3*runlength;
+ ntriplets_left-=runlength;
+ }
+ else
+ {
+#ifdef SHOWIT
+ fprintf(stderr,"Refused value: %d old is %d max is %d\n",new_small_index,small_index,max_large_index);
+ fflush(stderr);
+#endif
+ refused=1;
+ }
+ }
+#ifdef SHOWIT
+ fprintf(stderr,"Number of triplets left is %d\n",ntriplets_left);
+#endif
+ }
+ /* If we have large previous integers we must flush them now. */
+ if (has_large)
+ flush_large(coder,&has_large,has_large_ints,has_large,large_index,large_nbits,compress_buffer,&output_ptr);
+ Ptngc_pack_flush(coder,&output_ptr);
+ output_length=(int)(output_ptr-output);
+#ifdef SHOWIT
+ fprintf(stderr,"Done block: nbits=%d nvalues=%d (%g)\n",nbits_sum,nvalues_sum,(double)nbits_sum/nvalues_sum);
+#endif
+ *length=output_length;
+ return output;
+}
+
+
+int Ptngc_unpack_array_xtc2(struct coder *coder,unsigned char *packed,int *output, int length)
+{
+ unsigned char *ptr=packed;
+ int bitptr=0;
+ int minint[3];
+ int large_index[3];
+ int small_index;
+ int prevcoord[3];
+ int ntriplets_left=length/3;
+ int swapatoms=0;
+ int runlength=0;
+ int large_nbits;
+ unsigned char compress_buffer[18*4]; /* Holds compressed result for 3 large ints or up to 18 small ints. */
+ int encode_ints[21]; /* Up to 3 large + 18 small ints can be encoded at once */
+ (void)coder;
+
+ /* Read min integers. */
+ minint[0]=unpositive_int(readbits(&ptr,&bitptr,32));
+ minint[1]=unpositive_int(readbits(&ptr,&bitptr,32));
+ minint[2]=unpositive_int(readbits(&ptr,&bitptr,32));
+ /* Read large indices */
+ large_index[0]=readbits(&ptr,&bitptr,8);
+ large_index[1]=readbits(&ptr,&bitptr,8);
+ large_index[2]=readbits(&ptr,&bitptr,8);
+ /* Read small index */
+ small_index=readbits(&ptr,&bitptr,8);
+
+ large_nbits=compute_magic_bits(large_index);
+
+#ifdef SHOWIT
+ fprintf(stderr,"Minimum integers: %d %d %d\n",minint[0],minint[1],minint[2]);
+ fprintf(stderr,"Large indices: %d %d %d\n",large_index[0],large_index[1],large_index[2]);
+ fprintf(stderr,"Small index: %d\n",small_index);
+ fprintf(stderr,"large_nbits=%d\n",large_nbits);
+#endif
+
+ /* Initial prevcoord is the minimum integers. */
+ prevcoord[0]=minint[0];
+ prevcoord[1]=minint[1];
+ prevcoord[2]=minint[2];
+
+ while (ntriplets_left)
+ {
+ int instr=read_instruction(&ptr,&bitptr);
+#ifdef SHOWIT
+ if ((instr>=0) && (instr<MAXINSTR))
+ fprintf(stderr,"Decoded instruction %s\n",instrnames[instr]);
+#endif
+ if ((instr==INSTR_DEFAULT) /* large+small */
+ || (instr==INSTR_ONLY_LARGE) /* only large */
+ || (instr==INSTR_ONLY_SMALL)) /* only small */
+ {
+ int large_ints[3]={0,0,0};
+ if (instr!=INSTR_ONLY_SMALL)
+ {
+ /* Clear the compress buffer. */
+ int i;
+ for (i=0; i<18*4; i++)
+ compress_buffer[i]=0;
+ /* Get the large value. */
+ readmanybits(&ptr,&bitptr,large_nbits,compress_buffer);
+ trajcoder_base_decompress(compress_buffer,3,large_index,encode_ints);
+ large_ints[0]=encode_ints[0];
+ large_ints[1]=encode_ints[1];
+ large_ints[2]=encode_ints[2];
+#ifdef SHOWIT
+ fprintf(stderr,"large ints: %d %d %d\n",large_ints[0],large_ints[1],large_ints[2]);
+#endif
+ }
+ if (instr!=INSTR_ONLY_LARGE)
+ {
+ int small_idx[3];
+ int i;
+ /* The same base is used for the small changes. */
+ small_idx[0]=small_index;
+ small_idx[1]=small_index;
+ small_idx[2]=small_index;
+ /* Clear the compress buffer. */
+ for (i=0; i<18*4; i++)
+ compress_buffer[i]=0;
+ /* Get the small values. */
+ readmanybits(&ptr,&bitptr,magic_bits[small_index][runlength-1],compress_buffer);
+ trajcoder_base_decompress(compress_buffer,3*runlength,small_idx,encode_ints);
+#ifdef SHOWIT
+ for (i=0; i<runlength; i++)
+ fprintf(stderr,"small ints: %d %d %d\n",encode_ints[i*3+0],encode_ints[i*3+1],encode_ints[i*3+2]);
+#endif
+ }
+ if (instr==INSTR_DEFAULT)
+ {
+ /* Check for swapped atoms */
+ if (swapatoms)
+ {
+ /* Unswap the atoms. */
+ int i;
+ for (i=0; i<3; i++)
+ {
+ int in[3], out[3];
+ in[0]=large_ints[i];
+ in[1]=unpositive_int(encode_ints[i]);
+ in[2]=unpositive_int(encode_ints[3+i]);
+ swap_ints(in,out);
+ large_ints[i]=out[0];
+ encode_ints[i]=positive_int(out[1]);
+ encode_ints[3+i]=positive_int(out[2]);
+ }
+ }
+ }
+ /* Output result. */
+ if (instr!=INSTR_ONLY_SMALL)
+ {
+ /* Output large value */
+ *output++=large_ints[0]+minint[0];
+ *output++=large_ints[1]+minint[1];
+ *output++=large_ints[2]+minint[2];
+ prevcoord[0]=large_ints[0];
+ prevcoord[1]=large_ints[1];
+ prevcoord[2]=large_ints[2];
+#ifdef SHOWIT
+ fprintf(stderr,"Prevcoord after unpacking of large: %d %d %d\n",
+ prevcoord[0],prevcoord[1],prevcoord[2]);
+ fprintf(stderr,"VALUE:%d %6d %6d %6d\n",
+ length/3-ntriplets_left,
+ prevcoord[0]+minint[0],
+ prevcoord[1]+minint[1],
+ prevcoord[2]+minint[2]);
+#endif
+ ntriplets_left--;
+ }
+ if (instr!=INSTR_ONLY_LARGE)
+ {
+ /* Output small values */
+ int i;
+#ifdef SHOWIT
+ fprintf(stderr,"Prevcoord before unpacking of small: %d %d %d\n",
+ prevcoord[0],prevcoord[1],prevcoord[2]);
+#endif
+ for (i=0; i<runlength; i++)
+ {
+ int v[3];
+ v[0]=unpositive_int(encode_ints[i*3]);
+ v[1]=unpositive_int(encode_ints[i*3+1]);
+ v[2]=unpositive_int(encode_ints[i*3+2]);
+ prevcoord[0]+=v[0];
+ prevcoord[1]+=v[1];
+ prevcoord[2]+=v[2];
+#ifdef SHOWIT
+ fprintf(stderr,"Prevcoord after unpacking of small: %d %d %d\n",
+ prevcoord[0],prevcoord[1],prevcoord[2]);
+ fprintf(stderr,"Unpacked small values: %6d %6d %6d\t\t%6d %6d %6d\n",v[0],v[1],v[2],prevcoord[0],prevcoord[1],prevcoord[2]);
+ fprintf(stderr,"VALUE:%d %6d %6d %6d\n",
+ length/3-(ntriplets_left-i),
+ prevcoord[0]+minint[0],
+ prevcoord[1]+minint[1],
+ prevcoord[2]+minint[2]);
+#endif
+ *output++=prevcoord[0]+minint[0];
+ *output++=prevcoord[1]+minint[1];
+ *output++=prevcoord[2]+minint[2];
+ }
+ ntriplets_left-=runlength;
+ }
+ }
+ else if (instr==INSTR_LARGE_RLE)
+ {
+ int i,j;
+ int large_ints[3];
+ /* How many large atoms in this sequence? */
+ int n=(int)readbits(&ptr,&bitptr,4)+3; /* 3-18 large atoms */
+ for (i=0; i<n; i++)
+ {
+ /* Clear the compress buffer. */
+ for (j=0; j<18*4; j++)
+ compress_buffer[j]=0;
+ /* Get the large value. */
+ readmanybits(&ptr,&bitptr,large_nbits,compress_buffer);
+ trajcoder_base_decompress(compress_buffer,3,large_index,encode_ints);
+ large_ints[0]=encode_ints[0];
+ large_ints[1]=encode_ints[1];
+ large_ints[2]=encode_ints[2];
+ /* Output large value */
+ *output++=large_ints[0]+minint[0];
+ *output++=large_ints[1]+minint[1];
+ *output++=large_ints[2]+minint[2];
+ prevcoord[0]=large_ints[0];
+ prevcoord[1]=large_ints[1];
+ prevcoord[2]=large_ints[2];
+ }
+ ntriplets_left-=n;
+ }
+ else if (instr==INSTR_BASE_RUNLENGTH)
+ {
+ unsigned int code=readbits(&ptr,&bitptr,4);
+ int change;
+ if (code==15)
+ {
+ change=0;
+ runlength=6;
+ }
+ else
+ {
+ int ichange=code%3;
+ runlength=code/3+1;
+ change=ichange-1;
+ }
+ small_index+=change;
+ }
+ else if (instr==INSTR_FLIP)
+ {
+ swapatoms=1-swapatoms;
+ }
+ else if (instr==INSTR_LARGE_BASE_CHANGE)
+ {
+ unsigned int ichange=readbits(&ptr,&bitptr,2);
+ int change=(int)(ichange&0x1U)+1;
+ if (ichange&0x2U)
+ change=-change;
+ small_index+=change;
+ }
+ else
+ {
+ fprintf(stderr,"TRAJNG: BUG! Encoded unknown instruction.\n");
+ exit(EXIT_FAILURE);
+ }
+#ifdef SHOWIT
+ fprintf(stderr,"Number of triplets left is %d\n",ntriplets_left);
+#endif
+ }
+ return 0;
+}
--- /dev/null
+/* This code is part of the tng compression routines.
+ *
+ * Written by Daniel Spangberg
+ * Copyright (c) 2010, 2013, The GROMACS development team.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+/* This code is heavily influenced by
+ http://hpcv100.rc.rug.nl/xdrf.html
+ Based on coordinate compression (c) by Frans van Hoesel.
+ and GROMACS xtc files (http://www.gromacs.org)
+ (c) Copyright (c) Erik Lindahl, David van der Spoel
+*/
+
+/* The cost estimates are ripped right out of xtc2.c, so take these
+ with a grain (truckload) of salt. */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "../../include/compression/warnmalloc.h"
+#include "../../include/compression/widemuldiv.h"
+#include "../../include/compression/bwlzh.h"
+
+static const double iflipgaincheck=0.89089871814033927; /* 1./(2**(1./6)) */
+
+#define MAX_LARGE_RLE 1024 /* Maximum number of large atoms for large RLE. */
+#define MAX_SMALL_RLE 12 /* Maximum number of small atoms in one group. */
+
+#define TRESHOLD_INTRA_INTER_DIRECT 1.5 /* How much larger can the direct
+ frame deltas for the small
+ triplets be and be accepted anyway
+ as better than the intra/inter frame
+ deltas. For better instructions/RLEs. */
+
+#define TRESHOLD_INTER_INTRA 5.0 /* How much larger can the intra
+ frame deltas for the small
+ triplets be and be accepted anyway
+ as better than the inter frame
+ deltas. */
+
+/* Difference in indices used for determining whether to store as
+ large or small. A fun detail in this compression algorithm is that
+ if everything works fine, large can often be smaller than small, or
+ at least not as large as is large in magic.c. This is a key idea of
+ xtc3. */
+#define QUITE_LARGE 3
+#define IS_LARGE 6
+
+#if 0
+#define SHOWIT
+#endif
+
+#if 0
+#define SHOWIT_LIGHT
+#endif
+
+/* These routines are in xtc2.c */
+int Ptngc_magic(unsigned int i);
+int Ptngc_find_magic_index(unsigned int maxval);
+
+static unsigned int positive_int(int item)
+{
+ int s=0;
+ if (item>0)
+ s=1+(item-1)*2;
+ else if (item<0)
+ s=2+(-item-1)*2;
+ return s;
+}
+
+static int unpositive_int(int val)
+{
+ int s=(val+1)/2;
+ if ((val%2)==0)
+ s=-s;
+ return s;
+}
+
+
+/* Sequence instructions */
+#define INSTR_DEFAULT 0U
+#define INSTR_SMALL_RUNLENGTH 1U
+#define INSTR_ONLY_LARGE 2U
+#define INSTR_ONLY_SMALL 3U
+#define INSTR_FLIP 4U
+#define INSTR_LARGE_RLE 5U
+#define INSTR_LARGE_DIRECT 6U
+#define INSTR_LARGE_INTRA_DELTA 7U
+#define INSTR_LARGE_INTER_DELTA 8U
+
+#define MAXINSTR 9
+
+struct xtc3_context
+{
+ unsigned int *instructions;
+ int ninstr, ninstr_alloc;
+ unsigned int *rle;
+ int nrle, nrle_alloc;
+ unsigned int *large_direct;
+ int nlargedir, nlargedir_alloc;
+ unsigned int *large_intra_delta;
+ int nlargeintra, nlargeintra_alloc;
+ unsigned int *large_inter_delta;
+ int nlargeinter, nlargeinter_alloc;
+ unsigned int *smallintra;
+ int nsmallintra, nsmallintra_alloc;
+ int minint[3],maxint[3];
+ int has_large;
+ int has_large_ints[MAX_LARGE_RLE*3]; /* Large cache. */
+ int has_large_type[MAX_LARGE_RLE]; /* What kind of type this large
+ int is. */
+ int current_large_type;
+};
+
+static void init_xtc3_context(struct xtc3_context *xtc3_context)
+{
+ xtc3_context->instructions=NULL;
+ xtc3_context->ninstr=0;
+ xtc3_context->ninstr_alloc=0;
+ xtc3_context->rle=NULL;
+ xtc3_context->nrle=0;
+ xtc3_context->nrle_alloc=0;
+ xtc3_context->large_direct=NULL;
+ xtc3_context->nlargedir=0;
+ xtc3_context->nlargedir_alloc=0;
+ xtc3_context->large_intra_delta=NULL;
+ xtc3_context->nlargeintra=0;
+ xtc3_context->nlargeintra_alloc=0;
+ xtc3_context->large_inter_delta=NULL;
+ xtc3_context->nlargeinter=0;
+ xtc3_context->nlargeinter_alloc=0;
+ xtc3_context->smallintra=NULL;
+ xtc3_context->nsmallintra=0;
+ xtc3_context->nsmallintra_alloc=0;
+ xtc3_context->has_large=0;
+ xtc3_context->current_large_type=0;
+}
+
+static void free_xtc3_context(struct xtc3_context *xtc3_context)
+{
+ free(xtc3_context->instructions);
+ free(xtc3_context->rle);
+ free(xtc3_context->large_direct);
+ free(xtc3_context->large_intra_delta);
+ free(xtc3_context->large_inter_delta);
+ free(xtc3_context->smallintra);
+}
+
+/* Modifies three integer values for better compression of water */
+static void swap_ints(int *in, int *out)
+{
+ out[0]=in[0]+in[1];
+ out[1]=-in[1];
+ out[2]=in[1]+in[2];
+}
+
+static void swap_is_better(int *input, int *minint, int *sum_normal, int *sum_swapped)
+{
+ int normal_max=0;
+ int swapped_max=0;
+ int i,j;
+ int normal[3];
+ int swapped[3];
+ for (i=0; i<3; i++)
+ {
+ normal[0]=input[i]-minint[i];
+ normal[1]=input[3+i]-input[i]; /* minint[i]-minint[i] cancels out */
+ normal[2]=input[6+i]-input[3+i]; /* minint[i]-minint[i] cancels out */
+ swap_ints(normal,swapped);
+ for (j=1; j<3; j++)
+ {
+ if (positive_int(normal[j])>(unsigned int)normal_max)
+ normal_max=positive_int(normal[j]);
+ if (positive_int(swapped[j])>(unsigned int)swapped_max)
+ swapped_max=positive_int(swapped[j]);
+ }
+ }
+ if (normal_max==0)
+ normal_max=1;
+ if (swapped_max==0)
+ swapped_max=1;
+ *sum_normal=normal_max;
+ *sum_swapped=swapped_max;
+}
+
+static void allocate_enough_memory(unsigned int **ptr, int *nele, int *nele_alloc)
+{
+ (*nele)++;
+ if (*nele>*nele_alloc)
+ {
+ *nele_alloc=*nele + *nele/2;
+ *ptr=warnrealloc(*ptr,*nele_alloc*sizeof **ptr);
+ }
+}
+
+static void insert_value_in_array(unsigned int **ptr, int *nele, int *nele_alloc,
+ unsigned int value,
+ char *arrayname)
+{
+#ifndef SHOWIT
+ (void)arrayname;
+#endif
+ allocate_enough_memory(ptr,nele,nele_alloc);
+#ifdef SHOWIT
+ fprintf(stderr,"Inserting value %u into array %s @ %d\n",value,arrayname,(*nele)-1);
+#endif
+ (*ptr)[(*nele)-1]=value;
+}
+
+
+
+static void swapdecide(struct xtc3_context *xtc3_context, int *input,int *swapatoms, int *large_index, int *minint)
+{
+ int didswap=0;
+ int normal,swapped;
+ (void)large_index;
+ swap_is_better(input,minint,&normal,&swapped);
+ /* We have to determine if it is worth to change the behaviour.
+ If diff is positive it means that it is worth something to
+ swap. But it costs 4 bits to do the change. If we assume that
+ we gain 0.17 bit by the swap per value, and the runlength>2
+ for four molecules in a row, we gain something. So check if we
+ gain at least 0.17 bits to even attempt the swap.
+ */
+#ifdef SHOWIT
+ fprintf(stderr,"Trying Flip: %g %g\n",(double)swapped/normal, (double)normal/swapped);
+#endif
+ if (((swapped<normal) && (fabs((double)swapped/normal)<iflipgaincheck)) ||
+ ((normal<swapped) && (fabs((double)normal/swapped)<iflipgaincheck)))
+ {
+ if (swapped<normal)
+ {
+ if (!*swapatoms)
+ {
+ *swapatoms=1;
+ didswap=1;
+ }
+ }
+ else
+ {
+ if (*swapatoms)
+ {
+ *swapatoms=0;
+ didswap=1;
+ }
+ }
+ }
+ if (didswap)
+ {
+#ifdef SHOWIT
+ fprintf(stderr,"Flip. Swapatoms is now %d\n",*swapatoms);
+#endif
+ insert_value_in_array(&xtc3_context->instructions,
+ &xtc3_context->ninstr,
+ &xtc3_context->ninstr_alloc,
+ INSTR_FLIP,"instr");
+ }
+}
+
+/* It is "large" if we have to increase the small index quite a
+ bit. Not so much to be rejected by the not very large check
+ later. */
+static int is_quite_large(int *input, int small_index, int max_large_index)
+{
+ int is=0;
+ int i;
+ if (small_index+QUITE_LARGE>=max_large_index)
+ is=1;
+ else
+ {
+ for (i=0; i<3; i++)
+ if (positive_int(input[i])>(unsigned int)Ptngc_magic(small_index+QUITE_LARGE))
+ {
+ is=1;
+ break;
+ }
+ }
+ return is;
+}
+
+#ifdef SHOWIT
+int nbits_sum;
+int nvalues_sum;
+#endif
+
+static void insert_batch(int *input_ptr, int ntriplets_left, int *prevcoord, int *encode_ints, int startenc, int *nenc)
+{
+ int nencode=startenc*3;
+ int tmp_prevcoord[3];
+
+ tmp_prevcoord[0]=prevcoord[0];
+ tmp_prevcoord[1]=prevcoord[1];
+ tmp_prevcoord[2]=prevcoord[2];
+
+ if (startenc)
+ {
+ int i;
+ for (i=0; i<startenc; i++)
+ {
+ tmp_prevcoord[0]+=encode_ints[i*3];
+ tmp_prevcoord[1]+=encode_ints[i*3+1];
+ tmp_prevcoord[2]+=encode_ints[i*3+2];
+#ifdef SHOWIT
+ fprintf(stderr,"%6d: %6d %6d %6d\t\t%6d %6d %6d\t\t%6d %6d %6d\n",i*3,
+ tmp_prevcoord[0],tmp_prevcoord[1],tmp_prevcoord[2],
+ encode_ints[i*3],
+ encode_ints[i*3+1],
+ encode_ints[i*3+2],
+ positive_int(encode_ints[i*3]),
+ positive_int(encode_ints[i*3+1]),
+ positive_int(encode_ints[i*3+2]));
+#endif
+ }
+ }
+
+#ifdef SHOWIT
+ fprintf(stderr,"New batch\n");
+#endif
+ while ((nencode<3+MAX_SMALL_RLE*3) && (nencode<ntriplets_left*3))
+ {
+ encode_ints[nencode]=input_ptr[nencode]-tmp_prevcoord[0];
+ encode_ints[nencode+1]=input_ptr[nencode+1]-tmp_prevcoord[1];
+ encode_ints[nencode+2]=input_ptr[nencode+2]-tmp_prevcoord[2];
+#ifdef SHOWIT
+ fprintf(stderr,"%6d: %6d %6d %6d\t\t%6d %6d %6d\t\t%6d %6d %6d\n",nencode,
+ input_ptr[nencode],
+ input_ptr[nencode+1],
+ input_ptr[nencode+2],
+ encode_ints[nencode],
+ encode_ints[nencode+1],
+ encode_ints[nencode+2],
+ positive_int(encode_ints[nencode]),
+ positive_int(encode_ints[nencode+1]),
+ positive_int(encode_ints[nencode+2]));
+#endif
+ tmp_prevcoord[0]=input_ptr[nencode];
+ tmp_prevcoord[1]=input_ptr[nencode+1];
+ tmp_prevcoord[2]=input_ptr[nencode+2];
+ nencode+=3;
+ }
+ *nenc=nencode;
+}
+
+static void large_instruction_change(struct xtc3_context *xtc3_context, int i)
+{
+ /* If the first large is of a different kind than the currently used we must
+ emit an "instruction" to change the large type. */
+ if (xtc3_context->has_large_type[i]!=xtc3_context->current_large_type)
+ {
+ unsigned int instr;
+ xtc3_context->current_large_type=xtc3_context->has_large_type[i];
+ if (xtc3_context->current_large_type==0)
+ instr=INSTR_LARGE_DIRECT;
+ else if (xtc3_context->current_large_type==1)
+ instr=INSTR_LARGE_INTRA_DELTA;
+ else
+ instr=INSTR_LARGE_INTER_DELTA;
+ insert_value_in_array(&xtc3_context->instructions,
+ &xtc3_context->ninstr,
+ &xtc3_context->ninstr_alloc,
+ instr,"instr");
+ }
+}
+
+static void write_three_large(struct xtc3_context *xtc3_context,
+ int i)
+{
+ int m;
+ if (xtc3_context->current_large_type==0)
+ {
+ for (m=0; m<3; m++)
+ insert_value_in_array(&xtc3_context->large_direct,
+ &xtc3_context->nlargedir,
+ &xtc3_context->nlargedir_alloc,
+ xtc3_context->has_large_ints[i*3+m],"large direct");
+ }
+ else if (xtc3_context->current_large_type==1)
+ {
+ for (m=0; m<3; m++)
+ insert_value_in_array(&xtc3_context->large_intra_delta,
+ &xtc3_context->nlargeintra,
+ &xtc3_context->nlargeintra_alloc,
+ xtc3_context->has_large_ints[i*3+m],"large intra");
+ }
+ else
+ {
+ for (m=0; m<3; m++)
+ insert_value_in_array(&xtc3_context->large_inter_delta,
+ &xtc3_context->nlargeinter,
+ &xtc3_context->nlargeinter_alloc,
+ xtc3_context->has_large_ints[i*3+m],"large inter");
+ }
+}
+
+static void flush_large(struct xtc3_context *xtc3_context,
+ int n) /* How many to flush. */
+{
+ int i;
+ i=0;
+ while (i<n)
+ {
+ int j,k;
+ /* If the first large is of a different kind than the currently used we must
+ emit an "instruction" to change the large type. */
+ large_instruction_change(xtc3_context,i);
+ /* How many large of the same kind in a row? */
+ for (j=0;
+ (i+j<n) &&
+ (xtc3_context->has_large_type[i+j]==xtc3_context->has_large_type[i]);
+ j++);
+ if (j<3)
+ {
+ for (k=0; k<j; k++)
+ {
+ insert_value_in_array(&xtc3_context->instructions,
+ &xtc3_context->ninstr,
+ &xtc3_context->ninstr_alloc,
+ INSTR_ONLY_LARGE,"instr");
+ write_three_large(xtc3_context,i+k);
+ }
+ }
+ else
+ {
+ insert_value_in_array(&xtc3_context->instructions,
+ &xtc3_context->ninstr,
+ &xtc3_context->ninstr_alloc,
+ INSTR_LARGE_RLE,"instr");
+ insert_value_in_array(&xtc3_context->rle,
+ &xtc3_context->nrle,
+ &xtc3_context->nrle_alloc,
+ (unsigned int)j,"rle (large)");
+ for (k=0; k<j; k++)
+ write_three_large(xtc3_context,i+k);
+ }
+ i+=j;
+ }
+ if ((xtc3_context->has_large-n)!=0)
+ {
+ int j;
+ for (i=0; i<xtc3_context->has_large-n; i++)
+ {
+ xtc3_context->has_large_type[i]=xtc3_context->has_large_type[i+n];
+ for (j=0; j<3; j++)
+ xtc3_context->has_large_ints[i*3+j]=xtc3_context->has_large_ints[(i+n)*3+j];
+ }
+ }
+ xtc3_context->has_large-=n; /* Number of remaining large atoms in buffer */
+}
+
+static double compute_intlen(unsigned int *ints)
+{
+ /* The largest value. */
+ unsigned int m=ints[0];
+ if (ints[1]>m)
+ m=ints[1];
+ if (ints[2]>m)
+ m=ints[2];
+ return (double)m;
+}
+
+static void buffer_large(struct xtc3_context *xtc3_context, int *input, int inpdata,
+ int natoms, int intradelta_ok)
+{
+ unsigned int direct[3], intradelta[3]={0,}, interdelta[3]={0,};
+ double minlen;
+ int best_type;
+ int frame=inpdata/(natoms*3);
+ int atomframe=inpdata%(natoms*3);
+ /* If it is full we must write them all. */
+ if (xtc3_context->has_large==MAX_LARGE_RLE)
+ flush_large(xtc3_context,xtc3_context->has_large); /* Flush all. */
+ /* Find out which is the best choice for the large integer. Direct coding, or some
+ kind of delta coding? */
+ /* First create direct coding. */
+ direct[0]=(unsigned int)(input[inpdata]-xtc3_context->minint[0]);
+ direct[1]=(unsigned int)(input[inpdata+1]-xtc3_context->minint[1]);
+ direct[2]=(unsigned int)(input[inpdata+2]-xtc3_context->minint[2]);
+ minlen=compute_intlen(direct);
+ best_type=0; /* Direct. */
+#if 1
+ /* Then try intra coding if we can. */
+ if ((intradelta_ok) && (atomframe>=3))
+ {
+ double thislen;
+ intradelta[0]=positive_int(input[inpdata]-input[inpdata-3]);
+ intradelta[1]=positive_int(input[inpdata+1]-input[inpdata-2]);
+ intradelta[2]=positive_int(input[inpdata+2]-input[inpdata-1]);
+ thislen=compute_intlen(intradelta);
+ if (thislen*TRESHOLD_INTRA_INTER_DIRECT<minlen)
+ {
+ minlen=thislen;
+ best_type=1; /* Intra delta */
+ }
+ }
+#endif
+#if 1
+ /* Then try inter coding if we can. */
+ if (frame>0)
+ {
+ double thislen;
+ interdelta[0]=positive_int(input[inpdata]-input[inpdata-natoms*3]);
+ interdelta[1]=positive_int(input[inpdata+1]-input[inpdata-natoms*3+1]);
+ interdelta[2]=positive_int(input[inpdata+2]-input[inpdata-natoms*3+2]);
+ thislen=compute_intlen(interdelta);
+ if (thislen*TRESHOLD_INTRA_INTER_DIRECT<minlen)
+ {
+ best_type=2; /* Inter delta */
+ }
+ }
+#endif
+ xtc3_context->has_large_type[xtc3_context->has_large]=best_type;
+ if (best_type==0)
+ {
+ xtc3_context->has_large_ints[xtc3_context->has_large*3]=direct[0];
+ xtc3_context->has_large_ints[xtc3_context->has_large*3+1]=direct[1];
+ xtc3_context->has_large_ints[xtc3_context->has_large*3+2]=direct[2];
+ }
+ else if (best_type==1)
+ {
+ xtc3_context->has_large_ints[xtc3_context->has_large*3]=intradelta[0];
+ xtc3_context->has_large_ints[xtc3_context->has_large*3+1]=intradelta[1];
+ xtc3_context->has_large_ints[xtc3_context->has_large*3+2]=intradelta[2];
+ }
+ else if (best_type==2)
+ {
+ xtc3_context->has_large_ints[xtc3_context->has_large*3]=interdelta[0];
+ xtc3_context->has_large_ints[xtc3_context->has_large*3+1]=interdelta[1];
+ xtc3_context->has_large_ints[xtc3_context->has_large*3+2]=interdelta[2];
+ }
+ xtc3_context->has_large++;
+}
+
+static void output_int(unsigned char *output,int *outdata, unsigned int n)
+{
+ output[(*outdata)++]=((unsigned int)n)&0xFFU;
+ output[(*outdata)++]=(((unsigned int)n)>>8)&0xFFU;
+ output[(*outdata)++]=(((unsigned int)n)>>16)&0xFFU;
+ output[(*outdata)++]=(((unsigned int)n)>>24)&0xFFU;
+}
+
+#if 0
+static void printarray(unsigned int *a, int n, char *name)
+{
+ int i;
+ for (i=0; i<n; i++)
+ fprintf(stderr,"%u %s\n",a[i],name);
+}
+#endif
+
+/* The base_compress routine first compresses all x coordinates, then
+ y and finally z. The bases used for each can be different. The
+ MAXBASEVALS value determines how many coordinates are compressed
+ into a single number. Only resulting whole bytes are dealt with for
+ simplicity. MAXMAXBASEVALS is the insanely large value to accept
+ files written with that value. BASEINTERVAL determines how often a
+ new base is actually computed and stored in the output
+ file. MAXBASEVALS*BASEINTERVAL values are stored using the same
+ base in BASEINTERVAL different integers. Note that the primarily
+ the decompression using a large MAXBASEVALS becomes very slow. */
+#define MAXMAXBASEVALS 16384U
+#define MAXBASEVALS 24U
+#define BASEINTERVAL 8
+
+/* How many bytes are needed to store n values in base base */
+static int base_bytes(unsigned int base, int n)
+{
+ int i,j;
+ unsigned int largeint[MAXMAXBASEVALS+1];
+ unsigned int largeint_tmp[MAXMAXBASEVALS+1];
+ int numbytes=0;
+ for (i=0; i<n+1; i++)
+ largeint[i]=0U;
+ for (i=0; i<n; i++)
+ {
+ if (i!=0)
+ {
+ Ptngc_largeint_mul(base,largeint,largeint_tmp,n+1);
+ for (j=0; j<n+1; j++)
+ largeint[j]=largeint_tmp[j];
+ }
+ Ptngc_largeint_add(base-1U,largeint,n+1);
+ }
+ for (i=0; i<n; i++)
+ if (largeint[i])
+ for (j=0; j<4; j++)
+ if ((largeint[i]>>(j*8))&0xFFU)
+ numbytes=i*4+j+1;
+ return numbytes;
+}
+
+static void base_compress(unsigned int *data, int len, unsigned char *output, int *outlen)
+{
+ unsigned int largeint[MAXBASEVALS+1];
+ unsigned int largeint_tmp[MAXBASEVALS+1];
+ int ixyz, i;
+ unsigned int j;
+ int nwrittenout=0;
+ unsigned int numbytes=0;
+ /* Store the MAXBASEVALS value in the output. */
+ output[nwrittenout++]=(unsigned char)(MAXBASEVALS&0xFFU);
+ output[nwrittenout++]=(unsigned char)((MAXBASEVALS>>8)&0xFFU);
+ /* Store the BASEINTERVAL value in the output. */
+ output[nwrittenout++]=(unsigned char)(BASEINTERVAL&0xFFU);
+ for (ixyz=0; ixyz<3; ixyz++)
+ {
+ unsigned int base=0U;
+ int nvals=0;
+ int basegiven=0;
+ for (j=0; j<MAXBASEVALS+1; j++)
+ largeint[j]=0U;
+ for (i=ixyz; i<len; i+=3)
+ {
+ if (nvals==0)
+ {
+ int basecheckvals=0;
+ int k;
+ if (basegiven==0)
+ {
+ base=0U;
+ /* Find the largest value for this particular coordinate. */
+ for (k=i; k<len; k+=3)
+ {
+ if (data[k]>base)
+ base=data[k];
+ basecheckvals++;
+ if (basecheckvals==MAXBASEVALS*BASEINTERVAL)
+ break;
+ }
+ /* The base is one larger than the largest values. */
+ base++;
+ if (base<2)
+ base=2;
+ /* Store the base in the output. */
+ output[nwrittenout++]=(unsigned char)(base&0xFFU);
+ output[nwrittenout++]=(unsigned char)((base>>8)&0xFFU);
+ output[nwrittenout++]=(unsigned char)((base>>16)&0xFFU);
+ output[nwrittenout++]=(unsigned char)((base>>24)&0xFFU);
+ basegiven=BASEINTERVAL;
+ /* How many bytes is needed to store MAXBASEVALS values using this base? */
+ numbytes=base_bytes(base,MAXBASEVALS);
+ }
+ basegiven--;
+#ifdef SHOWIT
+ fprintf(stderr,"Base for %d is %u. I need %d bytes for %d values.\n",ixyz,base,numbytes,MAXBASEVALS);
+#endif
+ }
+ if (nvals!=0)
+ {
+ Ptngc_largeint_mul(base,largeint,largeint_tmp,MAXBASEVALS+1);
+ for (j=0; j<MAXBASEVALS+1; j++)
+ largeint[j]=largeint_tmp[j];
+ }
+ Ptngc_largeint_add(data[i],largeint,MAXBASEVALS+1);
+#ifdef SHOWIT
+ fprintf(stderr,"outputting value %u\n",data[i]);
+#endif
+ nvals++;
+ if (nvals==MAXBASEVALS)
+ {
+#ifdef SHOWIT
+ fprintf(stderr,"Writing largeint: ");
+#endif
+ for (j=0; j<numbytes; j++)
+ {
+ int ilarge=j/4;
+ int ibyte=j%4;
+ output[nwrittenout++]=(unsigned char)((largeint[ilarge]>>(ibyte*8))&(0xFFU));
+#ifdef SHOWIT
+ fprintf(stderr,"%02x",(unsigned int)output[nwrittenout-1]);
+#endif
+ }
+#ifdef SHOWIT
+ fprintf(stderr,"\n");
+#endif
+ nvals=0;
+ for (j=0; j<MAXBASEVALS+1; j++)
+ largeint[j]=0U;
+ }
+ }
+ if (nvals)
+ {
+ numbytes=base_bytes(base,nvals);
+#ifdef SHOWIT
+ fprintf(stderr,"Base for %d is %u. I need %d bytes for %d values.\n",ixyz,base,numbytes,nvals);
+#endif
+ for (j=0; j<numbytes; j++)
+ {
+ int ilarge=j/4;
+ int ibyte=j%4;
+ output[nwrittenout++]=(unsigned char)((largeint[ilarge]>>(ibyte*8))&(0xFFU));
+ }
+ }
+ }
+ *outlen=nwrittenout;
+}
+
+static void base_decompress(unsigned char *input, int len, unsigned int *output)
+{
+ unsigned int largeint[MAXMAXBASEVALS+1];
+ unsigned int largeint_tmp[MAXMAXBASEVALS+1];
+ int ixyz, i, j;
+ int maxbasevals=(int)((unsigned int)(input[0])|(((unsigned int)(input[1]))<<8));
+ int baseinterval=(int)input[2];
+ if (maxbasevals>(int)MAXMAXBASEVALS)
+ {
+ fprintf(stderr,"Read a larger maxbasevals value from the file than I can handle. Fix"
+ " by increasing MAXMAXBASEVALS to at least %d. Although, this is"
+ " probably a bug in TRAJNG, since MAXMAXBASEVALS should already be insanely large enough.\n",maxbasevals);
+ exit(EXIT_FAILURE);
+ }
+ input+=3;
+ for (ixyz=0; ixyz<3; ixyz++)
+ {
+ int numbytes=0;
+ int nvals_left=len/3;
+ int outvals=ixyz;
+ int basegiven=0;
+ unsigned int base=0U;
+#ifdef SHOWIT
+ fprintf(stderr,"Base for %d is %u. I need %d bytes for %d values.\n",ixyz,base,numbytes,maxbasevals);
+#endif
+ while (nvals_left)
+ {
+ int n;
+ if (basegiven==0)
+ {
+ base=(unsigned int)(input[0])|
+ (((unsigned int)(input[1]))<<8)|
+ (((unsigned int)(input[2]))<<16)|
+ (((unsigned int)(input[3]))<<24);
+ input+=4;
+ basegiven=baseinterval;
+ /* How many bytes is needed to store maxbasevals values using this base? */
+ numbytes=base_bytes(base,maxbasevals);
+ }
+ basegiven--;
+ if (nvals_left<maxbasevals)
+ {
+ numbytes=base_bytes(base,nvals_left);
+#ifdef SHOWIT
+ fprintf(stderr,"Base for %d is %u. I need %d bytes for %d values.\n",ixyz,base,numbytes,nvals_left);
+#endif
+ }
+ for (j=0; j<maxbasevals+1; j++)
+ largeint[j]=0U;
+#ifdef SHOWIT
+ fprintf(stderr,"Reading largeint: ");
+#endif
+ if (numbytes/4 < maxbasevals+1)
+ {
+ for (j=0; j<numbytes; j++)
+ {
+ int ilarge=j/4;
+ int ibyte=j%4;
+ largeint[ilarge]|=((unsigned int)input[j])<<(ibyte*8);
+#ifdef SHOWIT
+ fprintf(stderr,"%02x",(unsigned int)input[j]);
+#endif
+ }
+ }
+#ifdef SHOWIT
+ fprintf(stderr,"\n");
+#endif
+ input+=numbytes;
+ /* Do the long division required to get the output values. */
+ n=maxbasevals;
+ if (n>nvals_left)
+ n=nvals_left;
+ for (i=n-1; i>=0; i--)
+ {
+ output[outvals+i*3]=Ptngc_largeint_div(base,largeint,largeint_tmp,maxbasevals+1);
+ for (j=0; j<maxbasevals+1; j++)
+ largeint[j]=largeint_tmp[j];
+ }
+#ifdef SHOWIT
+ for (i=0; i<n; i++)
+ fprintf(stderr,"outputting value %u\n",output[outvals+i*3]);
+#endif
+ outvals+=n*3;
+ nvals_left-=n;
+ }
+ }
+}
+
+/* If a large proportion of the integers are large (More than 10\% are >14 bits) we return 0, otherwise 1 */
+static int heuristic_bwlzh(unsigned int *ints, int nints)
+{
+ int i,num;
+ num=0;
+ for (i=0; i<nints; i++)
+ if (ints[i]>=16384)
+ num++;
+ if (num>nints/10)
+ return 0;
+ else
+ return 1;
+}
+
+/* Speed selects how careful to try to find the most efficient compression. The BWLZH algo is expensive!
+ Speed <=2 always avoids BWLZH everywhere it is possible.
+ Speed 3 and 4 and 5 use heuristics (check proportion of large value). This should mostly be safe.
+ Speed 5 enables the LZ77 component of BWLZH.
+ Speed 6 always tests if BWLZH is better and if it is uses it. This can be very slow.
+ */
+unsigned char *Ptngc_pack_array_xtc3(int *input, int *length, int natoms, int speed)
+{
+ unsigned char *output=NULL;
+ int i,ienc,j;
+ int outdata=0;
+ /* Pack triplets. */
+ int ntriplets=*length/3;
+ int intmax;
+ int max_small;
+ int small_index;
+ int max_large_index;
+ int large_index[3];
+ int prevcoord[3];
+ int runlength=0; /* Initial runlength. "Stupidly" set to zero for
+ simplicity and explicity */
+ int swapatoms=0; /* Initial guess is that we should not swap the
+ first two atoms in each large+small
+ transition */
+ int didswap; /* Whether swapping was actually done. */
+ int inpdata=0;
+ int encode_ints[3+MAX_SMALL_RLE*3]; /* Up to 3 large + 24 small ints can be encoded at once */
+ int nencode;
+ int ntriplets_left=ntriplets;
+ int refused=0;
+ unsigned char *bwlzh_buf=NULL;
+ int bwlzh_buf_len;
+ unsigned char *base_buf=NULL;
+ int base_buf_len;
+
+ struct xtc3_context xtc3_context;
+ init_xtc3_context(&xtc3_context);
+
+ xtc3_context.maxint[0]=xtc3_context.minint[0]=input[0];
+ xtc3_context.maxint[1]=xtc3_context.minint[1]=input[1];
+ xtc3_context.maxint[2]=xtc3_context.minint[2]=input[2];
+
+ /* Values of speed should be sane. */
+ if (speed<1)
+ speed=1;
+ if (speed>6)
+ speed=6;
+
+#ifdef SHOWIT
+ nbits_sum=0;
+ nvalues_sum=0;
+#endif
+ /* Allocate enough memory for output */
+ if (*length < 48)
+ output=warnmalloc(8*48*sizeof *output);
+ else
+ output=warnmalloc(8* *length*sizeof *output);
+
+
+ for (i=1; i<ntriplets; i++)
+ for (j=0; j<3; j++)
+ {
+ if (input[i*3+j]>xtc3_context.maxint[j])
+ xtc3_context.maxint[j]=input[i*3+j];
+ if (input[i*3+j]<xtc3_context.minint[j])
+ xtc3_context.minint[j]=input[i*3+j];
+ }
+
+ large_index[0]=Ptngc_find_magic_index(xtc3_context.maxint[0]-xtc3_context.minint[0]+1);
+ large_index[1]=Ptngc_find_magic_index(xtc3_context.maxint[1]-xtc3_context.minint[1]+1);
+ large_index[2]=Ptngc_find_magic_index(xtc3_context.maxint[2]-xtc3_context.minint[2]+1);
+ max_large_index=large_index[0];
+ if (large_index[1]>max_large_index)
+ max_large_index=large_index[1];
+ if (large_index[2]>max_large_index)
+ max_large_index=large_index[2];
+
+#ifdef SHOWIT
+ for (j=0; j<3; j++)
+ fprintf(stderr,"minint[%d]=%d. maxint[%d]=%d large_index[%d]=%d value=%d\n",j,xtc3_context.minint[j],j,xtc3_context.maxint[j],
+ j,large_index[j],Ptngc_magic(large_index[j]));
+#endif
+
+ /* Guess initial small index */
+ small_index=max_large_index/2;
+
+ /* Find the largest value that is not large. Not large is half index of
+ large. */
+ max_small=Ptngc_magic(small_index);
+ intmax=0;
+ for (i=0; i<*length; i++)
+ {
+ int item=input[i];
+ int s=positive_int(item);
+ if (s>intmax)
+ if (s<max_small)
+ intmax=s;
+ }
+ /* This value is not critical, since if I guess wrong, the code will
+ just insert instructions to increase this value. */
+ small_index=Ptngc_find_magic_index(intmax);
+#ifdef SHOWIT
+ fprintf(stderr,"initial small_index=%d value=%d\n",small_index,Ptngc_magic(small_index));
+#endif
+
+ output_int(output,&outdata,positive_int(xtc3_context.minint[0]));
+ output_int(output,&outdata,positive_int(xtc3_context.minint[1]));
+ output_int(output,&outdata,positive_int(xtc3_context.minint[2]));
+
+#if 0
+#ifdef SHOWIT
+ for (i=0; i<ntriplets_left; i++)
+ fprintf(stderr,"VALUE:%d %6d %6d %6d\n",
+ i,
+ input[inpdata+i*3],
+ input[inpdata+i*3+1],
+ input[inpdata+i*3+2]);
+#endif
+#endif
+
+ /* Initial prevcoord is the minimum integers. */
+ prevcoord[0]=xtc3_context.minint[0];
+ prevcoord[1]=xtc3_context.minint[1];
+ prevcoord[2]=xtc3_context.minint[2];
+
+ while (ntriplets_left)
+ {
+ if (ntriplets_left<0)
+ {
+ fprintf(stderr,"TRAJNG: BUG! ntriplets_left<0!\n");
+ exit(EXIT_FAILURE);
+ }
+ /* If only less than three atoms left we just write them all as large integers. Here no swapping is done! */
+ if (ntriplets_left<3)
+ {
+ for (ienc=0; ienc<ntriplets_left; ienc++)
+ {
+ buffer_large(&xtc3_context,input,inpdata,natoms,1);
+ inpdata+=3;
+ ntriplets_left--;
+ }
+ flush_large(&xtc3_context,xtc3_context.has_large); /* Flush all */
+ }
+ else
+ {
+ int min_runlength=0;
+ int largest_required_base;
+ int largest_runlength_base;
+ int largest_required_index;
+ int largest_runlength_index;
+ int new_runlength;
+ int new_small_index;
+ int iter_runlength;
+ int iter_small_index;
+ int rle_index_dep;
+ didswap=0;
+ /* Insert the next batch of integers to be encoded into the buffer */
+#ifdef SHOWIT
+ fprintf(stderr,"Initial batch\n");
+#endif
+ insert_batch(input+inpdata,ntriplets_left,prevcoord,encode_ints,0,&nencode);
+
+ /* First we must decide if the next value is large (does not reasonably fit in current small encoding)
+ Also, if we have not written any values yet, we must begin by writing a large atom. */
+ if ((inpdata==0) || (is_quite_large(encode_ints,small_index,max_large_index)) || (refused))
+ {
+ /* If any of the next two atoms are large we should probably write them as large and not swap them */
+ int no_swap=0;
+ if ((is_quite_large(encode_ints+3,small_index,max_large_index)) || (is_quite_large(encode_ints+6,small_index,max_large_index)))
+ no_swap=1;
+#if 1
+ if (!no_swap)
+ {
+ /* If doing inter-frame coding results in smaller values we should not do any swapping either. */
+ int frame=inpdata/(natoms*3);
+ if (frame>0)
+ {
+ unsigned int delta[3], delta2[3];
+ delta[0]=positive_int(input[inpdata+3]-input[inpdata-natoms*3+3]);
+ delta[1]=positive_int(input[inpdata+4]-input[inpdata-natoms*3+4]);
+ delta[2]=positive_int(input[inpdata+5]-input[inpdata-natoms*3+5]);
+ delta2[0]=positive_int(encode_ints[3]);
+ delta2[1]=positive_int(encode_ints[4]);
+ delta2[2]=positive_int(encode_ints[5]);
+#ifdef SHOWIT
+ fprintf(stderr,"A1: inter delta: %u %u %u. intra delta=%u %u %u\n",
+ delta[0],delta[1],delta[2],
+ delta2[0],delta2[1],delta2[2]);
+#endif
+ if (compute_intlen(delta)*TRESHOLD_INTER_INTRA<compute_intlen(delta2))
+ {
+ delta[0]=positive_int(input[inpdata+6]-input[inpdata-natoms*3+6]);
+ delta[1]=positive_int(input[inpdata+7]-input[inpdata-natoms*3+7]);
+ delta[2]=positive_int(input[inpdata+8]-input[inpdata-natoms*3+8]);
+ delta2[0]=positive_int(encode_ints[6]);
+ delta2[1]=positive_int(encode_ints[7]);
+ delta2[2]=positive_int(encode_ints[8]);
+#ifdef SHOWIT
+ fprintf(stderr,"A2: inter delta: %u %u %u. intra delta=%u %u %u\n",
+ delta[0],delta[1],delta[2],
+ delta2[0],delta2[1],delta2[2]);
+#endif
+ if (compute_intlen(delta)*TRESHOLD_INTER_INTRA<compute_intlen(delta2))
+ {
+ no_swap=1;
+#ifdef SHOWIT
+ fprintf(stderr,"SETTING NO SWAP!\n");
+#endif
+ }
+ }
+ }
+ }
+#endif
+ if (!no_swap)
+ {
+ /* Next we must decide if we should swap the first
+ two values. */
+#if 1
+ swapdecide(&xtc3_context,input+inpdata,&swapatoms,large_index,xtc3_context.minint);
+#else
+ swapatoms=0;
+#endif
+ /* If we should do the integer swapping manipulation we should do it now */
+ if (swapatoms)
+ {
+ didswap=1;
+ for (i=0; i<3; i++)
+ {
+ int in[3], out[3];
+ in[0]=input[inpdata+i];
+ in[1]=input[inpdata+3+i]-input[inpdata+i];
+ in[2]=input[inpdata+6+i]-input[inpdata+3+i];
+ swap_ints(in,out);
+ encode_ints[i]=out[0];
+ encode_ints[3+i]=out[1];
+ encode_ints[6+i]=out[2];
+ }
+ /* We have swapped atoms, so the minimum run-length is 2 */
+#ifdef SHOWIT
+ fprintf(stderr,"Swap atoms results in:\n");
+ for (i=0; i<3; i++)
+ fprintf(stderr,"%d: %6d %6d %6d\t\t%6d %6d %6d\n",i*3,
+ encode_ints[i*3],
+ encode_ints[i*3+1],
+ encode_ints[i*3+2],
+ positive_int(encode_ints[i*3]),
+ positive_int(encode_ints[i*3+1]),
+ positive_int(encode_ints[i*3+2]));
+
+#endif
+ min_runlength=2;
+ }
+ }
+ /* Cache large value for later possible combination with
+ a sequence of small integers. */
+ if ((swapatoms) && (didswap))
+ {
+ buffer_large(&xtc3_context,input,inpdata+3,natoms,0); /* This is a swapped integer, so inpdata is one atom later and
+ intra coding is not ok. */
+ for (ienc=0; ienc<3; ienc++)
+ prevcoord[ienc]=input[inpdata+3+ienc];
+ }
+ else
+ {
+ buffer_large(&xtc3_context,input,inpdata,natoms,1);
+ for (ienc=0; ienc<3; ienc++)
+ prevcoord[ienc]=input[inpdata+ienc];
+ }
+
+
+#ifdef SHOWIT
+ fprintf(stderr,"Prevcoord after packing of large: %d %d %d\n",
+ prevcoord[0],prevcoord[1],prevcoord[2]);
+#endif
+
+ /* We have written a large integer so we have one less atoms to worry about */
+ inpdata+=3;
+ ntriplets_left--;
+
+ refused=0;
+
+ /* Insert the next batch of integers to be encoded into the buffer */
+#ifdef SHOWIT
+ fprintf(stderr,"Update batch due to large int.\n");
+#endif
+ if ((swapatoms) && (didswap))
+ {
+ /* Keep swapped values. */
+ for (i=0; i<2; i++)
+ for (ienc=0; ienc<3; ienc++)
+ encode_ints[i*3+ienc]=encode_ints[(i+1)*3+ienc];
+ }
+ insert_batch(input+inpdata,ntriplets_left,prevcoord,encode_ints,min_runlength,&nencode);
+ }
+ /* Here we should only have differences for the atom coordinates. */
+ /* Convert the ints to positive ints */
+ for (ienc=0; ienc<nencode; ienc++)
+ {
+ int pint=positive_int(encode_ints[ienc]);
+ encode_ints[ienc]=pint;
+ }
+ /* Now we must decide what base and runlength to do. If we have swapped atoms it will be at least 2.
+ If even the next atom is large, we will not do anything. */
+ largest_required_base=0;
+ /* Determine required base */
+ for (ienc=0; ienc<min_runlength*3; ienc++)
+ if (encode_ints[ienc]>largest_required_base)
+ largest_required_base=encode_ints[ienc];
+ /* Also compute what the largest base is for the current runlength setting! */
+ largest_runlength_base=0;
+ for (ienc=0; (ienc<runlength*3) && (ienc<nencode); ienc++)
+ if (encode_ints[ienc]>largest_runlength_base)
+ largest_runlength_base=encode_ints[ienc];
+
+ largest_required_index=Ptngc_find_magic_index(largest_required_base);
+ largest_runlength_index=Ptngc_find_magic_index(largest_runlength_base);
+
+ if (largest_required_index<largest_runlength_index)
+ {
+ new_runlength=min_runlength;
+ new_small_index=largest_required_index;
+ }
+ else
+ {
+ new_runlength=runlength;
+ new_small_index=largest_runlength_index;
+ }
+
+ /* Only allow increase of runlength wrt min_runlength */
+ if (new_runlength<min_runlength)
+ new_runlength=min_runlength;
+
+ /* If the current runlength is longer than the number of
+ triplets left stop it from being so. */
+ if (new_runlength>ntriplets_left)
+ new_runlength=ntriplets_left;
+
+ /* We must at least try to get some small integers going. */
+ if (new_runlength==0)
+ {
+ new_runlength=1;
+ new_small_index=small_index;
+ }
+
+ iter_runlength=new_runlength;
+ iter_small_index=new_small_index;
+
+ /* Iterate to find optimal encoding and runlength */
+#ifdef SHOWIT
+ fprintf(stderr,"Entering iterative loop.\n");
+ fflush(stderr);
+#endif
+
+ do {
+ new_runlength=iter_runlength;
+ new_small_index=iter_small_index;
+
+#ifdef SHOWIT
+ fprintf(stderr,"Test new_small_index=%d Base=%d\n",new_small_index,Ptngc_magic(new_small_index));
+#endif
+ /* What is the largest runlength
+ we can do with the currently
+ selected encoding? Also the max supported runlength is MAX_SMALL_RLE triplets! */
+ for (ienc=0; ienc<nencode && ienc<MAX_SMALL_RLE*3; ienc++)
+ {
+ int test_index=Ptngc_find_magic_index(encode_ints[ienc]);
+ if (test_index>new_small_index)
+ break;
+ }
+ if (ienc/3>new_runlength)
+ {
+ iter_runlength=ienc/3;
+#ifdef SHOWIT
+ fprintf(stderr,"I found a new possible runlength: %d\n",iter_runlength);
+#endif
+ }
+
+ /* How large encoding do we have to use? */
+ largest_runlength_base=0;
+ for (ienc=0; ienc<iter_runlength*3; ienc++)
+ if (encode_ints[ienc]>largest_runlength_base)
+ largest_runlength_base=encode_ints[ienc];
+ largest_runlength_index=Ptngc_find_magic_index(largest_runlength_base);
+ if (largest_runlength_index!=new_small_index)
+ {
+ iter_small_index=largest_runlength_index;
+#ifdef SHOWIT
+ fprintf(stderr,"I found a new possible small index: %d Base=%d\n",iter_small_index,Ptngc_magic(iter_small_index));
+#endif
+ }
+ } while ((new_runlength!=iter_runlength) ||
+ (new_small_index!=iter_small_index));
+
+#ifdef SHOWIT
+ fprintf(stderr,"Exit iterative loop.\n");
+ fflush(stderr);
+#endif
+
+ /* Verify that we got something good. We may have caught a
+ substantially larger atom. If so we should just bail
+ out and let the loop get on another lap. We may have a
+ minimum runlength though and then we have to fulfill
+ the request to write out these atoms! */
+ rle_index_dep=0;
+ if (new_runlength<3)
+ rle_index_dep=IS_LARGE;
+ else if (new_runlength<6)
+ rle_index_dep=QUITE_LARGE;
+ if ((min_runlength)
+ || ((new_small_index<small_index+IS_LARGE) && (new_small_index+rle_index_dep<max_large_index))
+#if 1
+ || (new_small_index+IS_LARGE<max_large_index)
+#endif
+)
+ {
+ /* If doing inter-frame coding of large integers results
+ in smaller values than the small value we should not
+ produce a sequence of small values here. */
+ int frame=inpdata/(natoms*3);
+ int numsmaller=0;
+#if 1
+ if ((!swapatoms) && (frame>0))
+ {
+ for (i=0; i<new_runlength; i++)
+ {
+ unsigned int delta[3];
+ unsigned int delta2[3];
+ delta[0]=positive_int(input[inpdata+i*3]-input[inpdata-natoms*3+i*3]);
+ delta[1]=positive_int(input[inpdata+i*3+1]-input[inpdata-natoms*3+i*3+1]);
+ delta[2]=positive_int(input[inpdata+i*3+2]-input[inpdata-natoms*3+i*3+2]);
+ delta2[0]=positive_int(encode_ints[i*3]);
+ delta2[1]=positive_int(encode_ints[i*3+1]);
+ delta2[2]=positive_int(encode_ints[i*3+2]);
+ if (compute_intlen(delta)*TRESHOLD_INTER_INTRA<compute_intlen(delta2))
+ numsmaller++;
+ }
+ }
+#endif
+ /* Most of the values should become smaller, otherwise
+ we should encode them with intra coding. */
+ if ((!swapatoms) && (numsmaller>=2*new_runlength/3))
+ {
+ /* Put all the values in large arrays, instead of the small array */
+ if (new_runlength)
+ {
+ for (i=0; i<new_runlength; i++)
+ buffer_large(&xtc3_context,input,inpdata+i*3,natoms,1);
+ for (i=0; i<3; i++)
+ prevcoord[i]=input[inpdata+(new_runlength-1)*3+i];
+ inpdata+=3*new_runlength;
+ ntriplets_left-=new_runlength;
+ }
+ }
+ else
+ {
+ if ((new_runlength!=runlength) || (new_small_index!=small_index))
+ {
+ int change=new_small_index-small_index;
+
+ if (new_small_index<=0)
+ change=0;
+
+ if (change<0)
+ {
+ int ixx;
+ for (ixx=0; ixx<new_runlength; ixx++)
+ {
+ int rejected;
+ do {
+ int ixyz;
+ double isum=0.; /* ints can be almost 32 bit so multiplication will overflow. So do doubles. */
+ for (ixyz=0; ixyz<3; ixyz++)
+ {
+ /* encode_ints is already positive (and multiplied by 2 versus the original, just as magic ints) */
+ double id=encode_ints[ixx*3+ixyz];
+ isum+=id*id;
+ }
+ rejected=0;
+#ifdef SHOWIT
+ fprintf(stderr,"Tested decrease %d of index: %g>=%g?\n",change,isum,(double)Ptngc_magic(small_index+change)*(double)Ptngc_magic(small_index+change));
+#endif
+ if (isum>(double)Ptngc_magic(small_index+change)*(double)Ptngc_magic(small_index+change))
+ {
+#ifdef SHOWIT
+ fprintf(stderr,"Rejected decrease %d of index due to length of vector: %g>=%g\n",change,isum,(double)Ptngc_magic(small_index+change)*(double)Ptngc_magic(small_index+change));
+#endif
+ rejected=1;
+ change++;
+ }
+ } while ((change<0) && (rejected));
+ if (change==0)
+ break;
+ }
+ }
+
+ /* Always accept the new small indices here. */
+ small_index=new_small_index;
+ /* If we have a new runlength emit it */
+ if (runlength!=new_runlength)
+ {
+ runlength=new_runlength;
+ insert_value_in_array(&xtc3_context.instructions,
+ &xtc3_context.ninstr,
+ &xtc3_context.ninstr_alloc,
+ INSTR_SMALL_RUNLENGTH,"instr");
+ insert_value_in_array(&xtc3_context.rle,
+ &xtc3_context.nrle,
+ &xtc3_context.nrle_alloc,
+ (unsigned int)runlength,"rle (small)");
+ }
+#ifdef SHOWIT
+ fprintf(stderr,"Current small index: %d Base=%d\n",small_index,Ptngc_magic(small_index));
+#endif
+ }
+ /* If we have a large previous integer we can combine it with a sequence of small ints. */
+ if (xtc3_context.has_large)
+ {
+ /* If swapatoms is set to 1 but we did actually not
+ do any swapping, we must first write out the
+ large atom and then the small. If swapatoms is 1
+ and we did swapping we can use the efficient
+ encoding. */
+ if ((swapatoms) && (!didswap))
+ {
+#ifdef SHOWIT
+ fprintf(stderr,"Swapatoms was set to 1 but we did not do swapping!\n");
+ fprintf(stderr,"Only one large integer.\n");
+#endif
+ /* Flush all large atoms. */
+ flush_large(&xtc3_context,xtc3_context.has_large);
+#ifdef SHOWIT
+ fprintf(stderr,"Sequence of only small integers.\n");
+#endif
+ insert_value_in_array(&xtc3_context.instructions,
+ &xtc3_context.ninstr,
+ &xtc3_context.ninstr_alloc,
+ INSTR_ONLY_SMALL,"instr");
+ }
+ else
+ {
+
+#ifdef SHOWIT
+ fprintf(stderr,"Sequence of one large and small integers (good compression).\n");
+#endif
+ /* Flush all large atoms but one! */
+ if (xtc3_context.has_large>1)
+ flush_large(&xtc3_context,xtc3_context.has_large-1);
+
+ /* Here we must check if we should emit a large
+ type change instruction. */
+ large_instruction_change(&xtc3_context,0);
+
+ insert_value_in_array(&xtc3_context.instructions,
+ &xtc3_context.ninstr,
+ &xtc3_context.ninstr_alloc,
+ INSTR_DEFAULT,"instr");
+
+ write_three_large(&xtc3_context,0);
+ xtc3_context.has_large=0;
+ }
+ }
+ else
+ {
+#ifdef SHOWIT
+ fprintf(stderr,"Sequence of only small integers.\n");
+#endif
+ insert_value_in_array(&xtc3_context.instructions,
+ &xtc3_context.ninstr,
+ &xtc3_context.ninstr_alloc,
+ INSTR_ONLY_SMALL,"instr");
+ }
+ /* Insert the small integers into the small integer array. */
+ for (ienc=0; ienc<runlength*3; ienc++)
+ insert_value_in_array(&xtc3_context.smallintra,
+ &xtc3_context.nsmallintra,
+ &xtc3_context.nsmallintra_alloc,
+ (unsigned int)encode_ints[ienc],"smallintra");
+
+#ifdef SHOWIT
+ for (ienc=0; ienc<runlength; ienc++)
+ fprintf(stderr,"Small: %d %d %d\n",
+ encode_ints[ienc*3],
+ encode_ints[ienc*3+1],
+ encode_ints[ienc*3+2]);
+#endif
+ /* Update prevcoord. */
+ for (ienc=0; ienc<runlength; ienc++)
+ {
+#ifdef SHOWIT
+ fprintf(stderr,"Prevcoord in packing: %d %d %d\n",
+ prevcoord[0],prevcoord[1],prevcoord[2]);
+#endif
+ prevcoord[0]+=unpositive_int(encode_ints[ienc*3]);
+ prevcoord[1]+=unpositive_int(encode_ints[ienc*3+1]);
+ prevcoord[2]+=unpositive_int(encode_ints[ienc*3+2]);
+ }
+#ifdef SHOWIT
+ fprintf(stderr,"Prevcoord in packing: %d %d %d\n",
+ prevcoord[0],prevcoord[1],prevcoord[2]);
+#endif
+
+ inpdata+=3*runlength;
+ ntriplets_left-=runlength;
+#if 1
+ }
+#endif
+ }
+ else
+ {
+#ifdef SHOWIT
+ fprintf(stderr,"Refused value: %d old is %d max is %d\n",new_small_index,small_index,max_large_index);
+ fflush(stderr);
+#endif
+ refused=1;
+ }
+ }
+#ifdef SHOWIT
+ fprintf(stderr,"Number of triplets left is %d\n",ntriplets_left);
+#endif
+ }
+
+ /* If we have large previous integers we must flush them now. */
+ if (xtc3_context.has_large)
+ flush_large(&xtc3_context,xtc3_context.has_large);
+
+ /* Now it is time to compress all the data in the buffers with the bwlzh or base algo. */
+
+#if 0
+ /* Inspect the data. */
+ printarray(xtc3_context.instructions,xtc3_context.ninstr,"A instr");
+ printarray(xtc3_context.rle,xtc3_context.nrle,"A rle");
+ printarray(xtc3_context.large_direct,xtc3_context.nlargedir,"A largedir");
+ printarray(xtc3_context.large_intra_delta,xtc3_context.nlargeintra,"A largeintra");
+ printarray(xtc3_context.large_inter_delta,xtc3_context.nlargeinter,"A largeinter");
+ printarray(xtc3_context.smallintra,xtc3_context.nsmallintra,"A smallintra");
+ exit(0);
+#endif
+
+#if defined(SHOWIT) || defined(SHOWIT_LIGHT)
+ fprintf(stderr,"instructions: %d\n",xtc3_context.ninstr);
+#endif
+
+#if defined(SHOWIT) || defined(SHOWIT_LIGHT)
+#define bwlzh_compress bwlzh_compress_verbose
+#define bwlzh_compress_no_lz77 bwlzh_compress_no_lz77_verbose
+#endif
+
+ output_int(output,&outdata,(unsigned int)xtc3_context.ninstr);
+ if (xtc3_context.ninstr)
+ {
+ bwlzh_buf=warnmalloc(bwlzh_get_buflen(xtc3_context.ninstr));
+ if (speed>=5)
+ bwlzh_compress(xtc3_context.instructions,xtc3_context.ninstr,bwlzh_buf,&bwlzh_buf_len);
+ else
+ bwlzh_compress_no_lz77(xtc3_context.instructions,xtc3_context.ninstr,bwlzh_buf,&bwlzh_buf_len);
+ output_int(output,&outdata,(unsigned int)bwlzh_buf_len);
+ memcpy(output+outdata,bwlzh_buf,bwlzh_buf_len);
+ outdata+=bwlzh_buf_len;
+ free(bwlzh_buf);
+ }
+
+#if defined(SHOWIT) || defined(SHOWIT_LIGHT)
+ fprintf(stderr,"rle: %d\n",xtc3_context.nrle);
+#endif
+
+ output_int(output,&outdata,(unsigned int)xtc3_context.nrle);
+ if (xtc3_context.nrle)
+ {
+ bwlzh_buf=warnmalloc(bwlzh_get_buflen(xtc3_context.nrle));
+ if (speed>=5)
+ bwlzh_compress(xtc3_context.rle,xtc3_context.nrle,bwlzh_buf,&bwlzh_buf_len);
+ else
+ bwlzh_compress_no_lz77(xtc3_context.rle,xtc3_context.nrle,bwlzh_buf,&bwlzh_buf_len);
+ output_int(output,&outdata,(unsigned int)bwlzh_buf_len);
+ memcpy(output+outdata,bwlzh_buf,bwlzh_buf_len);
+ outdata+=bwlzh_buf_len;
+ free(bwlzh_buf);
+ }
+
+#if defined(SHOWIT) || defined(SHOWIT_LIGHT)
+ fprintf(stderr,"large direct: %d\n",xtc3_context.nlargedir);
+#endif
+
+ output_int(output,&outdata,(unsigned int)xtc3_context.nlargedir);
+ if (xtc3_context.nlargedir)
+ {
+ if ((speed<=2) || ((speed<=5) && (!heuristic_bwlzh(xtc3_context.large_direct,xtc3_context.nlargedir))))
+ {
+ bwlzh_buf=NULL;
+ bwlzh_buf_len=INT_MAX;
+ }
+ else
+ {
+ bwlzh_buf=warnmalloc(bwlzh_get_buflen(xtc3_context.nlargedir));
+ if (speed>=5)
+ bwlzh_compress(xtc3_context.large_direct,xtc3_context.nlargedir,bwlzh_buf,&bwlzh_buf_len);
+ else
+ bwlzh_compress_no_lz77(xtc3_context.large_direct,xtc3_context.nlargedir,bwlzh_buf,&bwlzh_buf_len);
+ }
+ /* If this can be written smaller using base compression we should do that. */
+ base_buf=warnmalloc((xtc3_context.nlargedir+3)*sizeof(int));
+ base_compress(xtc3_context.large_direct,xtc3_context.nlargedir,base_buf,&base_buf_len);
+#if defined(SHOWIT) || defined(SHOWIT_LIGHT)
+ fprintf(stderr,"Large direct: Base len=%d. BWLZH len=%d\n",base_buf_len,bwlzh_buf_len);
+#endif
+ if (base_buf_len<bwlzh_buf_len)
+ {
+ output[outdata++]=0U;
+ output_int(output,&outdata,(unsigned int)base_buf_len);
+ memcpy(output+outdata,base_buf,base_buf_len);
+ outdata+=base_buf_len;
+ }
+ else
+ {
+ output[outdata++]=1U;
+ output_int(output,&outdata,(unsigned int)bwlzh_buf_len);
+ memcpy(output+outdata,bwlzh_buf,bwlzh_buf_len);
+ outdata+=bwlzh_buf_len;
+ }
+ free(bwlzh_buf);
+ free(base_buf);
+ }
+
+#if defined(SHOWIT) || defined(SHOWIT_LIGHT)
+ fprintf(stderr,"large intra: %d\n",xtc3_context.nlargeintra);
+#endif
+
+ output_int(output,&outdata,(unsigned int)xtc3_context.nlargeintra);
+ if (xtc3_context.nlargeintra)
+ {
+ if ((speed<=2) || ((speed<=5) && (!heuristic_bwlzh(xtc3_context.large_intra_delta,xtc3_context.nlargeintra))))
+ {
+ bwlzh_buf=NULL;
+ bwlzh_buf_len=INT_MAX;
+ }
+ else
+ {
+ bwlzh_buf=warnmalloc(bwlzh_get_buflen(xtc3_context.nlargeintra));
+ if (speed>=5)
+ bwlzh_compress(xtc3_context.large_intra_delta,xtc3_context.nlargeintra,bwlzh_buf,&bwlzh_buf_len);
+ else
+ bwlzh_compress_no_lz77(xtc3_context.large_intra_delta,xtc3_context.nlargeintra,bwlzh_buf,&bwlzh_buf_len);
+ }
+ /* If this can be written smaller using base compression we should do that. */
+ base_buf=warnmalloc((xtc3_context.nlargeintra+3)*sizeof(int));
+ base_compress(xtc3_context.large_intra_delta,xtc3_context.nlargeintra,base_buf,&base_buf_len);
+#if defined(SHOWIT) || defined(SHOWIT_LIGHT)
+ fprintf(stderr,"Large intra: Base len=%d. BWLZH len=%d\n",base_buf_len,bwlzh_buf_len);
+#endif
+ if (base_buf_len<bwlzh_buf_len)
+ {
+ output[outdata++]=0U;
+ output_int(output,&outdata,(unsigned int)base_buf_len);
+ memcpy(output+outdata,base_buf,base_buf_len);
+ outdata+=base_buf_len;
+ }
+ else
+ {
+ output[outdata++]=1U;
+ output_int(output,&outdata,(unsigned int)bwlzh_buf_len);
+ memcpy(output+outdata,bwlzh_buf,bwlzh_buf_len);
+ outdata+=bwlzh_buf_len;
+ }
+ free(bwlzh_buf);
+ free(base_buf);
+ }
+
+#if defined(SHOWIT) || defined(SHOWIT_LIGHT)
+ fprintf(stderr,"large inter: %d\n",xtc3_context.nlargeinter);
+#endif
+
+ output_int(output,&outdata,(unsigned int)xtc3_context.nlargeinter);
+ if (xtc3_context.nlargeinter)
+ {
+ if ((speed<=2) || ((speed<=5) && (!heuristic_bwlzh(xtc3_context.large_inter_delta,xtc3_context.nlargeinter))))
+ {
+ bwlzh_buf=NULL;
+ bwlzh_buf_len=INT_MAX;
+ }
+ else
+ {
+ bwlzh_buf=warnmalloc(bwlzh_get_buflen(xtc3_context.nlargeinter));
+ if (speed>=5)
+ bwlzh_compress(xtc3_context.large_inter_delta,xtc3_context.nlargeinter,bwlzh_buf,&bwlzh_buf_len);
+ else
+ bwlzh_compress_no_lz77(xtc3_context.large_inter_delta,xtc3_context.nlargeinter,bwlzh_buf,&bwlzh_buf_len);
+ }
+ /* If this can be written smaller using base compression we should do that. */
+ base_buf=warnmalloc((xtc3_context.nlargeinter+3)*sizeof(int));
+ base_compress(xtc3_context.large_inter_delta,xtc3_context.nlargeinter,base_buf,&base_buf_len);
+#if defined(SHOWIT) || defined(SHOWIT_LIGHT)
+ fprintf(stderr,"Large inter: Base len=%d. BWLZH len=%d\n",base_buf_len,bwlzh_buf_len);
+#endif
+ if (base_buf_len<bwlzh_buf_len)
+ {
+ output[outdata++]=0U;
+ output_int(output,&outdata,(unsigned int)base_buf_len);
+ memcpy(output+outdata,base_buf,base_buf_len);
+ outdata+=base_buf_len;
+ }
+ else
+ {
+ output[outdata++]=1U;
+ output_int(output,&outdata,(unsigned int)bwlzh_buf_len);
+ memcpy(output+outdata,bwlzh_buf,bwlzh_buf_len);
+ outdata+=bwlzh_buf_len;
+ }
+ free(bwlzh_buf);
+ free(base_buf);
+ }
+
+#if defined(SHOWIT) || defined(SHOWIT_LIGHT)
+ fprintf(stderr,"small intra: %d\n",xtc3_context.nsmallintra);
+#endif
+
+ output_int(output,&outdata,(unsigned int)xtc3_context.nsmallintra);
+ if (xtc3_context.nsmallintra)
+ {
+ if ((speed<=2) || ((speed<=5) && (!heuristic_bwlzh(xtc3_context.smallintra,xtc3_context.nsmallintra))))
+ {
+ bwlzh_buf=NULL;
+ bwlzh_buf_len=INT_MAX;
+ }
+ else
+ {
+ bwlzh_buf=warnmalloc(bwlzh_get_buflen(xtc3_context.nsmallintra));
+ if (speed>=5)
+ bwlzh_compress(xtc3_context.smallintra,xtc3_context.nsmallintra,bwlzh_buf,&bwlzh_buf_len);
+ else
+ bwlzh_compress_no_lz77(xtc3_context.smallintra,xtc3_context.nsmallintra,bwlzh_buf,&bwlzh_buf_len);
+ }
+ /* If this can be written smaller using base compression we should do that. */
+ base_buf=warnmalloc((xtc3_context.nsmallintra+3)*sizeof(int));
+ base_compress(xtc3_context.smallintra,xtc3_context.nsmallintra,base_buf,&base_buf_len);
+#if defined(SHOWIT) || defined(SHOWIT_LIGHT)
+ fprintf(stderr,"Small intra: Base len=%d. BWLZH len=%d\n",base_buf_len,bwlzh_buf_len);
+#endif
+ if (base_buf_len<bwlzh_buf_len)
+ {
+ output[outdata++]=0U;
+ output_int(output,&outdata,(unsigned int)base_buf_len);
+ memcpy(output+outdata,base_buf,base_buf_len);
+ outdata+=base_buf_len;
+ }
+ else
+ {
+ output[outdata++]=1U;
+ output_int(output,&outdata,(unsigned int)bwlzh_buf_len);
+ memcpy(output+outdata,bwlzh_buf,bwlzh_buf_len);
+ outdata+=bwlzh_buf_len;
+ }
+ free(bwlzh_buf);
+ free(base_buf);
+ }
+ *length=outdata;
+
+ free_xtc3_context(&xtc3_context);
+ return output;
+}
+
+static void decompress_bwlzh_block(unsigned char **ptr,
+ int nvals,
+ unsigned int **vals)
+{
+ int bwlzh_buf_len=(int)(((unsigned int)(*ptr)[0]) |
+ (((unsigned int)(*ptr)[1])<<8) |
+ (((unsigned int)(*ptr)[2])<<16) |
+ (((unsigned int)(*ptr)[3])<<24));
+ (*ptr)+=4;
+ *vals=warnmalloc(nvals*sizeof (**vals));
+ bwlzh_decompress(*ptr,nvals,*vals);
+ (*ptr)+=bwlzh_buf_len;
+}
+
+static void decompress_base_block(unsigned char **ptr,
+ int nvals,
+ unsigned int **vals)
+{
+ int base_buf_len=(int)(((unsigned int)(*ptr)[0]) |
+ (((unsigned int)(*ptr)[1])<<8) |
+ (((unsigned int)(*ptr)[2])<<16) |
+ (((unsigned int)(*ptr)[3])<<24));
+ (*ptr)+=4;
+ *vals=warnmalloc(nvals*sizeof (**vals));
+ base_decompress(*ptr,nvals,*vals);
+ (*ptr)+=base_buf_len;
+}
+
+static void unpack_one_large(struct xtc3_context *xtc3_context,
+ int *ilargedir, int *ilargeintra,
+ int *ilargeinter, int *prevcoord,
+ int *minint, int *output,
+ int outdata, int didswap,
+ int natoms, int current_large_type)
+{
+ int large_ints[3]={0,0,0};
+ if (current_large_type==0 && xtc3_context->large_direct)
+ {
+ large_ints[0]=(int)xtc3_context->large_direct[(*ilargedir)]+minint[0];
+ large_ints[1]=(int)xtc3_context->large_direct[(*ilargedir)+1]+minint[1];
+ large_ints[2]=(int)xtc3_context->large_direct[(*ilargedir)+2]+minint[2];
+ (*ilargedir)+=3;
+ }
+ else if (current_large_type==1 && xtc3_context->large_intra_delta)
+ {
+ large_ints[0]=unpositive_int(xtc3_context->large_intra_delta[(*ilargeintra)])+prevcoord[0];
+ large_ints[1]=unpositive_int(xtc3_context->large_intra_delta[(*ilargeintra)+1])+prevcoord[1];
+ large_ints[2]=unpositive_int(xtc3_context->large_intra_delta[(*ilargeintra)+2])+prevcoord[2];
+ (*ilargeintra)+=3;
+ }
+ else if (xtc3_context->large_inter_delta)
+ {
+ large_ints[0]=unpositive_int(xtc3_context->large_inter_delta[(*ilargeinter)])
+ +output[outdata-natoms*3+didswap*3];
+ large_ints[1]=unpositive_int(xtc3_context->large_inter_delta[(*ilargeinter)+1])
+ +output[outdata-natoms*3+1+didswap*3];
+ large_ints[2]=unpositive_int(xtc3_context->large_inter_delta[(*ilargeinter)+2])
+ +output[outdata-natoms*3+2+didswap*3];
+ (*ilargeinter)+=3;
+ }
+ prevcoord[0]=large_ints[0];
+ prevcoord[1]=large_ints[1];
+ prevcoord[2]=large_ints[2];
+ output[outdata]=large_ints[0];
+ output[outdata+1]=large_ints[1];
+ output[outdata+2]=large_ints[2];
+#ifdef SHOWIT
+ fprintf(stderr,"Unpack one large: %d %d %d\n",prevcoord[0],prevcoord[1],prevcoord[2]);
+#endif
+}
+
+
+int Ptngc_unpack_array_xtc3(unsigned char *packed,int *output, int length, int natoms)
+{
+ int i;
+ int minint[3];
+ unsigned char *ptr=packed;
+ int prevcoord[3];
+ int outdata=0;
+ int ntriplets_left=length/3;
+ int swapatoms=0;
+ int runlength=0;
+ int current_large_type=0;
+ int iinstr=0;
+ int irle=0;
+ int ilargedir=0;
+ int ilargeintra=0;
+ int ilargeinter=0;
+ int ismallintra=0;
+
+ struct xtc3_context xtc3_context;
+ init_xtc3_context(&xtc3_context);
+
+ for (i=0; i<3; i++)
+ {
+ minint[i]=unpositive_int((int)(((unsigned int)ptr[0]) |
+ (((unsigned int)ptr[1])<<8) |
+ (((unsigned int)ptr[2])<<16) |
+ (((unsigned int)ptr[3])<<24)));
+ ptr+=4;
+ }
+
+ xtc3_context.ninstr=(int)(((unsigned int)ptr[0]) |
+ (((unsigned int)ptr[1])<<8) |
+ (((unsigned int)ptr[2])<<16) |
+ (((unsigned int)ptr[3])<<24));
+ ptr+=4;
+ if (xtc3_context.ninstr)
+ decompress_bwlzh_block(&ptr,xtc3_context.ninstr,&xtc3_context.instructions);
+
+ xtc3_context.nrle=(int)(((unsigned int)ptr[0]) |
+ (((unsigned int)ptr[1])<<8) |
+ (((unsigned int)ptr[2])<<16) |
+ (((unsigned int)ptr[3])<<24));
+ ptr+=4;
+ if (xtc3_context.nrle)
+ decompress_bwlzh_block(&ptr,xtc3_context.nrle,&xtc3_context.rle);
+
+ xtc3_context.nlargedir=(int)(((unsigned int)ptr[0]) |
+ (((unsigned int)ptr[1])<<8) |
+ (((unsigned int)ptr[2])<<16) |
+ (((unsigned int)ptr[3])<<24));
+ ptr+=4;
+ if (xtc3_context.nlargedir)
+ {
+ if (*ptr++==1)
+ decompress_bwlzh_block(&ptr,xtc3_context.nlargedir,&xtc3_context.large_direct);
+ else
+ decompress_base_block(&ptr,xtc3_context.nlargedir,&xtc3_context.large_direct);
+ }
+
+ xtc3_context.nlargeintra=(int)(((unsigned int)ptr[0]) |
+ (((unsigned int)ptr[1])<<8) |
+ (((unsigned int)ptr[2])<<16) |
+ (((unsigned int)ptr[3])<<24));
+ ptr+=4;
+ if (xtc3_context.nlargeintra)
+ {
+ if (*ptr++==1)
+ decompress_bwlzh_block(&ptr,xtc3_context.nlargeintra,&xtc3_context.large_intra_delta);
+ else
+ decompress_base_block(&ptr,xtc3_context.nlargeintra,&xtc3_context.large_intra_delta);
+ }
+
+ xtc3_context.nlargeinter=(int)(((unsigned int)ptr[0]) |
+ (((unsigned int)ptr[1])<<8) |
+ (((unsigned int)ptr[2])<<16) |
+ (((unsigned int)ptr[3])<<24));
+ ptr+=4;
+ if (xtc3_context.nlargeinter)
+ {
+ if (*ptr++==1)
+ decompress_bwlzh_block(&ptr,xtc3_context.nlargeinter,&xtc3_context.large_inter_delta);
+ else
+ decompress_base_block(&ptr,xtc3_context.nlargeinter,&xtc3_context.large_inter_delta);
+ }
+
+ xtc3_context.nsmallintra=(int)(((unsigned int)ptr[0]) |
+ (((unsigned int)ptr[1])<<8) |
+ (((unsigned int)ptr[2])<<16) |
+ (((unsigned int)ptr[3])<<24));
+ ptr+=4;
+ if (xtc3_context.nsmallintra)
+ {
+ if (*ptr++==1)
+ decompress_bwlzh_block(&ptr,xtc3_context.nsmallintra,&xtc3_context.smallintra);
+ else
+ decompress_base_block(&ptr,xtc3_context.nsmallintra,&xtc3_context.smallintra);
+ }
+
+ /* Initial prevcoord is the minimum integers. */
+ prevcoord[0]=minint[0];
+ prevcoord[1]=minint[1];
+ prevcoord[2]=minint[2];
+
+ while (ntriplets_left>0 && iinstr<xtc3_context.ninstr)
+ {
+ int instr=xtc3_context.instructions[iinstr++];
+#ifdef SHOWIT
+ fprintf(stderr,"instr=%d @ %d\n",instr,iinstr-1);
+#endif
+#ifdef SHOWIT
+ fprintf(stderr,"ntriplets left=%d\n",ntriplets_left);
+#endif
+ if ((instr==INSTR_DEFAULT) /* large+small */
+ || (instr==INSTR_ONLY_LARGE) /* only large */
+ || (instr==INSTR_ONLY_SMALL)) /* only small */
+ {
+ if (instr!=INSTR_ONLY_SMALL)
+ {
+ int didswap=0;
+ if ((instr==INSTR_DEFAULT) && (swapatoms))
+ didswap=1;
+ unpack_one_large(&xtc3_context,&ilargedir, &ilargeintra, &ilargeinter,
+ prevcoord, minint, output, outdata, didswap,
+ natoms, current_large_type);
+ ntriplets_left--;
+ outdata+=3;
+ }
+ if (instr!=INSTR_ONLY_LARGE)
+ {
+ for (i=0; i<runlength; i++)
+ {
+ prevcoord[0]+=unpositive_int(xtc3_context.smallintra[ismallintra]);
+ prevcoord[1]+=unpositive_int(xtc3_context.smallintra[ismallintra+1]);
+ prevcoord[2]+=unpositive_int(xtc3_context.smallintra[ismallintra+2]);
+ ismallintra+=3;
+ output[outdata+i*3]=prevcoord[0];
+ output[outdata+i*3+1]=prevcoord[1];
+ output[outdata+i*3+2]=prevcoord[2];
+#ifdef SHOWIT
+ fprintf(stderr,"Unpack small: %d %d %d\n",prevcoord[0],prevcoord[1],prevcoord[2]);
+#endif
+ }
+ if ((instr==INSTR_DEFAULT) && (swapatoms))
+ {
+ for (i=0; i<3; i++)
+ {
+ int tmp=output[outdata-3+i];
+ output[outdata-3+i]=output[outdata+i];
+ output[outdata+i]=tmp;
+ }
+#ifdef SHOWIT
+ fprintf(stderr,"Unswap results in\n");
+ for (i=0; i<3; i++)
+ fprintf(stderr,"%d %d %d\n",output[outdata-3+i*3],output[outdata-2+i*3],output[outdata-1+i*3]);
+#endif
+ }
+ ntriplets_left-=runlength;
+ outdata+=runlength*3;
+ }
+ }
+ else if (instr==INSTR_LARGE_RLE && irle<xtc3_context.nrle)
+ {
+ int large_rle=xtc3_context.rle[irle++];
+#ifdef SHOWIT
+ fprintf(stderr,"large_rle=%d @ %d\n",large_rle,irle-1);
+#endif
+ for (i=0; i<large_rle; i++)
+ {
+ unpack_one_large(&xtc3_context,&ilargedir, &ilargeintra, &ilargeinter,
+ prevcoord, minint, output, outdata, 0,
+ natoms, current_large_type);
+ ntriplets_left--;
+ outdata+=3;
+ }
+ }
+ else if (instr==INSTR_SMALL_RUNLENGTH && irle<xtc3_context.nrle)
+ {
+ runlength=xtc3_context.rle[irle++];
+#ifdef SHOWIT
+ fprintf(stderr,"small_rle=%d @ %d\n",runlength,irle-1);
+#endif
+ }
+ else if (instr==INSTR_FLIP)
+ {
+ swapatoms=1-swapatoms;
+#ifdef SHOWIT
+ fprintf(stderr,"new flip=%d\n",swapatoms);
+#endif
+ }
+ else if (instr==INSTR_LARGE_DIRECT)
+ {
+ current_large_type=0;
+#ifdef SHOWIT
+ fprintf(stderr,"large direct\n");
+#endif
+ }
+ else if (instr==INSTR_LARGE_INTRA_DELTA)
+ {
+ current_large_type=1;
+#ifdef SHOWIT
+ fprintf(stderr,"large intra delta\n");
+#endif
+ }
+ else if (instr==INSTR_LARGE_INTER_DELTA)
+ {
+ current_large_type=2;
+#ifdef SHOWIT
+ fprintf(stderr,"large inter delta\n");
+#endif
+ }
+ }
+ if (ntriplets_left<0)
+ {
+ fprintf(stderr,"TRAJNG XTC3: A bug has been found. At end ntriplets_left<0\n");
+ exit(EXIT_FAILURE);
+ }
+ free_xtc3_context(&xtc3_context);
+ return 0;
+}
--- /dev/null
+if(TNG_BUILD_FORTRAN)
+ add_library(tng_io tng_io.c md5.c tng_io_fortran.c)
+else()
+ add_library(tng_io tng_io.c md5.c)
+endif()
+
+set_property(TARGET tng_io PROPERTY LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
+set_property(TARGET tng_io PROPERTY ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
+
+install(TARGETS tng_io
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib)
+
+if(HAVE_INTTYPES_H)
+ set_property(TARGET tng_io APPEND PROPERTY COMPILE_DEFINITIONS USE_STD_INTTYPES_H)
+endif()
+
+# This test is for md5. The TNG library itself determines the actual byte order -
+# not just if it is small or big endian.
+include(TestBigEndian)
+test_big_endian(TNG_INTEGER_BIG_ENDIAN)
+if(TNG_INTEGER_BIG_ENDIAN)
+ set_property(TARGET tng_io APPEND PROPERTY COMPILE_DEFINITIONS TNG_INTEGER_BIG_ENDIAN)
+endif()
+
+if(ZLIB_FOUND)
+ set_property(TARGET tng_io APPEND PROPERTY COMPILE_DEFINITIONS USE_ZLIB)
+ target_link_libraries(tng_io tng_compress ${ZLIB_LIBRARIES})
+else()
+ target_link_libraries(tng_io tng_compress)
+endif()
--- /dev/null
+/* This file has been modified in the TNG library distribution. Modifications
+ * are marked below. */
+
+/* The define below was added in the TNG library distribution of this file. */
+#ifdef TNG_INTEGER_BIG_ENDIAN
+#define ARCH_IS_BIG_ENDIAN 1
+#else
+#define ARCH_IS_BIG_ENDIAN 0
+#endif
+
+/* The defines below were added in TNG library distribution of this file
+ * in order to compile properly in MSVC */
+
+#ifndef USE_WINDOWS
+#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
+#define USE_WINDOWS
+#endif /* win32... */
+#endif /* not defined USE_WINDOWS */
+
+#ifdef USE_WINDOWS
+#define TNG_INLINE __inline
+#else
+#define TNG_INLINE inline
+#endif
+
+/*
+ Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ ghost@aladdin.com
+
+ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.c is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+ either statically or dynamically; added missing #include <string.h>
+ in library.
+ 2002-03-11 lpd Corrected argument list for main(), and added int return
+ type, in test program and T value program.
+ 2002-02-21 lpd Added missing #include <stdio.h> in test program.
+ 2000-07-03 lpd Patched to eliminate warnings about "constant is
+ unsigned in ANSI C, signed in traditional"; made test program
+ self-checking.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+ 1999-05-03 lpd Original version.
+ */
+
+#include "../../include/md5.h"
+#include <string.h>
+
+#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
+#ifdef ARCH_IS_BIG_ENDIAN
+# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
+#else
+# define BYTE_ORDER 0
+#endif
+
+#define T_MASK ((md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3 0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6 0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9 0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13 0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16 0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19 0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22 0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25 0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28 0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31 0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35 0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38 0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41 0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44 0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47 0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50 0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53 0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57 0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60 0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63 0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+/* In the TNG library inline has been changed to TNG_INLINE */
+static TNG_INLINE void
+md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
+{
+ md5_word_t
+ a = pms->abcd[0], b = pms->abcd[1],
+ c = pms->abcd[2], d = pms->abcd[3];
+ md5_word_t t;
+#if BYTE_ORDER > 0
+ /* Define storage only for big-endian CPUs. */
+ md5_word_t X[16];
+#else
+ /* Define storage for little-endian or both types of CPUs. */
+ md5_word_t xbuf[16];
+ /* cppcheck-suppress unassignedVariable */
+ const md5_word_t *X;
+#endif
+
+ {
+#if BYTE_ORDER == 0
+ /*
+ * Determine dynamically whether this is a big-endian or
+ * little-endian machine, since we can use a more efficient
+ * algorithm on the latter.
+ */
+ static const int w = 1;
+
+ if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
+#endif
+#if BYTE_ORDER <= 0 /* little-endian */
+ {
+ /*
+ * On little-endian machines, we can process properly aligned
+ * data without copying it.
+ */
+ if (!((data - (const md5_byte_t *)0) & 3)) {
+ /* data are properly aligned */
+ X = (const md5_word_t *)data;
+ } else {
+ /* not aligned */
+ memcpy(xbuf, data, 64);
+ X = xbuf;
+ }
+ }
+#endif
+#if BYTE_ORDER == 0
+ else /* dynamic big-endian */
+#endif
+#if BYTE_ORDER >= 0 /* big-endian */
+ {
+ /*
+ * On big-endian machines, we must arrange the bytes in the
+ * right order.
+ */
+ const md5_byte_t *xp = data;
+ int i;
+
+# if BYTE_ORDER == 0
+ X = xbuf; /* (dynamic only) */
+# else
+# define xbuf X /* (static only) */
+# endif
+ for (i = 0; i < 16; ++i, xp += 4)
+ xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+ }
+#endif
+ }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+ /* Round 1. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + F(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 7, T1);
+ SET(d, a, b, c, 1, 12, T2);
+ SET(c, d, a, b, 2, 17, T3);
+ SET(b, c, d, a, 3, 22, T4);
+ SET(a, b, c, d, 4, 7, T5);
+ SET(d, a, b, c, 5, 12, T6);
+ SET(c, d, a, b, 6, 17, T7);
+ SET(b, c, d, a, 7, 22, T8);
+ SET(a, b, c, d, 8, 7, T9);
+ SET(d, a, b, c, 9, 12, T10);
+ SET(c, d, a, b, 10, 17, T11);
+ SET(b, c, d, a, 11, 22, T12);
+ SET(a, b, c, d, 12, 7, T13);
+ SET(d, a, b, c, 13, 12, T14);
+ SET(c, d, a, b, 14, 17, T15);
+ SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+ /* Round 2. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + G(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 1, 5, T17);
+ SET(d, a, b, c, 6, 9, T18);
+ SET(c, d, a, b, 11, 14, T19);
+ SET(b, c, d, a, 0, 20, T20);
+ SET(a, b, c, d, 5, 5, T21);
+ SET(d, a, b, c, 10, 9, T22);
+ SET(c, d, a, b, 15, 14, T23);
+ SET(b, c, d, a, 4, 20, T24);
+ SET(a, b, c, d, 9, 5, T25);
+ SET(d, a, b, c, 14, 9, T26);
+ SET(c, d, a, b, 3, 14, T27);
+ SET(b, c, d, a, 8, 20, T28);
+ SET(a, b, c, d, 13, 5, T29);
+ SET(d, a, b, c, 2, 9, T30);
+ SET(c, d, a, b, 7, 14, T31);
+ SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+ /* Round 3. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + H(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 5, 4, T33);
+ SET(d, a, b, c, 8, 11, T34);
+ SET(c, d, a, b, 11, 16, T35);
+ SET(b, c, d, a, 14, 23, T36);
+ SET(a, b, c, d, 1, 4, T37);
+ SET(d, a, b, c, 4, 11, T38);
+ SET(c, d, a, b, 7, 16, T39);
+ SET(b, c, d, a, 10, 23, T40);
+ SET(a, b, c, d, 13, 4, T41);
+ SET(d, a, b, c, 0, 11, T42);
+ SET(c, d, a, b, 3, 16, T43);
+ SET(b, c, d, a, 6, 23, T44);
+ SET(a, b, c, d, 9, 4, T45);
+ SET(d, a, b, c, 12, 11, T46);
+ SET(c, d, a, b, 15, 16, T47);
+ SET(b, c, d, a, 2, 23, T48);
+#undef SET
+
+ /* Round 4. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + I(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 6, T49);
+ SET(d, a, b, c, 7, 10, T50);
+ SET(c, d, a, b, 14, 15, T51);
+ SET(b, c, d, a, 5, 21, T52);
+ SET(a, b, c, d, 12, 6, T53);
+ SET(d, a, b, c, 3, 10, T54);
+ SET(c, d, a, b, 10, 15, T55);
+ SET(b, c, d, a, 1, 21, T56);
+ SET(a, b, c, d, 8, 6, T57);
+ SET(d, a, b, c, 15, 10, T58);
+ SET(c, d, a, b, 6, 15, T59);
+ SET(b, c, d, a, 13, 21, T60);
+ SET(a, b, c, d, 4, 6, T61);
+ SET(d, a, b, c, 11, 10, T62);
+ SET(c, d, a, b, 2, 15, T63);
+ SET(b, c, d, a, 9, 21, T64);
+#undef SET
+
+ /* Then perform the following additions. (That is increment each
+ of the four registers by the value it had before this block
+ was started.) */
+ pms->abcd[0] += a;
+ pms->abcd[1] += b;
+ pms->abcd[2] += c;
+ pms->abcd[3] += d;
+}
+
+void
+md5_init(md5_state_t *pms)
+{
+ pms->count[0] = pms->count[1] = 0;
+ pms->abcd[0] = 0x67452301;
+ pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+ pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+ pms->abcd[3] = 0x10325476;
+}
+
+void
+md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
+{
+ const md5_byte_t *p = data;
+ int left = nbytes;
+ int offset = (pms->count[0] >> 3) & 63;
+ md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+ if (nbytes <= 0)
+ return;
+
+ /* Update the message length. */
+ pms->count[1] += nbytes >> 29;
+ pms->count[0] += nbits;
+ if (pms->count[0] < nbits)
+ pms->count[1]++;
+
+ /* Process an initial partial block. */
+ if (offset) {
+ int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+ memcpy(pms->buf + offset, p, copy);
+ if (offset + copy < 64)
+ return;
+ p += copy;
+ left -= copy;
+ md5_process(pms, pms->buf);
+ }
+
+ /* Process full blocks. */
+ for (; left >= 64; p += 64, left -= 64)
+ md5_process(pms, p);
+
+ /* Process a final partial block. */
+ if (left)
+ memcpy(pms->buf, p, left);
+}
+
+void
+md5_finish(md5_state_t *pms, md5_byte_t digest[16])
+{
+ static const md5_byte_t pad[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ md5_byte_t data[8];
+ int i;
+
+ /* Save the length before padding. */
+ for (i = 0; i < 8; ++i)
+ data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+ /* Pad to 56 bytes mod 64. */
+ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+ /* Append the length. */
+ md5_append(pms, data, 8);
+ for (i = 0; i < 16; ++i)
+ digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
--- /dev/null
+/* This code is part of the tng binary trajectory format.
+ *
+ * VERSION 1.4
+ *
+ * Written by Magnus Lundborg
+ * Copyright (c) 2012-2013, The GROMACS development team.
+ * Check out http://www.gromacs.org for more information.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+#ifdef USE_STD_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <math.h>
+#ifdef USE_ZLIB
+#include <zlib.h>
+#endif
+
+#include "../../include/tng_io.h"
+#include "../../include/md5.h"
+#include "../../include/compression/tng_compress.h"
+
+
+struct tng_bond {
+ /** One of the atoms of the bond */
+ int64_t from_atom_id;
+ /** The other atom of the bond */
+ int64_t to_atom_id;
+};
+
+struct tng_atom {
+ /** The residue containing this atom */
+ tng_residue_t residue;
+ /** A unique (per molecule) ID number of the atom */
+ int64_t id;
+ /** The atom_type (depending on the forcefield) */
+ char *atom_type;
+ /** The name of the atom */
+ char *name;
+};
+
+struct tng_residue {
+ /** The chain containing this residue */
+ tng_chain_t chain;
+ /** A unique (per chain) ID number of the residue */
+ int64_t id;
+ /** The name of the residue */
+ char *name;
+ /** The number of atoms in the residue */
+ int64_t n_atoms;
+ /** A list of atoms in the residue */
+ int64_t atoms_offset;
+};
+
+struct tng_chain {
+ /** The molecule containing this chain */
+ tng_molecule_t molecule;
+ /** A unique (per molecule) ID number of the chain */
+ int64_t id;
+ /** The name of the chain */
+ char *name;
+ /** The number of residues in the chain */
+ int64_t n_residues;
+ /** A list of residues in the chain */
+ tng_residue_t residues;
+};
+
+struct tng_molecule {
+ /** A unique ID number of the molecule */
+ int64_t id;
+ /** Quaternary structure of the molecule.
+ * 1 => monomeric
+ * 2 => dimeric
+ * 3 => trimeric
+ * etc */
+ int64_t quaternary_str;
+ /** The number of chains in the molecule */
+ int64_t n_chains;
+ /** The number of residues in the molecule */
+ int64_t n_residues;
+ /** The number of atoms in the molecule */
+ int64_t n_atoms;
+ /** The number of bonds in the molecule. If the bonds are not specified this
+ * value can be 0. */
+ int64_t n_bonds;
+ /** The name of the molecule */
+ char *name;
+ /** A list of chains in the molecule */
+ tng_chain_t chains;
+ /** A list of residues in the molecule */
+ tng_residue_t residues;
+ /** A list of the atoms in the molecule */
+ tng_atom_t atoms;
+ /** A list of the bonds in the molecule */
+ tng_bond_t bonds;
+};
+
+struct tng_gen_block {
+ /** The size of the block header in bytes */
+ int64_t header_contents_size;
+ /** The size of the block contents in bytes */
+ int64_t block_contents_size;
+ /** The ID of the block to determine its type */
+ int64_t id;
+ /** The MD5 hash of the block to verify integrity */
+ char md5_hash[TNG_MD5_HASH_LEN];
+ /** The name of the block */
+ char *name;
+ /** The library version used to write the block */
+ int64_t block_version;
+ int64_t alt_hash_type;
+ int64_t alt_hash_len;
+ char *alt_hash;
+ int64_t signature_type;
+ int64_t signature_len;
+ char *signature;
+ /** The full block header contents */
+ char *header_contents;
+ /** The full block contents */
+ char *block_contents;
+};
+
+struct tng_particle_mapping {
+ /** The index number of the first particle in this mapping block */
+ int64_t num_first_particle;
+ /** The number of particles list in this mapping block */
+ int64_t n_particles;
+ /** the mapping of index numbers to the real particle numbers in the
+ * trajectory. real_particle_numbers[0] is the real particle number
+ * (as it is numbered in the molecular system) of the first particle
+ * in the data blocks covered by this particle mapping block */
+ int64_t *real_particle_numbers;
+};
+
+struct tng_trajectory_frame_set {
+ /** The number of different particle mapping blocks present. */
+ int64_t n_mapping_blocks;
+ /** The atom mappings of this frame set */
+ struct tng_particle_mapping *mappings;
+ /** The first frame of this frame set */
+ int64_t first_frame;
+ /** The number of frames in this frame set */
+ int64_t n_frames;
+ /** The number of written frames in this frame set (used when writing one
+ * frame at a time). */
+ int64_t n_written_frames;
+ /** The number of frames not yet written to file in this frame set
+ * (used from the utility functions to finish the writing properly. */
+ int64_t n_unwritten_frames;
+
+
+ /** A list of the number of each molecule type - only used when using
+ * variable number of atoms */
+ int64_t *molecule_cnt_list;
+ /** The number of particles/atoms - only used when using variable number
+ * of atoms */
+ int64_t n_particles;
+ /** The file position of the next frame set */
+ int64_t next_frame_set_file_pos;
+ /** The file position of the previous frame set */
+ int64_t prev_frame_set_file_pos;
+ /** The file position of the frame set one long stride step ahead */
+ int64_t medium_stride_next_frame_set_file_pos;
+ /** The file position of the frame set one long stride step behind */
+ int64_t medium_stride_prev_frame_set_file_pos;
+ /** The file position of the frame set one long stride step ahead */
+ int64_t long_stride_next_frame_set_file_pos;
+ /** The file position of the frame set one long stride step behind */
+ int64_t long_stride_prev_frame_set_file_pos;
+ /** Time stamp (in seconds) of first frame in frame set */
+ double first_frame_time;
+
+ /* The data blocks in a frame set are trajectory data blocks */
+ /** The number of trajectory data blocks of particle dependent data */
+ int n_particle_data_blocks;
+ /** A list of data blocks containing particle dependent data */
+ struct tng_particle_data *tr_particle_data;
+ /** The number of trajectory data blocks independent of particles */
+ int n_data_blocks;
+ /** A list of data blocks containing particle indepdendent data */
+ struct tng_non_particle_data *tr_data;
+};
+
+/* FIXME: Should there be a pointer to a tng_gen_block from each data block? */
+struct tng_particle_data {
+ /** The block ID of the data block containing this particle data.
+ * This is used to determine the kind of data that is stored */
+ int64_t block_id;
+ /** The name of the data block. This is used to determine the kind of
+ * data that is stored */
+ char *block_name;
+ /** The type of data stored. */
+ char datatype;
+ /** The frame number of the first data value */
+ int64_t first_frame_with_data;
+ /** The number of frames in this frame set */
+ int64_t n_frames;
+ /** The number of values stored per frame */
+ int64_t n_values_per_frame;
+ /** The number of frames between each data point - e.g. when
+ * storing sparse data. */
+ int64_t stride_length;
+ /** ID of the CODEC used for compression 0 == no compression. */
+ int64_t codec_id;
+ /** If reading one frame at a time this is the last read frame */
+ int64_t last_retrieved_frame;
+ /** The multiplier used for getting integer values for compression */
+ double compression_multiplier;
+ /** A 1-dimensional array of values of length
+ * [sizeof (datatype)] * n_frames * n_particles * n_values_per_frame */
+ void *values;
+ /** If storing character data store it in a 3-dimensional array */
+ char ****strings;
+};
+
+struct tng_non_particle_data {
+ /** The ID of the data block */
+ int64_t block_id;
+ /** The name of the data block. This is used to determine the kind of
+ * data that is stored */
+ char *block_name;
+ /** The type of data stored. */
+ char datatype;
+ /** The first frame number of the first data value */
+ int64_t first_frame_with_data;
+ /** The number of frames in this data block */
+ int64_t n_frames;
+ /** The number of values stored per frame */
+ int64_t n_values_per_frame;
+ /** The number of frames between each data value, e.g. if storing data
+ * that is not saved every frame. */
+ int64_t stride_length;
+ /** ID of the CODEC used for compression. 0 == no compression. */
+ int64_t codec_id;
+ /** If reading one frame at a time this is the last read frame */
+ int64_t last_retrieved_frame;
+ /** Compressed data is stored as integers. This compression multiplier is
+ * the multiplication factor to convert from integer to float/double */
+ double compression_multiplier;
+ /** A 1-dimensional array of values of length
+ * [sizeof (datatype)] * n_frames * n_values_per_frame */
+ void *values;
+ /** If storing character data store it in a 3-dimensional array */
+ char ***strings;
+};
+
+
+
+struct tng_trajectory {
+ /** The path of the input trajectory file */
+ char *input_file_path;
+ /** A handle to the input file */
+ FILE *input_file;
+ /** The length of the input file */
+ long input_file_len;
+ /** The path of the output trajectory file */
+ char *output_file_path;
+ /** A handle to the output file */
+ FILE *output_file;
+ /** Function to swap 32 bit values to and from the endianness of the
+ * input file */
+ tng_function_status (*input_endianness_swap_func_32)(const tng_trajectory_t, int32_t *);
+ /** Function to swap 64 bit values to and from the endianness of the
+ * input file */
+ tng_function_status (*input_endianness_swap_func_64)(const tng_trajectory_t, int64_t *);
+ /** Function to swap 32 bit values to and from the endianness of the
+ * input file */
+ tng_function_status (*output_endianness_swap_func_32)(const tng_trajectory_t, int32_t *);
+ /** Function to swap 64 bit values to and from the endianness of the
+ * input file */
+ tng_function_status (*output_endianness_swap_func_64)(const tng_trajectory_t, int64_t *);
+ /** The endianness of 32 bit values of the current computer */
+ char endianness_32;
+ /** The endianness of 64 bit values of the current computer */
+ char endianness_64;
+
+ /** The name of the program producing this trajectory */
+ char *first_program_name;
+ /** The forcefield used in the simulations */
+ char *forcefield_name;
+ /** The name of the user running the simulations */
+ char *first_user_name;
+ /** The name of the computer on which the simulations were performed */
+ char *first_computer_name;
+ /** The PGP signature of the user creating the file. */
+ char *first_pgp_signature;
+ /** The name of the program used when making last modifications to the
+ * file */
+ char *last_program_name;
+ /** The name of the user making the last modifications to the file */
+ char *last_user_name;
+ /** The name of the computer on which the last modifications were made */
+ char *last_computer_name;
+ /** The PGP signature of the user making the last modifications to the
+ * file. */
+ char *last_pgp_signature;
+ /** The time (n seconds since 1970) when the file was created */
+ int64_t time;
+ /** The exponential of the value of the distance unit used. The default
+ * distance unit is nm (1e-9), i.e. distance_unit_exponential = -9. If
+ * the measurements are in Å the distance_unit_exponential = -10. */
+ int64_t distance_unit_exponential;
+
+ /** A flag indicating if the number of atoms can vary throughout the
+ * simulation, e.g. using a grand canonical ensemble */
+ char var_num_atoms_flag;
+ /** The number of frames in a frame set. It is allowed to have frame sets
+ * with fewer frames, but this will help searching for specific frames */
+ int64_t frame_set_n_frames;
+ /** The number of frame sets in a medium stride step */
+ int64_t medium_stride_length;
+ /** The number of frame sets in a long stride step */
+ int64_t long_stride_length;
+ /** The current (can change from one frame set to another) time length
+ * (in seconds) of one frame */
+ double time_per_frame;
+
+ /** The number of different kinds of molecules in the trajectory */
+ int64_t n_molecules;
+ /** A list of molecules in the trajectory */
+ tng_molecule_t molecules;
+ /** A list of the count of each molecule - if using variable number of
+ * particles this will be specified in each frame set */
+ int64_t *molecule_cnt_list;
+ /** The total number of particles/atoms. If using variable number of
+ * particles this will be specified in each frame set */
+ int64_t n_particles;
+
+ /** The pos in the src file of the first frame set */
+ int64_t first_trajectory_frame_set_input_file_pos;
+ /** The pos in the dest file of the first frame set */
+ int64_t first_trajectory_frame_set_output_file_pos;
+ /** The pos in the src file of the last frame set */
+ int64_t last_trajectory_frame_set_input_file_pos;
+ /** The pos in the dest file of the last frame set */
+ int64_t last_trajectory_frame_set_output_file_pos;
+ /** The currently active frame set */
+ struct tng_trajectory_frame_set current_trajectory_frame_set;
+ /** The pos in the src file of the current frame set */
+ long current_trajectory_frame_set_input_file_pos;
+ /** The pos in the dest file of the current frame set */
+ long current_trajectory_frame_set_output_file_pos;
+ /** The number of frame sets in the trajectory N.B. Not saved in file and
+ * cannot be trusted to be up-to-date */
+ int64_t n_trajectory_frame_sets;
+
+ /** The number of trajectory blocks in the file */
+ int64_t n_trajectory_blocks;
+
+ /* These data blocks are non-trajectory data blocks */
+ /** The number of non-frame dependent particle dependent data blocks */
+ int n_particle_data_blocks;
+ /** A list of data blocks containing particle dependent data */
+ struct tng_particle_data *non_tr_particle_data;
+
+ /** The number of frame and particle independent data blocks */
+ int n_data_blocks;
+ /** A list of frame and particle indepdendent data blocks */
+ struct tng_non_particle_data *non_tr_data;
+
+ /** TNG compression algorithm for compressing positions */
+ int *compress_algo_pos;
+ /** TNG compression algorithm for compressing velocities */
+ int *compress_algo_vel;
+ /** The precision used for lossy compression */
+ double compression_precision;
+};
+
+#ifndef USE_WINDOWS
+#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
+#define USE_WINDOWS
+#endif /* win32... */
+#endif /* not defined USE_WINDOWS */
+
+#ifdef USE_WINDOWS
+#define TNG_INLINE __inline
+#define TNG_SNPRINTF _snprintf
+#else
+#define TNG_INLINE inline
+#define TNG_SNPRINTF snprintf
+#endif
+
+static TNG_INLINE int tng_min_i(int a, int b)
+{
+ return (a < b ? a : b);
+}
+
+/*
+static TNG_INLINE int tng_max_i(int a, int b)
+{
+ return (a > b ? a : b);
+}
+*/
+static TNG_INLINE int64_t tng_min_i64(int64_t a, int64_t b)
+{
+ return (a < b ? a : b);
+}
+
+static TNG_INLINE int64_t tng_max_i64(int64_t a, int64_t b)
+{
+ return (a > b ? a : b);
+}
+
+/*
+static TNG_INLINE float tng_min_f(float a, float b)
+{
+ return (a < b ? a : b);
+}
+
+static TNG_INLINE float tng_max_f(float a, float b)
+{
+ return (a > b ? a : b);
+}
+
+static TNG_INLINE double tng_min_d(double a, double b)
+{
+ return (a < b ? a : b);
+}
+
+static TNG_INLINE double tng_max_d(double a, double b)
+{
+ return (a > b ? a : b);
+}
+*/
+
+/** This function swaps the byte order of a 32 bit numerical variable
+ * to big endian.
+ * It does not only work with integer, but e.g. floats need casting.
+ * If the byte order is already big endian no change is needed.
+ * @param tng_data is a trajectory data container.
+ * @param v is a pointer to a 32 bit numerical value (float or integer).
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
+ * byte order is not recognised.
+ */
+static tng_function_status tng_swap_byte_order_big_endian_32
+ (const tng_trajectory_t tng_data, int32_t *v)
+{
+ switch(tng_data->endianness_32)
+ {
+ case TNG_LITTLE_ENDIAN_32: /* Byte order is reversed. */
+ *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */
+ ((*v & 0x00FF0000) >> 8) | /* Move 2nd byte to pos 3 */
+ ((*v & 0x0000FF00) << 8) | /* Move 3rd byte to pos 2 */
+ ((*v & 0x000000FF) << 24); /* Move last byte to first */
+
+ return(TNG_SUCCESS);
+
+ case TNG_BYTE_PAIR_SWAP_32: /* byte pair swap */
+ *v = ((*v & 0xFFFF0000) >> 16) |
+ ((*v & 0x0000FFFF) << 16);
+
+ return(TNG_SUCCESS);
+
+ case TNG_BIG_ENDIAN_32: /* Already correct */
+ return(TNG_SUCCESS);
+
+ default:
+ return(TNG_FAILURE);
+ }
+}
+
+/** This function swaps the byte order of a 64 bit numerical variable
+ * to big endian.
+ * It does not only work with integer, but e.g. floats need casting.
+ * The byte order swapping routine can convert four different byte
+ * orders to big endian.
+ * If the byte order is already big endian no change is needed.
+ * @param tng_data is a trajectory data container.
+ * @param v is a pointer to a 64 bit numerical value (double or integer).
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
+ * byte order is not recognised.
+ */
+static tng_function_status tng_swap_byte_order_big_endian_64
+ (const tng_trajectory_t tng_data, int64_t *v)
+{
+ switch(tng_data->endianness_64)
+ {
+ case TNG_LITTLE_ENDIAN_64: /* Byte order is reversed. */
+ *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */
+ ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */
+ ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */
+ ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */
+ ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */
+ ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */
+ ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */
+ ((*v & 0x00000000000000FFLL) << 56); /* Move last byte to first */
+
+ return(TNG_SUCCESS);
+
+ case TNG_QUAD_SWAP_64: /* Byte quad swap */
+ *v = ((*v & 0xFFFFFFFF00000000LL) >> 32) |
+ ((*v & 0x00000000FFFFFFFFLL) << 32);
+
+ return(TNG_SUCCESS);
+
+ case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swap */
+ *v = ((*v & 0xFFFF0000FFFF0000LL) >> 16) |
+ ((*v & 0x0000FFFF0000FFFFLL) << 16);
+
+ return(TNG_SUCCESS);
+
+ case TNG_BYTE_SWAP_64: /* Byte swap */
+ *v = ((*v & 0xFF00FF00FF00FF00LL) >> 8) |
+ ((*v & 0x00FF00FF00FF00FFLL) << 8);
+
+ return(TNG_SUCCESS);
+
+ case TNG_BIG_ENDIAN_64: /* Already correct */
+ return(TNG_SUCCESS);
+
+ default:
+ return(TNG_FAILURE);
+ }
+}
+
+/** This function swaps the byte order of a 32 bit numerical variable
+ * to little endian.
+ * It does not only work with integer, but e.g. floats need casting.
+ * If the byte order is already little endian no change is needed.
+ * @param tng_data is a trajectory data container.
+ * @param v is a pointer to a 32 bit numerical value (float or integer).
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
+ * byte order is not recognised.
+ */
+static tng_function_status tng_swap_byte_order_little_endian_32
+ (const tng_trajectory_t tng_data, int32_t *v)
+{
+ switch(tng_data->endianness_32)
+ {
+ case TNG_LITTLE_ENDIAN_32: /* Already correct */
+ return(TNG_SUCCESS);
+
+ case TNG_BYTE_PAIR_SWAP_32: /* byte pair swapped big endian to little endian */
+ *v = ((*v & 0xFF00FF00) >> 8) |
+ ((*v & 0x00FF00FF) << 8);
+
+ return(TNG_SUCCESS);
+
+ case TNG_BIG_ENDIAN_32: /* Byte order is reversed. */
+ *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */
+ ((*v & 0x00FF0000) >> 8) | /* Move 2nd byte to pos 3 */
+ ((*v & 0x0000FF00) << 8) | /* Move 3rd byte to pos 2 */
+ ((*v & 0x000000FF) << 24); /* Move last byte to first */
+
+ return(TNG_SUCCESS);
+
+ default:
+ return(TNG_FAILURE);
+ }
+}
+
+/** This function swaps the byte order of a 64 bit numerical variable
+ * to little endian.
+ * It does not only work with integer, but e.g. floats need casting.
+ * The byte order swapping routine can convert four different byte
+ * orders to little endian.
+ * If the byte order is already little endian no change is needed.
+ * @param tng_data is a trajectory data container.
+ * @param v is a pointer to a 64 bit numerical value (double or integer).
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
+ * byte order is not recognised.
+ */
+static tng_function_status tng_swap_byte_order_little_endian_64
+ (const tng_trajectory_t tng_data, int64_t *v)
+{
+ switch(tng_data->endianness_64)
+ {
+ case TNG_LITTLE_ENDIAN_64: /* Already correct */
+ return(TNG_SUCCESS);
+
+ case TNG_QUAD_SWAP_64: /* Byte quad swapped big endian to little endian */
+ *v = ((*v & 0xFF000000FF000000LL) >> 24) |
+ ((*v & 0x00FF000000FF0000LL) >> 8) |
+ ((*v & 0x0000FF000000FF00LL) << 8) |
+ ((*v & 0x000000FF000000FFLL) << 24);
+
+ return(TNG_SUCCESS);
+
+ case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swapped big endian to little endian */
+ *v = ((*v & 0xFF00FF0000000000LL) >> 40) |
+ ((*v & 0x00FF00FF00000000LL) >> 24) |
+ ((*v & 0x00000000FF00FF00LL) << 24) |
+ ((*v & 0x0000000000FF00FFLL) << 40);
+
+ return(TNG_SUCCESS);
+
+ case TNG_BYTE_SWAP_64: /* Byte swapped big endian to little endian */
+ *v = ((*v & 0xFFFF000000000000LL) >> 48) |
+ ((*v & 0x0000FFFF00000000LL) >> 16) |
+ ((*v & 0x00000000FFFF0000LL) << 16) |
+ ((*v & 0x000000000000FFFFLL) << 48);
+
+ return(TNG_SUCCESS);
+
+ case TNG_BIG_ENDIAN_64: /* Byte order is reversed. */
+ *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */
+ ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */
+ ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */
+ ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */
+ ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */
+ ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */
+ ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */
+ ((*v & 0x00000000000000FFLL) << 56); /* Move last byte to first */
+
+ return(TNG_SUCCESS);
+
+ default:
+ return(TNG_FAILURE);
+ }
+}
+/** Generate the md5 hash of a block.
+ * The hash is created based on the actual block contents.
+ * @param block is a general block container.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+static tng_function_status tng_block_md5_hash_generate(tng_gen_block_t block)
+{
+ md5_state_t md5_state;
+
+ md5_init(&md5_state);
+ md5_append(&md5_state, (md5_byte_t *)block->block_contents,
+ (int)block->block_contents_size);
+ md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
+
+ return(TNG_SUCCESS);
+}
+
+/** Compare the current block md5 hash (e.g. read from file) with the md5 hash
+ * calculated from the current contents.
+ * If the current md5 hash is not set skip the comparison.
+ * @param block is a general block container.
+ * @param results If the hashes match results is set to TNG_TRUE, otherwise it is
+ * set to TNG_FALSE. If the hash was not set results is set to TNG_TRUE.
+ * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the hash was not
+ * set.
+ */
+static tng_function_status tng_md5_hash_match_verify(tng_gen_block_t block,
+ tng_bool *results)
+{
+ md5_state_t md5_state;
+ char hash[TNG_MD5_HASH_LEN];
+
+ TNG_ASSERT(block->block_contents_size > 0, "The block contents size must be > 0");
+
+ *results = TNG_TRUE;
+ if(strncmp(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0)
+ {
+ return(TNG_FAILURE);
+ }
+ md5_init(&md5_state);
+ md5_append(&md5_state, (md5_byte_t *)block->block_contents,
+ (int)block->block_contents_size);
+ md5_finish(&md5_state, (md5_byte_t *)hash);
+
+ if(strncmp(block->md5_hash, hash, 16) != 0)
+ {
+ *results = TNG_FALSE;
+ }
+
+ return(TNG_SUCCESS);
+}
+
+/** Open the input file if it is not already opened.
+ * @param tng_data is a trajectory data container.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_input_file_init(tng_trajectory_t tng_data)
+{
+ if(!tng_data->input_file)
+ {
+ if(!tng_data->input_file_path)
+ {
+ fprintf(stderr, "TNG library: No file specified for reading. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ tng_data->input_file = fopen(tng_data->input_file_path, "r");
+ if(!tng_data->input_file)
+ {
+ fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
+ tng_data->input_file_path, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ }
+ return(TNG_SUCCESS);
+}
+
+/** Open the output file if it is not already opened
+ * @param tng_data is a trajectory data container.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_output_file_init(tng_trajectory_t tng_data)
+{
+ if(!tng_data->output_file)
+ {
+ if(!tng_data->output_file_path)
+ {
+ fprintf(stderr, "TNG library: No file specified for writing. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ tng_data->output_file = fopen(tng_data->output_file_path, "w+");
+
+ if(!tng_data->output_file)
+ {
+ fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
+ tng_data->output_file_path, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ }
+ return(TNG_SUCCESS);
+}
+
+/** Setup a file block container.
+ * @param block_p a pointer to memory to initialise as a file block container.
+ * @details Memory is allocated during initialisation.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_block_init(struct tng_gen_block **block_p)
+{
+ tng_gen_block_t block;
+
+ *block_p = malloc(sizeof(struct tng_gen_block));
+
+ if(!*block_p)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
+ sizeof(struct tng_gen_block), __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ block = *block_p;
+
+ block->id = -1;
+ /* Reset the md5_hash */
+ memcpy(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN);
+ block->name = 0;
+ block->block_version = TNG_VERSION;
+ block->header_contents = 0;
+ block->header_contents_size = 0;
+ block->block_contents = 0;
+ block->block_contents_size = 0;
+
+ return(TNG_SUCCESS);
+}
+
+/**
+ * @brief Clean up a file block container.
+ * @param block_p a pointer to the file block container to destroy.
+ * @details All allocated memory in the data structure is freed, as well as
+ * block_p itself.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+static tng_function_status tng_block_destroy(struct tng_gen_block **block_p)
+{
+ tng_gen_block_t block = *block_p;
+
+ if(!*block_p)
+ {
+ return(TNG_SUCCESS);
+ }
+
+/* fprintf(stderr, "TNG library: Destroying block\n"); */
+ if(block->name)
+ {
+ free(block->name);
+ block->name = 0;
+ }
+ if(block->header_contents)
+ {
+ free(block->header_contents);
+ block->header_contents = 0;
+ }
+ if(block->block_contents)
+ {
+ free(block->block_contents);
+ block->block_contents = 0;
+ }
+
+ free(*block_p);
+ *block_p = 0;
+
+ return(TNG_SUCCESS);
+}
+
+/** Read the header of a data block, regardless of its type
+ * @param tng_data is a trajectory data container.
+ * @param block is a general block container.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_block_header_read
+ (tng_trajectory_t tng_data, tng_gen_block_t block)
+{
+ int len, offset = 0;
+
+ TNG_ASSERT(block != 0, "TNG library: Trying to read to uninitialized block (NULL pointer).");
+
+ if(tng_input_file_init(tng_data) != TNG_SUCCESS)
+ {
+ return(TNG_CRITICAL);
+ }
+
+ /* First read the header size to be able to read the whole header. */
+ if(fread(&block->header_contents_size, sizeof(block->header_contents_size),
+ 1, tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Cannot read header size. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ /* If this was the size of the general info block check the endianness */
+ if(ftell(tng_data->input_file) < 9)
+ {
+ /* File is little endian */
+ if ( *((const char*)&block->header_contents_size) != 0x00 &&
+ *((const char*)(&block->header_contents_size) + 7) == 0x00)
+ {
+ /* If the architecture endianness is little endian no byte swap
+ * will be needed. Otherwise use the functions to swap to little
+ * endian */
+ if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
+ {
+ tng_data->input_endianness_swap_func_32 = 0;
+ }
+ else
+ {
+ tng_data->input_endianness_swap_func_32 =
+ &tng_swap_byte_order_little_endian_32;
+ }
+ if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
+ {
+ tng_data->input_endianness_swap_func_64 = 0;
+ }
+ else
+ {
+ tng_data->input_endianness_swap_func_64 =
+ &tng_swap_byte_order_little_endian_64;
+ }
+ }
+ /* File is big endian */
+ else
+ {
+ /* If the architecture endianness is big endian no byte swap
+ * will be needed. Otherwise use the functions to swap to big
+ * endian */
+ if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
+ {
+ tng_data->input_endianness_swap_func_32 = 0;
+ }
+ else
+ {
+ tng_data->input_endianness_swap_func_32 =
+ &tng_swap_byte_order_big_endian_32;
+ }
+ if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
+ {
+ tng_data->input_endianness_swap_func_64 = 0;
+ }
+ else
+ {
+ tng_data->input_endianness_swap_func_64 =
+ &tng_swap_byte_order_big_endian_64;
+ }
+ }
+ }
+
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &block->header_contents_size)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+
+ /* Move the reading position to the beginning of the header. */
+ fseek(tng_data->input_file, -(long)sizeof(block->header_contents_size),
+ SEEK_CUR);
+
+ /* If there is already memory allocated for the contents free it (we do not
+ * know if the size is correct). */
+ if(block->header_contents)
+ {
+ free(block->header_contents);
+ }
+
+ block->header_contents = malloc(block->header_contents_size);
+ if(!block->header_contents)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ block->header_contents_size, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ /* Read the whole header into header_contents. This way it can be saved
+ * even if it cannot be interpreted
+ * for one reason or another. */
+ if(fread(block->header_contents, block->header_contents_size, 1,
+ tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Cannot read header. %s: %d\n", __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ /* The header contents size has already been read. Skip ahead. */
+ offset = sizeof(block->header_contents_size);
+
+
+ /* Copy the respective parameters from the header contents block */
+ memcpy(&block->block_contents_size, block->header_contents+offset,
+ sizeof(block->block_contents_size));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &block->block_contents_size)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+
+ offset += sizeof(block->block_contents_size);
+
+ memcpy(&block->id, block->header_contents+offset, sizeof(block->id));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &block->id)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+
+ offset += sizeof(block->id);
+
+ memcpy(block->md5_hash, block->header_contents+offset, TNG_MD5_HASH_LEN);
+ offset += TNG_MD5_HASH_LEN;
+
+ if(block->name && strcmp(block->name, block->header_contents+offset) != 0)
+ {
+ free(block->name);
+ block->name = 0;
+ }
+ len = tng_min_i((int)strlen(block->header_contents+offset) + 1, TNG_MAX_STR_LEN);
+ if(!block->name)
+ {
+ block->name = malloc(len);
+ if(!block->name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ strncpy(block->name, block->header_contents+offset, len);
+ }
+ offset += len;
+
+ memcpy(&block->block_version, block->header_contents+offset,
+ sizeof(block->block_version));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &block->block_version)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+
+ return(TNG_SUCCESS);
+}
+
+/** Write a whole block, both header and contents, regardless of it type
+ * @param tng_data is a trajectory data container.
+ * @param block is a general block container.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+/* Disabled until it is used.*/
+/*
+// static tng_function_status tng_block_verbatim_write(tng_trajectory_t tng_data,
+// tng_gen_block_t block)
+// {
+// if(!block->header_contents)
+// {
+// fprintf(stderr, "TNG library: No contents to write. %s: %d\n", __FILE__, __LINE__);
+// return(TNG_FAILURE);
+// }
+// if(fwrite(block->header_contents, block->header_contents_size, 1,
+// tng_data->output_file) != 1)
+// {
+// fprintf(stderr, "TNG library: Could not write all header data. %s: %d\n",
+// __FILE__, __LINE__);
+// return(TNG_CRITICAL);
+// }
+//
+// if(!block->block_contents)
+// {
+// fprintf(stderr, "TNG library: No block data to write. %s: %d\n",
+// __FILE__, __LINE__);
+// return(TNG_FAILURE);
+// }
+// if(fwrite(block->block_contents, block->block_contents_size, 1,
+// tng_data->output_file) != 1)
+// {
+// fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
+// __FILE__, __LINE__);
+// return(TNG_CRITICAL);
+// }
+// return(TNG_SUCCESS);
+// }
+*/
+/** Write the header of a data block, regardless of its type
+ * @param tng_data is a trajectory data container.
+ * @param block is a general block container.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_block_header_write
+ (tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ const char hash_mode)
+{
+ int name_len, offset = 0;
+
+ TNG_ASSERT(block != 0, "TNG library: Trying to write uninitialized block (NULL pointer).");
+
+ if(tng_output_file_init(tng_data) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ if(!block->name)
+ {
+ block->name = malloc(1);
+ if(!block->name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ block->name[0] = 0;
+ }
+
+ name_len = tng_min_i((int)strlen(block->name) + 1, TNG_MAX_STR_LEN);
+
+ if(hash_mode == TNG_USE_HASH)
+ {
+ tng_block_md5_hash_generate(block);
+ }
+
+ /* Calculate the size of the header to write */
+ block->header_contents_size = sizeof(block->header_contents_size) +
+ sizeof(block->block_contents_size) +
+ sizeof(block->id) +
+ sizeof(block->block_version) +
+ TNG_MD5_HASH_LEN +
+ name_len;
+
+ if(block->header_contents)
+ {
+ free(block->header_contents);
+ }
+
+ block->header_contents = malloc(block->header_contents_size);
+ if(!block->header_contents)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ block->header_contents_size, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ /* First copy all data into the header_contents block and finally write
+ * the whole block at once. */
+ memcpy(block->header_contents, &block->header_contents_size,
+ sizeof(block->header_contents_size));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(block->header_contents_size);
+
+ memcpy(block->header_contents+offset, &block->block_contents_size,
+ sizeof(block->block_contents_size));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(block->block_contents_size);
+
+ memcpy(block->header_contents+offset, &block->id, sizeof(block->id));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(block->id);
+
+ memcpy(block->header_contents+offset, block->md5_hash, TNG_MD5_HASH_LEN);
+ offset += TNG_MD5_HASH_LEN;
+
+ strncpy(block->header_contents+offset, block->name, name_len);
+ offset += name_len;
+
+ memcpy(block->header_contents+offset, &block->block_version,
+ sizeof(block->block_version));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+
+ if(fwrite(block->header_contents, block->header_contents_size,
+ 1, tng_data->output_file) != 1)
+ {
+ fprintf(stderr, "TNG library: Could not write all header data. %s: %d\n", __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ return(TNG_SUCCESS);
+}
+
+/** Read a general info block. This is the first block of a TNG file.
+ * Populate the fields in tng_data.
+ * @param tng_data is a trajectory data container.
+ * @param block is a general block container.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_general_info_block_read
+ (tng_trajectory_t tng_data, tng_gen_block_t block,
+ const char hash_mode)
+{
+ int len, offset = 0;
+ tng_bool same_hash;
+
+ void *temp;
+
+ TNG_ASSERT(block != 0, "TNG library: Trying to read data to an uninitialized block (NULL pointer)");
+
+ if(tng_input_file_init(tng_data) != TNG_SUCCESS)
+ {
+ return(TNG_CRITICAL);
+ }
+
+ temp = realloc(block->block_contents, block->block_contents_size);
+ if(!temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ block->block_contents_size, __FILE__, __LINE__);
+ free(block->block_contents);
+ block->block_contents = 0;
+ return(TNG_CRITICAL);
+ }
+ block->block_contents = temp;
+
+ /* Read the whole block into block_contents to be able to write it to disk
+ * even if it cannot be interpreted. */
+ if(fread(block->block_contents, block->block_contents_size, 1,
+ tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ /* FIXME: Does not check if the size of the contents matches the expected
+ * size or if the contents can be read. */
+
+ if(hash_mode == TNG_USE_HASH)
+ {
+ tng_md5_hash_match_verify(block, &same_hash);
+ if(same_hash != TNG_TRUE)
+ {
+ fprintf(stderr, "TNG library: General info block contents corrupt. Hashes do not match. "
+ "%s: %d\n",
+ __FILE__, __LINE__);
+ /* return(TNG_FAILURE); */
+ }
+ }
+
+ len = tng_min_i((int)strlen(block->block_contents) + 1, TNG_MAX_STR_LEN);
+ temp = realloc(tng_data->first_program_name, len);
+ if(!temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ free(tng_data->first_program_name);
+ tng_data->first_program_name = 0;
+ return(TNG_CRITICAL);
+ }
+ tng_data->first_program_name = temp;
+ strncpy(tng_data->first_program_name, block->block_contents, len);
+ offset += len;
+
+ len = tng_min_i((int)strlen(block->block_contents + offset) + 1, TNG_MAX_STR_LEN);
+ temp = realloc(tng_data->last_program_name, len);
+ if(!temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ free(tng_data->last_program_name);
+ tng_data->last_program_name = 0;
+ return(TNG_CRITICAL);
+ }
+ tng_data->last_program_name = temp;
+ strncpy(tng_data->last_program_name, block->block_contents + offset, len);
+ offset += len;
+
+ len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
+ temp = realloc(tng_data->first_user_name, len);
+ if(!temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ free(tng_data->first_user_name);
+ tng_data->first_user_name = 0;
+ return(TNG_CRITICAL);
+ }
+ tng_data->first_user_name = temp;
+ strncpy(tng_data->first_user_name, block->block_contents+offset, len);
+ offset += len;
+
+ len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
+ temp = realloc(tng_data->last_user_name, len);
+ if(!temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ free(tng_data->last_user_name);
+ tng_data->last_user_name = 0;
+ return(TNG_CRITICAL);
+ }
+ tng_data->last_user_name = temp;
+ strncpy(tng_data->last_user_name, block->block_contents+offset, len);
+ offset += len;
+
+ len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
+ temp = realloc(tng_data->first_computer_name, len);
+ if(!temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ free(tng_data->first_computer_name);
+ tng_data->first_computer_name = 0;
+ return(TNG_CRITICAL);
+ }
+ tng_data->first_computer_name = temp;
+ strncpy(tng_data->first_computer_name, block->block_contents+offset, len);
+ offset += len;
+
+ len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
+ temp = realloc(tng_data->last_computer_name, len);
+ if(!temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ free(tng_data->last_computer_name);
+ tng_data->last_computer_name = 0;
+ return(TNG_CRITICAL);
+ }
+ tng_data->last_computer_name = temp;
+ strncpy(tng_data->last_computer_name, block->block_contents+offset, len);
+ offset += len;
+
+ len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
+ temp = realloc(tng_data->first_pgp_signature, len);
+ if(!temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ free(tng_data->first_pgp_signature);
+ tng_data->first_pgp_signature = 0;
+ return(TNG_CRITICAL);
+ }
+ tng_data->first_pgp_signature = temp;
+ strncpy(tng_data->first_pgp_signature, block->block_contents+offset, len);
+ offset += len;
+
+ len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
+ temp = realloc(tng_data->last_pgp_signature, len);
+ if(!temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ free(tng_data->last_pgp_signature);
+ tng_data->last_pgp_signature = 0;
+ return(TNG_CRITICAL);
+ }
+ tng_data->last_pgp_signature = temp;
+ strncpy(tng_data->last_pgp_signature, block->block_contents+offset, len);
+ offset += len;
+
+ len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
+ temp = realloc(tng_data->forcefield_name, len);
+ if(!temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ free(tng_data->forcefield_name);
+ tng_data->forcefield_name = 0;
+ return(TNG_CRITICAL);
+ }
+ tng_data->forcefield_name = temp;
+ strncpy(tng_data->forcefield_name, block->block_contents+offset, len);
+ offset += len;
+
+ memcpy(&tng_data->time, block->block_contents+offset,
+ sizeof(tng_data->time));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &tng_data->time)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(tng_data->time);
+
+ memcpy(&tng_data->var_num_atoms_flag, block->block_contents+offset,
+ sizeof(tng_data->var_num_atoms_flag));
+ offset += sizeof(tng_data->var_num_atoms_flag);
+
+ memcpy(&tng_data->frame_set_n_frames, block->block_contents+offset,
+ sizeof(tng_data->frame_set_n_frames));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &tng_data->frame_set_n_frames)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(tng_data->frame_set_n_frames);
+
+ memcpy(&tng_data->first_trajectory_frame_set_input_file_pos,
+ block->block_contents+offset,
+ sizeof(tng_data->first_trajectory_frame_set_input_file_pos));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &tng_data->first_trajectory_frame_set_input_file_pos)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(tng_data->first_trajectory_frame_set_input_file_pos);
+
+ tng_data->current_trajectory_frame_set.next_frame_set_file_pos =
+ tng_data->first_trajectory_frame_set_input_file_pos;
+
+
+ memcpy(&tng_data->last_trajectory_frame_set_input_file_pos,
+ block->block_contents+offset,
+ sizeof(tng_data->last_trajectory_frame_set_input_file_pos));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &tng_data->last_trajectory_frame_set_input_file_pos)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(tng_data->last_trajectory_frame_set_input_file_pos);
+
+ memcpy(&tng_data->medium_stride_length, block->block_contents+offset,
+ sizeof(tng_data->medium_stride_length));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &tng_data->medium_stride_length)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(tng_data->medium_stride_length);
+
+ memcpy(&tng_data->long_stride_length, block->block_contents+offset,
+ sizeof(tng_data->long_stride_length));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &tng_data->long_stride_length)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(tng_data->long_stride_length);
+
+ if(block->block_version >= 3)
+ {
+ memcpy(&tng_data->distance_unit_exponential, block->block_contents+offset,
+ sizeof(tng_data->distance_unit_exponential));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &tng_data->distance_unit_exponential)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ }
+
+ return(TNG_SUCCESS);
+}
+
+/** Write a general info block. This is the first block of a TNG file.
+ * @param tng_data is a trajectory data container.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_general_info_block_write
+ (tng_trajectory_t tng_data,
+ const char hash_mode)
+{
+ int first_program_name_len, first_user_name_len;
+ int first_computer_name_len, first_pgp_signature_len;
+ int last_program_name_len, last_user_name_len;
+ int last_computer_name_len, last_pgp_signature_len;
+ int forcefield_name_len, name_len;
+ int offset = 0;
+ tng_gen_block_t block;
+
+ if(tng_output_file_init(tng_data) != TNG_SUCCESS)
+ {
+ return(TNG_CRITICAL);
+ }
+
+ fseek(tng_data->output_file, 0, SEEK_SET);
+
+ /* If the strings are unallocated allocate memory for just string
+ * termination */
+ if(!tng_data->first_program_name)
+ {
+ tng_data->first_program_name = malloc(1);
+ if(!tng_data->first_program_name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ tng_data->first_program_name[0] = 0;
+ }
+ if(!tng_data->last_program_name)
+ {
+ tng_data->last_program_name = malloc(1);
+ if(!tng_data->last_program_name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ tng_data->last_program_name[0] = 0;
+ }
+ if(!tng_data->first_user_name)
+ {
+ tng_data->first_user_name = malloc(1);
+ if(!tng_data->first_user_name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ tng_data->first_user_name[0] = 0;
+ }
+ if(!tng_data->last_user_name)
+ {
+ tng_data->last_user_name = malloc(1);
+ if(!tng_data->last_user_name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ tng_data->last_user_name[0] = 0;
+ }
+ if(!tng_data->first_computer_name)
+ {
+ tng_data->first_computer_name = malloc(1);
+ if(!tng_data->first_computer_name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ tng_data->first_computer_name[0] = 0;
+ }
+ if(!tng_data->last_computer_name)
+ {
+ tng_data->last_computer_name = malloc(1);
+ if(!tng_data->last_computer_name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ tng_data->last_computer_name[0] = 0;
+ }
+ if(!tng_data->first_pgp_signature)
+ {
+ tng_data->first_pgp_signature = malloc(1);
+ if(!tng_data->first_pgp_signature)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ tng_data->first_pgp_signature[0] = 0;
+ }
+ if(!tng_data->last_pgp_signature)
+ {
+ tng_data->last_pgp_signature = malloc(1);
+ if(!tng_data->last_pgp_signature)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ tng_data->last_pgp_signature[0] = 0;
+ }
+ if(!tng_data->forcefield_name)
+ {
+ tng_data->forcefield_name = malloc(1);
+ if(!tng_data->forcefield_name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ tng_data->forcefield_name[0] = 0;
+ }
+
+ tng_block_init(&block);
+
+ name_len = (int)strlen("GENERAL INFO");
+
+ block->name = malloc(name_len + 1);
+ if(!block->name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
+ name_len+1, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ strcpy(block->name, "GENERAL INFO");
+ block->id = TNG_GENERAL_INFO;
+
+ first_program_name_len = tng_min_i((int)strlen(tng_data->first_program_name) + 1,
+ TNG_MAX_STR_LEN);
+ last_program_name_len = tng_min_i((int)strlen(tng_data->last_program_name) + 1,
+ TNG_MAX_STR_LEN);
+ first_user_name_len = tng_min_i((int)strlen(tng_data->first_user_name) + 1,
+ TNG_MAX_STR_LEN);
+ last_user_name_len = tng_min_i((int)strlen(tng_data->last_user_name) + 1,
+ TNG_MAX_STR_LEN);
+ first_computer_name_len = tng_min_i((int)strlen(tng_data->first_computer_name) + 1,
+ TNG_MAX_STR_LEN);
+ last_computer_name_len = tng_min_i((int)strlen(tng_data->last_computer_name) + 1,
+ TNG_MAX_STR_LEN);
+ first_pgp_signature_len = tng_min_i((int)strlen(tng_data->first_pgp_signature) + 1,
+ TNG_MAX_STR_LEN);
+ last_pgp_signature_len = tng_min_i((int)strlen(tng_data->last_pgp_signature) + 1,
+ TNG_MAX_STR_LEN);
+ forcefield_name_len = tng_min_i((int)strlen(tng_data->forcefield_name) + 1,
+ TNG_MAX_STR_LEN);
+
+ block->block_contents_size = sizeof(tng_data->time) +
+ sizeof(tng_data->var_num_atoms_flag) +
+ sizeof(tng_data->frame_set_n_frames) +
+ sizeof(tng_data->first_trajectory_frame_set_input_file_pos) +
+ sizeof(tng_data->last_trajectory_frame_set_input_file_pos) +
+ sizeof(tng_data->medium_stride_length) +
+ sizeof(tng_data->long_stride_length) +
+ sizeof(tng_data->distance_unit_exponential) +
+ first_program_name_len +
+ last_program_name_len +
+ first_user_name_len +
+ last_user_name_len +
+ first_computer_name_len +
+ last_computer_name_len +
+ first_pgp_signature_len +
+ last_pgp_signature_len +
+ forcefield_name_len;
+
+ if(block->block_contents)
+ {
+ free(block->block_contents);
+ }
+ block->block_contents = malloc(block->block_contents_size);
+ if(!block->block_contents)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ block->block_contents_size, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ strncpy(block->block_contents, tng_data->first_program_name, first_program_name_len);
+ offset += first_program_name_len;
+
+ strncpy(block->block_contents+offset, tng_data->last_program_name, last_program_name_len);
+ offset += last_program_name_len;
+
+ strncpy(block->block_contents+offset, tng_data->first_user_name, first_user_name_len);
+ offset += first_user_name_len;
+
+ strncpy(block->block_contents+offset, tng_data->last_user_name, last_user_name_len);
+ offset += last_user_name_len;
+
+ strncpy(block->block_contents+offset, tng_data->first_computer_name,
+ first_computer_name_len);
+ offset += first_computer_name_len;
+
+ strncpy(block->block_contents+offset, tng_data->last_computer_name,
+ last_computer_name_len);
+ offset += last_computer_name_len;
+
+ strncpy(block->block_contents+offset, tng_data->first_pgp_signature,
+ first_pgp_signature_len);
+ offset += first_pgp_signature_len;
+
+ strncpy(block->block_contents+offset, tng_data->last_pgp_signature,
+ last_pgp_signature_len);
+ offset += last_pgp_signature_len;
+
+ strncpy(block->block_contents+offset, tng_data->forcefield_name,
+ forcefield_name_len);
+ offset += forcefield_name_len;
+
+ memcpy(block->block_contents+offset, &tng_data->time,
+ sizeof(tng_data->time));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(tng_data->time);
+
+ memcpy(block->block_contents+offset, &tng_data->var_num_atoms_flag,
+ sizeof(tng_data->var_num_atoms_flag));
+ offset += sizeof(tng_data->var_num_atoms_flag);
+
+ memcpy(block->block_contents+offset, &tng_data->frame_set_n_frames,
+ sizeof(tng_data->frame_set_n_frames));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(tng_data->frame_set_n_frames);
+
+ memcpy(block->block_contents+offset,
+ &tng_data->first_trajectory_frame_set_input_file_pos,
+ sizeof(tng_data->first_trajectory_frame_set_input_file_pos));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(tng_data->first_trajectory_frame_set_input_file_pos);
+
+ memcpy(block->block_contents+offset,
+ &tng_data->last_trajectory_frame_set_input_file_pos,
+ sizeof(tng_data->last_trajectory_frame_set_input_file_pos));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(tng_data->last_trajectory_frame_set_input_file_pos);
+
+ memcpy(block->block_contents+offset, &tng_data->medium_stride_length,
+ sizeof(tng_data->medium_stride_length));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(tng_data->medium_stride_length);
+
+ memcpy(block->block_contents+offset, &tng_data->long_stride_length,
+ sizeof(tng_data->long_stride_length));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(tng_data->long_stride_length);
+
+ memcpy(block->block_contents+offset, &tng_data->distance_unit_exponential,
+ sizeof(tng_data->distance_unit_exponential));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+
+ if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
+ tng_data->output_file_path, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(fwrite(block->block_contents, block->block_contents_size, 1,
+ tng_data->output_file) != 1)
+ {
+ fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ tng_block_destroy(&block);
+
+ return(TNG_SUCCESS);
+}
+
+/** Read the chain data of a molecules block.
+ * @param tng_data is a trajectory data container.
+ * @param block is a general block container.
+ * @param chain is the chain data container.
+ * @param offset is the offset of the block input and is updated when reading.
+ * @return TNG_SUCCESS(0) is successful.
+ */
+static tng_function_status tng_chain_data_read(tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ tng_chain_t chain,
+ int *offset)
+{
+ int len;
+
+ TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
+
+ memcpy(&chain->id, block->block_contents+*offset,
+ sizeof(chain->id));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &chain->id)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ *offset += sizeof(chain->id);
+
+ len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
+ TNG_MAX_STR_LEN);
+ chain->name = malloc(len);
+ strncpy(chain->name,
+ block->block_contents+*offset, len);
+ *offset += len;
+
+ memcpy(&chain->n_residues, block->block_contents+*offset,
+ sizeof(chain->n_residues));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &chain->n_residues)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ *offset += sizeof(chain->n_residues);
+
+ return(TNG_SUCCESS);
+}
+
+/** Write the chain data of a molecules block.
+ * @param tng_data is a trajectory data container.
+ * @param block is a general block container.
+ * @param chain is the chain data container.
+ * @param offset is the offset of the block output and is updated when writing.
+ * @return TNG_SUCCESS(0) is successful.
+ */
+static tng_function_status tng_chain_data_write(tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ tng_chain_t chain,
+ int *offset)
+{
+ int len;
+
+ TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
+
+ memcpy(block->block_contents+*offset, &chain->id, sizeof(chain->id));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+*offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ *offset += sizeof(chain->id);
+
+ len = tng_min_i((int)strlen(chain->name) + 1, TNG_MAX_STR_LEN);
+ strncpy(block->block_contents + *offset, chain->name, len);
+ *offset += len;
+
+ memcpy(block->block_contents+*offset, &chain->n_residues,
+ sizeof(chain->n_residues));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+*offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ *offset += sizeof(chain->n_residues);
+
+ return(TNG_SUCCESS);
+}
+
+/** Read the residue data of a molecules block.
+ * @param tng_data is a trajectory data container.
+ * @param block is a general block container.
+ * @param residue is the residue data container.
+ * @param offset is the offset of the block input and is updated when reading.
+ * @return TNG_SUCCESS(0) is successful.
+ */
+static tng_function_status tng_residue_data_read(tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ tng_residue_t residue,
+ int *offset)
+{
+ int len;
+
+ TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
+
+ memcpy(&residue->id, block->block_contents+*offset,
+ sizeof(residue->id));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &residue->id)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ *offset += sizeof(residue->id);
+
+ len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
+ TNG_MAX_STR_LEN);
+ residue->name = malloc(len);
+ strncpy(residue->name,
+ block->block_contents+*offset, len);
+ *offset += len;
+
+ memcpy(&residue->n_atoms, block->block_contents+*offset,
+ sizeof(residue->n_atoms));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &residue->n_atoms)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ *offset += sizeof(residue->n_atoms);
+
+ return(TNG_SUCCESS);
+}
+
+/** Write the residue data of a molecules block.
+ * @param tng_data is a trajectory data container.
+ * @param block is a general block container.
+ * @param residue is the residue data container.
+ * @param offset is the offset of the block output and is updated when writing.
+ * @return TNG_SUCCESS(0) is successful.
+ */
+static tng_function_status tng_residue_data_write(tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ tng_residue_t residue,
+ int *offset)
+{
+ int len;
+
+ TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
+
+ memcpy(block->block_contents+*offset, &residue->id, sizeof(residue->id));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+*offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ *offset += sizeof(residue->id);
+
+ len = tng_min_i((int)strlen(residue->name) + 1, TNG_MAX_STR_LEN);
+ strncpy(block->block_contents + *offset, residue->name, len);
+ *offset += len;
+
+ memcpy(block->block_contents+*offset, &residue->n_atoms,
+ sizeof(residue->n_atoms));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+*offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ *offset += sizeof(residue->n_atoms);
+
+ return(TNG_SUCCESS);
+}
+
+/** Read the atom data of a molecules block.
+ * @param tng_data is a trajectory data container.
+ * @param block is a general block container.
+ * @param atom is the atom data container.
+ * @param offset is the offset of the block input and is updated when reading.
+ * @return TNG_SUCCESS(0) is successful.
+ */
+static tng_function_status tng_atom_data_read(tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ tng_atom_t atom,
+ int *offset)
+{
+ int len;
+
+ TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
+
+ memcpy(&atom->id, block->block_contents+*offset,
+ sizeof(atom->id));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &atom->id)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ *offset += sizeof(atom->id);
+
+ len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
+ TNG_MAX_STR_LEN);
+ atom->name = malloc(len);
+ strncpy(atom->name,
+ block->block_contents+*offset, len);
+ *offset += len;
+
+ len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
+ TNG_MAX_STR_LEN);
+ atom->atom_type = malloc(len);
+ strncpy(atom->atom_type,
+ block->block_contents+*offset, len);
+ *offset += len;
+
+ return(TNG_SUCCESS);
+}
+
+/** Write the atom data of a molecules block.
+ * @param tng_data is a trajectory data container.
+ * @param block is a general block container.
+ * @param atom is the atom data container.
+ * @param offset is the offset of the block output and is updated when writing.
+ * @return TNG_SUCCESS(0) is successful.
+ */
+static tng_function_status tng_atom_data_write(tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ tng_atom_t atom,
+ int *offset)
+{
+ int len;
+
+ TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
+
+ memcpy(block->block_contents+*offset, &atom->id,
+ sizeof(atom->id));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+*offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ *offset += sizeof(atom->id);
+
+ len = tng_min_i((int)strlen(atom->name) + 1, TNG_MAX_STR_LEN);
+ strncpy(block->block_contents + *offset, atom->name, len);
+ *offset += len;
+
+ len = tng_min_i((int)strlen(atom->atom_type) + 1, TNG_MAX_STR_LEN);
+ strncpy(block->block_contents + *offset, atom->atom_type, len);
+ *offset += len;
+
+ return(TNG_SUCCESS);
+}
+
+/** Read a molecules block. Contains chain, residue and atom data
+ * @param tng_data is a trajectory data container.
+ * @param block is a general block container.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_molecules_block_read
+ (tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ const char hash_mode)
+{
+ int64_t i, j, k, l;
+ int len, offset = 0;
+ tng_molecule_t molecule;
+ tng_chain_t chain;
+ tng_residue_t residue;
+ tng_atom_t atom;
+ tng_bond_t bond;
+ tng_bool same_hash;
+
+ if(tng_input_file_init(tng_data) != TNG_SUCCESS)
+ {
+ return(TNG_CRITICAL);
+ }
+
+ if(block->block_contents)
+ {
+ free(block->block_contents);
+ }
+
+ block->block_contents = malloc(block->block_contents_size);
+ if(!block->block_contents)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ block->block_contents_size, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ /* Read the whole block into block_contents to be able to write it to disk
+ * even if it cannot be interpreted. */
+ if(fread(block->block_contents, block->block_contents_size, 1,
+ tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
+ }
+
+ /* FIXME: Does not check if the size of the contents matches the expected
+ * size or if the contents can be read. */
+
+ if(hash_mode == TNG_USE_HASH)
+ {
+ tng_md5_hash_match_verify(block, &same_hash);
+ if(same_hash != TNG_TRUE)
+ {
+ fprintf(stderr, "TNG library: Molecules block contents corrupt. Hashes do not match. "
+ "%s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+
+ if(tng_data->molecules)
+ {
+ for(i=tng_data->n_molecules; i--;)
+ {
+ tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
+ }
+ free(tng_data->molecules);
+ tng_data->molecules = 0;
+ tng_data->n_molecules = 0;
+ }
+
+ memcpy(&tng_data->n_molecules, block->block_contents,
+ sizeof(tng_data->n_molecules));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &tng_data->n_molecules)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(tng_data->n_molecules);
+
+ if(tng_data->molecules)
+ {
+ free(tng_data->molecules);
+ }
+
+ tng_data->n_particles = 0;
+
+ tng_data->molecules = malloc(tng_data->n_molecules *
+ sizeof(struct tng_molecule));
+ if(!tng_data->molecules)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ tng_data->n_molecules * sizeof(struct tng_molecule),
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ if(!tng_data->var_num_atoms_flag)
+ {
+ if(tng_data->molecule_cnt_list)
+ {
+ free(tng_data->molecule_cnt_list);
+ }
+ tng_data->molecule_cnt_list = malloc(sizeof(int64_t) *
+ tng_data->n_molecules);
+ if(!tng_data->molecule_cnt_list)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ tng_data->n_molecules * sizeof(struct tng_molecule),
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ }
+
+ /* Read each molecule from file */
+ for(i=0; i < tng_data->n_molecules; i++)
+ {
+ molecule = &tng_data->molecules[i];
+
+ memcpy(&molecule->id, block->block_contents+offset,
+ sizeof(molecule->id));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &molecule->id)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(molecule->id);
+
+/* fprintf(stderr, "TNG library: Read id: %"PRId64" offset: %d\n", molecule->id, offset);*/
+ len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
+ molecule->name = malloc(len);
+ strncpy(molecule->name, block->block_contents+offset, len);
+ offset += len;
+
+ memcpy(&molecule->quaternary_str, block->block_contents+offset,
+ sizeof(molecule->quaternary_str));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &molecule->quaternary_str)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(molecule->quaternary_str);
+
+ if(!tng_data->var_num_atoms_flag)
+ {
+ memcpy(&tng_data->molecule_cnt_list[i],
+ block->block_contents+offset,
+ sizeof(int64_t));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &tng_data->molecule_cnt_list[i])
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(int64_t);
+ }
+
+
+ memcpy(&molecule->n_chains, block->block_contents+offset,
+ sizeof(molecule->n_chains));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &molecule->n_chains)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(molecule->n_chains);
+
+ memcpy(&molecule->n_residues, block->block_contents+offset,
+ sizeof(molecule->n_residues));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &molecule->n_residues)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(molecule->n_residues);
+
+ memcpy(&molecule->n_atoms, block->block_contents+offset,
+ sizeof(molecule->n_atoms));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &molecule->n_atoms)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(molecule->n_atoms);
+
+ tng_data->n_particles += molecule->n_atoms *
+ tng_data->molecule_cnt_list[i];
+
+ if(molecule->n_chains > 0)
+ {
+ molecule->chains = malloc(molecule->n_chains *
+ sizeof(struct tng_chain));
+ if(!molecule->chains)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ molecule->n_chains * sizeof(struct tng_chain),
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ chain = molecule->chains;
+ }
+ else
+ {
+ chain = 0;
+ }
+
+ if(molecule->n_residues > 0)
+ {
+ molecule->residues = malloc(molecule->n_residues *
+ sizeof(struct tng_residue));
+ if(!molecule->residues)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ molecule->n_residues * sizeof(struct tng_residue),
+ __FILE__, __LINE__);
+ if(molecule->chains)
+ {
+ free(molecule->chains);
+ molecule->chains = 0;
+ }
+ return(TNG_CRITICAL);
+ }
+
+ residue = molecule->residues;
+ }
+ else
+ {
+ residue = 0;
+ }
+
+ molecule->atoms = malloc(molecule->n_atoms *
+ sizeof(struct tng_atom));
+ if(!molecule->atoms)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ molecule->n_atoms * sizeof(struct tng_atom),
+ __FILE__, __LINE__);
+ if(molecule->chains)
+ {
+ free(molecule->chains);
+ molecule->chains = 0;
+ }
+ if(molecule->residues)
+ {
+ free(molecule->residues);
+ molecule->residues = 0;
+ }
+ return(TNG_CRITICAL);
+ }
+
+ atom = molecule->atoms;
+
+ if(molecule->n_chains > 0)
+ {
+ /* Read the chains of the molecule */
+ for(j=molecule->n_chains; j--;)
+ {
+ chain->molecule = molecule;
+
+ tng_chain_data_read(tng_data, block, chain, &offset);
+
+ chain->residues = molecule->residues;
+ residue = chain->residues;
+
+ /* Read the residues of the chain */
+ for(k=chain->n_residues; k--;)
+ {
+ residue->chain = chain;
+
+ tng_residue_data_read(tng_data, block, residue, &offset);
+
+ residue->atoms_offset = atom - molecule->atoms;
+ /* Read the atoms of the residue */
+ for(l=residue->n_atoms; l--;)
+ {
+ atom->residue = residue;
+
+ tng_atom_data_read(tng_data, block, atom, &offset);
+
+ atom++;
+ }
+ residue++;
+ }
+ chain++;
+ }
+ }
+ else
+ {
+ if(molecule->n_residues > 0)
+ {
+ for(k=molecule->n_residues; k--;)
+ {
+ residue->chain = 0;
+
+ tng_residue_data_read(tng_data, block, residue, &offset);
+
+ residue->atoms_offset = atom - molecule->atoms;
+ /* Read the atoms of the residue */
+ for(l=residue->n_atoms; l--;)
+ {
+ atom->residue = residue;
+
+ tng_atom_data_read(tng_data, block, atom, &offset);
+
+ atom++;
+ }
+ residue++;
+ }
+ }
+ else
+ {
+ for(l=molecule->n_atoms; l--;)
+ {
+ atom->residue = 0;
+
+ tng_atom_data_read(tng_data, block, atom, &offset);
+
+ atom++;
+ }
+ }
+ }
+
+ memcpy(&molecule->n_bonds, block->block_contents+offset,
+ sizeof(molecule->n_bonds));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &molecule->n_bonds)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(molecule->n_bonds);
+
+ if(molecule->n_bonds > 0)
+ {
+ tng_data->molecules[i].bonds = malloc(molecule->n_bonds *
+ sizeof(struct tng_bond));
+ if(!molecule->bonds)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ molecule->n_bonds * sizeof(struct tng_bond),
+ __FILE__, __LINE__);
+ if(molecule->chains)
+ {
+ free(molecule->chains);
+ molecule->chains = 0;
+ }
+ if(molecule->residues)
+ {
+ free(molecule->residues);
+ molecule->residues = 0;
+ }
+ if(molecule->atoms)
+ {
+ free(molecule->atoms);
+ molecule->atoms = 0;
+ }
+ return(TNG_CRITICAL);
+ }
+
+ bond = molecule->bonds;
+
+ for(j=molecule->n_bonds; j--;)
+ {
+ memcpy(&bond->from_atom_id, block->block_contents+offset,
+ sizeof(bond->from_atom_id));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &bond->from_atom_id)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(bond->from_atom_id);
+
+ memcpy(&bond->to_atom_id, block->block_contents+offset,
+ sizeof(bond->to_atom_id));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &bond->to_atom_id)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(bond->to_atom_id);
+
+ bond++;
+ }
+ }
+ else
+ {
+ molecule->bonds = 0;
+ }
+ }
+
+ return(TNG_SUCCESS);
+}
+
+/** Write a molecules block.
+ * @param tng_data is a trajectory data container.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_molecules_block_write
+ (tng_trajectory_t tng_data,
+ const char hash_mode)
+{
+ int len = 0, name_len, offset = 0;
+ int64_t i, j, k, l;
+ tng_molecule_t molecule;
+ tng_chain_t chain;
+ tng_residue_t residue;
+ tng_atom_t atom;
+ tng_bond_t bond;
+ tng_gen_block_t block;
+
+ if(tng_output_file_init(tng_data) != TNG_SUCCESS)
+ {
+ return(TNG_CRITICAL);
+ }
+
+ /* First predict the size of the block */
+ for(i = 0; i < tng_data->n_molecules; i++)
+ {
+ molecule = &tng_data->molecules[i];
+ if(!molecule->name)
+ {
+ molecule->name = malloc(1);
+ if(!molecule->name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ molecule->name[0] = 0;
+ }
+ len += tng_min_i((int)strlen(molecule->name) + 1, TNG_MAX_STR_LEN);
+
+ chain = molecule->chains;
+ for(j = molecule->n_chains; j--;)
+ {
+ len += sizeof(chain->id);
+
+ if(!chain->name)
+ {
+ chain->name = malloc(1);
+ if(!chain->name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ chain->name[0] = 0;
+ }
+ len += tng_min_i((int)strlen(chain->name) + 1, TNG_MAX_STR_LEN);
+
+ len += sizeof(chain->n_residues);
+
+ chain++;
+ }
+
+ residue = molecule->residues;
+ for(j = molecule->n_residues; j--;)
+ {
+ len += sizeof(residue->id);
+
+ if(!residue->name)
+ {
+ residue->name = malloc(1);
+ if(!residue->name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ residue->name[0] = 0;
+ }
+ len += tng_min_i((int)strlen(residue->name) + 1, TNG_MAX_STR_LEN);
+
+ len += sizeof(residue->n_atoms);
+
+ residue++;
+ }
+
+ atom = molecule->atoms;
+ for(j = molecule->n_atoms; j--;)
+ {
+ len += sizeof(atom->id);
+ if(!atom->name)
+ {
+ atom->name = malloc(1);
+ if(!atom->name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ atom->name[0] = 0;
+ }
+ len += tng_min_i((int)strlen(atom->name) + 1, TNG_MAX_STR_LEN);
+
+ if(!atom->atom_type)
+ {
+ atom->atom_type = malloc(1);
+ if(!atom->atom_type)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ atom->atom_type[0] = 0;
+ }
+ len += tng_min_i((int)strlen(atom->atom_type) + 1, TNG_MAX_STR_LEN);
+
+ atom++;
+ }
+
+ for(j = molecule->n_bonds; j--;)
+ {
+ len += sizeof(bond->from_atom_id) + sizeof(bond->to_atom_id);
+ }
+ }
+
+ tng_block_init(&block);
+
+ name_len = (int)strlen("MOLECULES");
+
+ block->name = malloc(name_len + 1);
+ if(!block->name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
+ name_len+1, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ strcpy(block->name, "MOLECULES");
+ block->id = TNG_MOLECULES;
+
+ block->block_contents_size = sizeof(tng_data->n_molecules) +
+ (sizeof(molecule->id) +
+ sizeof(molecule->quaternary_str) +
+ sizeof(molecule->n_chains) +
+ sizeof(molecule->n_residues) +
+ sizeof(molecule->n_atoms) +
+ sizeof(molecule->n_bonds)) *
+ tng_data->n_molecules +
+ len;
+
+ if(!tng_data->var_num_atoms_flag)
+ {
+ block->block_contents_size += tng_data->n_molecules * sizeof(int64_t);
+ }
+
+ block->block_contents = malloc(block->block_contents_size);
+ if(!block->block_contents)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ block->block_contents_size, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ memcpy(block->block_contents+offset, &tng_data->n_molecules,
+ sizeof(tng_data->n_molecules));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(tng_data->n_molecules);
+
+ for(i = 0; i < tng_data->n_molecules; i++)
+ {
+ molecule = &tng_data->molecules[i];
+ memcpy(block->block_contents+offset, &molecule->id,
+ sizeof(molecule->id));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(molecule->id);
+
+/* fprintf(stderr, "TNG library: Wrote id: %"PRId64" offset: %d\n", molecule->id, offset); */
+ len = tng_min_i((int)strlen(molecule->name) + 1, TNG_MAX_STR_LEN);
+ strncpy(block->block_contents + offset, molecule->name, len);
+ offset += len;
+
+ memcpy(block->block_contents+offset, &molecule->quaternary_str,
+ sizeof(molecule->quaternary_str));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(molecule->quaternary_str);
+
+ if(!tng_data->var_num_atoms_flag)
+ {
+ memcpy(block->block_contents+offset,
+ &tng_data->molecule_cnt_list[i], sizeof(int64_t));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(int64_t);
+ }
+
+ memcpy(block->block_contents+offset, &molecule->n_chains,
+ sizeof(molecule->n_chains));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(molecule->n_chains);
+
+ memcpy(block->block_contents+offset, &molecule->n_residues,
+ sizeof(molecule->n_residues));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(molecule->n_residues);
+
+ memcpy(block->block_contents+offset, &molecule->n_atoms,
+ sizeof(molecule->n_atoms));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(molecule->n_atoms);
+
+ if(molecule->n_chains > 0)
+ {
+ chain = molecule->chains;
+ for(j = molecule->n_chains; j--;)
+ {
+ tng_chain_data_write(tng_data, block, chain, &offset);
+
+ residue = chain->residues;
+ for(k = chain->n_residues; k--;)
+ {
+ tng_residue_data_write(tng_data, block, residue, &offset);
+
+ atom = molecule->atoms + residue->atoms_offset;
+ for(l = residue->n_atoms; l--;)
+ {
+ tng_atom_data_write(tng_data, block, atom, &offset);
+
+ atom++;
+ }
+ residue++;
+ }
+ chain++;
+ }
+ }
+ else
+ {
+ if(molecule->n_residues > 0)
+ {
+ residue = molecule->residues;
+ for(k = molecule->n_residues; k--;)
+ {
+ tng_residue_data_write(tng_data, block, residue, &offset);
+
+ atom = molecule->atoms + residue->atoms_offset;
+ for(l = residue->n_atoms; l--;)
+ {
+ tng_atom_data_write(tng_data, block, atom, &offset);
+
+ atom++;
+ }
+ residue++;
+ }
+ }
+ else
+ {
+ atom = molecule->atoms;
+ for(l = molecule->n_atoms; l--;)
+ {
+ tng_atom_data_write(tng_data, block, atom, &offset);
+
+ atom++;
+ }
+ }
+ }
+
+ memcpy(block->block_contents+offset, &molecule->n_bonds,
+ sizeof(molecule->n_bonds));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(molecule->n_bonds);
+
+ bond = molecule->bonds;
+ for(j = molecule->n_bonds; j--;)
+ {
+ memcpy(block->block_contents+offset, &bond->from_atom_id,
+ sizeof(bond->from_atom_id));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(bond->from_atom_id);
+
+ memcpy(block->block_contents+offset, &bond->to_atom_id,
+ sizeof(bond->to_atom_id));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(bond->to_atom_id);
+
+ bond++;
+ }
+ }
+
+ if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
+ tng_data->output_file_path, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(fwrite(block->block_contents, block->block_contents_size, 1,
+ tng_data->output_file) != 1)
+ {
+ fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
+ __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ tng_block_destroy(&block);
+
+ return(TNG_SUCCESS);
+}
+
+/** Read a frame set block. Update tng_data->current_trajectory_frame_set
+ * @param tng_data is a trajectory data container.
+ * @param block is a general block container.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_frame_set_block_read
+ (tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ const char hash_mode)
+{
+ long file_pos;
+ int offset = 0;
+ int64_t i, prev_n_particles;
+ tng_bool same_hash;
+ tng_trajectory_frame_set_t frame_set =
+ &tng_data->current_trajectory_frame_set;
+
+ if(tng_input_file_init(tng_data) != TNG_SUCCESS)
+ {
+ return(TNG_CRITICAL);
+ }
+
+ if(block->block_contents)
+ {
+ free(block->block_contents);
+ }
+
+ block->block_contents = malloc(block->block_contents_size);
+ if(!block->block_contents)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ block->block_contents_size, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ /* Read the whole block into block_contents to be able to write it to
+ * disk even if it cannot be interpreted. */
+ if(fread(block->block_contents, block->block_contents_size, 1,
+ tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ /* FIXME: Does not check if the size of the contents matches the expected
+ * size or if the contents can be read. */
+
+ file_pos = (int64_t)ftell(tng_data->input_file) -
+ (long)(block->block_contents_size + block->header_contents_size);
+
+ if(hash_mode == TNG_USE_HASH)
+ {
+ tng_md5_hash_match_verify(block, &same_hash);
+ if(same_hash != TNG_TRUE)
+ {
+ fprintf(stderr, "TNG library: Frame set block contents corrupt. File pos %ld Hashes do not match. "
+ "%s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ /* return(TNG_FAILURE); */
+ }
+ }
+
+ tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
+
+ tng_frame_set_particle_mapping_free(tng_data);
+
+ if(tng_data->first_trajectory_frame_set_input_file_pos <= 0)
+ {
+ tng_data->first_trajectory_frame_set_input_file_pos = file_pos;
+ }
+ /* FIXME: Should check the frame number instead of the file_pos, in case
+ * frame sets are not in order */
+ if(tng_data->last_trajectory_frame_set_input_file_pos < file_pos)
+ {
+ tng_data->last_trajectory_frame_set_input_file_pos = file_pos;
+ }
+
+ memcpy(&frame_set->first_frame, block->block_contents,
+ sizeof(frame_set->first_frame));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &frame_set->first_frame)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(frame_set->first_frame);
+
+ memcpy(&frame_set->n_frames, block->block_contents + offset,
+ sizeof(frame_set->n_frames));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &frame_set->n_frames)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(frame_set->n_frames);
+
+ if(tng_data->var_num_atoms_flag)
+ {
+ prev_n_particles = frame_set->n_particles;
+ frame_set->n_particles = 0;
+ /* If the list of molecule counts has already been created assume that
+ * it is of correct size. */
+ if(!frame_set->molecule_cnt_list)
+ {
+ frame_set->molecule_cnt_list =
+ malloc(sizeof(int64_t) * tng_data->n_molecules);
+
+ if(!frame_set->molecule_cnt_list)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(int64_t) * tng_data->n_molecules,
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ }
+ for(i = 0; i < tng_data->n_molecules; i++)
+ {
+ memcpy(&frame_set->molecule_cnt_list[i],
+ block->block_contents + offset,
+ sizeof(int64_t));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &frame_set->molecule_cnt_list[i])
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(int64_t);
+ frame_set->n_particles += tng_data->molecules[i].n_atoms *
+ frame_set->molecule_cnt_list[i];
+ }
+ if(prev_n_particles && frame_set->n_particles != prev_n_particles)
+ {
+ /* FIXME: Particle dependent data memory management */
+ }
+ }
+
+ memcpy(&frame_set->next_frame_set_file_pos,
+ block->block_contents + offset,
+ sizeof(frame_set->next_frame_set_file_pos));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &frame_set->next_frame_set_file_pos)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(frame_set->next_frame_set_file_pos);
+
+ memcpy(&frame_set->prev_frame_set_file_pos,
+ block->block_contents + offset,
+ sizeof(frame_set->prev_frame_set_file_pos));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &frame_set->prev_frame_set_file_pos)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(frame_set->prev_frame_set_file_pos);
+
+ memcpy(&frame_set->medium_stride_next_frame_set_file_pos,
+ block->block_contents + offset,
+ sizeof(frame_set->medium_stride_next_frame_set_file_pos));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &frame_set->medium_stride_next_frame_set_file_pos)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(frame_set->medium_stride_next_frame_set_file_pos);
+
+ memcpy(&frame_set->medium_stride_prev_frame_set_file_pos,
+ block->block_contents + offset,
+ sizeof(frame_set->medium_stride_prev_frame_set_file_pos));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &frame_set->medium_stride_prev_frame_set_file_pos)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(frame_set->medium_stride_prev_frame_set_file_pos);
+
+ memcpy(&frame_set->long_stride_next_frame_set_file_pos,
+ block->block_contents + offset,
+ sizeof(frame_set->long_stride_next_frame_set_file_pos));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &frame_set->long_stride_next_frame_set_file_pos)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(frame_set->long_stride_next_frame_set_file_pos);
+
+ memcpy(&frame_set->long_stride_prev_frame_set_file_pos,
+ block->block_contents + offset,
+ sizeof(frame_set->long_stride_prev_frame_set_file_pos));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &frame_set->long_stride_prev_frame_set_file_pos)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(frame_set->long_stride_prev_frame_set_file_pos);
+
+ if(block->block_version >= 3)
+ {
+ memcpy(&frame_set->first_frame_time,
+ block->block_contents + offset,
+ sizeof(frame_set->first_frame_time));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ (int64_t *)&frame_set->first_frame_time)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(frame_set->first_frame_time);
+
+ memcpy(&tng_data->time_per_frame,
+ block->block_contents + offset,
+ sizeof(tng_data->time_per_frame));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ (int64_t *)&tng_data->time_per_frame)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ }
+ else
+ {
+ frame_set->first_frame_time = -1;
+ tng_data->time_per_frame = -1;
+ }
+
+ frame_set->n_written_frames = frame_set->n_frames;
+
+ return(TNG_SUCCESS);
+}
+
+/** Write tng_data->current_trajectory_frame_set to file
+ * @param tng_data is a trajectory data container.
+ * @param block is a general block container.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_frame_set_block_write
+ (tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ const char hash_mode)
+{
+ char *temp_name;
+ int64_t i;
+ int offset = 0;
+ unsigned int name_len;
+ tng_trajectory_frame_set_t frame_set =
+ &tng_data->current_trajectory_frame_set;
+
+ if(tng_output_file_init(tng_data) != TNG_SUCCESS)
+ {
+ return(TNG_CRITICAL);
+ }
+
+ name_len = (int)strlen("TRAJECTORY FRAME SET");
+
+ if(!block->name || strlen(block->name) < name_len)
+ {
+ temp_name = realloc(block->name, name_len + 1);
+ if(!temp_name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
+ name_len+1, __FILE__, __LINE__);
+ free(block->name);
+ block->name = 0;
+ return(TNG_CRITICAL);
+ }
+ block->name = temp_name;
+ }
+ strcpy(block->name, "TRAJECTORY FRAME SET");
+ block->id = TNG_TRAJECTORY_FRAME_SET;
+
+ block->block_contents_size = sizeof(int64_t) * 8;
+ block->block_contents_size += sizeof(double) * 2;
+
+ if(tng_data->var_num_atoms_flag)
+ {
+ block->block_contents_size += sizeof(int64_t) * tng_data->n_molecules;
+ }
+
+ if(block->block_contents)
+ {
+ free(block->block_contents);
+ }
+ block->block_contents = malloc(block->block_contents_size);
+ if(!block->block_contents)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ block->block_contents_size, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ memcpy(block->block_contents, &frame_set->first_frame,
+ sizeof(frame_set->first_frame));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(frame_set->first_frame);
+
+ memcpy(block->block_contents+offset, &frame_set->n_frames,
+ sizeof(frame_set->n_frames));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(frame_set->n_frames);
+
+ if(tng_data->var_num_atoms_flag)
+ {
+ for(i = 0; i < tng_data->n_molecules; i++)
+ {
+ memcpy(block->block_contents+offset,
+ &frame_set->molecule_cnt_list[i],
+ sizeof(int64_t));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(int64_t);
+ }
+ }
+
+
+ memcpy(block->block_contents+offset, &frame_set->next_frame_set_file_pos,
+ sizeof(frame_set->next_frame_set_file_pos));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(frame_set->next_frame_set_file_pos);
+
+ memcpy(block->block_contents+offset, &frame_set->prev_frame_set_file_pos,
+ sizeof(frame_set->prev_frame_set_file_pos));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(frame_set->prev_frame_set_file_pos);
+
+ memcpy(block->block_contents+offset,
+ &frame_set->medium_stride_next_frame_set_file_pos,
+ sizeof(frame_set->medium_stride_next_frame_set_file_pos));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(frame_set->medium_stride_next_frame_set_file_pos);
+
+ memcpy(block->block_contents+offset,
+ &frame_set->medium_stride_prev_frame_set_file_pos,
+ sizeof(frame_set->medium_stride_prev_frame_set_file_pos));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(frame_set->medium_stride_prev_frame_set_file_pos);
+
+ memcpy(block->block_contents+offset,
+ &frame_set->long_stride_next_frame_set_file_pos,
+ sizeof(frame_set->long_stride_next_frame_set_file_pos));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(frame_set->long_stride_next_frame_set_file_pos);
+
+ memcpy(block->block_contents+offset,
+ &frame_set->long_stride_prev_frame_set_file_pos,
+ sizeof(frame_set->long_stride_prev_frame_set_file_pos));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(frame_set->long_stride_prev_frame_set_file_pos);
+
+ memcpy(block->block_contents+offset,
+ &frame_set->first_frame_time,
+ sizeof(frame_set->first_frame_time));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(frame_set->first_frame_time);
+
+ memcpy(block->block_contents+offset,
+ &tng_data->time_per_frame,
+ sizeof(tng_data->time_per_frame));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+
+ if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
+ tng_data->output_file_path, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ if(fwrite(block->block_contents, block->block_contents_size, 1,
+ tng_data->output_file) != 1)
+ {
+ fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ return(TNG_SUCCESS);
+}
+
+
+/** Read an atom mappings block (translating between real atom indexes and how
+ * the atom info is written in this frame set).
+ * @param tng_data is a trajectory data container.
+ * @param block is a general block container.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_trajectory_mapping_block_read
+ (tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ const char hash_mode)
+{
+ int64_t i;
+ int offset = 0;
+ tng_bool same_hash;
+ tng_trajectory_frame_set_t frame_set =
+ &tng_data->current_trajectory_frame_set;
+
+ tng_particle_mapping_t mapping, mappings;
+
+ if(tng_input_file_init(tng_data) != TNG_SUCCESS)
+ {
+ return(TNG_CRITICAL);
+ }
+
+ if(block->block_contents)
+ {
+ free(block->block_contents);
+ }
+
+ block->block_contents = malloc(block->block_contents_size);
+ if(!block->block_contents)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ block->block_contents_size, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ /* Read the whole block into block_contents to be able to write it to disk
+ * even if it cannot be interpreted. */
+ if(fread(block->block_contents, block->block_contents_size, 1,
+ tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ /* FIXME: Does not check if the size of the contents matches the expected
+ * size or if the contents can be read. */
+
+ if(hash_mode == TNG_USE_HASH)
+ {
+ tng_md5_hash_match_verify(block, &same_hash);
+ if(same_hash != TNG_TRUE)
+ {
+ fprintf(stderr, "TNG library: Particle mapping block contents corrupt. Hashes do not match. "
+ "%s: %d\n",
+ __FILE__, __LINE__);
+ /* return(TNG_FAILURE); */
+ }
+ }
+
+ frame_set->n_mapping_blocks++;
+ mappings = realloc(frame_set->mappings,
+ sizeof(struct tng_particle_mapping) *
+ frame_set->n_mapping_blocks);
+ if(!mappings)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ block->block_contents_size, __FILE__, __LINE__);
+ free(frame_set->mappings);
+ frame_set->mappings = 0;
+ return(TNG_CRITICAL);
+ }
+ frame_set->mappings = mappings;
+ mapping = &mappings[frame_set->n_mapping_blocks - 1];
+
+
+ memcpy(&mapping->num_first_particle, block->block_contents+offset,
+ sizeof(mapping->num_first_particle));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &mapping->num_first_particle)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(mapping->num_first_particle);
+
+ memcpy(&mapping->n_particles, block->block_contents+offset,
+ sizeof(mapping->n_particles));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &mapping->n_particles)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(mapping->n_particles);
+
+ mapping->real_particle_numbers = malloc(mapping->n_particles *
+ sizeof(int64_t));
+ if(!mapping->real_particle_numbers)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ mapping->n_particles * sizeof(int64_t), __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ /* If the byte order needs to be swapped the data must be read one value at
+ * a time and swapped */
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ for(i = 0; i < mapping->n_particles; i++)
+ {
+ memcpy(&mapping->real_particle_numbers[i],
+ block->block_contents + offset,
+ sizeof(int64_t));
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &mapping->real_particle_numbers[i])
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ offset += sizeof(int64_t);
+ }
+ }
+ /* Otherwise the data can be read all at once */
+ else
+ {
+ memcpy(mapping->real_particle_numbers, block->block_contents + offset,
+ mapping->n_particles * sizeof(int64_t));
+ }
+
+
+ return(TNG_SUCCESS);
+}
+
+/** Write the atom mappings of the current trajectory frame set
+ * @param tng_data is a trajectory data container.
+ * @param block is a general block container.
+ * @param mapping_block_nr is the index of the mapping block to write.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
+ * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
+ * has occurred or TNG_CRITICAL (2) if a major error has occured.
+ */
+static tng_function_status tng_trajectory_mapping_block_write
+ (tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ int mapping_block_nr,
+ const char hash_mode)
+{
+ char *temp_name;
+ int i, offset = 0;
+ unsigned int name_len;
+ tng_particle_mapping_t mapping =
+ &tng_data->current_trajectory_frame_set.mappings[mapping_block_nr];
+
+ if(mapping_block_nr >=
+ tng_data->current_trajectory_frame_set.n_mapping_blocks)
+ {
+ fprintf(stderr, "TNG library: Mapping block index out of bounds. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_FAILURE);
+ }
+
+ if(tng_output_file_init(tng_data) != TNG_SUCCESS)
+ {
+ return(TNG_CRITICAL);
+ }
+
+ name_len = (int)strlen("PARTICLE MAPPING");
+
+ if(!block->name || strlen(block->name) < name_len)
+ {
+ temp_name = realloc(block->name, name_len + 1);
+ if(!temp_name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
+ name_len+1, __FILE__, __LINE__);
+ free(block->name);
+ block->name = 0;
+ return(TNG_CRITICAL);
+ }
+ block->name = temp_name;
+ }
+ strcpy(block->name, "PARTICLE MAPPING");
+ block->id = TNG_PARTICLE_MAPPING;
+
+ block->block_contents_size = sizeof(int64_t) * (2 + mapping->n_particles);
+
+ if(block->block_contents)
+ {
+ free(block->block_contents);
+ }
+ block->block_contents = malloc(block->block_contents_size);
+ if(!block->block_contents)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ block->block_contents_size, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ memcpy(block->block_contents, &mapping->num_first_particle,
+ sizeof(mapping->num_first_particle));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(mapping->num_first_particle);
+
+ memcpy(block->block_contents+offset, &mapping->n_particles,
+ sizeof(mapping->n_particles));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(mapping->n_particles);
+
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ for(i = 0; i < mapping->n_particles; i++)
+ {
+ memcpy(block->block_contents+offset, &mapping->real_particle_numbers[i],
+ sizeof(int64_t));
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ offset += sizeof(int64_t);
+ }
+ }
+ else
+ {
+ memcpy(block->block_contents+offset, mapping->real_particle_numbers,
+ mapping->n_particles * sizeof(int64_t));
+ }
+
+
+ if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
+ tng_data->output_file_path, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ if(fwrite(block->block_contents, block->block_contents_size, 1,
+ tng_data->output_file) != 1)
+ {
+ fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ return(TNG_SUCCESS);
+}
+
+/** Prepare a block for storing particle data
+ * @param tng_data is a trajectory data container.
+ * @param block_type_flag specifies if this is a trajectory block or a
+ * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_particle_data_block_create
+ (tng_trajectory_t tng_data,
+ const char block_type_flag)
+{
+ tng_trajectory_frame_set_t frame_set =
+ &tng_data->current_trajectory_frame_set;
+
+ tng_particle_data_t data;
+
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK)
+ {
+ frame_set->n_particle_data_blocks++;
+ data = realloc(frame_set->tr_particle_data,
+ sizeof(struct tng_particle_data) *
+ frame_set->n_particle_data_blocks);
+ if(!data)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
+ sizeof(struct tng_particle_data) *
+ frame_set->n_particle_data_blocks,
+ __FILE__, __LINE__);
+ free(frame_set->tr_particle_data);
+ frame_set->tr_particle_data = 0;
+ return(TNG_CRITICAL);
+ }
+ frame_set->tr_particle_data = data;
+ }
+ else
+ {
+ tng_data->n_particle_data_blocks++;
+ data = realloc(tng_data->non_tr_particle_data,
+ sizeof(struct tng_particle_data) *
+ tng_data->n_particle_data_blocks);
+ if(!data)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
+ sizeof(struct tng_particle_data) *
+ tng_data->n_particle_data_blocks,
+ __FILE__, __LINE__);
+ free(tng_data->non_tr_particle_data);
+ tng_data->non_tr_particle_data = 0;
+ return(TNG_CRITICAL);
+ }
+ tng_data->non_tr_particle_data = data;
+ }
+
+ return(TNG_SUCCESS);
+}
+
+static tng_function_status tng_compress(tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ const int64_t n_frames,
+ const int64_t n_particles,
+ const char type,
+ void *start_pos)
+{
+ int nalgo;
+ int new_len;
+ int *alt_algo = 0;
+ char *dest, *temp;
+ int64_t algo_find_n_frames;
+ unsigned long offset;
+ float f_precision;
+ double d_precision;
+
+ if(block->id != TNG_TRAJ_POSITIONS &&
+ block->id != TNG_TRAJ_VELOCITIES)
+ {
+ fprintf(stderr, "TNG library: Can only compress positions and velocities with the "
+ "TNG method. %s: %d\n", __FILE__, __LINE__);
+ return(TNG_FAILURE);
+ }
+ if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
+ {
+ fprintf(stderr, "TNG library: Data type not supported. %s: %d\n", __FILE__, __LINE__);
+ return(TNG_FAILURE);
+ }
+
+ if(n_frames <= 0 || n_particles <= 0)
+ {
+ fprintf(stderr, "TNG library: Missing frames or particles. Cannot compress data "
+ "with the TNG method. %s: %d\n", __FILE__, __LINE__);
+ return(TNG_FAILURE);
+ }
+
+ f_precision = 1/tng_data->compression_precision;
+ d_precision = 1/tng_data->compression_precision;
+
+ if(block->id == TNG_TRAJ_POSITIONS)
+ {
+ /* If there is only one frame in this frame set and there might be more
+ * do not store the algorithm as the compression algorithm, but find
+ * the best one without storing it */
+ if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
+ {
+ nalgo = tng_compress_nalgo();
+ alt_algo=malloc(nalgo * sizeof *tng_data->compress_algo_pos);
+ if(type == TNG_FLOAT_DATA)
+ {
+ dest = tng_compress_pos_float_find_algo(start_pos, (int)n_particles,
+ (int)n_frames,
+ f_precision,
+ 0, alt_algo,
+ &new_len);
+
+ }
+ else
+ {
+ dest = tng_compress_pos_find_algo(start_pos, (int)n_particles,
+ (int)n_frames,
+ d_precision,
+ 0, alt_algo,
+ &new_len);
+ }
+ }
+ else if(!tng_data->compress_algo_pos)
+ {
+ if(n_frames > 10)
+ {
+ algo_find_n_frames = 5;
+ }
+ else
+ {
+ algo_find_n_frames = n_frames;
+ }
+
+ nalgo = tng_compress_nalgo();
+ tng_data->compress_algo_pos=malloc(nalgo *
+ sizeof *tng_data->compress_algo_pos);
+ if(type == TNG_FLOAT_DATA)
+ {
+ dest = tng_compress_pos_float_find_algo(start_pos, (int)n_particles,
+ (int)algo_find_n_frames,
+ f_precision,
+ 0, tng_data->
+ compress_algo_pos,
+ &new_len);
+
+ if(algo_find_n_frames < n_frames)
+ {
+ dest = tng_compress_pos_float(start_pos, (int)n_particles,
+ (int)n_frames,
+ f_precision,
+ 0, tng_data->compress_algo_pos,
+ &new_len);
+ }
+ }
+ else
+ {
+ dest = tng_compress_pos_find_algo(start_pos, (int)n_particles,
+ (int)algo_find_n_frames,
+ d_precision,
+ 0, tng_data->
+ compress_algo_pos,
+ &new_len);
+
+ if(algo_find_n_frames < n_frames)
+ {
+ dest = tng_compress_pos(start_pos, (int)n_particles,
+ (int)n_frames,
+ d_precision, 0,
+ tng_data->compress_algo_pos,
+ &new_len);
+ }
+ }
+ }
+ else
+ {
+ if(type == TNG_FLOAT_DATA)
+ {
+ dest = tng_compress_pos_float(start_pos, (int)n_particles,
+ (int)n_frames,
+ f_precision, 0,
+ tng_data->compress_algo_pos, &new_len);
+ }
+ else
+ {
+ dest = tng_compress_pos(start_pos, (int)n_particles,
+ (int)n_frames,
+ d_precision, 0,
+ tng_data->compress_algo_pos,
+ &new_len);
+ }
+ }
+ }
+ else if(block->id == TNG_TRAJ_VELOCITIES)
+ {
+ /* If there is only one frame in this frame set and there might be more
+ * do not store the algorithm as the compression algorithm, but find
+ * the best one without storing it */
+ if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
+ {
+ nalgo = tng_compress_nalgo();
+ alt_algo=malloc(nalgo * sizeof *tng_data->compress_algo_pos);
+ if(type == TNG_FLOAT_DATA)
+ {
+ dest = tng_compress_vel_float_find_algo(start_pos, (int)n_particles,
+ (int)n_frames,
+ f_precision,
+ 0, alt_algo,
+ &new_len);
+
+ }
+ else
+ {
+ dest = tng_compress_vel_find_algo(start_pos, (int)n_particles,
+ (int)n_frames,
+ d_precision,
+ 0, alt_algo,
+ &new_len);
+ }
+ }
+ else if(!tng_data->compress_algo_vel)
+ {
+ if(n_frames > 10)
+ {
+ algo_find_n_frames = 5;
+ }
+ else
+ {
+ algo_find_n_frames = n_frames;
+ }
+
+ nalgo = tng_compress_nalgo();
+ tng_data->compress_algo_vel=malloc(nalgo *
+ sizeof *tng_data->compress_algo_vel);
+
+ if(type == TNG_FLOAT_DATA)
+ {
+ dest = tng_compress_vel_float_find_algo(start_pos, (int)n_particles,
+ (int)algo_find_n_frames,
+ f_precision,
+ 0, tng_data->
+ compress_algo_vel,
+ &new_len);
+ if(algo_find_n_frames < n_frames)
+ {
+ dest = tng_compress_vel_float(start_pos, (int)n_particles,
+ (int)n_frames,
+ f_precision,
+ 0, tng_data->compress_algo_vel,
+ &new_len);
+ }
+ }
+ else
+ {
+ dest = tng_compress_vel_find_algo(start_pos, (int)n_particles,
+ (int)algo_find_n_frames,
+ d_precision,
+ 0, tng_data->
+ compress_algo_vel,
+ &new_len);
+ if(algo_find_n_frames < n_frames)
+ {
+ dest = tng_compress_vel(start_pos, (int)n_particles,
+ (int)n_frames,
+ d_precision,
+ 0, tng_data->compress_algo_vel,
+ &new_len);
+ }
+ }
+ }
+ else
+ {
+ if(type == TNG_FLOAT_DATA)
+ {
+ dest = tng_compress_vel_float(start_pos, (int)n_particles,
+ (int)n_frames,
+ f_precision,
+ 0, tng_data->
+ compress_algo_vel,
+ &new_len);
+ }
+ else
+ {
+ dest = tng_compress_vel(start_pos, (int)n_particles,
+ (int)n_frames,
+ d_precision,
+ 0, tng_data->
+ compress_algo_vel,
+ &new_len);
+ }
+ }
+ }
+ else
+ {
+ fprintf(stderr, "TNG library: Can only compress positions and velocities using TNG-MF1 algorithms.\n");
+ return(TNG_FAILURE);
+ }
+
+ offset = (unsigned long)((char *)start_pos - block->block_contents);
+
+ if(alt_algo)
+ {
+ free(alt_algo);
+ }
+
+ block->block_contents_size = new_len + offset;
+
+ temp = realloc(block->block_contents, block->block_contents_size);
+ if(!temp)
+ {
+ free(block->block_contents);
+ block->block_contents = 0;
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ block->block_contents_size, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ block->block_contents = temp;
+ if(dest)
+ {
+ memcpy(temp + offset, dest, new_len);
+ free(dest);
+ }
+ else
+ {
+ fprintf(stderr, "TNG library: Error during TNG compression. %s: %d\n", __FILE__, __LINE__);
+ return(TNG_FAILURE);
+ }
+
+ return(TNG_SUCCESS);
+}
+
+static tng_function_status tng_uncompress(tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ const char type,
+ void *start_pos,
+ const unsigned long uncompressed_len)
+{
+ char *temp;
+ double *d_dest = 0;
+ float *f_dest = 0;
+ unsigned long offset;
+ int result;
+ (void)tng_data;
+
+ TNG_ASSERT(uncompressed_len, "TNG library: The full length of the uncompressed data must be > 0.");
+
+ if(block->id != TNG_TRAJ_POSITIONS &&
+ block->id != TNG_TRAJ_VELOCITIES)
+ {
+ fprintf(stderr, "TNG library: Can only uncompress positions and velocities with the"
+ "TNG method.\n");
+ return(TNG_FAILURE);
+ }
+ if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
+ {
+ fprintf(stderr, "TNG library: Data type not supported.\n");
+ return(TNG_FAILURE);
+ }
+
+ if(type == TNG_FLOAT_DATA)
+ {
+ f_dest = malloc(uncompressed_len);
+ if(!f_dest)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
+ uncompressed_len, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ result = tng_compress_uncompress_float(start_pos, f_dest);
+ }
+ else
+ {
+ d_dest = malloc(uncompressed_len);
+ if(!d_dest)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
+ uncompressed_len, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ result = tng_compress_uncompress(start_pos, d_dest);
+ }
+
+ if(result == 1)
+ {
+ fprintf(stderr, "TNG library: Cannot uncompress TNG compressed block.\n");
+ return(TNG_FAILURE);
+ }
+
+ offset = (unsigned long)((char *)start_pos - (char *)block->block_contents);
+
+ block->block_contents_size = (int64_t)(uncompressed_len + offset);
+
+ temp = realloc(block->block_contents, uncompressed_len + offset);
+ if(!temp)
+ {
+ free(block->block_contents);
+ block->block_contents = 0;
+ if(d_dest)
+ {
+ free(d_dest);
+ }
+ if(f_dest)
+ {
+ free(f_dest);
+ }
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ block->block_contents_size, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ if(type == TNG_FLOAT_DATA)
+ {
+ memcpy(temp + offset, f_dest, uncompressed_len);
+ }
+ else
+ {
+ memcpy(temp + offset, d_dest, uncompressed_len);
+ }
+
+ block->block_contents = temp;
+
+ if(d_dest)
+ {
+ free(d_dest);
+ }
+ if(f_dest)
+ {
+ free(f_dest);
+ }
+ return(TNG_SUCCESS);
+}
+
+#ifdef USE_ZLIB
+static tng_function_status tng_gzip_compress(tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ void *start_pos, const int len)
+{
+ Bytef *dest;
+ char *temp;
+ unsigned long max_len, stat, offset;
+ (void)tng_data;
+
+ max_len = compressBound(len);
+ dest = malloc(max_len);
+
+ stat = compress(dest, &max_len, start_pos, len);
+ if(stat != (unsigned long)Z_OK)
+ {
+ free(dest);
+ if(stat == (unsigned long)Z_MEM_ERROR)
+ {
+ fprintf(stderr, "TNG library: Not enough memory. ");
+ }
+ else if(stat == (unsigned long)Z_BUF_ERROR)
+ {
+ fprintf(stderr, "TNG library: Destination buffer too small. ");
+ }
+ fprintf(stderr, "TNG library: Error gzipping data. %s: %d\n", __FILE__, __LINE__);
+ return(TNG_FAILURE);
+ }
+
+ offset = (char *)start_pos - block->block_contents;
+
+ block->block_contents_size = max_len + offset;
+
+ temp = realloc(block->block_contents, block->block_contents_size);
+ if(!temp)
+ {
+ free(block->block_contents);
+ free(dest);
+ block->block_contents = 0;
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ block->block_contents_size, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ block->block_contents = temp;
+
+ memcpy(temp + offset, dest, max_len);
+
+ free(dest);
+
+ return(TNG_SUCCESS);
+}
+
+static tng_function_status tng_gzip_uncompress(tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ void *start_pos,
+ unsigned long uncompressed_len)
+{
+ Bytef *dest;
+ char *temp;
+ unsigned long stat;
+ int offset;
+ (void)tng_data;
+
+ offset = (char *)start_pos - (char *)block->block_contents;
+
+ dest = malloc(uncompressed_len);
+
+ stat = uncompress(dest, &uncompressed_len, (Bytef *) start_pos,
+ block->block_contents_size - offset);
+
+ if(stat != Z_OK)
+ {
+ free(dest);
+ if(stat == (unsigned long)Z_MEM_ERROR)
+ {
+ fprintf(stderr, "TNG library: Not enough memory. ");
+ }
+ else if(stat == (unsigned long)Z_BUF_ERROR)
+ {
+ fprintf(stderr, "TNG library: Destination buffer too small. ");
+ }
+ else if(stat == (unsigned long)Z_DATA_ERROR)
+ {
+ fprintf(stderr, "TNG library: Data corrupt. ");
+ }
+ fprintf(stderr, "TNG library: Error uncompressing gzipped data. %s: %d\n", __FILE__,
+ __LINE__);
+ return(TNG_FAILURE);
+ }
+
+
+ block->block_contents_size = uncompressed_len + offset;
+
+ temp = realloc(block->block_contents, uncompressed_len + offset);
+ if(!temp)
+ {
+ free(block->block_contents);
+ block->block_contents = 0;
+ free(dest);
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ block->block_contents_size, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ memcpy(temp + offset, dest, uncompressed_len);
+
+ block->block_contents = temp;
+
+ free(dest);
+ return(TNG_SUCCESS);
+}
+#endif
+
+/** Allocate memory for storing particle data.
+ * The allocated block will be refered to by data->values.
+ * @param tng_data is a trajectory data container.
+ * @param data is the data struct, which will contain the allocated memory in
+ * data->values.
+ * @param n_frames is the number of frames of data to store.
+ * @param n_particles is the number of particles with data.
+ * @param n_values_per_frame is the number of data values per particle and
+ * frame.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_allocate_particle_data_mem
+ (tng_trajectory_t tng_data,
+ tng_particle_data_t data,
+ int64_t n_frames,
+ int64_t stride_length,
+ const int64_t n_particles,
+ const int64_t n_values_per_frame)
+{
+ void ***values;
+ int64_t i, j, k, size, frame_alloc;
+ (void)tng_data;
+
+ if(n_particles == 0 || n_values_per_frame == 0)
+ {
+ return(TNG_FAILURE);
+ }
+
+ if(data->strings && data->datatype == TNG_CHAR_DATA)
+ {
+ for(i = data->n_frames; i--;)
+ {
+ for(j = n_particles; j--;)
+ {
+ for(k = data->n_values_per_frame; k--;)
+ {
+ if(data->strings[i][j][k])
+ {
+ free(data->strings[i][j][k]);
+ }
+ }
+ free(data->strings[i][j]);
+ }
+ free(data->strings[i]);
+ }
+ free(data->strings);
+ }
+ data->n_frames = n_frames;
+ n_frames = tng_max_i64(1, n_frames);
+ data->stride_length = tng_max_i64(1, stride_length);
+ data->n_values_per_frame = n_values_per_frame;
+ frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
+
+ if(data->datatype == TNG_CHAR_DATA)
+ {
+ data->strings = malloc(sizeof(char ***) * frame_alloc);
+ for(i = frame_alloc; i-- ;)
+ {
+ data->strings[i] = malloc(sizeof(char **) *
+ n_particles);
+ if(!data->strings[i])
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(union data_values *) * n_particles,
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ for(j = n_particles; j--;)
+ {
+ data->strings[i][j] = malloc(sizeof(char *) *
+ n_values_per_frame);
+ if(!data->strings[i][j])
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(union data_values) * n_values_per_frame,
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ for(k = n_values_per_frame; k--;)
+ {
+ data->strings[i][j][k] = 0;
+ }
+ }
+ }
+ }
+ else
+ {
+ switch(data->datatype)
+ {
+ case TNG_INT_DATA:
+ size = sizeof(int64_t);
+ break;
+ case TNG_FLOAT_DATA:
+ size = sizeof(float);
+ break;
+ case TNG_DOUBLE_DATA:
+ default:
+ size = sizeof(double);
+ }
+
+ values = realloc(data->values,
+ size * frame_alloc *
+ n_particles * n_values_per_frame);
+ if(!values)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ size * frame_alloc *
+ n_particles * n_values_per_frame,
+ __FILE__, __LINE__);
+ free(data->values);
+ data->values = 0;
+ return(TNG_CRITICAL);
+ }
+ data->values = values;
+ }
+ return(TNG_SUCCESS);
+}
+
+static tng_function_status tng_particle_data_find
+ (tng_trajectory_t tng_data,
+ const int64_t id,
+ tng_particle_data_t *data)
+{
+ int64_t block_index, i;
+ tng_trajectory_frame_set_t frame_set = &tng_data->
+ current_trajectory_frame_set;
+ char block_type_flag;
+
+ if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
+ tng_data->current_trajectory_frame_set_output_file_pos > 0)
+ {
+ block_type_flag = TNG_TRAJECTORY_BLOCK;
+ }
+ else
+ {
+ block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
+ }
+
+ block_index = -1;
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK)
+ {
+ for(i = frame_set->n_particle_data_blocks; i-- ;)
+ {
+ *data = &frame_set->tr_particle_data[i];
+ if((*data)->block_id == id)
+ {
+ block_index = i;
+ break;
+ }
+ }
+ }
+ else
+ {
+ for(i = tng_data->n_particle_data_blocks; i-- ;)
+ {
+ *data = &tng_data->non_tr_particle_data[i];
+ if((*data)->block_id == id)
+ {
+ block_index = i;
+ break;
+ }
+ }
+ }
+ if(block_index == -1)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+static tng_function_status tng_data_find
+ (tng_trajectory_t tng_data,
+ const int64_t id,
+ tng_non_particle_data_t *data)
+{
+ int64_t block_index, i;
+ tng_trajectory_frame_set_t frame_set = &tng_data->
+ current_trajectory_frame_set;
+ char block_type_flag;
+
+ if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
+ tng_data->current_trajectory_frame_set_output_file_pos > 0)
+ {
+ block_type_flag = TNG_TRAJECTORY_BLOCK;
+ }
+ else
+ {
+ block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
+ }
+
+ block_index = -1;
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK)
+ {
+ for(i = frame_set->n_data_blocks; i-- ;)
+ {
+ *data = &frame_set->tr_data[i];
+ if((*data)->block_id == id)
+ {
+ block_index = i;
+ break;
+ }
+ }
+ if(block_index == -1)
+ {
+ for(i = tng_data->n_data_blocks; i-- ;)
+ {
+ *data = &tng_data->non_tr_data[i];
+ if((*data)->block_id == id)
+ {
+ block_index = i;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ for(i = tng_data->n_data_blocks; i-- ;)
+ {
+ *data = &tng_data->non_tr_data[i];
+ if((*data)->block_id == id)
+ {
+ block_index = i;
+ break;
+ }
+ }
+ }
+ if(block_index == -1)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+/** Read the values of a particle data block
+ * @param tng_data is a trajectory data container.
+ * @param block is the block to store the data (should already contain
+ * the block headers and the block contents).
+ * @param offset is the reading offset to point at the place where the actual
+ * values are stored, starting from the beginning of the block_contents. The
+ * offset is changed during the reading.
+ * @param datatype is the type of data of the data block (char, int, float or
+ * double).
+ * @param num_first_particle is the number of the first particle in the data
+ * block. This should be the same as in the corresponding particle mapping
+ * block.
+ * @param n_particles is the number of particles in the data block. This should
+ * be the same as in the corresponding particle mapping block.
+ * @param first_frame_with_data is the frame number of the first frame with data
+ * in this data block.
+ * @param stride_length is the number of frames between each data entry.
+ * @param n_frames is the number of frames in this data block.
+ * @param n_values is the number of values per particle and frame stored in this
+ * data block.
+ * @param codec_id is the ID of the codec to compress the data.
+ * @param multiplier is the multiplication factor applied to each data value
+ * before compression. This factor is applied since some compression algorithms
+ * work only on integers.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_particle_data_read
+ (tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ int *offset,
+ const char datatype,
+ const int64_t num_first_particle,
+ const int64_t n_particles,
+ const int64_t first_frame_with_data,
+ const int64_t stride_length,
+ int64_t n_frames,
+ const int64_t n_values,
+ const int64_t codec_id,
+ const double multiplier)
+{
+ int64_t i, j, k, tot_n_particles, n_frames_div;
+ int size, len;
+ unsigned long data_size;
+ char ***first_dim_values, **second_dim_values;
+ tng_particle_data_t data;
+ tng_trajectory_frame_set_t frame_set =
+ &tng_data->current_trajectory_frame_set;
+ char block_type_flag;
+
+ TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
+
+ switch(datatype)
+ {
+ case TNG_CHAR_DATA:
+ size = 1;
+ break;
+ case TNG_INT_DATA:
+ size = sizeof(int64_t);
+ break;
+ case TNG_FLOAT_DATA:
+ size = sizeof(float);
+ break;
+ case TNG_DOUBLE_DATA:
+ default:
+ size = sizeof(double);
+ }
+
+ /* If the block does not exist, create it */
+ if(tng_particle_data_find(tng_data, block->id, &data) != TNG_SUCCESS)
+ {
+ if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
+ {
+ block_type_flag = TNG_TRAJECTORY_BLOCK;
+ }
+ else
+ {
+ block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
+ }
+
+ if(tng_particle_data_block_create(tng_data, block_type_flag) !=
+ TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK)
+ {
+ data = &frame_set->tr_particle_data[frame_set->
+ n_particle_data_blocks - 1];
+ }
+ else
+ {
+ data = &tng_data->non_tr_particle_data[tng_data->
+ n_particle_data_blocks - 1];
+ }
+ data->block_id = block->id;
+
+ data->block_name = malloc(strlen(block->name) + 1);
+ if(!data->block_name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
+ (int)strlen(block->name)+1, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ strcpy(data->block_name, block->name);
+
+ data->datatype = datatype;
+
+ data->values = 0;
+ /* FIXME: Memory leak from strings. */
+ data->strings = 0;
+ data->n_frames = 0;
+ data->codec_id = codec_id;
+ data->compression_multiplier = multiplier;
+ data->last_retrieved_frame = -1;
+ }
+
+ if(/*block_type_flag == TNG_TRAJECTORY_BLOCK &&*/
+ tng_data->current_trajectory_frame_set_input_file_pos > 0 &&
+ tng_data->var_num_atoms_flag)
+ {
+ tot_n_particles = frame_set->n_particles;
+ }
+ else
+ {
+ tot_n_particles = tng_data->n_particles;
+ }
+
+ n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
+
+ if(codec_id != TNG_UNCOMPRESSED)
+ {
+ data_size = (unsigned long)(n_frames_div * size * n_particles * n_values);
+ switch(codec_id)
+ {
+ case TNG_XTC_COMPRESSION:
+ fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
+ break;
+ case TNG_TNG_COMPRESSION:
+/* fprintf(stderr, "TNG library: Before TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
+ if(tng_uncompress(tng_data, block, datatype,
+ block->block_contents + *offset,
+ data_size) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Could not read tng compressed block data. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+/* fprintf(stderr, "TNG library: After TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
+ break;
+#ifdef USE_ZLIB
+ case TNG_GZIP_COMPRESSION:
+/* fprintf(stderr, "TNG library: Before GZIP uncompression: %"PRId64"\n", block->block_contents_size);*/
+ if(tng_gzip_uncompress(tng_data, block,
+ block->block_contents + *offset,
+ data_size) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
+ __LINE__);
+ return(TNG_CRITICAL);
+ }
+/* fprintf(stderr, "TNG library: After GZIP uncompression: %"PRId64"\n", block->block_contents_size);*/
+ break;
+#endif
+ }
+ }
+ /* Allocate memory */
+ if(!data->values || data->n_frames != n_frames ||
+ data->n_values_per_frame != n_values)
+ {
+ if(tng_allocate_particle_data_mem(tng_data, data, n_frames,
+ stride_length,
+ tot_n_particles, n_values) !=
+ TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory for particle data. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ }
+
+ data->first_frame_with_data = first_frame_with_data;
+
+ if(datatype == TNG_CHAR_DATA)
+ {
+ for(i = 0; i < n_frames_div; i++)
+ {
+ first_dim_values = data->strings[i];
+ for(j = num_first_particle; j < num_first_particle + n_particles;
+ j++)
+ {
+ second_dim_values = first_dim_values[j];
+ for(k = 0; k < n_values; k++)
+ {
+ len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
+ TNG_MAX_STR_LEN);
+ if(second_dim_values[k])
+ {
+ free(second_dim_values[k]);
+ }
+ second_dim_values[k] = malloc(len);
+ if(!second_dim_values[k])
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
+ len, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ strncpy(second_dim_values[k],
+ block->block_contents+*offset, len);
+ *offset += len;
+ }
+ }
+ }
+ }
+ else
+ {
+ memcpy((char *)data->values + n_frames_div * size * n_values *
+ num_first_particle,
+ block->block_contents + *offset,
+ block->block_contents_size - *offset);
+ switch(datatype)
+ {
+ case TNG_FLOAT_DATA:
+ if(tng_data->input_endianness_swap_func_32)
+ {
+ for(i = 0; i < (block->block_contents_size - *offset); i+=size)
+ {
+ if(tng_data->input_endianness_swap_func_32(tng_data,
+ (int32_t *)((char *)data->values + i))
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ }
+ break;
+ case TNG_INT_DATA:
+ case TNG_DOUBLE_DATA:
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ for(i = 0; i < (block->block_contents_size - *offset); i+=size)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ (int64_t *)((char *)data->values + i))
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ }
+ break;
+ case TNG_CHAR_DATA:
+ break;
+ }
+ }
+ return(TNG_SUCCESS);
+}
+
+/** Write a particle data block
+ * @param tng_data is a trajectory data container.
+ * @param block is the block to store the data (should already contain
+ * the block headers and the block contents).
+ * @param block_index is the index number of the data block in the frame set.
+ * @param mapping is the particle mapping that is relevant for the data block.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_particle_data_block_write
+ (tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ const int64_t block_index,
+ const tng_particle_mapping_t mapping,
+ const char hash_mode)
+{
+ int64_t n_particles, num_first_particle, n_frames, stride_length;
+ int64_t frame_step, data_start_pos;
+ int64_t i, j, k;
+ int size;
+ size_t len, offset = 0;
+ char dependency, temp, *temp_name;
+ double multiplier;
+ char ***first_dim_values, **second_dim_values;
+ tng_trajectory_frame_set_t frame_set;
+ tng_function_status stat;
+
+ tng_particle_data_t data;
+ char block_type_flag;
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ /* If we have already started writing frame sets it is too late to write
+ * non-trajectory data blocks */
+ if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
+ {
+ block_type_flag = TNG_TRAJECTORY_BLOCK;
+ }
+ else
+ {
+ block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
+ }
+
+ if(tng_output_file_init(tng_data) != TNG_SUCCESS)
+ {
+ return(TNG_CRITICAL);
+ }
+
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK)
+ {
+ data = &frame_set->tr_particle_data[block_index];
+
+ /* If this data block has not had any data added in this frame set
+ * do not write it. */
+ if(data->first_frame_with_data < frame_set->first_frame)
+ {
+ return(TNG_SUCCESS);
+ }
+
+ stride_length = tng_max_i64(1, data->stride_length);
+ }
+ else
+ {
+ data = &tng_data->non_tr_particle_data[block_index];
+ stride_length = 1;
+ }
+
+ switch(data->datatype)
+ {
+ case TNG_CHAR_DATA:
+ size = 1;
+ break;
+ case TNG_INT_DATA:
+ size = sizeof(int64_t);
+ break;
+ case TNG_FLOAT_DATA:
+ size = sizeof(float);
+ break;
+ case TNG_DOUBLE_DATA:
+ default:
+ size = sizeof(double);
+ }
+
+ len = strlen(data->block_name) + 1;
+
+ if(!block->name || strlen(block->name) < len)
+ {
+ temp_name = realloc(block->name, len);
+ if(!temp_name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%lud bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ free(block->name);
+ block->name = 0;
+ return(TNG_CRITICAL);
+ }
+ block->name = temp_name;
+ }
+ strncpy(block->name, data->block_name, len);
+ block->id = data->block_id;
+
+ /* If writing frame independent data data->n_frames is 0, but n_frames
+ is used for the loop writing the data (and reserving memory) and needs
+ to be at least 1 */
+ n_frames = tng_max_i64(1, data->n_frames);
+
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK)
+ {
+ /* If the frame set is finished before writing the full number of frames
+ make sure the data block is not longer than the frame set. */
+ n_frames = tng_min_i64(n_frames, frame_set->n_frames);
+
+ n_frames -= (data->first_frame_with_data - frame_set->first_frame);
+ }
+
+ frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
+ n_frames / stride_length;
+
+ /* TNG compression will use compression precision to get integers from
+ * floating point data. The compression multiplier stores that information
+ * to be able to return the precision of the compressed data. */
+ if(data->codec_id == TNG_TNG_COMPRESSION)
+ {
+ data->compression_multiplier = tng_data->compression_precision;
+ }
+ /* Uncompressed data blocks do not use compression multipliers at all.
+ * GZip compression does not need it either. */
+ else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
+ {
+ data->compression_multiplier = 1.0;
+ }
+
+ if(mapping && mapping->n_particles != 0)
+ {
+ n_particles = mapping->n_particles;
+ num_first_particle = mapping->num_first_particle;
+ }
+ else
+ {
+ num_first_particle = 0;
+ if(tng_data->var_num_atoms_flag)
+ {
+ n_particles = frame_set->n_particles;
+ }
+ else
+ {
+ n_particles = tng_data->n_particles;
+ }
+ }
+
+ block->block_contents_size = sizeof(char) * 2 +
+ sizeof(data->n_values_per_frame) +
+ sizeof(data->codec_id) +
+ sizeof(num_first_particle) +
+ sizeof(n_particles);
+
+ if(stride_length > 1)
+ {
+ block->block_contents_size += sizeof(data->first_frame_with_data) +
+ sizeof(data->stride_length);
+ }
+
+ if(data->codec_id != TNG_UNCOMPRESSED)
+ {
+ block->block_contents_size += sizeof(data->compression_multiplier);
+ }
+
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0)
+ {
+ dependency = TNG_FRAME_DEPENDENT + TNG_PARTICLE_DEPENDENT;
+ }
+ else
+ {
+ dependency = TNG_PARTICLE_DEPENDENT;
+ }
+ if(dependency & TNG_FRAME_DEPENDENT)
+ {
+ block->block_contents_size += sizeof(char);
+ }
+
+ data_start_pos = block->block_contents_size;
+
+ if(data->datatype == TNG_CHAR_DATA)
+ {
+ for(i = n_frames; i--;)
+ {
+ first_dim_values = data->strings[i];
+ for(j = num_first_particle; j < num_first_particle + n_particles;
+ j++)
+ {
+ second_dim_values = first_dim_values[j];
+ for(k = data->n_values_per_frame; k--;)
+ {
+ block->block_contents_size +=
+ strlen(second_dim_values[k]) + 1;
+ }
+ }
+ }
+ }
+ else
+ {
+ block->block_contents_size += size * frame_step *
+ n_particles * data->n_values_per_frame;
+ }
+
+ if(block->block_contents)
+ {
+ free(block->block_contents);
+ }
+ block->block_contents = malloc(block->block_contents_size);
+ if(!block->block_contents)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ block->block_contents_size, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+
+ memcpy(block->block_contents, &data->datatype, sizeof(char));
+ offset += sizeof(char);
+
+ memcpy(block->block_contents+offset, &dependency, sizeof(char));
+ offset += sizeof(char);
+
+ if(dependency & TNG_FRAME_DEPENDENT)
+ {
+ if(stride_length > 1)
+ {
+ temp = 1;
+ }
+ else
+ {
+ temp = 0;
+ }
+ memcpy(block->block_contents+offset, &temp, sizeof(char));
+ offset += sizeof(char);
+ }
+
+ memcpy(block->block_contents+offset, &data->n_values_per_frame,
+ sizeof(data->n_values_per_frame));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(data->n_values_per_frame);
+
+ memcpy(block->block_contents+offset, &data->codec_id,
+ sizeof(data->codec_id));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(data->codec_id);
+
+ if(data->codec_id != TNG_UNCOMPRESSED)
+ {
+ memcpy(block->block_contents+offset, &data->compression_multiplier,
+ sizeof(data->compression_multiplier));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(data->compression_multiplier);
+ }
+
+ if(data->n_frames > 0 && stride_length > 1)
+ {
+ /* FIXME: first_frame_with_data is not reliably set */
+ if(data->first_frame_with_data == 0)
+ {
+ data->first_frame_with_data = frame_set->first_frame;
+ }
+ memcpy(block->block_contents+offset, &data->first_frame_with_data,
+ sizeof(data->first_frame_with_data));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(data->first_frame_with_data);
+
+ memcpy(block->block_contents+offset, &stride_length,
+ sizeof(stride_length));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(stride_length);
+ }
+
+
+ memcpy(block->block_contents+offset, &num_first_particle,
+ sizeof(num_first_particle));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(num_first_particle);
+
+ memcpy(block->block_contents+offset, &n_particles, sizeof(n_particles));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(n_particles);
+
+ if(data->datatype == TNG_CHAR_DATA)
+ {
+ if(data->strings)
+ {
+ for(i = 0; i < frame_step; i++)
+ {
+ first_dim_values = data->strings[i];
+ for(j = num_first_particle; j < num_first_particle + n_particles;
+ j++)
+ {
+ second_dim_values = first_dim_values[j];
+ for(k = 0; k < data->n_values_per_frame; k++)
+ {
+ len = (unsigned int)strlen(second_dim_values[k]) + 1;
+ strncpy(block->block_contents+offset,
+ second_dim_values[k], len);
+ offset += len;
+ }
+ }
+ }
+ }
+ }
+ else if(data->values)
+ {
+ memcpy(block->block_contents + offset, data->values,
+ block->block_contents_size - offset);
+
+ switch(data->datatype)
+ {
+ case TNG_FLOAT_DATA:
+ if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
+ data->codec_id == TNG_TNG_COMPRESSION)
+ {
+ if(tng_data->input_endianness_swap_func_32)
+ {
+ for(i = offset; i < block->block_contents_size; i+=size)
+ {
+ if(tng_data->input_endianness_swap_func_32(tng_data,
+ (int32_t *)(block->block_contents + i))
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ }
+ }
+ else
+ {
+ multiplier = data->compression_multiplier;
+ if(fabs(multiplier - 1.0) > 0.00001 ||
+ tng_data->input_endianness_swap_func_32)
+ {
+ for(i = offset; i < block->block_contents_size; i+=size)
+ {
+ *(float *)(block->block_contents + i) *= (float)multiplier;
+ if(tng_data->input_endianness_swap_func_32 &&
+ tng_data->input_endianness_swap_func_32(tng_data,
+ (int32_t *)(block->block_contents + i))
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ }
+ }
+ break;
+ case TNG_INT_DATA:
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ for(i = offset; i < block->block_contents_size; i+=size)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ (int64_t *)(block->block_contents + i))
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ }
+ break;
+ case TNG_DOUBLE_DATA:
+ if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
+ data->codec_id == TNG_TNG_COMPRESSION)
+ {
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ for(i = offset; i < block->block_contents_size; i+=size)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ (int64_t *)(block->block_contents + i))
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ }
+ }
+ else
+ {
+ multiplier = data->compression_multiplier;
+ if(fabs(multiplier - 1.0) > 0.00001 ||
+ tng_data->input_endianness_swap_func_64)
+ {
+ for(i = offset; i < block->block_contents_size; i+=size)
+ {
+ *(double *)(block->block_contents + i) *= multiplier;
+ if(tng_data->input_endianness_swap_func_64 &&
+ tng_data->input_endianness_swap_func_64(tng_data,
+ (int64_t *)(block->block_contents + i))
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ }
+ }
+ break;
+ case TNG_CHAR_DATA:
+ break;
+ }
+ }
+ else
+ {
+ memset(block->block_contents+offset, 0, block->block_contents_size - offset);
+ }
+
+ frame_set->n_written_frames += frame_set->n_unwritten_frames;
+ frame_set->n_unwritten_frames = 0;
+
+ if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0)
+ {
+ switch(data->codec_id)
+ {
+ case TNG_XTC_COMPRESSION:
+ fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
+ data->codec_id = TNG_UNCOMPRESSED;
+ break;
+ case TNG_TNG_COMPRESSION:
+ stat = tng_compress(tng_data, block, frame_step,
+ n_particles, data->datatype,
+ block->block_contents + data_start_pos);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Could not write tng compressed block data. %s: %d\n",
+ __FILE__, __LINE__);
+ if(stat == TNG_CRITICAL)
+ {
+ return(TNG_CRITICAL);
+ }
+ /* Set the data again, but with no compression (to write only
+ * the relevant data) */
+ data->codec_id = TNG_UNCOMPRESSED;
+ stat = tng_particle_data_block_write(tng_data, block,
+ block_index, mapping,
+ hash_mode);
+ return(stat);
+ }
+ break;
+#ifdef USE_ZLIB
+ case TNG_GZIP_COMPRESSION:
+ /* fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size);*/
+ stat = tng_gzip_compress(tng_data, block,
+ block->block_contents + data_start_pos,
+ block->block_contents_size - data_start_pos);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
+ __LINE__);
+ if(stat == TNG_CRITICAL)
+ {
+ return(TNG_CRITICAL);
+ }
+ /* Set the data again, but with no compression (to write only
+ * the relevant data) */
+ data->codec_id = TNG_UNCOMPRESSED;
+ stat = tng_particle_data_block_write(tng_data, block,
+ block_index, mapping,
+ hash_mode);
+ return(stat);
+ }
+ /* fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size);*/
+ break;
+#endif
+ }
+ }
+
+ if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
+ tng_data->output_file_path, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ if(fwrite(block->block_contents, block->block_contents_size, 1,
+ tng_data->output_file) != 1)
+ {
+ fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__,
+ __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ return(TNG_SUCCESS);
+}
+
+/* TEST: */
+/** Create a non-particle data block
+ * @param tng_data is a trajectory data container.
+ * @param block_type_flag specifies if this is a trajectory block or a
+ * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_data_block_create
+ (tng_trajectory_t tng_data,
+ const char block_type_flag)
+{
+ tng_trajectory_frame_set_t frame_set =
+ &tng_data->current_trajectory_frame_set;
+
+ tng_non_particle_data_t data;
+
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK)
+ {
+ frame_set->n_data_blocks++;
+ data = realloc(frame_set->tr_data, sizeof(struct tng_non_particle_data) *
+ frame_set->n_data_blocks);
+ if(!data)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
+ sizeof(struct tng_non_particle_data) * frame_set->n_data_blocks,
+ __FILE__, __LINE__);
+ free(frame_set->tr_data);
+ frame_set->tr_data = 0;
+ return(TNG_CRITICAL);
+ }
+ frame_set->tr_data = data;
+ }
+ else
+ {
+ tng_data->n_data_blocks++;
+ data = realloc(tng_data->non_tr_data, sizeof(struct tng_non_particle_data) *
+ tng_data->n_data_blocks);
+ if(!data)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
+ sizeof(struct tng_non_particle_data) * tng_data->n_data_blocks,
+ __FILE__, __LINE__);
+ free(tng_data->non_tr_data);
+ tng_data->non_tr_data = 0;
+ return(TNG_CRITICAL);
+ }
+ tng_data->non_tr_data = data;
+ }
+
+ return(TNG_SUCCESS);
+}
+
+/* TEST: */
+/** Allocate memory for storing non-particle data.
+ * The allocated block will be refered to by data->values.
+ * @param tng_data is a trajectory data container.
+ * @param data is the data struct, which will contain the allocated memory in
+ * data->values.
+ * @param n_frames is the number of frames of data to store.
+ * @param n_values_per_frame is the number of data values per frame.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_allocate_data_mem
+ (tng_trajectory_t tng_data,
+ tng_non_particle_data_t data,
+ int64_t n_frames,
+ int64_t stride_length,
+ const int64_t n_values_per_frame)
+{
+ void **values;
+ int64_t i, j, size, frame_alloc;
+ (void)tng_data;
+
+ if(data->strings && data->datatype == TNG_CHAR_DATA)
+ {
+ for(i = data->n_frames; i--;)
+ {
+ for(j = data->n_values_per_frame; j--;)
+ {
+ if(data->strings[i][j])
+ {
+ free(data->strings[i][j]);
+ data->strings[i][j] = 0;
+ }
+ }
+ free(data->strings[i]);
+ data->strings[i] = 0;
+ }
+ free(data->strings);
+ }
+ data->n_frames = n_frames;
+ data->stride_length = tng_max_i64(1, stride_length);
+ n_frames = tng_max_i64(1, n_frames);
+ data->n_values_per_frame = n_values_per_frame;
+ frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
+
+ if(data->datatype == TNG_CHAR_DATA)
+ {
+ data->strings = malloc(sizeof(char **) * frame_alloc);
+ for(i = frame_alloc; i-- ;)
+ {
+ data->strings[i] = malloc(sizeof(char *) * n_values_per_frame);
+ if(!data->strings[i])
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ n_values_per_frame,
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ for(j = n_values_per_frame; j--;)
+ {
+ data->strings[i][j] = 0;
+ }
+ }
+ }
+ else
+ {
+ switch(data->datatype)
+ {
+ case TNG_INT_DATA:
+ size = sizeof(int64_t);
+ break;
+ case TNG_FLOAT_DATA:
+ size = sizeof(float);
+ break;
+ case TNG_DOUBLE_DATA:
+ default:
+ size = sizeof(double);
+ }
+
+ values = realloc(data->values,
+ size * frame_alloc *
+ n_values_per_frame);
+ if(!values)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ size * frame_alloc *
+ n_values_per_frame,
+ __FILE__, __LINE__);
+ free(data->values);
+ data->values = 0;
+ return(TNG_CRITICAL);
+ }
+ data->values = values;
+ }
+
+ return(TNG_SUCCESS);
+}
+
+/** Read the values of a non-particle data block
+ * @param tng_data is a trajectory data container.
+ * @param block is the block to store the data (should already contain
+ * the block headers and the block contents).
+ * @param offset is the reading offset to point at the place where the actual
+ * values are stored, starting from the beginning of the block_contents. The
+ * offset is changed during the reading.
+ * @param datatype is the type of data of the data block (char, int, float or
+ * double).
+ * @param first_frame_with_data is the frame number of the first frame with data
+ * in this data block.
+ * @param stride_length is the number of frames between each data entry.
+ * @param n_frames is the number of frames in this data block.
+ * @param n_values is the number of values per frame stored in this data block.
+ * @param codec_id is the ID of the codec to compress the data.
+ * @param multiplier is the multiplication factor applied to each data value
+ * before compression. This factor is applied since some compression algorithms
+ * work only on integers.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_data_read(tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ int *offset,
+ const char datatype,
+ const int64_t first_frame_with_data,
+ const int64_t stride_length,
+ int64_t n_frames,
+ const int64_t n_values,
+ const int64_t codec_id,
+ const double multiplier)
+{
+ int64_t i, j, n_frames_div;
+ int size, len;
+#ifdef USE_ZLIB
+ unsigned long data_size;
+#endif
+ tng_non_particle_data_t data;
+ tng_trajectory_frame_set_t frame_set =
+ &tng_data->current_trajectory_frame_set;
+ char block_type_flag;
+
+ TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
+
+/* fprintf(stderr, "TNG library: %s\n", block->name);*/
+
+ switch(datatype)
+ {
+ case TNG_CHAR_DATA:
+ size = 1;
+ break;
+ case TNG_INT_DATA:
+ size = sizeof(int64_t);
+ break;
+ case TNG_FLOAT_DATA:
+ size = sizeof(float);
+ break;
+ case TNG_DOUBLE_DATA:
+ default:
+ size = sizeof(double);
+ }
+
+ /* If the block does not exist, create it */
+ if(tng_data_find(tng_data, block->id, &data) != TNG_SUCCESS)
+ {
+ if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
+ {
+ block_type_flag = TNG_TRAJECTORY_BLOCK;
+ }
+ else
+ {
+ block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
+ }
+
+ if(tng_data_block_create(tng_data, block_type_flag) !=
+ TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK)
+ {
+ data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
+ }
+ else
+ {
+ data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
+ }
+ data->block_id = block->id;
+
+ data->block_name = malloc(strlen(block->name) + 1);
+ if(!data->block_name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
+ (int)strlen(block->name)+1, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ strcpy(data->block_name, block->name);
+
+ data->datatype = datatype;
+
+ data->values = 0;
+ /* FIXME: Memory leak from strings. */
+ data->strings = 0;
+ data->n_frames = 0;
+ data->codec_id = codec_id;
+ data->compression_multiplier = multiplier;
+ data->last_retrieved_frame = -1;
+ }
+
+ n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
+
+ if(codec_id != TNG_UNCOMPRESSED)
+ {
+ switch(codec_id)
+ {
+#ifdef USE_ZLIB
+ case TNG_GZIP_COMPRESSION:
+ data_size = n_frames_div * size * n_values;
+ /* fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
+ if(tng_gzip_uncompress(tng_data, block,
+ block->block_contents + *offset,
+ data_size) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
+ __LINE__);
+ return(TNG_CRITICAL);
+ }
+ /* fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
+ break;
+#endif
+ }
+ }
+
+ /* Allocate memory */
+ if(!data->values || data->n_frames != n_frames ||
+ data->n_values_per_frame != n_values)
+ {
+ if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
+ n_values) !=
+ TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory for data. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ }
+
+ data->first_frame_with_data = first_frame_with_data;
+
+ if(datatype == TNG_CHAR_DATA)
+ {
+ for(i = 0; i < n_frames_div; i++)
+ {
+ for(j = 0; j < n_values; j++)
+ {
+ len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
+ TNG_MAX_STR_LEN);
+ if(data->strings[i][j])
+ {
+ free(data->strings[i][j]);
+ }
+ data->strings[i][j] = malloc(len);
+ if(!data->strings[i][j])
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
+ len, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ strncpy(data->strings[i][j], block->block_contents+*offset,
+ len);
+ *offset += len;
+ }
+ }
+ }
+ else
+ {
+ memcpy(data->values, block->block_contents + *offset,
+ block->block_contents_size - *offset);
+ switch(datatype)
+ {
+ case TNG_FLOAT_DATA:
+ if(tng_data->input_endianness_swap_func_32)
+ {
+ for(i = 0; i < (block->block_contents_size - *offset); i+=size)
+ {
+ if(tng_data->input_endianness_swap_func_32(tng_data,
+ (int32_t *)((char *)data->values + i))
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ }
+ break;
+ case TNG_INT_DATA:
+ case TNG_DOUBLE_DATA:
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ for(i = 0; i < (block->block_contents_size - *offset); i+=size)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ (int64_t *)((char *)data->values + i))
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ }
+ break;
+ case TNG_CHAR_DATA:
+ break;
+ }
+ }
+ return(TNG_SUCCESS);
+}
+
+/** Write a non-particle data block
+ * @param tng_data is a trajectory data container.
+ * @param block is the block to store the data (should already contain
+ * the block headers and the block contents).
+ * @param block_index is the index number of the data block in the frame set.
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_data_block_write(tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ const int64_t block_index,
+ const char hash_mode)
+{
+ int64_t n_frames, stride_length, frame_step;
+ int64_t i, j;
+ int offset = 0, size;
+ unsigned int len;
+#ifdef USE_ZLIB
+ int data_start_pos;
+ tng_function_status stat;
+#endif
+ char temp, dependency, *temp_name;
+ double multiplier;
+ tng_trajectory_frame_set_t frame_set =
+ &tng_data->current_trajectory_frame_set;
+
+ tng_non_particle_data_t data;
+ char block_type_flag;
+
+ /* If we have already started writing frame sets it is too late to write
+ * non-trajectory data blocks */
+ if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
+ {
+ block_type_flag = TNG_TRAJECTORY_BLOCK;
+ }
+ else
+ {
+ block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
+ }
+
+ if(tng_output_file_init(tng_data) != TNG_SUCCESS)
+ {
+ return(TNG_CRITICAL);
+ }
+
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK)
+ {
+ data = &frame_set->tr_data[block_index];
+
+ /* If this data block has not had any data added in this frame set
+ * do not write it. */
+ if(data->first_frame_with_data < frame_set->first_frame)
+ {
+ return(TNG_SUCCESS);
+ }
+
+ stride_length = tng_max_i64(1, data->stride_length);
+ }
+ else
+ {
+ data = &tng_data->non_tr_data[block_index];
+ stride_length = 1;
+ }
+
+ switch(data->datatype)
+ {
+ case TNG_CHAR_DATA:
+ size = 1;
+ break;
+ case TNG_INT_DATA:
+ size = sizeof(int64_t);
+ break;
+ case TNG_FLOAT_DATA:
+ size = sizeof(float);
+ break;
+ case TNG_DOUBLE_DATA:
+ default:
+ size = sizeof(double);
+ }
+
+ len = (unsigned int)strlen(data->block_name) + 1;
+
+ if(!block->name || strlen(block->name) < len)
+ {
+ temp_name = realloc(block->name, len);
+ if(!temp_name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len+1,
+ __FILE__, __LINE__);
+ free(block->name);
+ block->name = 0;
+ return(TNG_CRITICAL);
+ }
+ block->name = temp_name;
+ }
+ strncpy(block->name, data->block_name, len);
+ block->id = data->block_id;
+
+ /* If writing frame independent data data->n_frames is 0, but n_frames
+ is used for the loop writing the data (and reserving memory) and needs
+ to be at least 1 */
+ n_frames = tng_max_i64(1, data->n_frames);
+
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK)
+ {
+ /* If the frame set is finished before writing the full number of frames
+ make sure the data block is not longer than the frame set. */
+ n_frames = tng_min_i64(n_frames, frame_set->n_frames);
+
+ n_frames -= (data->first_frame_with_data - frame_set->first_frame);
+ }
+
+ frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
+ n_frames / stride_length;
+
+ /* TNG compression will use compression precision to get integers from
+ * floating point data. The compression multiplier stores that information
+ * to be able to return the precision of the compressed data. */
+ if(data->codec_id == TNG_TNG_COMPRESSION)
+ {
+ data->compression_multiplier = tng_data->compression_precision;
+ }
+ /* Uncompressed data blocks do not use compression multipliers at all.
+ * GZip compression does not need it either. */
+ else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
+ {
+ data->compression_multiplier = 1.0;
+ }
+
+ block->block_contents_size = sizeof(char) * 2 +
+ sizeof(data->n_values_per_frame) +
+ sizeof(data->codec_id);
+
+ if(stride_length > 1)
+ {
+ block->block_contents_size += sizeof(data->first_frame_with_data) +
+ sizeof(data->stride_length);
+ }
+
+ if(data->codec_id != TNG_UNCOMPRESSED)
+ {
+ block->block_contents_size += sizeof(data->compression_multiplier);
+ }
+
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0)
+ {
+ dependency = TNG_FRAME_DEPENDENT;
+ }
+ else
+ {
+ dependency = 0;
+ }
+ if(dependency & TNG_FRAME_DEPENDENT)
+ {
+ block->block_contents_size += sizeof(char);
+ }
+
+#ifdef USE_ZLIB
+ data_start_pos = block->block_contents_size;
+#endif
+
+ if(data->datatype == TNG_CHAR_DATA)
+ {
+ for(i = n_frames; i--;)
+ {
+ for(j = data->n_values_per_frame; j--;)
+ {
+ block->block_contents_size += strlen(data->strings[i][j]) + 1;
+ }
+ }
+ }
+ else
+ {
+ block->block_contents_size += size * frame_step *
+ data->n_values_per_frame;
+ }
+
+ if(block->block_contents)
+ {
+ free(block->block_contents);
+ }
+ block->block_contents = malloc(block->block_contents_size);
+ if(!block->block_contents)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ block->block_contents_size, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+
+ memcpy(block->block_contents, &data->datatype, sizeof(char));
+ offset += sizeof(char);
+
+ memcpy(block->block_contents+offset, &dependency, sizeof(char));
+ offset += sizeof(char);
+
+ if(dependency & TNG_FRAME_DEPENDENT)
+ {
+ if(stride_length > 1)
+ {
+ temp = 1;
+ }
+ else
+ {
+ temp = 0;
+ }
+ memcpy(block->block_contents+offset, &temp, sizeof(char));
+ offset += sizeof(char);
+ }
+
+ memcpy(block->block_contents+offset, &data->n_values_per_frame,
+ sizeof(data->n_values_per_frame));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(data->n_values_per_frame);
+
+ memcpy(block->block_contents+offset, &data->codec_id,
+ sizeof(data->codec_id));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(data->codec_id);
+
+ if(data->codec_id != TNG_UNCOMPRESSED)
+ {
+ memcpy(block->block_contents+offset, &data->compression_multiplier,
+ sizeof(data->compression_multiplier));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(data->compression_multiplier);
+ }
+
+ if(data->n_frames > 0 && stride_length > 1)
+ {
+ /* FIXME: first_frame_with_data is not reliably set */
+ if(data->first_frame_with_data == 0)
+ {
+ data->first_frame_with_data = frame_set->first_frame;
+ }
+ memcpy(block->block_contents+offset, &data->first_frame_with_data,
+ sizeof(data->first_frame_with_data));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(data->first_frame_with_data);
+
+ memcpy(block->block_contents+offset, &stride_length,
+ sizeof(data->stride_length));
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)block->header_contents+offset)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ offset += sizeof(data->stride_length);
+ }
+
+ if(data->datatype == TNG_CHAR_DATA)
+ {
+ if(data->strings)
+ {
+ for(i = 0; i < frame_step; i++)
+ {
+ for(j = 0; j < data->n_values_per_frame; j++)
+ {
+ len = (unsigned int)strlen(data->strings[i][j]) + 1;
+ strncpy(block->block_contents+offset, data->strings[i][j],
+ len);
+ offset += len;
+ }
+ }
+ }
+ }
+ else if(data->values)
+ {
+ memcpy(block->block_contents + offset, data->values,
+ block->block_contents_size - offset);
+ switch(data->datatype)
+ {
+ case TNG_FLOAT_DATA:
+ if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
+ data->codec_id == TNG_TNG_COMPRESSION)
+ {
+ if(tng_data->input_endianness_swap_func_32)
+ {
+ for(i = offset; i < block->block_contents_size; i+=size)
+ {
+ if(tng_data->input_endianness_swap_func_32(tng_data,
+ (int32_t *)(block->block_contents + i))
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ }
+ }
+ else
+ {
+ multiplier = data->compression_multiplier;
+ if(fabs(multiplier - 1.0) > 0.00001 ||
+ tng_data->input_endianness_swap_func_32)
+ {
+ for(i = offset; block->block_contents_size; i+=size)
+ {
+ *(float *)(block->block_contents + i) *= (float)multiplier;
+ if(tng_data->input_endianness_swap_func_32 &&
+ tng_data->input_endianness_swap_func_32(tng_data,
+ (int32_t *)(block->block_contents + i))
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ }
+ }
+ break;
+ case TNG_INT_DATA:
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ for(i = offset; i < block->block_contents_size; i+=size)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ (int64_t *)(block->block_contents + i))
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ }
+ break;
+ case TNG_DOUBLE_DATA:
+ if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
+ data->codec_id == TNG_TNG_COMPRESSION)
+ {
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ for(i = offset; i < block->block_contents_size; i+=size)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ (int64_t *)(block->block_contents + i))
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ }
+ }
+ else
+ {
+ multiplier = data->compression_multiplier;
+ if(fabs(multiplier - 1.0) > 0.00001 ||
+ tng_data->input_endianness_swap_func_64)
+ {
+ for(i = offset; i < block->block_contents_size; i+=size)
+ {
+ *(double *)(block->block_contents + i) *= multiplier;
+ if(tng_data->input_endianness_swap_func_64 &&
+ tng_data->input_endianness_swap_func_64(tng_data,
+ (int64_t *)(block->block_contents + i))
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ }
+ }
+ break;
+ case TNG_CHAR_DATA:
+ break;
+ }
+ }
+ else
+ {
+ memset(block->block_contents+offset, 0, block->block_contents_size - offset);
+ }
+
+ frame_set->n_written_frames += frame_set->n_unwritten_frames;
+ frame_set->n_unwritten_frames = 0;
+
+ if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0)
+ {
+ switch(data->codec_id)
+ {
+#ifdef USE_ZLIB
+ case TNG_GZIP_COMPRESSION:
+ /* fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
+ stat = tng_gzip_compress(tng_data, block,
+ block->block_contents + data_start_pos,
+ block->block_contents_size - data_start_pos);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
+ __LINE__);
+ if(stat == TNG_CRITICAL)
+ {
+ return(TNG_CRITICAL);
+ }
+ data->codec_id = TNG_UNCOMPRESSED;
+ }
+ /* fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
+ break;
+#endif
+ }
+ }
+
+ if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
+ tng_data->output_file_path, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ if(fwrite(block->block_contents, block->block_contents_size, 1,
+ tng_data->output_file) != 1)
+ {
+ fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ return(TNG_SUCCESS);
+}
+
+/** Read the meta information of a data block (particle or non-particle data).
+ * @param tng_data is a trajectory data container.
+ * @param block is the block to store the data (should already contain
+ * the block headers).
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_data_block_meta_information_read
+ (tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ int *offset,
+ char *datatype,
+ char *dependency,
+ char *sparse_data,
+ int64_t *n_values,
+ int64_t *codec_id,
+ int64_t *first_frame_with_data,
+ int64_t *stride_length,
+ int64_t *n_frames,
+ int64_t *num_first_particle,
+ int64_t *block_n_particles,
+ double *multiplier)
+{
+ int meta_size;
+ char *contents;
+
+ if(block->block_contents)
+ {
+ contents = block->block_contents;
+ }
+ else
+ {
+ meta_size = 3 * sizeof(char) + sizeof(double) + 6 * sizeof(int64_t);
+ contents = malloc(meta_size);
+
+ if(!contents)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
+ meta_size, __FILE__, __LINE__);
+ }
+
+ if(fread(contents, meta_size, 1, tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Cannot read data block meta information. %s: %d\n", __FILE__, __LINE__);
+ free(contents);
+ return(TNG_CRITICAL);
+ }
+ }
+
+ memcpy(datatype, contents+*offset,
+ sizeof(*datatype));
+ *offset += sizeof(*datatype);
+
+ memcpy(dependency, contents+*offset,
+ sizeof(*dependency));
+ *offset += sizeof(*dependency);
+
+ if(*dependency & TNG_FRAME_DEPENDENT)
+ {
+ memcpy(sparse_data, contents+*offset,
+ sizeof(*sparse_data));
+ *offset += sizeof(*sparse_data);
+ }
+
+ memcpy(n_values, contents+*offset,
+ sizeof(*n_values));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ n_values)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ *offset += sizeof(*n_values);
+
+ memcpy(codec_id, contents+*offset,
+ sizeof(*codec_id));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ codec_id)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ *offset += sizeof(*codec_id);
+
+ if(*codec_id != TNG_UNCOMPRESSED)
+ {
+ memcpy(multiplier, contents+*offset,
+ sizeof(*multiplier));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ (int64_t *) multiplier)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ *offset += sizeof(*multiplier);
+ }
+ else
+ {
+ *multiplier = 1;
+ }
+
+ if(*dependency & TNG_FRAME_DEPENDENT)
+ {
+ if(*sparse_data)
+ {
+ memcpy(first_frame_with_data, contents+*offset,
+ sizeof(*first_frame_with_data));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ first_frame_with_data)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ *offset += sizeof(*first_frame_with_data);
+
+ memcpy(stride_length, contents+*offset,
+ sizeof(*stride_length));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ stride_length)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ *offset += sizeof(*stride_length);
+ *n_frames = tng_data->current_trajectory_frame_set.n_frames -
+ (*first_frame_with_data -
+ tng_data->current_trajectory_frame_set.first_frame);
+ }
+ else
+ {
+ *first_frame_with_data = 0;
+ *stride_length = 1;
+ *n_frames = tng_data->current_trajectory_frame_set.n_frames;
+ }
+ }
+ else
+ {
+ *first_frame_with_data = 0;
+ *stride_length = 1;
+ *n_frames = 1;
+ }
+
+ if (*dependency & TNG_PARTICLE_DEPENDENT)
+ {
+ memcpy(num_first_particle, contents+*offset,
+ sizeof(*num_first_particle));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ num_first_particle)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ *offset += sizeof(*num_first_particle);
+
+ memcpy(block_n_particles, contents+*offset,
+ sizeof(*block_n_particles));
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ block_n_particles)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ *offset += sizeof(*block_n_particles);
+ }
+
+ if(!block->block_contents)
+ {
+ free(contents);
+ }
+ return(TNG_SUCCESS);
+}
+
+/** Read the contents of a data block (particle or non-particle data).
+ * @param tng_data is a trajectory data container.
+ * @param block is the block to store the data (should already contain
+ * the block headers).
+ * @param hash_mode is an option to decide whether to use the md5 hash or not.
+ * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
+ * compared to the md5 hash of the read contents to ensure valid data.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_data_block_contents_read
+ (tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ const char hash_mode)
+{
+ int64_t n_values, codec_id, n_frames, first_frame_with_data;
+ int64_t stride_length, block_n_particles, num_first_particle;
+ double multiplier;
+ char datatype, dependency, sparse_data;
+ int offset = 0;
+ tng_bool same_hash;
+
+ if(tng_input_file_init(tng_data) != TNG_SUCCESS)
+ {
+ return(TNG_CRITICAL);
+ }
+
+ if(block->block_contents)
+ {
+ free(block->block_contents);
+ }
+
+ block->block_contents = malloc(block->block_contents_size);
+ if(!block->block_contents)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ block->block_contents_size, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ /* Read the whole block into block_contents to be able to write it to
+ * disk even if it cannot be interpreted. */
+ if(fread(block->block_contents, block->block_contents_size, 1,
+ tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ /* FIXME: Does not check if the size of the contents matches the expected
+ * size or if the contents can be read. */
+
+ if(hash_mode == TNG_USE_HASH)
+ {
+ tng_md5_hash_match_verify(block, &same_hash);
+ if(same_hash != TNG_TRUE)
+ {
+ fprintf(stderr, "TNG library: '%s' data block contents corrupt. Hashes do not match. %s: %d\n",
+ block->name, __FILE__, __LINE__);
+ /* return(TNG_FAILURE); */
+ }
+ }
+
+ if(tng_data_block_meta_information_read(tng_data, block,
+ &offset, &datatype,
+ &dependency, &sparse_data,
+ &n_values, &codec_id,
+ &first_frame_with_data,
+ &stride_length, &n_frames,
+ &num_first_particle,
+ &block_n_particles,
+ &multiplier) == TNG_CRITICAL)
+ {
+ fprintf(stderr, "TNG library: Cannot read data block (%s) meta information. %s: %d\n",
+ block->name, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ if (dependency & TNG_PARTICLE_DEPENDENT)
+ {
+ return(tng_particle_data_read(tng_data, block,
+ &offset, datatype,
+ num_first_particle,
+ block_n_particles,
+ first_frame_with_data,
+ stride_length,
+ n_frames, n_values,
+ codec_id, multiplier));
+ }
+ else
+ {
+ return(tng_data_read(tng_data, block,
+ &offset, datatype,
+ first_frame_with_data,
+ stride_length,
+ n_frames, n_values,
+ codec_id, multiplier));
+ }
+}
+
+/** Update the md5 hash of a block already written to the file
+ * @param tng_data is a trajectory data container.
+ * @param block is the block, of which to update the md5 hash.
+ * @param header_start_pos is the file position where the block header starts.
+ * @param contents_start_pos is the file position where the block contents
+ * start.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_md5_hash_update(tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ const int64_t header_start_pos,
+ const int64_t contents_start_pos)
+{
+ if(block->block_contents)
+ {
+ free(block->block_contents);
+ }
+
+ block->block_contents = malloc(block->block_contents_size);
+ fseek(tng_data->output_file, (long)contents_start_pos, SEEK_SET);
+ if(fread(block->block_contents, block->block_contents_size, 1,
+ tng_data->output_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ tng_block_md5_hash_generate(block);
+
+ fseek(tng_data->output_file, (long)header_start_pos + 3 * sizeof(int64_t),
+ SEEK_SET);
+ fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file);
+
+ return(TNG_SUCCESS);
+}
+
+/** Update the frame set pointers in the file header (general info block),
+ * already written to disk
+ * @param tng_data is a trajectory data container.
+ * @param hash_mode specifies whether to update the block md5 hash when
+ * updating the pointers.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_header_pointers_update
+ (tng_trajectory_t tng_data, const char hash_mode)
+{
+ tng_gen_block_t block;
+ FILE *temp = tng_data->input_file;
+ int64_t output_file_pos, pos, contents_start_pos;
+
+ if(tng_output_file_init(tng_data) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ tng_data->input_file = tng_data->output_file;
+
+ tng_block_init(&block);
+
+ output_file_pos = ftell(tng_data->output_file);
+ fseek(tng_data->output_file, 0, SEEK_SET);
+
+ if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot read general info header. %s: %d\n",
+ __FILE__, __LINE__);
+ tng_data->input_file = temp;
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ contents_start_pos = ftell(tng_data->output_file);
+
+ fseek(tng_data->output_file, (long)block->block_contents_size - 5 *
+ sizeof(int64_t), SEEK_CUR);
+
+ tng_data->input_file = temp;
+
+ pos = tng_data->first_trajectory_frame_set_output_file_pos;
+
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &pos)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+
+ if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
+ {
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ pos = tng_data->last_trajectory_frame_set_output_file_pos;
+
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &pos)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+
+ if(fwrite(&pos,
+ sizeof(int64_t), 1, tng_data->output_file) != 1)
+ {
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(hash_mode == TNG_USE_HASH)
+ {
+ tng_md5_hash_update(tng_data, block, 0, contents_start_pos);
+ }
+
+ tng_block_destroy(&block);
+
+ fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
+
+ return(TNG_SUCCESS);
+}
+
+/** Update the frame set pointers in the current frame set block, already
+ * written to disk. It also updates the pointers of the blocks pointing to
+ * the current frame set block.
+ * @param tng_data is a trajectory data container.
+ * @param hash_mode specifies whether to update the block md5 hash when
+ * updating the pointers.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_frame_set_pointers_update
+ (tng_trajectory_t tng_data, const char hash_mode)
+{
+ tng_gen_block_t block;
+ tng_trajectory_frame_set_t frame_set;
+ FILE *temp = tng_data->input_file;
+ int64_t pos, output_file_pos, header_start_pos, contents_start_pos;
+
+ if(tng_output_file_init(tng_data) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ tng_block_init(&block);
+ output_file_pos = ftell(tng_data->output_file);
+
+ tng_data->input_file = tng_data->output_file;
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ /* Update previous frame set */
+ if(frame_set->prev_frame_set_file_pos != -1 &&
+ frame_set->prev_frame_set_file_pos != 0)
+ {
+ fseek(tng_data->output_file, (long)frame_set->prev_frame_set_file_pos,
+ SEEK_SET);
+
+ header_start_pos = frame_set->prev_frame_set_file_pos;
+
+ if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot read frame header. %s: %d\n",
+ __FILE__, __LINE__);
+ tng_data->input_file = temp;
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ contents_start_pos = ftell(tng_data->output_file);
+
+ fseek(tng_data->output_file, (long)block->block_contents_size - (6 *
+ sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
+
+ pos = tng_data->current_trajectory_frame_set_output_file_pos;
+
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &pos)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+
+ if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
+ {
+ tng_data->input_file = temp;
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(hash_mode == TNG_USE_HASH)
+ {
+ tng_md5_hash_update(tng_data, block, header_start_pos,
+ contents_start_pos);
+ }
+ fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
+ }
+
+ /* Update the frame set one medium stride step before */
+ if(frame_set->medium_stride_prev_frame_set_file_pos != -1 &&
+ frame_set->medium_stride_prev_frame_set_file_pos != 0)
+ {
+ fseek(tng_data->output_file,
+ (long)frame_set->medium_stride_prev_frame_set_file_pos,
+ SEEK_SET);
+
+ if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
+ __FILE__, __LINE__);
+ tng_data->input_file = temp;
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ contents_start_pos = ftell(tng_data->output_file);
+
+ fseek(tng_data->output_file, (long)block->block_contents_size - (4 *
+ sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
+
+ pos = tng_data->current_trajectory_frame_set_output_file_pos;
+
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &pos)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+
+ if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
+ {
+ tng_data->input_file = temp;
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(hash_mode == TNG_USE_HASH)
+ {
+ tng_md5_hash_update(tng_data, block,
+ frame_set->medium_stride_prev_frame_set_file_pos,
+ contents_start_pos);
+ }
+ }
+
+ /* Update the frame set one long stride step before */
+ if(frame_set->long_stride_prev_frame_set_file_pos != -1 &&
+ frame_set->long_stride_prev_frame_set_file_pos != 0)
+ {
+ fseek(tng_data->output_file,
+ (long)frame_set->long_stride_prev_frame_set_file_pos,
+ SEEK_SET);
+
+ if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
+ __FILE__, __LINE__);
+ tng_data->input_file = temp;
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ contents_start_pos = ftell(tng_data->output_file);
+
+ fseek(tng_data->output_file, (long)block->block_contents_size - (2 *
+ sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
+
+ pos = tng_data->current_trajectory_frame_set_output_file_pos;
+
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &pos)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+
+ if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
+ {
+ tng_data->input_file = temp;
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(hash_mode == TNG_USE_HASH)
+ {
+ tng_md5_hash_update(tng_data, block,
+ frame_set->long_stride_prev_frame_set_file_pos,
+ contents_start_pos);
+ }
+ }
+
+ fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
+
+ tng_data->input_file = temp;
+
+ tng_block_destroy(&block);
+
+ return(TNG_SUCCESS);
+}
+/*
+// ** Move the blocks in a frame set so that there is no unused space between
+// * them. This can only be done on the last frame set in the file and should
+// * be done e.g. if the last frame set in the file has fewer frames than
+// * default or after compressing data blocks in a frame set.
+// * @param tng_data is a trajectory data container.
+// * @details the current_trajectory_frame_set is the one that will be modified.
+// * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the frame set
+// * cannot be aligned or TNG_CRITICAL (2) if a major error has occured.
+// * FIXME: This function is not finished!!!
+// *
+// static tng_function_status tng_frame_set_align(tng_trajectory_t tng_data)
+// {
+// tng_gen_block_t block;
+// tng_trajectory_frame_set_t frame_set;
+// FILE *temp = tng_data->input_file;
+// int64_t pos, contents_start_pos, output_file_len;
+//
+// frame_set = &tng_data->current_trajectory_frame_set;
+//
+// if(frame_set->n_written_frames == frame_set->n_frames)
+// {
+// return(TNG_SUCCESS);
+// }
+//
+// if(tng_data->current_trajectory_frame_set_output_file_pos !=
+// tng_data->last_trajectory_frame_set_output_file_pos)
+// {
+// }
+//
+// if(tng_output_file_init(tng_data) != TNG_SUCCESS)
+// {
+// fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
+// __FILE__, __LINE__);
+// return(TNG_CRITICAL);
+// }
+//
+// tng_block_init(&block);
+// // output_file_pos = ftell(tng_data->output_file);
+//
+// tng_data->input_file = tng_data->output_file;
+//
+// pos = tng_data->current_trajectory_frame_set_output_file_pos;
+//
+// fseek(tng_data->output_file, pos, SEEK_SET);
+// if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
+// {
+// fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
+// __FILE__, __LINE__);
+// tng_data->input_file = temp;
+// tng_block_destroy(&block);
+// return(TNG_CRITICAL);
+// }
+//
+// contents_start_pos = ftell(tng_data->output_file);
+//
+// fseek(tng_data->output_file, 0, SEEK_END);
+// output_file_len = ftell(tng_data->output_file);
+// pos = contents_start_pos + block->block_contents_size;
+// fseek(tng_data->output_file, pos,
+// SEEK_SET);
+//
+// while(pos < output_file_len)
+// {
+// if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
+// {
+// fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
+// __FILE__, __LINE__);
+// tng_data->input_file = temp;
+// tng_block_destroy(&block);
+// return(TNG_CRITICAL);
+// }
+// pos += block->header_contents_size + block->block_contents_size;
+// fseek(tng_data->output_file, pos, SEEK_SET);
+// }
+//
+// return(TNG_SUCCESS);
+// }
+*/
+/** Finish writing the current frame set. Update the number of frames
+ * and the hashes of the frame set and all its data blocks (if hash_mode
+ * == TNG_USE_HASH).
+ * @param tng_data is a trajectory data container.
+ * @param hash_mode specifies whether to update the block md5 hash when
+ * updating the pointers.
+ * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+ * error has occured.
+ */
+static tng_function_status tng_frame_set_finalize
+ (tng_trajectory_t tng_data, const char hash_mode)
+{
+ tng_gen_block_t block;
+ tng_trajectory_frame_set_t frame_set;
+ FILE *temp = tng_data->input_file;
+ int64_t pos, contents_start_pos, output_file_len;
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ if(frame_set->n_written_frames == frame_set->n_frames)
+ {
+ return(TNG_SUCCESS);
+ }
+
+ if(tng_output_file_init(tng_data) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ tng_block_init(&block);
+/* output_file_pos = ftell(tng_data->output_file); */
+
+ tng_data->input_file = tng_data->output_file;
+
+ pos = tng_data->current_trajectory_frame_set_output_file_pos;
+
+ fseek(tng_data->output_file, (long)pos, SEEK_SET);
+
+ if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
+ __FILE__, __LINE__);
+ tng_data->input_file = temp;
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ contents_start_pos = ftell(tng_data->output_file);
+
+ fseek(tng_data->output_file, sizeof(frame_set->first_frame), SEEK_CUR);
+ if(fwrite(&frame_set->n_written_frames, sizeof(frame_set->n_frames),
+ 1, tng_data->output_file) != 1)
+ {
+ tng_data->input_file = temp;
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+
+ if(hash_mode == TNG_USE_HASH)
+ {
+ tng_md5_hash_update(tng_data, block, pos,
+ pos + block->header_contents_size);
+ }
+
+ fseek(tng_data->output_file, 0, SEEK_END);
+ output_file_len = ftell(tng_data->output_file);
+ pos = contents_start_pos + block->block_contents_size;
+ fseek(tng_data->output_file, (long)pos, SEEK_SET);
+
+ while(pos < output_file_len)
+ {
+ if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
+ __FILE__, __LINE__);
+ tng_data->input_file = temp;
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(hash_mode == TNG_USE_HASH)
+ {
+ tng_md5_hash_update(tng_data, block, pos,
+ pos + block->header_contents_size);
+ }
+ pos += block->header_contents_size + block->block_contents_size;
+ fseek(tng_data->output_file, (long)pos, SEEK_SET);
+ }
+
+ tng_data->input_file = temp;
+ tng_block_destroy(&block);
+ return(TNG_SUCCESS);
+}
+
+/*
+// ** Sets the name of a file contents block
+// * @param tng_data is a trajectory data container.
+// * @param block is the block, of which to change names.
+// * @param new_name is the new name of the block.
+// * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
+// * error has occured.
+//
+// static tng_function_status tng_block_name_set(tng_trajectory_t tng_data,
+// tng_gen_block_t block,
+// const char *new_name)
+// {
+// int len;
+//
+// len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
+//
+// * If the currently stored string length is not enough to store the new
+// * string it is freed and reallocated. *
+// if(block->name && strlen(block->name) < len)
+// {
+// free(block->name);
+// block->name = 0;
+// }
+// if(!block->name)
+// {
+// block->name = malloc(len);
+// if(!block->name)
+// {
+// fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
+// __FILE__, __LINE__);
+// return(TNG_CRITICAL);
+// }
+// }
+//
+// strncpy(block->name, new_name, len);
+//
+// return(TNG_SUCCESS);
+// }
+*/
+
+tng_function_status tng_atom_residue_get(tng_trajectory_t tng_data,
+ const tng_atom_t atom,
+ tng_residue_t *residue)
+{
+ (void) tng_data;
+
+ TNG_ASSERT(atom, "TNG library: atom must not be NULL");
+
+ *residue = atom->residue;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status tng_atom_name_get(tng_trajectory_t tng_data,
+ const tng_atom_t atom,
+ char *name,
+ const int max_len)
+{
+ (void) tng_data;
+ TNG_ASSERT(atom, "TNG library: atom must not be NULL");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
+
+ strncpy(name, atom->name, max_len - 1);
+ name[max_len - 1] = 0;
+
+ if(strlen(atom->name) > (unsigned int)max_len - 1)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status tng_atom_name_set(tng_trajectory_t tng_data,
+ tng_atom_t atom,
+ const char *new_name)
+{
+ unsigned int len;
+ (void)tng_data;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
+
+ len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
+
+ /* If the currently stored string length is not enough to store the new
+ * string it is freed and reallocated. */
+ if(atom->name && strlen(atom->name) < len)
+ {
+ free(atom->name);
+ atom->name = 0;
+ }
+ if(!atom->name)
+ {
+ atom->name = malloc(len);
+ if(!atom->name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ }
+
+ strncpy(atom->name, new_name, len);
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status tng_atom_type_get(tng_trajectory_t tng_data,
+ const tng_atom_t atom,
+ char *type,
+ const int max_len)
+{
+ (void) tng_data;
+ TNG_ASSERT(atom, "TNG library: atom must not be NULL");
+ TNG_ASSERT(type, "TNG library: type must not be a NULL pointer");
+
+ strncpy(type, atom->atom_type, max_len - 1);
+ type[max_len - 1] = 0;
+
+ if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status tng_atom_type_set(tng_trajectory_t tng_data,
+ tng_atom_t atom,
+ const char *new_type)
+{
+ unsigned int len;
+ (void)tng_data;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(new_type, "TNG library: new_type must not be a NULL pointer.");
+
+ len = tng_min_i((int)strlen(new_type) + 1, TNG_MAX_STR_LEN);
+
+ /* If the currently stored string length is not enough to store the new
+ * string it is freed and reallocated. */
+ if(atom->atom_type && strlen(atom->atom_type) < len)
+ {
+ free(atom->atom_type);
+ atom->atom_type = 0;
+ }
+ if(!atom->atom_type)
+ {
+ atom->atom_type = malloc(len);
+ if(!atom->atom_type)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ }
+
+ strncpy(atom->atom_type, new_type, len);
+
+ return(TNG_SUCCESS);
+}
+
+/** Initialise an atom struct
+ * @param atom is the atom to initialise.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+static tng_function_status tng_atom_init(tng_atom_t atom)
+{
+ atom->name = 0;
+ atom->atom_type = 0;
+
+ return(TNG_SUCCESS);
+}
+
+/** Free the memory in an atom struct
+ * @param atom is the atom to destroy.
+ * @return TNG_SUCCESS (0) if successful.
+ */
+static tng_function_status tng_atom_destroy(tng_atom_t atom)
+{
+ if(atom->name)
+ {
+ free(atom->name);
+ atom->name = 0;
+ }
+ if(atom->atom_type)
+ {
+ free(atom->atom_type);
+ atom->atom_type = 0;
+ }
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_add
+ (tng_trajectory_t tng_data,
+ const char *name,
+ tng_molecule_t *molecule)
+{
+ int64_t id, i;
+ tng_bool found_id = TNG_TRUE;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
+
+ /* Find an unused ID */
+ id = 0;
+ while(found_id)
+ {
+ found_id = TNG_FALSE;
+ for(i = tng_data->n_molecules; i--;)
+ {
+ if(tng_data->molecules[i].id == id)
+ {
+ found_id = TNG_TRUE;
+ i = 0;
+ }
+ }
+ if(found_id)
+ {
+ id++;
+ }
+ }
+
+ return(tng_molecule_w_id_add(tng_data, name, id, molecule));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_w_id_add
+ (tng_trajectory_t tng_data,
+ const char *name,
+ const int64_t id,
+ tng_molecule_t *molecule)
+{
+ tng_molecule_t new_molecules;
+ int64_t *new_molecule_cnt_list, i;
+ tng_function_status stat = TNG_SUCCESS;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
+
+ new_molecules = realloc(tng_data->molecules,
+ sizeof(struct tng_molecule) *
+ (tng_data->n_molecules + 1));
+
+ if(!new_molecules)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
+ __FILE__, __LINE__);
+ free(tng_data->molecules);
+ tng_data->molecules = 0;
+ return(TNG_CRITICAL);
+ }
+
+ new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
+ sizeof(int64_t) *
+ (tng_data->n_molecules + 1));
+
+ if(!new_molecule_cnt_list)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(int64_t) * (tng_data->n_molecules + 1),
+ __FILE__, __LINE__);
+ free(tng_data->molecule_cnt_list);
+ tng_data->molecule_cnt_list = 0;
+ free(new_molecules);
+ return(TNG_CRITICAL);
+ }
+
+ tng_data->molecules = new_molecules;
+ tng_data->molecule_cnt_list = new_molecule_cnt_list;
+
+ *molecule = &new_molecules[tng_data->n_molecules];
+
+ tng_molecule_init(tng_data, *molecule);
+ tng_molecule_name_set(tng_data, *molecule, name);
+
+ /* FIXME: Should this be a function argument instead? */
+ tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
+
+ for(i = tng_data->n_molecules; i--;)
+ {
+ if(tng_data->molecules[i].id == id)
+ {
+ stat = TNG_FAILURE;
+ fprintf(stderr, "TNG library: Molecule ID %"PRId64" already in use. %s: %d\n", id,
+ __FILE__, __LINE__);
+ break;
+ }
+ }
+
+ (*molecule)->id = id;
+
+ tng_data->n_molecules++;
+
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_existing_add
+ (tng_trajectory_t tng_data,
+ tng_molecule_t *molecule_p)
+{
+ tng_bool found_id = TNG_TRUE;
+ tng_molecule_t new_molecules, molecule;
+ int64_t *new_molecule_cnt_list, i, id;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+
+ /* Find an unused ID */
+ id = 0;
+ while(found_id)
+ {
+ found_id = TNG_FALSE;
+ for(i = tng_data->n_molecules; i--;)
+ {
+ if(tng_data->molecules[i].id == id)
+ {
+ found_id = TNG_TRUE;
+ i = 0;
+ }
+ }
+ if(found_id)
+ {
+ id++;
+ }
+ }
+
+ new_molecules = realloc(tng_data->molecules,
+ sizeof(struct tng_molecule) *
+ (tng_data->n_molecules + 1));
+
+ if(!new_molecules)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
+ __FILE__, __LINE__);
+ free(tng_data->molecules);
+ tng_data->molecules = 0;
+ return(TNG_CRITICAL);
+ }
+
+ new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
+ sizeof(int64_t) *
+ (tng_data->n_molecules + 1));
+
+ if(!new_molecule_cnt_list)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(int64_t) * (tng_data->n_molecules + 1),
+ __FILE__, __LINE__);
+ free(tng_data->molecule_cnt_list);
+ tng_data->molecule_cnt_list = 0;
+ free(new_molecules);
+ return(TNG_CRITICAL);
+ }
+
+ molecule = *molecule_p;
+
+ tng_data->molecules = new_molecules;
+ tng_data->molecule_cnt_list = new_molecule_cnt_list;
+
+ new_molecules[tng_data->n_molecules] = *molecule;
+
+ tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
+
+ free(*molecule_p);
+
+ molecule = &new_molecules[tng_data->n_molecules];
+
+ *molecule_p = molecule;
+
+ molecule->id = id;
+
+ tng_data->n_molecules++;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status tng_molecule_name_get(tng_trajectory_t tng_data,
+ const tng_molecule_t molecule,
+ char *name,
+ const int max_len)
+{
+ (void) tng_data;
+ TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
+
+ strncpy(name, molecule->name, max_len - 1);
+ name[max_len - 1] = 0;
+
+ if(strlen(molecule->name) > (unsigned int)max_len - 1)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_name_set
+ (tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ const char *new_name)
+{
+ unsigned int len;
+ (void)tng_data;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
+
+ len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
+
+ /* If the currently stored string length is not enough to store the new
+ * string it is freed and reallocated. */
+ if(molecule->name && strlen(molecule->name) < len)
+ {
+ free(molecule->name);
+ molecule->name = 0;
+ }
+ if(!molecule->name)
+ {
+ molecule->name = malloc(len);
+ if(!molecule->name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ }
+
+ strncpy(molecule->name, new_name, len);
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_get
+ (tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ int64_t *cnt)
+{
+ int64_t i, index = -1;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(cnt, "TNG library: cnt must not be a NULL pointer.");
+
+ for(i = tng_data->n_molecules; i--;)
+ {
+ if(&tng_data->molecules[i] == molecule)
+ {
+ index = i;
+ i = 0;
+ }
+ }
+ if(index == -1)
+ {
+ return(TNG_FAILURE);
+ }
+ *cnt = tng_data->molecule_cnt_list[index];
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_set
+ (tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ const int64_t cnt)
+{
+ int64_t i, old_cnt, index = -1;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+
+ for(i = tng_data->n_molecules; i--;)
+ {
+ if(&tng_data->molecules[i] == molecule)
+ {
+ index = i;
+ i = 0;
+ }
+ }
+ if(index == -1)
+ {
+ fprintf(stderr, "TNG library: Could not find molecule in TNG trajectory. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_FAILURE);
+ }
+ if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
+ {
+ old_cnt = tng_data->molecule_cnt_list[index];
+ tng_data->molecule_cnt_list[index] = cnt;
+
+ tng_data->n_particles += (cnt-old_cnt) *
+ tng_data->molecules[index].n_atoms;
+ }
+ else
+ {
+ old_cnt = tng_data->current_trajectory_frame_set.molecule_cnt_list[index];
+ tng_data->current_trajectory_frame_set.molecule_cnt_list[index] = cnt;
+
+ tng_data->current_trajectory_frame_set.n_particles += (cnt-old_cnt) *
+ tng_data->molecules[index].n_atoms;
+ }
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_find
+ (tng_trajectory_t tng_data,
+ const char *name,
+ int64_t nr,
+ tng_molecule_t *molecule)
+{
+ int64_t i, n_molecules;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
+ TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
+
+ n_molecules = tng_data->n_molecules;
+
+ for(i = 0; i < n_molecules; i++)
+ {
+ *molecule = &tng_data->molecules[i];
+ if(name[0] == 0 || strcmp(name, (*molecule)->name) == 0)
+ {
+ if(nr == -1 || nr == (*molecule)->id)
+ {
+ return(TNG_SUCCESS);
+ }
+ }
+ }
+
+ *molecule = 0;
+
+ return(TNG_FAILURE);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_of_index_get
+ (tng_trajectory_t tng_data,
+ int64_t index,
+ tng_molecule_t *molecule)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
+
+ if(index >= tng_data->n_molecules)
+ {
+ *molecule = 0;
+ return(TNG_FAILURE);
+ }
+ *molecule = &tng_data->molecules[index];
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_system_copy(tng_trajectory_t tng_data_src,
+ tng_trajectory_t tng_data_dest)
+{
+ tng_molecule_t molecule, molecule_temp;
+ tng_chain_t chain, chain_temp;
+ tng_residue_t residue, residue_temp;
+ tng_atom_t atom, atom_temp;
+ tng_bond_t bond_temp;
+ tng_function_status stat;
+ int64_t i, j, k, l, *list_temp;
+
+ TNG_ASSERT(tng_data_src, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(tng_data_dest, "TNG library: Trajectory container not properly setup.");
+
+ for(i = 0; i < tng_data_dest->n_molecules; i++)
+ {
+ molecule = &tng_data_dest->molecules[i];
+ tng_molecule_destroy(tng_data_dest, molecule);
+ }
+
+ tng_data_dest->n_molecules = 0;
+ tng_data_dest->n_particles = 0;
+
+ molecule_temp = realloc(tng_data_dest->molecules,
+ sizeof(struct tng_molecule) * tng_data_src->n_molecules);
+ if(!molecule_temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(struct tng_molecule) * tng_data_src->n_molecules,
+ __FILE__, __LINE__);
+ free(tng_data_dest->molecules);
+ tng_data_dest->molecules = 0;
+ return(TNG_CRITICAL);
+ }
+ list_temp = realloc(tng_data_dest->molecule_cnt_list,
+ sizeof(int64_t) * tng_data_src->n_molecules);
+ if(!list_temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(int64_t) * tng_data_src->n_molecules,
+ __FILE__, __LINE__);
+ free(tng_data_dest->molecule_cnt_list);
+ tng_data_dest->molecule_cnt_list = 0;
+ free(molecule_temp);
+ return(TNG_CRITICAL);
+ }
+
+ tng_data_dest->molecules = molecule_temp;
+ tng_data_dest->molecule_cnt_list = list_temp;
+
+ for(i = 0; i < tng_data_src->n_molecules; i++)
+ {
+ molecule = &tng_data_src->molecules[i];
+ stat = tng_molecule_w_id_add(tng_data_dest, molecule->name, molecule->id,
+ &molecule_temp);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot create new molecule to make a copy. %s: %d\n",
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ molecule_temp->quaternary_str = molecule->quaternary_str;
+ for(j = 0; j < molecule->n_chains; j++)
+ {
+ chain = &molecule->chains[j];
+ stat = tng_molecule_chain_w_id_add(tng_data_dest, molecule_temp,
+ chain->name, chain->id,
+ &chain_temp);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot create new chain to make a copy. %s: %d\n",
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ for(k = 0; k < chain->n_residues; k++)
+ {
+ residue = &chain->residues[k];
+ stat = tng_chain_residue_w_id_add(tng_data_dest, chain_temp,
+ residue->name, residue->id,
+ &residue_temp);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot create new residue to make a copy. %s: %d\n",
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ for(l = 0; l < residue->n_atoms; l++)
+ {
+ atom = &molecule->atoms[residue->atoms_offset + l];
+ stat = tng_residue_atom_w_id_add(tng_data_dest, residue_temp,
+ atom->name, atom->atom_type,
+ atom->id, &atom_temp);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot create new atom to make a copy. %s: %d\n",
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ }
+ }
+ }
+ molecule_temp->n_bonds = molecule->n_bonds;
+ bond_temp = realloc(molecule_temp->bonds, sizeof(struct tng_bond) *
+ molecule->n_bonds);
+ if(!bond_temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(struct tng_bond) * molecule->n_bonds,
+ __FILE__, __LINE__);
+ free(molecule_temp->bonds);
+ molecule_temp->n_bonds = 0;
+ return(TNG_CRITICAL);
+ }
+ molecule_temp->bonds = bond_temp;
+ for(j = 0; j < molecule->n_bonds; j++)
+ {
+ molecule_temp->bonds[j] = molecule->bonds[j];
+ }
+ stat = tng_molecule_cnt_set(tng_data_dest, molecule_temp,
+ tng_data_src->molecule_cnt_list[i]);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot set molecule count. %s: %d.\n",
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_num_chains_get
+ (const tng_trajectory_t tng_data,
+ const tng_molecule_t molecule,
+ int64_t *n)
+{
+ (void) tng_data;
+ TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
+ TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
+
+ *n = molecule->n_chains;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_of_index_get
+ (tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ int64_t index,
+ tng_chain_t *chain)
+{
+ (void) tng_data;
+ TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
+ TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
+
+ if(index >= molecule->n_chains)
+ {
+ *chain = 0;
+ return(TNG_FAILURE);
+ }
+ *chain = &molecule->chains[index];
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_num_residues_get
+ (const tng_trajectory_t tng_data,
+ const tng_molecule_t molecule,
+ int64_t *n)
+{
+ (void) tng_data;
+ TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
+ TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
+
+ *n = molecule->n_residues;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_residue_of_index_get
+ (tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ int64_t index,
+ tng_residue_t *residue)
+{
+ (void) tng_data;
+ TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
+ TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
+
+ if(index >= molecule->n_residues)
+ {
+ *residue = 0;
+ return(TNG_FAILURE);
+ }
+ *residue = &molecule->residues[index];
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_num_atoms_get
+ (const tng_trajectory_t tng_data,
+ const tng_molecule_t molecule,
+ int64_t *n)
+{
+ (void) tng_data;
+ TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
+ TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
+
+ *n = molecule->n_atoms;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_of_index_get
+ (tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ int64_t index,
+ tng_atom_t *atom)
+{
+ (void) tng_data;
+ TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
+ TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
+
+ if(index >= molecule->n_atoms)
+ {
+ *atom = 0;
+ return(TNG_FAILURE);
+ }
+ *atom = &molecule->atoms[index];
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_find
+ (tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ const char *name,
+ int64_t nr,
+ tng_chain_t *chain)
+{
+ int64_t i, n_chains;
+ (void)tng_data;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
+
+ n_chains = molecule->n_chains;
+
+ for(i = 0; i < n_chains; i++)
+ {
+ *chain = &molecule->chains[i];
+ if(name[0] == 0 || strcmp(name, (*chain)->name) == 0)
+ {
+ if(nr == -1 || nr == (*chain)->id)
+ {
+ return(TNG_SUCCESS);
+ }
+ }
+ }
+
+ *chain = 0;
+
+ return(TNG_FAILURE);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_add
+ (tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ const char *name,
+ tng_chain_t *chain)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
+
+ return(tng_molecule_chain_w_id_add(tng_data, molecule, name,
+ molecule->n_chains + 1, chain));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_w_id_add
+ (tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ const char *name,
+ const int64_t id,
+ tng_chain_t *chain)
+{
+ int64_t i;
+ tng_chain_t new_chains;
+ tng_function_status stat = TNG_SUCCESS;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
+
+ new_chains = realloc(molecule->chains,
+ sizeof(struct tng_chain) *
+ (molecule->n_chains + 1));
+
+ if(!new_chains)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(struct tng_chain) * (molecule->n_chains + 1),
+ __FILE__, __LINE__);
+ free(molecule->chains);
+ molecule->chains = 0;
+ return(TNG_CRITICAL);
+ }
+
+ molecule->chains = new_chains;
+
+ *chain = &new_chains[molecule->n_chains];
+ (*chain)->name = 0;
+
+ tng_chain_name_set(tng_data, *chain, name);
+
+ (*chain)->molecule = molecule;
+ (*chain)->n_residues = 0;
+
+ for(i = molecule->n_chains; i--;)
+ {
+ if(molecule->chains[i].id == id)
+ {
+ stat = TNG_FAILURE;
+ fprintf(stderr, "TNG library: Chain ID already in use. %s: %d\n", __FILE__, __LINE__);
+ break;
+ }
+ }
+
+ molecule->n_chains++;
+
+ (*chain)->id = id;
+
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_bond_add
+ (const tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ const int64_t from_atom_id,
+ const int64_t to_atom_id,
+ tng_bond_t *bond)
+{
+ int64_t i;
+ tng_bond_t new_bonds;
+ (void)tng_data;
+
+ for(i = 0; i < molecule->n_bonds; i++)
+ {
+ *bond = &molecule->bonds[i];
+ /* Check if the bond already exists */
+ if(((*bond)->from_atom_id == from_atom_id && (*bond)->to_atom_id == to_atom_id) ||
+ ((*bond)->to_atom_id == from_atom_id && (*bond)->from_atom_id == to_atom_id))
+ {
+ return(TNG_SUCCESS);
+ }
+ }
+
+ new_bonds = realloc(molecule->bonds,
+ sizeof(struct tng_bond) *
+ (molecule->n_bonds + 1));
+
+ if(!new_bonds)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(struct tng_bond) * (molecule->n_bonds + 1),
+ __FILE__, __LINE__);
+ *bond = 0;
+ free(molecule->bonds);
+ molecule->bonds = 0;
+ return(TNG_CRITICAL);
+ }
+
+ molecule->bonds = new_bonds;
+
+ *bond = &new_bonds[molecule->n_bonds];
+
+ (*bond)->from_atom_id = from_atom_id;
+ (*bond)->to_atom_id = to_atom_id;
+
+ molecule->n_bonds++;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_find
+ (tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ const char *name,
+ int64_t id,
+ tng_atom_t *atom)
+{
+ int64_t i, n_atoms;
+ (void)tng_data;
+
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
+
+ n_atoms = molecule->n_atoms;
+
+ for(i = 0; i < n_atoms; i++)
+ {
+ *atom = &molecule->atoms[i];
+ if(name[0] == 0 || strcmp(name, (*atom)->name) == 0)
+ {
+ if(id == -1 || id == (*atom)->id)
+ {
+ return(TNG_SUCCESS);
+ }
+ }
+ }
+
+ *atom = 0;
+
+ return(TNG_FAILURE);
+}
+
+tng_function_status tng_chain_name_get(const tng_trajectory_t tng_data,
+ const tng_chain_t chain,
+ char *name,
+ const int max_len)
+{
+ (void) tng_data;
+ TNG_ASSERT(chain, "TNG library: chain must not be NULL");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
+
+ strncpy(name, chain->name, max_len - 1);
+ name[max_len - 1] = 0;
+
+ if(strlen(chain->name) > (unsigned int)max_len - 1)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_chain_name_set
+ (tng_trajectory_t tng_data,
+ tng_chain_t chain,
+ const char *new_name)
+{
+ unsigned int len;
+ (void)tng_data;
+
+ TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
+
+ len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
+
+ /* If the currently stored string length is not enough to store the new
+ * string it is freed and reallocated. */
+ if(chain->name && strlen(chain->name) < len)
+ {
+ free(chain->name);
+ chain->name = 0;
+ }
+ if(!chain->name)
+ {
+ chain->name = malloc(len);
+ if(!chain->name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ }
+
+ strncpy(chain->name, new_name, len);
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_chain_num_residues_get
+ (const tng_trajectory_t tng_data,
+ const tng_chain_t chain,
+ int64_t *n)
+{
+ (void) tng_data;
+ TNG_ASSERT(chain, "TNG library: chain must not be NULL");
+ TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
+
+ *n = chain->n_residues;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_chain_residue_of_index_get
+ (tng_trajectory_t tng_data,
+ tng_chain_t chain,
+ int64_t index,
+ tng_residue_t *residue)
+{
+ (void) tng_data;
+ TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
+ TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
+
+ if(index >= chain->n_residues)
+ {
+ *residue = 0;
+ return(TNG_FAILURE);
+ }
+ *residue = &chain->residues[index];
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_chain_residue_find
+ (tng_trajectory_t tng_data,
+ tng_chain_t chain,
+ const char *name,
+ int64_t id,
+ tng_residue_t *residue)
+{
+ int64_t i, n_residues;
+ (void)tng_data;
+
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
+
+ n_residues = chain->n_residues;
+
+ for(i = 0; i < n_residues; i++)
+ {
+ *residue = &chain->residues[i];
+ if(name[0] == 0 || strcmp(name, (*residue)->name) == 0)
+ {
+ if(id == -1 || id == (*residue)->id)
+ {
+ return(TNG_SUCCESS);
+ }
+ }
+ }
+
+ *residue = 0;
+
+ return(TNG_FAILURE);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_chain_residue_add
+ (tng_trajectory_t tng_data,
+ tng_chain_t chain,
+ const char *name,
+ tng_residue_t *residue)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
+
+ return(tng_chain_residue_w_id_add(tng_data, chain, name,
+ chain->n_residues + 1, residue));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_chain_residue_w_id_add
+ (tng_trajectory_t tng_data,
+ tng_chain_t chain,
+ const char *name,
+ const int64_t id,
+ tng_residue_t *residue)
+{
+ int64_t i, curr_index;
+ tng_residue_t new_residues, temp_residue, last_residue;
+ tng_molecule_t molecule = chain->molecule;
+ tng_function_status stat = TNG_SUCCESS;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
+
+ if(chain->n_residues)
+ {
+ curr_index = chain->residues - molecule->residues;
+ }
+ else
+ {
+ curr_index = -1;
+ }
+
+ new_residues = realloc(molecule->residues,
+ sizeof(struct tng_residue) *
+ (molecule->n_residues + 1));
+
+ if(!new_residues)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(struct tng_residue) * (molecule->n_residues + 1),
+ __FILE__, __LINE__);
+ free(molecule->residues);
+ molecule->residues = 0;
+ return(TNG_CRITICAL);
+ }
+
+ molecule->residues = new_residues;
+
+ if(curr_index != -1)
+ {
+ chain->residues = new_residues + curr_index;
+ if(molecule->n_residues)
+ {
+ last_residue = &new_residues[molecule->n_residues - 1];
+
+ temp_residue = chain->residues + (chain->n_residues - 1);
+ /* Make space in list of residues to add the new residues together with the other
+ * residues of this chain */
+ if(temp_residue != last_residue)
+ {
+ ++temp_residue;
+ memmove(temp_residue + 1, temp_residue,
+ last_residue - temp_residue);
+ }
+ }
+ }
+ else
+ {
+ curr_index = molecule->n_residues;
+ }
+
+ *residue = &molecule->residues[curr_index + chain->n_residues];
+
+ if(!chain->n_residues)
+ {
+ chain->residues = *residue;
+ }
+
+ (*residue)->name = 0;
+ tng_residue_name_set(tng_data, *residue, name);
+
+ (*residue)->chain = chain;
+ (*residue)->n_atoms = 0;
+ (*residue)->atoms_offset = 0;
+
+ for(i = chain->n_residues; i--;)
+ {
+ if(chain->residues[i].id == id)
+ {
+ stat = TNG_FAILURE;
+ fprintf(stderr, "TNG library: Residue ID already in use. %s: %d\n", __FILE__, __LINE__);
+ break;
+ }
+ }
+
+ chain->n_residues++;
+ molecule->n_residues++;
+
+ (*residue)->id = id;
+
+ return(stat);
+}
+
+tng_function_status tng_residue_name_get(tng_trajectory_t tng_data,
+ const tng_residue_t residue,
+ char *name,
+ const int max_len)
+{
+ (void) tng_data;
+ TNG_ASSERT(residue, "TNG library: residue must not be NULL");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
+
+ strncpy(name, residue->name, max_len - 1);
+ name[max_len - 1] = 0;
+
+ if(strlen(residue->name) > (unsigned int)max_len - 1)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_residue_name_set(tng_trajectory_t tng_data,
+ tng_residue_t residue,
+ const char *new_name)
+{
+ unsigned int len;
+ (void)tng_data;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
+
+ len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
+
+ /* If the currently stored string length is not enough to store the new
+ * string it is freed and reallocated. */
+ if(residue->name && strlen(residue->name) < len)
+ {
+ free(residue->name);
+ residue->name = 0;
+ }
+ if(!residue->name)
+ {
+ residue->name = malloc(len);
+ if(!residue->name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ }
+
+ strncpy(residue->name, new_name, len);
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_residue_num_atoms_get
+ (const tng_trajectory_t tng_data,
+ const tng_residue_t residue,
+ int64_t *n)
+{
+ (void) tng_data;
+ TNG_ASSERT(residue, "TNG library: residue must not be NULL");
+ TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
+
+ *n = residue->n_atoms;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_residue_atom_of_index_get
+ (tng_trajectory_t tng_data,
+ tng_residue_t residue,
+ int64_t index,
+ tng_atom_t *atom)
+{
+ tng_chain_t chain;
+ tng_molecule_t molecule;
+
+ (void) tng_data;
+ TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
+ TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
+
+ if(index >= residue->n_atoms)
+ {
+ *atom = 0;
+ return(TNG_FAILURE);
+ }
+ chain = residue->chain;
+ molecule = chain->molecule;
+
+ if(index + residue->atoms_offset >= molecule->n_atoms)
+ {
+ *atom = 0;
+ return(TNG_FAILURE);
+ }
+
+ *atom = &molecule->atoms[residue->atoms_offset + index];
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_residue_atom_add
+ (tng_trajectory_t tng_data,
+ tng_residue_t residue,
+ const char *atom_name,
+ const char *atom_type,
+ tng_atom_t *atom)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
+ TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
+
+ return(tng_residue_atom_w_id_add(tng_data, residue, atom_name, atom_type,
+ residue->chain->molecule->n_atoms + 1,
+ atom));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_residue_atom_w_id_add
+ (tng_trajectory_t tng_data,
+ tng_residue_t residue,
+ const char *atom_name,
+ const char *atom_type,
+ const int64_t id,
+ tng_atom_t *atom)
+{
+ int64_t i;
+ tng_atom_t new_atoms;
+ tng_molecule_t molecule = residue->chain->molecule;
+ tng_function_status stat = TNG_SUCCESS;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
+ TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
+
+ if(!residue->n_atoms)
+ {
+ residue->atoms_offset = molecule->n_atoms;
+ }
+
+ new_atoms = realloc(molecule->atoms,
+ sizeof(struct tng_atom) *
+ (molecule->n_atoms + 1));
+
+ if(!new_atoms)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(struct tng_atom) * (molecule->n_atoms + 1),
+ __FILE__, __LINE__);
+ free(molecule->atoms);
+ molecule->atoms = 0;
+ return(TNG_CRITICAL);
+ }
+
+ molecule->atoms = new_atoms;
+
+ *atom = &new_atoms[molecule->n_atoms];
+
+ tng_atom_init(*atom);
+ tng_atom_name_set(tng_data, *atom, atom_name);
+ tng_atom_type_set(tng_data, *atom, atom_type);
+
+ (*atom)->residue = residue;
+
+ for(i = molecule->n_atoms; i--;)
+ {
+ if(molecule->atoms[i].id == id)
+ {
+ stat = TNG_FAILURE;
+ fprintf(stderr, "TNG library: Atom ID %"PRId64" already in use. %s: %d\n", id, __FILE__, __LINE__);
+ break;
+ }
+ }
+
+ residue->n_atoms++;
+ molecule->n_atoms++;
+
+ (*atom)->id = id;
+
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_alloc(const tng_trajectory_t tng_data,
+ tng_molecule_t *molecule_p)
+{
+ *molecule_p = malloc(sizeof(struct tng_molecule));
+ if(!*molecule_p)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
+ sizeof(struct tng_molecule), __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ tng_molecule_init(tng_data, *molecule_p);
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_free(const tng_trajectory_t tng_data,
+ tng_molecule_t *molecule_p)
+{
+ if(!*molecule_p)
+ {
+ return(TNG_SUCCESS);
+ }
+
+ tng_molecule_destroy(tng_data, *molecule_p);
+
+ free(*molecule_p);
+ *molecule_p = 0;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_init(const tng_trajectory_t tng_data,
+ tng_molecule_t molecule)
+{
+ (void)tng_data;
+ molecule->quaternary_str = 1;
+ molecule->name = 0;
+ molecule->n_chains = 0;
+ molecule->chains = 0;
+ molecule->n_residues = 0;
+ molecule->residues = 0;
+ molecule->n_atoms = 0;
+ molecule->atoms = 0;
+ molecule->n_bonds = 0;
+ molecule->bonds = 0;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_destroy(const tng_trajectory_t tng_data,
+ tng_molecule_t molecule)
+{
+ int64_t i;
+ (void)tng_data;
+
+ if(molecule->name)
+ {
+ free(molecule->name);
+ molecule->name = 0;
+ }
+
+ if(molecule->chains)
+ {
+ for(i = molecule->n_chains; i--;)
+ {
+ if(molecule->chains[i].name)
+ {
+ free(molecule->chains[i].name);
+ molecule->chains[i].name = 0;
+ }
+ }
+ free(molecule->chains);
+ molecule->chains = 0;
+ }
+ molecule->n_chains = 0;
+
+ if(molecule->residues)
+ {
+ for(i = molecule->n_residues; i--;)
+ {
+ if(molecule->residues[i].name)
+ {
+ free(molecule->residues[i].name);
+ molecule->residues[i].name = 0;
+ }
+ }
+ free(molecule->residues);
+ molecule->residues = 0;
+ }
+ molecule->n_residues = 0;
+
+ if(molecule->atoms)
+ {
+ for(i = molecule->n_atoms; i--;)
+ {
+ tng_atom_destroy(&molecule->atoms[i]);
+ }
+ free(molecule->atoms);
+ molecule->atoms = 0;
+ }
+ molecule->n_atoms = 0;
+
+ if(molecule->bonds)
+ {
+ free(molecule->bonds);
+ molecule->bonds = 0;
+ }
+ molecule->n_bonds = 0;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_name_of_particle_nr_get
+ (const tng_trajectory_t tng_data,
+ const int64_t nr,
+ char *name,
+ int max_len)
+{
+ int64_t cnt = 0, i, *molecule_cnt_list = 0;
+ tng_molecule_t mol;
+ tng_bool found = TNG_FALSE;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
+
+ tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
+
+ if(!molecule_cnt_list)
+ {
+ return(TNG_FAILURE);
+ }
+
+ for(i = 0; i < tng_data->n_molecules; i++)
+ {
+ mol = &tng_data->molecules[i];
+ if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
+ {
+ cnt += mol->n_atoms * molecule_cnt_list[i];
+ continue;
+ }
+ found = TNG_TRUE;
+ break;
+ }
+ if(!found)
+ {
+ return(TNG_FAILURE);
+ }
+
+ strncpy(name, mol->name, max_len - 1);
+ name[max_len - 1] = 0;
+
+ if(strlen(mol->name) > (unsigned int)max_len - 1)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_id_of_particle_nr_get
+ (const tng_trajectory_t tng_data,
+ const int64_t nr,
+ int64_t *id)
+{
+ int64_t cnt = 0, i, *molecule_cnt_list = 0;
+ tng_molecule_t mol;
+ tng_bool found = TNG_FALSE;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
+
+ tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
+
+ if(!molecule_cnt_list)
+ {
+ return(TNG_FAILURE);
+ }
+
+ for(i = 0; i < tng_data->n_molecules; i++)
+ {
+ mol = &tng_data->molecules[i];
+ if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
+ {
+ cnt += mol->n_atoms * molecule_cnt_list[i];
+ continue;
+ }
+ found = TNG_TRUE;
+ break;
+ }
+ if(!found)
+ {
+ return(TNG_FAILURE);
+ }
+
+ *id = mol->id;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molsystem_bonds_get
+ (const tng_trajectory_t tng_data,
+ int64_t *n_bonds,
+ int64_t **from_atoms,
+ int64_t **to_atoms)
+{
+ int64_t atom_cnt = 0, cnt, mol_cnt, i, j, k;
+ int64_t from_atom, to_atom, *molecule_cnt_list = 0;
+ tng_molecule_t mol;
+ tng_bond_t bond;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(n_bonds, "TNG library: n_bonds must not be a NULL pointer.");
+ TNG_ASSERT(from_atoms, "TNG library: from_atoms must not be a NULL pointer.");
+ TNG_ASSERT(to_atoms, "TNG library: to_atoms must not be a NULL pointer.");
+
+ tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
+
+ if(!molecule_cnt_list)
+ {
+ return(TNG_FAILURE);
+ }
+
+ *n_bonds = 0;
+ /* First count the total number of bonds to allocate memory */
+ for(i = 0; i < tng_data->n_molecules; i++)
+ {
+ mol = &tng_data->molecules[i];
+ mol_cnt = molecule_cnt_list[i];
+ *n_bonds += mol_cnt * mol->n_bonds;
+ }
+ if(*n_bonds == 0)
+ {
+ return(TNG_SUCCESS);
+ }
+
+ *from_atoms = malloc(sizeof(int64_t) * (*n_bonds));
+ if(!*from_atoms)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ *to_atoms = malloc(sizeof(int64_t) * (*n_bonds));
+ if(!*to_atoms)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
+ free(*from_atoms);
+ *from_atoms = 0;
+ return(TNG_CRITICAL);
+ }
+
+ cnt = 0;
+ for(i = 0; i < tng_data->n_molecules; i++)
+ {
+ mol = &tng_data->molecules[i];
+ mol_cnt = molecule_cnt_list[i];
+ for(j = 0; j < mol_cnt; j++)
+ {
+ for(k = 0; k < mol->n_bonds; k++)
+ {
+ bond = &mol->bonds[k];
+ from_atom = atom_cnt + bond->from_atom_id;
+ to_atom = atom_cnt + bond->to_atom_id;
+ (*from_atoms)[cnt] = from_atom;
+ (*to_atoms)[cnt++] = to_atom;
+ }
+ atom_cnt += mol->n_atoms;
+ }
+ }
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_chain_name_of_particle_nr_get
+ (const tng_trajectory_t tng_data,
+ const int64_t nr,
+ char *name,
+ int max_len)
+{
+ int64_t cnt = 0, i, *molecule_cnt_list = 0;
+ tng_molecule_t mol;
+ tng_atom_t atom;
+ tng_bool found = TNG_FALSE;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
+
+ tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
+
+ if(!molecule_cnt_list)
+ {
+ return(TNG_FAILURE);
+ }
+
+ for(i = 0; i < tng_data->n_molecules; i++)
+ {
+ mol = &tng_data->molecules[i];
+ if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
+ {
+ cnt += mol->n_atoms * molecule_cnt_list[i];
+ continue;
+ }
+ atom = &mol->atoms[nr % mol->n_atoms];
+ found = TNG_TRUE;
+ break;
+ }
+ if(!found)
+ {
+ return(TNG_FAILURE);
+ }
+ if(!atom->residue || !atom->residue->chain)
+ {
+ return(TNG_FAILURE);
+ }
+
+ strncpy(name, atom->residue->chain->name, max_len - 1);
+ name[max_len - 1] = 0;
+
+ if(strlen(atom->residue->chain->name) > (unsigned int)max_len - 1)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_residue_name_of_particle_nr_get
+ (const tng_trajectory_t tng_data,
+ const int64_t nr,
+ char *name,
+ int max_len)
+{
+ int64_t cnt = 0, i, *molecule_cnt_list = 0;
+ tng_molecule_t mol;
+ tng_atom_t atom;
+ tng_bool found = TNG_FALSE;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
+
+ tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
+
+ if(!molecule_cnt_list)
+ {
+ return(TNG_FAILURE);
+ }
+
+ for(i = 0; i < tng_data->n_molecules; i++)
+ {
+ mol = &tng_data->molecules[i];
+ if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
+ {
+ cnt += mol->n_atoms * molecule_cnt_list[i];
+ continue;
+ }
+ atom = &mol->atoms[nr % mol->n_atoms];
+ found = TNG_TRUE;
+ break;
+ }
+ if(!found)
+ {
+ return(TNG_FAILURE);
+ }
+ if(!atom->residue)
+ {
+ return(TNG_FAILURE);
+ }
+
+ strncpy(name, atom->residue->name, max_len - 1);
+ name[max_len - 1] = 0;
+
+ if(strlen(atom->residue->name) > (unsigned int)max_len - 1)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_residue_id_of_particle_nr_get
+ (const tng_trajectory_t tng_data,
+ const int64_t nr,
+ int64_t *id)
+{
+ int64_t cnt = 0, i, *molecule_cnt_list = 0;
+ tng_molecule_t mol;
+ tng_atom_t atom;
+ tng_bool found = TNG_FALSE;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
+
+ tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
+
+ if(!molecule_cnt_list)
+ {
+ return(TNG_FAILURE);
+ }
+
+ for(i = 0; i < tng_data->n_molecules; i++)
+ {
+ mol = &tng_data->molecules[i];
+ if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
+ {
+ cnt += mol->n_atoms * molecule_cnt_list[i];
+ continue;
+ }
+ atom = &mol->atoms[nr % mol->n_atoms];
+ found = TNG_TRUE;
+ break;
+ }
+ if(!found)
+ {
+ return(TNG_FAILURE);
+ }
+ if(!atom->residue)
+ {
+ return(TNG_FAILURE);
+ }
+
+ *id = atom->residue->id;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_global_residue_id_of_particle_nr_get
+ (const tng_trajectory_t tng_data,
+ const int64_t nr,
+ int64_t *id)
+{
+ int64_t cnt = 0, i, offset = 0, *molecule_cnt_list = 0;
+ tng_molecule_t mol;
+ tng_atom_t atom;
+ tng_bool found = TNG_FALSE;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
+
+ tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
+
+ if(!molecule_cnt_list)
+ {
+ return(TNG_FAILURE);
+ }
+
+ for(i = 0; i < tng_data->n_molecules; i++)
+ {
+ mol = &tng_data->molecules[i];
+ if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
+ {
+ cnt += mol->n_atoms * molecule_cnt_list[i];
+ offset += mol->n_residues * molecule_cnt_list[i];
+ continue;
+ }
+ atom = &mol->atoms[nr % mol->n_atoms];
+ found = TNG_TRUE;
+ break;
+ }
+ if(!found)
+ {
+ return(TNG_FAILURE);
+ }
+ if(!atom->residue)
+ {
+ return(TNG_FAILURE);
+ }
+
+ offset += mol->n_residues * ((nr - cnt) / mol->n_atoms);
+
+ *id = atom->residue->id + offset;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_atom_name_of_particle_nr_get
+ (const tng_trajectory_t tng_data,
+ const int64_t nr,
+ char *name,
+ int max_len)
+{
+ int64_t cnt = 0, i, *molecule_cnt_list = 0;
+ tng_molecule_t mol;
+ tng_atom_t atom;
+ tng_bool found = TNG_FALSE;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
+
+ tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
+
+ if(!molecule_cnt_list)
+ {
+ return(TNG_FAILURE);
+ }
+
+ for(i = 0; i < tng_data->n_molecules; i++)
+ {
+ mol = &tng_data->molecules[i];
+ if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
+ {
+ cnt += mol->n_atoms * molecule_cnt_list[i];
+ continue;
+ }
+ atom = &mol->atoms[nr % mol->n_atoms];
+ found = TNG_TRUE;
+ break;
+ }
+ if(!found)
+ {
+ return(TNG_FAILURE);
+ }
+
+ strncpy(name, atom->name, max_len - 1);
+ name[max_len - 1] = 0;
+
+ if(strlen(atom->name) > (unsigned int)max_len - 1)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status tng_atom_type_of_particle_nr_get
+ (const tng_trajectory_t tng_data,
+ const int64_t nr,
+ char *type,
+ int max_len)
+{
+ int64_t cnt = 0, i, *molecule_cnt_list = 0;
+ tng_molecule_t mol;
+ tng_atom_t atom;
+ tng_bool found = TNG_FALSE;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
+
+ tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
+
+ if(!molecule_cnt_list)
+ {
+ return(TNG_FAILURE);
+ }
+
+ for(i = 0; i < tng_data->n_molecules; i++)
+ {
+ mol = &tng_data->molecules[i];
+ if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
+ {
+ cnt += mol->n_atoms * molecule_cnt_list[i];
+ continue;
+ }
+ atom = &mol->atoms[nr % mol->n_atoms];
+ found = TNG_TRUE;
+ break;
+ }
+ if(!found)
+ {
+ return(TNG_FAILURE);
+ }
+
+ strncpy(type, atom->atom_type, max_len - 1);
+ type[max_len - 1] = 0;
+
+ if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_particle_mapping_add
+ (tng_trajectory_t tng_data,
+ const int64_t num_first_particle,
+ const int64_t n_particles,
+ const int64_t *mapping_table)
+{
+ int64_t i;
+ tng_particle_mapping_t mapping;
+ tng_trajectory_frame_set_t frame_set;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ /* Sanity check of the particle ranges. Split into multiple if
+ * statements for improved readability */
+ for(i = 0; i < frame_set->n_mapping_blocks; i++)
+ {
+ mapping = &frame_set->mappings[i];
+ if(num_first_particle >= mapping->num_first_particle &&
+ num_first_particle < mapping->num_first_particle +
+ mapping->n_particles)
+ {
+ fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
+ return(TNG_FAILURE);
+ }
+ if(num_first_particle + n_particles >=
+ mapping->num_first_particle &&
+ num_first_particle + n_particles <
+ mapping->num_first_particle + mapping->n_particles)
+ {
+ fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
+ return(TNG_FAILURE);
+ }
+ if(mapping->num_first_particle >= num_first_particle &&
+ mapping->num_first_particle < num_first_particle +
+ n_particles)
+ {
+ fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
+ return(TNG_FAILURE);
+ }
+ if(mapping->num_first_particle + mapping->n_particles >
+ num_first_particle &&
+ mapping->num_first_particle + mapping->n_particles <
+ num_first_particle + n_particles)
+ {
+ fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
+ return(TNG_FAILURE);
+ }
+ }
+
+ frame_set->n_mapping_blocks++;
+
+ mapping = realloc(frame_set->mappings, sizeof(struct tng_particle_mapping) *
+ frame_set->n_mapping_blocks);
+
+ if(!mapping)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(struct tng_particle_mapping)*frame_set->n_mapping_blocks,
+ __FILE__, __LINE__);
+ free(frame_set->mappings);
+ frame_set->mappings = 0;
+ return(TNG_CRITICAL);
+ }
+ frame_set->mappings = mapping;
+
+ frame_set->mappings[frame_set->n_mapping_blocks - 1].num_first_particle = num_first_particle;
+ frame_set->mappings[frame_set->n_mapping_blocks - 1].n_particles = n_particles;
+
+ frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers = malloc(sizeof(int64_t) * n_particles);
+ if(!frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(int64_t) * n_particles, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ for(i=0; i<n_particles; i++)
+ {
+ frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers[i] = mapping_table[i];
+ }
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_particle_mapping_free(tng_trajectory_t tng_data)
+{
+ tng_trajectory_frame_set_t frame_set;
+ tng_particle_mapping_t mapping;
+ int64_t i;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ if(frame_set->n_mapping_blocks && frame_set->mappings)
+ {
+ for(i = frame_set->n_mapping_blocks; i--;)
+ {
+ mapping = &frame_set->mappings[i];
+ if(mapping->real_particle_numbers)
+ {
+ free(mapping->real_particle_numbers);
+ mapping->real_particle_numbers = 0;
+ }
+ }
+ free(frame_set->mappings);
+ frame_set->mappings = 0;
+ frame_set->n_mapping_blocks = 0;
+ }
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_trajectory_init(tng_trajectory_t *tng_data_p)
+{
+ time_t seconds;
+ tng_trajectory_frame_set_t frame_set;
+ tng_trajectory_t tng_data;
+
+ *tng_data_p = malloc(sizeof(struct tng_trajectory));
+ if(!*tng_data_p)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
+ sizeof(struct tng_trajectory), __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ tng_data = *tng_data_p;
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ tng_data->input_file_path = 0;
+ tng_data->input_file = 0;
+ tng_data->input_file_len = 0;
+ tng_data->output_file_path = 0;
+ tng_data->output_file = 0;
+
+ tng_data->first_program_name = 0;
+ tng_data->first_user_name = 0;
+ tng_data->first_computer_name = 0;
+ tng_data->first_pgp_signature = 0;
+ tng_data->last_program_name = 0;
+ tng_data->last_user_name = 0;
+ tng_data->last_computer_name = 0;
+ tng_data->last_pgp_signature = 0;
+ tng_data->forcefield_name = 0;
+
+ seconds = time(0);
+ if ( seconds == -1)
+ {
+ fprintf(stderr, "TNG library: Cannot get time. %s: %d\n", __FILE__, __LINE__);
+ }
+ else
+ {
+ tng_data->time = seconds;
+ }
+
+ tng_data->var_num_atoms_flag = TNG_CONSTANT_N_ATOMS;
+ tng_data->first_trajectory_frame_set_input_file_pos = -1;
+ tng_data->last_trajectory_frame_set_input_file_pos = -1;
+ tng_data->current_trajectory_frame_set_input_file_pos = -1;
+ tng_data->first_trajectory_frame_set_output_file_pos = -1;
+ tng_data->last_trajectory_frame_set_output_file_pos = -1;
+ tng_data->current_trajectory_frame_set_output_file_pos = -1;
+ tng_data->frame_set_n_frames = 100;
+ tng_data->n_trajectory_frame_sets = 0;
+ tng_data->n_trajectory_blocks = 0;
+ tng_data->medium_stride_length = 100;
+ tng_data->long_stride_length = 10000;
+
+ tng_data->time_per_frame = -1;
+
+ tng_data->n_particle_data_blocks = 0;
+ tng_data->n_data_blocks = 0;
+
+ tng_data->non_tr_particle_data = 0;
+ tng_data->non_tr_data = 0;
+
+ tng_data->compress_algo_pos = 0;
+ tng_data->compress_algo_vel = 0;
+ tng_data->compression_precision = 1000;
+ tng_data->distance_unit_exponential = -9;
+
+ frame_set->first_frame = -1;
+ frame_set->n_mapping_blocks = 0;
+ frame_set->mappings = 0;
+ frame_set->molecule_cnt_list = 0;
+
+ frame_set->n_particle_data_blocks = 0;
+ frame_set->n_data_blocks = 0;
+
+ frame_set->tr_particle_data = 0;
+ frame_set->tr_data = 0;
+
+ frame_set->n_written_frames = 0;
+ frame_set->n_unwritten_frames = 0;
+
+ frame_set->next_frame_set_file_pos = -1;
+ frame_set->prev_frame_set_file_pos = -1;
+ frame_set->medium_stride_next_frame_set_file_pos = -1;
+ frame_set->medium_stride_prev_frame_set_file_pos = -1;
+ frame_set->long_stride_next_frame_set_file_pos = -1;
+ frame_set->long_stride_prev_frame_set_file_pos = -1;
+
+ frame_set->first_frame_time = -1;
+
+ tng_data->n_molecules = 0;
+ tng_data->molecules = 0;
+ tng_data->molecule_cnt_list = 0;
+ tng_data->n_particles = 0;
+
+ {
+ /* Check the endianness of the computer */
+ static int32_t endianness_32 = 0x01234567;
+ /* 0x01234567 */
+ if ( *(const unsigned char*)&endianness_32 == 0x01 )
+ {
+ tng_data->endianness_32 = TNG_BIG_ENDIAN_32;
+ }
+
+ /* 0x67452301 */
+ else if( *(const unsigned char*)&endianness_32 == 0x67 )
+ {
+ tng_data->endianness_32 = TNG_LITTLE_ENDIAN_32;
+
+ }
+
+ /* 0x45670123 */
+ else if ( *(const unsigned char*)&endianness_32 == 0x45 )
+ {
+ tng_data->endianness_32 = TNG_BYTE_PAIR_SWAP_32;
+ }
+ }
+ {
+ static int64_t endianness_64 = 0x0123456789ABCDEFLL;
+ /* 0x0123456789ABCDEF */
+ if ( *(const unsigned char*)&endianness_64 == 0x01 )
+ {
+ tng_data->endianness_64 = TNG_BIG_ENDIAN_64;
+ }
+
+ /* 0xEFCDAB8967452301 */
+ else if ( *(const unsigned char*)&endianness_64 == 0xEF )
+ {
+ tng_data->endianness_64 = TNG_LITTLE_ENDIAN_64;
+ }
+
+ /* 0x89ABCDEF01234567 */
+ else if ( *(const unsigned char*)&endianness_64 == 0x89 )
+ {
+ tng_data->endianness_64 = TNG_QUAD_SWAP_64;
+ }
+
+ /* 0x45670123CDEF89AB */
+ else if ( *(const unsigned char*)&endianness_64 == 0x45 )
+ {
+ tng_data->endianness_64 = TNG_BYTE_PAIR_SWAP_64;
+ }
+
+ /* 0x23016745AB89EFCD */
+ else if ( *(const unsigned char*)&endianness_64 == 0x23 )
+ {
+ tng_data->endianness_64 = TNG_BYTE_SWAP_64;
+ }
+ }
+
+ /* By default do not swap the byte order, i.e. keep the byte order of the
+ * architecture. The input file endianness will be set when reading the
+ * header. The output endianness can be changed - before the file is
+ * written. */
+ tng_data->input_endianness_swap_func_32 = 0;
+ tng_data->input_endianness_swap_func_64 = 0;
+ tng_data->output_endianness_swap_func_32 = 0;
+ tng_data->output_endianness_swap_func_64 = 0;
+
+ tng_data->current_trajectory_frame_set.next_frame_set_file_pos = -1;
+ tng_data->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
+ tng_data->current_trajectory_frame_set.n_frames = 0;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *tng_data_p)
+{
+ int64_t i, j, k, l;
+ int64_t n_particles, n_values_per_frame;
+ tng_trajectory_t tng_data = *tng_data_p;
+ tng_trajectory_frame_set_t frame_set;
+
+ if(!*tng_data_p)
+ {
+ return(TNG_SUCCESS);
+ }
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ if(tng_data->input_file_path)
+ {
+ free(tng_data->input_file_path);
+ tng_data->input_file_path = 0;
+ }
+
+ if(tng_data->input_file)
+ {
+ fclose(tng_data->input_file);
+ tng_data->input_file = 0;
+ }
+
+ if(tng_data->output_file_path)
+ {
+ free(tng_data->output_file_path);
+ tng_data->output_file_path = 0;
+ }
+
+ if(tng_data->output_file)
+ {
+ /* FIXME: Do not always write the hash */
+ tng_frame_set_finalize(tng_data, TNG_USE_HASH);
+ fclose(tng_data->output_file);
+ tng_data->output_file = 0;
+ }
+
+ if(tng_data->first_program_name)
+ {
+ free(tng_data->first_program_name);
+ tng_data->first_program_name = 0;
+ }
+
+ if(tng_data->last_program_name)
+ {
+ free(tng_data->last_program_name);
+ tng_data->last_program_name = 0;
+ }
+
+ if(tng_data->first_user_name)
+ {
+ free(tng_data->first_user_name);
+ tng_data->first_user_name = 0;
+ }
+
+ if(tng_data->last_user_name)
+ {
+ free(tng_data->last_user_name);
+ tng_data->last_user_name = 0;
+ }
+
+ if(tng_data->first_computer_name)
+ {
+ free(tng_data->first_computer_name);
+ tng_data->first_computer_name = 0;
+ }
+
+ if(tng_data->last_computer_name)
+ {
+ free(tng_data->last_computer_name);
+ tng_data->last_computer_name = 0;
+ }
+
+ if(tng_data->first_pgp_signature)
+ {
+ free(tng_data->first_pgp_signature);
+ tng_data->first_pgp_signature = 0;
+ }
+
+ if(tng_data->last_pgp_signature)
+ {
+ free(tng_data->last_pgp_signature);
+ tng_data->last_pgp_signature = 0;
+ }
+
+ if(tng_data->forcefield_name)
+ {
+ free(tng_data->forcefield_name);
+ tng_data->forcefield_name = 0;
+ }
+
+ tng_frame_set_particle_mapping_free(tng_data);
+
+ if(frame_set->molecule_cnt_list)
+ {
+ free(frame_set->molecule_cnt_list);
+ frame_set->molecule_cnt_list = 0;
+ }
+
+ if(tng_data->var_num_atoms_flag)
+ {
+ n_particles = frame_set->n_particles;
+ }
+ else
+ {
+ n_particles = tng_data->n_particles;
+ }
+
+ if(tng_data->non_tr_particle_data)
+ {
+ for(i = tng_data->n_particle_data_blocks; i--; )
+ {
+ if(tng_data->non_tr_particle_data[i].values)
+ {
+ free(tng_data->non_tr_particle_data[i].values);
+ tng_data->non_tr_particle_data[i].values = 0;
+ }
+
+ if(tng_data->non_tr_particle_data[i].strings)
+ {
+ n_values_per_frame = tng_data->non_tr_particle_data[i].
+ n_values_per_frame;
+ if(tng_data->non_tr_particle_data[i].strings[0])
+ {
+ for(j = n_particles; j--;)
+ {
+ if(tng_data->non_tr_particle_data[i].strings[0][j])
+ {
+ for(k = n_values_per_frame; k--;)
+ {
+ if(tng_data->non_tr_particle_data[i].
+ strings[0][j][k])
+ {
+ free(tng_data->non_tr_particle_data[i].
+ strings[0][j][k]);
+ tng_data->non_tr_particle_data[i].
+ strings[0][j][k] = 0;
+ }
+ }
+ free(tng_data->non_tr_particle_data[i].
+ strings[0][j]);
+ tng_data->non_tr_particle_data[i].strings[0][j] = 0;
+ }
+ }
+ free(tng_data->non_tr_particle_data[i].strings[0]);
+ tng_data->non_tr_particle_data[i].strings[0] = 0;
+ }
+ free(tng_data->non_tr_particle_data[i].strings);
+ tng_data->non_tr_particle_data[i].strings = 0;
+ }
+
+ if(tng_data->non_tr_particle_data[i].block_name)
+ {
+ free(tng_data->non_tr_particle_data[i].block_name);
+ tng_data->non_tr_particle_data[i].block_name = 0;
+ }
+ }
+ free(tng_data->non_tr_particle_data);
+ tng_data->non_tr_particle_data = 0;
+ }
+
+ if(tng_data->non_tr_data)
+ {
+ for(i = tng_data->n_data_blocks; i--;)
+ {
+ if(tng_data->non_tr_data[i].values)
+ {
+ free(tng_data->non_tr_data[i].values);
+ tng_data->non_tr_data[i].values = 0;
+ }
+
+ if(tng_data->non_tr_data[i].strings)
+ {
+ n_values_per_frame = tng_data->non_tr_data[i].
+ n_values_per_frame;
+ if(tng_data->non_tr_data[i].strings[0])
+ {
+ for(j = n_values_per_frame; j--;)
+ {
+ if(tng_data->non_tr_data[i].strings[0][j])
+ {
+ free(tng_data->non_tr_data[i].strings[0][j]);
+ tng_data->non_tr_data[i].strings[0][j] = 0;
+ }
+ }
+ free(tng_data->non_tr_data[i].strings[0]);
+ tng_data->non_tr_data[i].strings[0] = 0;
+ }
+ free(tng_data->non_tr_data[i].strings);
+ tng_data->non_tr_data[i].strings = 0;
+ }
+
+ if(tng_data->non_tr_data[i].block_name)
+ {
+ free(tng_data->non_tr_data[i].block_name);
+ tng_data->non_tr_data[i].block_name = 0;
+ }
+ }
+ free(tng_data->non_tr_data);
+ tng_data->non_tr_data = 0;
+ }
+
+ tng_data->n_particle_data_blocks = 0;
+ tng_data->n_data_blocks = 0;
+
+ if(tng_data->compress_algo_pos)
+ {
+ free(tng_data->compress_algo_pos);
+ tng_data->compress_algo_pos = 0;
+ }
+ if(tng_data->compress_algo_vel)
+ {
+ free(tng_data->compress_algo_vel);
+ tng_data->compress_algo_vel = 0;
+ }
+
+ if(frame_set->tr_particle_data)
+ {
+ for(i = frame_set->n_particle_data_blocks; i--; )
+ {
+ if(frame_set->tr_particle_data[i].values)
+ {
+ free(frame_set->tr_particle_data[i].values);
+ frame_set->tr_particle_data[i].values = 0;
+ }
+
+ if(frame_set->tr_particle_data[i].strings)
+ {
+ n_values_per_frame = frame_set->tr_particle_data[i].
+ n_values_per_frame;
+ for(j = frame_set->tr_particle_data[i].n_frames; j--;)
+ {
+ if(frame_set->tr_particle_data[i].strings[j])
+ {
+ for(k = n_particles; k--;)
+ {
+ if(frame_set->tr_particle_data[i].
+ strings[j][k])
+ {
+ for(l = n_values_per_frame; l--;)
+ {
+ if(frame_set->tr_particle_data[i].
+ strings[j][k][l])
+ {
+ free(frame_set->tr_particle_data[i].
+ strings[j][k][l]);
+ frame_set->tr_particle_data[i].
+ strings[j][k][l] = 0;
+ }
+ }
+ free(frame_set->tr_particle_data[i].
+ strings[j][k]);
+ frame_set->tr_particle_data[i].
+ strings[j][k] = 0;
+ }
+ }
+ free(frame_set->tr_particle_data[i].strings[j]);
+ frame_set->tr_particle_data[i].strings[j] = 0;
+ }
+ }
+ free(frame_set->tr_particle_data[i].strings);
+ frame_set->tr_particle_data[i].strings = 0;
+ }
+
+ if(frame_set->tr_particle_data[i].block_name)
+ {
+ free(frame_set->tr_particle_data[i].block_name);
+ frame_set->tr_particle_data[i].block_name = 0;
+ }
+ }
+ free(frame_set->tr_particle_data);
+ frame_set->tr_particle_data = 0;
+ }
+
+ if(frame_set->tr_data)
+ {
+ for(i = frame_set->n_data_blocks; i--;)
+ {
+ if(frame_set->tr_data[i].values)
+ {
+ free(frame_set->tr_data[i].values);
+ frame_set->tr_data[i].values = 0;
+ }
+
+ if(frame_set->tr_data[i].strings)
+ {
+ n_values_per_frame = frame_set->tr_data[i].
+ n_values_per_frame;
+ for(j = frame_set->tr_data[i].n_frames; j--;)
+ {
+ if(frame_set->tr_data[i].strings[j])
+ {
+ for(k = n_values_per_frame; k--;)
+ {
+ if(frame_set->tr_data[i].strings[j][k])
+ {
+ free(frame_set->tr_data[i].strings[j][k]);
+ frame_set->tr_data[i].strings[j][k] = 0;
+ }
+ }
+ free(frame_set->tr_data[i].strings[j]);
+ frame_set->tr_data[i].strings[j] = 0;
+ }
+ }
+ free(frame_set->tr_data[i].strings);
+ frame_set->tr_data[i].strings = 0;
+ }
+
+ if(frame_set->tr_data[i].block_name)
+ {
+ free(frame_set->tr_data[i].block_name);
+ frame_set->tr_data[i].block_name = 0;
+ }
+ }
+ free(frame_set->tr_data);
+ frame_set->tr_data = 0;
+ }
+
+ frame_set->n_particle_data_blocks = 0;
+ frame_set->n_data_blocks = 0;
+
+ if(tng_data->molecules)
+ {
+ for(i=tng_data->n_molecules; i--;)
+ {
+ tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
+ }
+ free(tng_data->molecules);
+ tng_data->molecules = 0;
+ tng_data->n_molecules = 0;
+ }
+ if(tng_data->molecule_cnt_list)
+ {
+ free(tng_data->molecule_cnt_list);
+ tng_data->molecule_cnt_list = 0;
+ }
+
+ free(*tng_data_p);
+ *tng_data_p = 0;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_from_src(tng_trajectory_t src,
+ tng_trajectory_t *dest_p)
+{
+ tng_trajectory_frame_set_t frame_set;
+ tng_trajectory_t dest;
+
+ TNG_ASSERT(src != 0, "TNG library: Source trajectory must not be NULL.");
+
+ *dest_p = malloc(sizeof(struct tng_trajectory));
+ if(!*dest_p)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
+ sizeof(struct tng_trajectory), __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ dest = *dest_p;
+
+ frame_set = &dest->current_trajectory_frame_set;
+
+ strcpy(dest->input_file_path, src->input_file_path);
+ dest->input_file = 0;
+ dest->input_file_len = src->input_file_len;
+ strcpy(dest->output_file_path, src->output_file_path);
+ dest->output_file = 0;
+
+ dest->first_program_name = 0;
+ dest->first_user_name = 0;
+ dest->first_computer_name = 0;
+ dest->first_pgp_signature = 0;
+ dest->last_program_name = 0;
+ dest->last_user_name = 0;
+ dest->last_computer_name = 0;
+ dest->last_pgp_signature = 0;
+ dest->forcefield_name = 0;
+
+ dest->var_num_atoms_flag = src->var_num_atoms_flag;
+ dest->first_trajectory_frame_set_input_file_pos =
+ src->first_trajectory_frame_set_input_file_pos;
+ dest->last_trajectory_frame_set_input_file_pos =
+ src->last_trajectory_frame_set_input_file_pos;
+ dest->current_trajectory_frame_set_input_file_pos =
+ src->current_trajectory_frame_set_input_file_pos;
+ dest->first_trajectory_frame_set_output_file_pos =
+ src->first_trajectory_frame_set_output_file_pos;
+ dest->last_trajectory_frame_set_output_file_pos =
+ src->last_trajectory_frame_set_output_file_pos;
+ dest->current_trajectory_frame_set_output_file_pos =
+ src->current_trajectory_frame_set_output_file_pos;
+ dest->frame_set_n_frames = src->frame_set_n_frames;
+ dest->n_trajectory_frame_sets = src->n_trajectory_frame_sets;
+ dest->n_trajectory_blocks = src->n_trajectory_blocks;
+ dest->medium_stride_length = src->medium_stride_length;
+ dest->long_stride_length = src->long_stride_length;
+
+ dest->time_per_frame = src->time_per_frame;
+
+ /* Currently the non trajectory data blocks are not copied since it
+ * can lead to problems when freeing memory in a parallel block. */
+ dest->n_particle_data_blocks = 0;
+ dest->n_data_blocks = 0;
+ dest->non_tr_particle_data = 0;
+ dest->non_tr_data = 0;
+
+ dest->compress_algo_pos = 0;
+ dest->compress_algo_vel = 0;
+ dest->distance_unit_exponential = -9;
+ dest->compression_precision = 1000;
+
+ frame_set->n_mapping_blocks = 0;
+ frame_set->mappings = 0;
+ frame_set->molecule_cnt_list = 0;
+
+ frame_set->n_particle_data_blocks = 0;
+ frame_set->n_data_blocks = 0;
+
+ frame_set->tr_particle_data = 0;
+ frame_set->tr_data = 0;
+
+ frame_set->next_frame_set_file_pos = -1;
+ frame_set->prev_frame_set_file_pos = -1;
+ frame_set->medium_stride_next_frame_set_file_pos = -1;
+ frame_set->medium_stride_prev_frame_set_file_pos = -1;
+ frame_set->long_stride_next_frame_set_file_pos = -1;
+ frame_set->long_stride_prev_frame_set_file_pos = -1;
+ frame_set->first_frame = -1;
+
+ dest->n_molecules = 0;
+ dest->molecules = 0;
+ dest->molecule_cnt_list = 0;
+ dest->n_particles = src->n_particles;
+
+ dest->endianness_32 = src->endianness_32;
+ dest->endianness_64 = src->endianness_64;
+ dest->input_endianness_swap_func_32 = src->input_endianness_swap_func_32;
+ dest->input_endianness_swap_func_64 = src->input_endianness_swap_func_64;
+ dest->output_endianness_swap_func_32 = src->output_endianness_swap_func_32;
+ dest->output_endianness_swap_func_64 = src->output_endianness_swap_func_64;
+
+ dest->current_trajectory_frame_set.next_frame_set_file_pos = -1;
+ dest->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
+ dest->current_trajectory_frame_set.n_frames = 0;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_input_file_get(const tng_trajectory_t tng_data,
+ char *file_name, const int max_len)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
+
+ strncpy(file_name, tng_data->input_file_path, max_len - 1);
+ file_name[max_len - 1] = 0;
+
+ if(strlen(tng_data->input_file_path) > (unsigned int)max_len - 1)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_input_file_set(tng_trajectory_t tng_data,
+ const char *file_name)
+{
+ unsigned int len;
+ char *temp;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
+
+
+ if(tng_data->input_file_path && strcmp(tng_data->input_file_path,
+ file_name) == 0)
+ {
+ return(TNG_SUCCESS);
+ }
+
+ if(tng_data->input_file)
+ {
+ fclose(tng_data->input_file);
+ }
+
+ len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
+ temp = realloc(tng_data->input_file_path, len);
+ if(!temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ free(tng_data->input_file_path);
+ tng_data->input_file_path = 0;
+ return(TNG_CRITICAL);
+ }
+ tng_data->input_file_path = temp;
+
+ strncpy(tng_data->input_file_path, file_name, len);
+
+ return(tng_input_file_init(tng_data));
+}
+
+tng_function_status tng_output_file_get(const tng_trajectory_t tng_data,
+ char *file_name, const int max_len)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
+
+ strncpy(file_name, tng_data->output_file_path, max_len - 1);
+ file_name[max_len - 1] = 0;
+
+ if(strlen(tng_data->output_file_path) > (unsigned int)max_len - 1)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_output_file_set(tng_trajectory_t tng_data,
+ const char *file_name)
+{
+ int len;
+ char *temp;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
+
+ if(tng_data->output_file_path &&
+ strcmp(tng_data->output_file_path, file_name) == 0)
+ {
+ return(TNG_SUCCESS);
+ }
+
+ if(tng_data->output_file)
+ {
+ fclose(tng_data->output_file);
+ }
+
+ len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
+ temp = realloc(tng_data->output_file_path, len);
+ if(!temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ free(tng_data->output_file_path);
+ tng_data->output_file_path = 0;
+ return(TNG_CRITICAL);
+ }
+ tng_data->output_file_path = temp;
+
+ strncpy(tng_data->output_file_path, file_name, len);
+
+ return(tng_output_file_init(tng_data));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_output_append_file_set
+ (tng_trajectory_t tng_data,
+ const char *file_name)
+{
+ int len;
+ char *temp;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
+
+ if(tng_data->output_file_path &&
+ strcmp(tng_data->output_file_path, file_name) == 0)
+ {
+ return(TNG_SUCCESS);
+ }
+
+ if(tng_data->output_file)
+ {
+ fclose(tng_data->output_file);
+ }
+
+ len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
+ temp = realloc(tng_data->output_file_path, len);
+ if(!temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ free(tng_data->output_file_path);
+ tng_data->output_file_path = 0;
+ return(TNG_CRITICAL);
+ }
+ tng_data->output_file_path = temp;
+
+ strncpy(tng_data->output_file_path, file_name, len);
+
+ tng_data->output_file = fopen(tng_data->output_file_path, "r+");
+ if(!tng_data->output_file)
+ {
+ fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
+ tng_data->output_file_path, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_get
+ (tng_trajectory_t tng_data, tng_file_endianness *endianness)
+{
+ tng_endianness_32 end_32;
+ tng_endianness_64 end_64;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(endianness, "TNG library: endianness must not be a NULL pointer");
+
+ if(tng_data->output_endianness_swap_func_32)
+ {
+ /* If other endianness variants are added they must be added here as well */
+ if(tng_data->output_endianness_swap_func_32 ==
+ &tng_swap_byte_order_big_endian_32)
+ {
+ end_32 = TNG_BIG_ENDIAN_32;
+ }
+ else if(tng_data->output_endianness_swap_func_32 ==
+ &tng_swap_byte_order_little_endian_32)
+ {
+ end_32 = TNG_LITTLE_ENDIAN_32;
+ }
+ else
+ {
+ return(TNG_FAILURE);
+ }
+ }
+ else
+ {
+ end_32 = (tng_endianness_32)tng_data->endianness_32;
+ }
+
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ /* If other endianness variants are added they must be added here as well */
+ if(tng_data->output_endianness_swap_func_64 ==
+ &tng_swap_byte_order_big_endian_64)
+ {
+ end_64 = TNG_BIG_ENDIAN_64;
+ }
+ else if(tng_data->output_endianness_swap_func_64 ==
+ &tng_swap_byte_order_little_endian_64)
+ {
+ end_64 = TNG_LITTLE_ENDIAN_64;
+ }
+ else
+ {
+ return(TNG_FAILURE);
+ }
+ }
+ else
+ {
+ end_64 = (tng_endianness_64)tng_data->endianness_64;
+ }
+
+ if((int)end_32 != (int)end_64)
+ {
+ return(TNG_FAILURE);
+ }
+
+ if(end_32 == TNG_LITTLE_ENDIAN_32)
+ {
+ *endianness = TNG_LITTLE_ENDIAN;
+ }
+
+ else if(end_32 == TNG_BIG_ENDIAN_32)
+ {
+ *endianness = TNG_BIG_ENDIAN;
+ }
+ else
+ {
+ return(TNG_FAILURE);
+ }
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_set
+ (tng_trajectory_t tng_data,
+ const tng_file_endianness endianness)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+
+ /* Tne endianness cannot be changed if the data has already been written
+ * to the output file. */
+ if(ftell(tng_data->output_file) > 0)
+ {
+ return(TNG_FAILURE);
+ }
+
+ if(endianness == TNG_BIG_ENDIAN)
+ {
+ if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
+ {
+ tng_data->output_endianness_swap_func_32 = 0;
+ }
+ else
+ {
+ tng_data->output_endianness_swap_func_32 =
+ &tng_swap_byte_order_big_endian_32;
+ }
+ if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
+ {
+ tng_data->output_endianness_swap_func_64 = 0;
+ }
+ else
+ {
+ tng_data->output_endianness_swap_func_64 =
+ &tng_swap_byte_order_big_endian_64;
+ }
+ return(TNG_SUCCESS);
+ }
+ else if(endianness == TNG_LITTLE_ENDIAN)
+ {
+ if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
+ {
+ tng_data->output_endianness_swap_func_32 = 0;
+ }
+ else
+ {
+ tng_data->output_endianness_swap_func_32 =
+ &tng_swap_byte_order_little_endian_32;
+ }
+ if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
+ {
+ tng_data->output_endianness_swap_func_64 = 0;
+ }
+ else
+ {
+ tng_data->output_endianness_swap_func_64 =
+ &tng_swap_byte_order_little_endian_64;
+ }
+ return(TNG_SUCCESS);
+ }
+
+ /* If the specified endianness is neither big nor little endian return a
+ * failure. */
+ return(TNG_FAILURE);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_first_program_name_get
+ (const tng_trajectory_t tng_data,
+ char *name, const int max_len)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
+
+ strncpy(name, tng_data->first_program_name, max_len - 1);
+ name[max_len - 1] = 0;
+
+ if(strlen(tng_data->first_program_name) > (unsigned int)max_len - 1)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_first_program_name_set(tng_trajectory_t tng_data,
+ const char *new_name)
+{
+ unsigned int len;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
+
+ len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
+
+ if(tng_data->first_program_name && strlen(tng_data->first_program_name) < len)
+ {
+ free(tng_data->first_program_name);
+ tng_data->first_program_name = 0;
+ }
+ if(!tng_data->first_program_name)
+ {
+ tng_data->first_program_name = malloc(len);
+ if(!tng_data->first_program_name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ }
+
+ strncpy(tng_data->first_program_name, new_name, len);
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_last_program_name_get
+ (const tng_trajectory_t tng_data,
+ char *name, const int max_len)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
+
+ strncpy(name, tng_data->last_program_name, max_len - 1);
+ name[max_len - 1] = 0;
+
+ if(strlen(tng_data->last_program_name) > (unsigned int)max_len - 1)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_last_program_name_set
+ (tng_trajectory_t tng_data,
+ const char *new_name)
+{
+ unsigned int len;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
+
+ len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
+
+ if(tng_data->last_program_name && strlen(tng_data->last_program_name) < len)
+ {
+ free(tng_data->last_program_name);
+ tng_data->last_program_name = 0;
+ }
+ if(!tng_data->last_program_name)
+ {
+ tng_data->last_program_name = malloc(len);
+ if(!tng_data->last_program_name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ }
+
+ strncpy(tng_data->last_program_name, new_name, len);
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_first_user_name_get
+ (const tng_trajectory_t tng_data,
+ char *name, const int max_len)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
+
+ strncpy(name, tng_data->first_user_name, max_len - 1);
+ name[max_len - 1] = 0;
+
+ if(strlen(tng_data->first_user_name) > (unsigned int)max_len - 1)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_first_user_name_set
+ (tng_trajectory_t tng_data,
+ const char *new_name)
+{
+ unsigned int len;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
+
+ len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
+
+ /* If the currently stored string length is not enough to store the new
+ * string it is freed and reallocated. */
+ if(tng_data->first_user_name && strlen(tng_data->first_user_name) < len)
+ {
+ free(tng_data->first_user_name);
+ tng_data->first_user_name = 0;
+ }
+ if(!tng_data->first_user_name)
+ {
+ tng_data->first_user_name = malloc(len);
+ if(!tng_data->first_user_name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ }
+
+ strncpy(tng_data->first_user_name, new_name, len);
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_last_user_name_get
+ (const tng_trajectory_t tng_data,
+ char *name, const int max_len)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
+
+ strncpy(name, tng_data->last_user_name, max_len - 1);
+ name[max_len - 1] = 0;
+
+ if(strlen(tng_data->last_user_name) > (unsigned int)max_len - 1)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_last_user_name_set
+ (tng_trajectory_t tng_data,
+ const char *new_name)
+{
+ unsigned int len;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
+
+ len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
+
+ /* If the currently stored string length is not enough to store the new
+ * string it is freed and reallocated. */
+ if(tng_data->last_user_name && strlen(tng_data->last_user_name) < len)
+ {
+ free(tng_data->last_user_name);
+ tng_data->last_user_name = 0;
+ }
+ if(!tng_data->last_user_name)
+ {
+ tng_data->last_user_name = malloc(len);
+ if(!tng_data->last_user_name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ }
+
+ strncpy(tng_data->last_user_name, new_name, len);
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_get
+ (const tng_trajectory_t tng_data,
+ char *name, const int max_len)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
+
+ strncpy(name, tng_data->first_computer_name, max_len - 1);
+ name[max_len - 1] = 0;
+
+ if(strlen(tng_data->first_computer_name) > (unsigned int)max_len - 1)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_set
+ (tng_trajectory_t tng_data,
+ const char *new_name)
+{
+ unsigned int len;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
+
+ len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
+
+ /* If the currently stored string length is not enough to store the new
+ * string it is freed and reallocated. */
+ if(tng_data->first_computer_name && strlen(tng_data->first_computer_name) < len)
+ {
+ free(tng_data->first_computer_name);
+ tng_data->first_computer_name = 0;
+ }
+ if(!tng_data->first_computer_name)
+ {
+ tng_data->first_computer_name = malloc(len);
+ if(!tng_data->first_computer_name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ }
+
+ strncpy(tng_data->first_computer_name, new_name, len);
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_get
+ (const tng_trajectory_t tng_data,
+ char *name, const int max_len)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
+
+ strncpy(name, tng_data->last_computer_name, max_len - 1);
+ name[max_len - 1] = 0;
+
+ if(strlen(tng_data->last_computer_name) > (unsigned int)max_len - 1)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_set
+ (tng_trajectory_t tng_data,
+ const char *new_name)
+{
+ unsigned int len;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
+
+ len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
+
+ /* If the currently stored string length is not enough to store the new
+ * string it is freed and reallocated. */
+ if(tng_data->last_computer_name && strlen(tng_data->last_computer_name) <
+ len)
+ {
+ free(tng_data->last_computer_name);
+ tng_data->last_computer_name = 0;
+ }
+ if(!tng_data->last_computer_name)
+ {
+ tng_data->last_computer_name = malloc(len);
+ if(!tng_data->last_computer_name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ }
+
+ strncpy(tng_data->last_computer_name, new_name, len);
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_first_signature_get
+ (const tng_trajectory_t tng_data,
+ char *signature, const int max_len)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
+
+ strncpy(signature, tng_data->first_pgp_signature, max_len - 1);
+ signature[max_len - 1] = 0;
+
+ if(strlen(tng_data->first_pgp_signature) > (unsigned int)max_len - 1)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_first_signature_set
+ (tng_trajectory_t tng_data,
+ const char *signature)
+{
+ unsigned int len;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
+
+ len = tng_min_i((int)strlen(signature) + 1, TNG_MAX_STR_LEN);
+
+ /* If the currently stored string length is not enough to store the new
+ * string it is freed and reallocated. */
+ if(tng_data->first_pgp_signature && strlen(tng_data->first_pgp_signature) <
+ len)
+ {
+ free(tng_data->first_pgp_signature);
+ tng_data->first_pgp_signature = 0;
+ }
+ if(!tng_data->first_pgp_signature)
+ {
+ tng_data->first_pgp_signature = malloc(len);
+ if(!tng_data->first_pgp_signature)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ }
+
+ strncpy(tng_data->first_pgp_signature, signature, len);
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_last_signature_get
+ (const tng_trajectory_t tng_data,
+ char *signature, const int max_len)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
+
+ strncpy(signature, tng_data->last_pgp_signature, max_len - 1);
+ signature[max_len - 1] = 0;
+
+ if(strlen(tng_data->last_pgp_signature) > (unsigned int)max_len - 1)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_last_signature_set
+ (tng_trajectory_t tng_data,
+ const char *signature)
+{
+ unsigned int len;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
+
+ len = tng_min_i((int)strlen(signature) + 1, TNG_MAX_STR_LEN);
+
+ /* If the currently stored string length is not enough to store the new
+ * string it is freed and reallocated. */
+ if(tng_data->last_pgp_signature && strlen(tng_data->last_pgp_signature) <
+ len)
+ {
+ free(tng_data->last_pgp_signature);
+ tng_data->last_pgp_signature = 0;
+ }
+ if(!tng_data->last_pgp_signature)
+ {
+ tng_data->last_pgp_signature = malloc(len);
+ if(!tng_data->last_pgp_signature)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ }
+
+ strncpy(tng_data->last_pgp_signature, signature, len);
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_get
+ (const tng_trajectory_t tng_data,
+ char *name, const int max_len)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
+
+ strncpy(name, tng_data->forcefield_name, max_len - 1);
+ name[max_len - 1] = 0;
+
+ if(strlen(tng_data->forcefield_name) > (unsigned int)max_len - 1)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_set
+ (tng_trajectory_t tng_data,
+ const char *new_name)
+{
+ unsigned int len;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
+
+ len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
+
+ /* If the currently stored string length is not enough to store the new
+ * string it is freed and reallocated. */
+ if(tng_data->forcefield_name && strlen(tng_data->forcefield_name) < len)
+ {
+ free(tng_data->forcefield_name);
+ tng_data->forcefield_name = 0;
+ }
+ if(!tng_data->forcefield_name)
+ {
+ tng_data->forcefield_name = malloc(len);
+ if(!tng_data->forcefield_name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ }
+
+ strncpy(tng_data->forcefield_name, new_name, len);
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_get
+ (const tng_trajectory_t tng_data,
+ int64_t *len)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
+
+ *len = tng_data->medium_stride_length;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_set
+ (tng_trajectory_t tng_data,
+ const int64_t len)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+
+ if(len >= tng_data->long_stride_length)
+ {
+ return(TNG_FAILURE);
+ }
+ tng_data->medium_stride_length = len;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_get
+ (const tng_trajectory_t tng_data,
+ int64_t *len)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
+
+ *len = tng_data->long_stride_length;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_set
+ (tng_trajectory_t tng_data,
+ const int64_t len)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+
+ if(len <= tng_data->medium_stride_length)
+ {
+ return(TNG_FAILURE);
+ }
+ tng_data->long_stride_length = len;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_get
+ (const tng_trajectory_t tng_data,
+ double *time)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
+
+ *time = tng_data->time_per_frame;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_set
+ (tng_trajectory_t tng_data,
+ const double time)
+{
+ tng_trajectory_frame_set_t frame_set;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(time >= 0, "TNG library: The time per frame must be >= 0.");
+
+ if(fabs(time - tng_data->time_per_frame) < 0.00001)
+ {
+ return(TNG_SUCCESS);
+ }
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ /* If the current frame set is not finished write it to disk before
+ changing time per frame. */
+ if(tng_data->time_per_frame > 0 && frame_set->n_unwritten_frames > 0)
+ {
+ frame_set->n_frames = frame_set->n_unwritten_frames;
+ tng_frame_set_write(tng_data, TNG_USE_HASH);
+ }
+ tng_data->time_per_frame = time;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_input_file_len_get
+ (const tng_trajectory_t tng_data,
+ int64_t *len)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
+
+ *len = tng_data->input_file_len;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_num_frames_get
+ (const tng_trajectory_t tng_data,
+ int64_t *n)
+{
+ tng_gen_block_t block;
+ tng_function_status stat;
+ long file_pos;
+ int64_t last_file_pos, first_frame, n_frames;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
+ TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
+
+ file_pos = ftell(tng_data->input_file);
+ last_file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
+
+ if(last_file_pos <= 0)
+ {
+ return(TNG_FAILURE);
+ }
+
+ tng_block_init(&block);
+ fseek(tng_data->input_file,
+ (long)last_file_pos,
+ SEEK_SET);
+ /* Read block headers first to see that a frame set block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", last_file_pos,
+ __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_FAILURE);
+ }
+ tng_block_destroy(&block);
+
+ if(fread(&first_frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Cannot read first frame of frame set. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ if(fread(&n_frames, sizeof(int64_t), 1, tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Cannot read n frames of frame set. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ fseek(tng_data->input_file, file_pos, SEEK_SET);
+
+ *n = first_frame + n_frames;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_compression_precision_get
+ (const tng_trajectory_t tng_data,
+ double *precision)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+
+ *precision = tng_data->compression_precision;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_compression_precision_set
+ (tng_trajectory_t tng_data,
+ const double precision)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+
+ tng_data->compression_precision = precision;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_implicit_num_particles_set
+ (tng_trajectory_t tng_data,
+ const int64_t n)
+{
+ tng_molecule_t mol;
+ tng_chain_t chain;
+ tng_residue_t res;
+ tng_atom_t atom;
+ tng_function_status stat;
+ int64_t diff, n_mod, n_impl;
+
+ TNG_ASSERT(n >= 0, "TNG library: The number of molecules must be >= 0");
+
+ diff = n - tng_data->n_particles;
+
+ stat = tng_molecule_find(tng_data, "TNG_IMPLICIT_MOL", -1, &mol);
+ if(stat == TNG_SUCCESS)
+ {
+ tng_molecule_cnt_get(tng_data, mol, &n_impl);
+ diff -= n_impl * mol->n_atoms;
+ }
+
+ if(diff == 0)
+ {
+ if(stat == TNG_SUCCESS)
+ {
+ stat = tng_molecule_cnt_set(tng_data, mol, 0);
+ return(stat);
+ }
+ return(TNG_SUCCESS);
+ }
+ else if(diff < 0)
+ {
+ fprintf(stderr, "TNG library: Already more actual particles than requested implicit ");
+ fprintf(stderr, "particle count.\n");
+ fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
+ __FILE__, __LINE__);
+ /* FIXME: Should we set the count of all other molecules to 0 and add
+ * implicit molecules? */
+ return(TNG_FAILURE);
+ }
+ if(stat != TNG_SUCCESS)
+ {
+ stat = tng_molecule_add(tng_data,
+ "TNG_IMPLICIT_MOL",
+ &mol);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ stat = tng_molecule_chain_add(tng_data, mol, "", &chain);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ stat = tng_chain_residue_add(tng_data, chain, "", &res);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ stat = tng_residue_atom_add(tng_data, res, "", "", &atom);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ }
+ else
+ {
+ if(mol->n_atoms > 1)
+ {
+ n_mod = diff % mol->n_atoms;
+ if(n_mod != 0)
+ {
+ fprintf(stderr, "TNG library: Number of atoms in implicit molecule ");
+ fprintf(stderr, "not compatible with requested implicit particle cnt.\n");
+ fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_FAILURE);
+ }
+ diff /= mol->n_atoms;
+ }
+ }
+ stat = tng_molecule_cnt_set(tng_data, mol, diff);
+
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_num_particles_get
+ (const tng_trajectory_t tng_data,
+ int64_t *n)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
+
+ if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
+ {
+ *n = tng_data->n_particles;
+ }
+ else
+ {
+ *n = tng_data->current_trajectory_frame_set.n_particles;
+ }
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_num_particles_variable_get
+ (const tng_trajectory_t tng_data,
+ char *variable)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(variable, "TNG library: variable must not be a NULL pointer");
+
+ *variable = tng_data->var_num_atoms_flag;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_num_molecule_types_get
+ (const tng_trajectory_t tng_data,
+ int64_t *n)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
+
+ *n = tng_data->n_molecules;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_num_molecules_get
+ (const tng_trajectory_t tng_data,
+ int64_t *n)
+{
+ int64_t *cnt_list = 0, cnt = 0, i;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
+
+ tng_molecule_cnt_list_get(tng_data, &cnt_list);
+
+ if(!cnt_list)
+ {
+ return(TNG_FAILURE);
+ }
+
+ for(i = tng_data->n_molecules; i --;)
+ {
+ cnt += cnt_list[i];
+ }
+
+ *n = cnt;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_list_get
+ (const tng_trajectory_t tng_data,
+ int64_t **mol_cnt_list)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+
+ if(tng_data->var_num_atoms_flag)
+ {
+ *mol_cnt_list = tng_data->current_trajectory_frame_set.
+ molecule_cnt_list;
+ }
+ else
+ {
+ *mol_cnt_list = tng_data->molecule_cnt_list;
+ }
+ if(*mol_cnt_list == 0)
+ {
+ return(TNG_FAILURE);
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_get
+ (const tng_trajectory_t tng_data,
+ int64_t *exp)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(exp, "TNG library: exp must not be a NULL pointer");
+
+ *exp = tng_data->distance_unit_exponential;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_set
+ (const tng_trajectory_t tng_data,
+ const int64_t exp)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+
+ tng_data->distance_unit_exponential = exp;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_get
+ (const tng_trajectory_t tng_data,
+ int64_t *n)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
+
+ *n = tng_data->frame_set_n_frames;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_set
+ (const tng_trajectory_t tng_data,
+ const int64_t n)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+
+ tng_data->frame_set_n_frames = n;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_num_frame_sets_get
+ (const tng_trajectory_t tng_data,
+ int64_t *n)
+{
+ int64_t long_stride_length, medium_stride_length;
+ int64_t file_pos, orig_frame_set_file_pos;
+ tng_trajectory_frame_set_t frame_set;
+ struct tng_trajectory_frame_set orig_frame_set;
+ tng_gen_block_t block;
+ tng_function_status stat;
+ int64_t cnt = 0;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
+
+ orig_frame_set = tng_data->current_trajectory_frame_set;
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ orig_frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
+ file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
+
+ tng_block_init(&block);
+ fseek(tng_data->input_file,
+ (long)file_pos,
+ SEEK_SET);
+ tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", file_pos,
+ __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_block_read_next(tng_data, block,
+ TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ ++cnt;
+
+ long_stride_length = tng_data->long_stride_length;
+ medium_stride_length = tng_data->medium_stride_length;
+
+ /* Take long steps forward until a long step forward would be too long or
+ * the last frame set is found */
+ file_pos = frame_set->long_stride_next_frame_set_file_pos;
+ while(file_pos > 0)
+ {
+ if(file_pos > 0)
+ {
+ cnt += long_stride_length;
+ fseek(tng_data->input_file, (long)file_pos, SEEK_SET);
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_block_read_next(tng_data, block,
+ TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ }
+ file_pos = frame_set->long_stride_next_frame_set_file_pos;
+ }
+
+ /* Take medium steps forward until a medium step forward would be too long
+ * or the last frame set is found */
+ file_pos = frame_set->medium_stride_next_frame_set_file_pos;
+ while(file_pos > 0)
+ {
+ if(file_pos > 0)
+ {
+ cnt += medium_stride_length;
+ fseek(tng_data->input_file,
+ (long)file_pos,
+ SEEK_SET);
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_block_read_next(tng_data, block,
+ TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ }
+ file_pos = frame_set->medium_stride_next_frame_set_file_pos;
+ }
+
+ /* Take one step forward until the last frame set is found */
+ file_pos = frame_set->next_frame_set_file_pos;
+ while(file_pos > 0)
+ {
+ if(file_pos > 0)
+ {
+ ++cnt;
+ fseek(tng_data->input_file,
+ (long)file_pos,
+ SEEK_SET);
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_block_read_next(tng_data, block,
+ TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ }
+ file_pos = frame_set->next_frame_set_file_pos;
+ }
+
+ tng_block_destroy(&block);
+
+ *n = tng_data->n_trajectory_frame_sets = cnt;
+
+ *frame_set = orig_frame_set;
+
+ fseek(tng_data->input_file,
+ (long)tng_data->first_trajectory_frame_set_input_file_pos,
+ SEEK_SET);
+
+ tng_data->current_trajectory_frame_set_input_file_pos = orig_frame_set_file_pos;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_current_frame_set_get
+ (tng_trajectory_t tng_data,
+ tng_trajectory_frame_set_t *frame_set_p)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+
+ *frame_set_p = &tng_data->current_trajectory_frame_set;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
+ (tng_trajectory_t tng_data,
+ const int64_t nr)
+{
+ int64_t long_stride_length, medium_stride_length;
+ int64_t file_pos, curr_nr = 0, n_frame_sets;
+ tng_trajectory_frame_set_t frame_set;
+ tng_gen_block_t block;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(nr >= 0, "The frame set number (nr) must be >= 0");
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ stat = tng_num_frame_sets_get(tng_data, &n_frame_sets);
+
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+
+ if(nr >= n_frame_sets)
+ {
+ return(TNG_FAILURE);
+ }
+
+ long_stride_length = tng_data->long_stride_length;
+ medium_stride_length = tng_data->medium_stride_length;
+
+ /* FIXME: The frame set number of the current frame set is not stored */
+
+ if(nr < n_frame_sets - 1 - nr)
+ {
+ /* Start from the beginning */
+ file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
+ }
+ else
+ {
+ /* Start from the end */
+ file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
+ curr_nr = n_frame_sets - 1;
+ }
+ if(file_pos <= 0)
+ {
+ return(TNG_FAILURE);
+ }
+
+ tng_block_init(&block);
+ fseek(tng_data->input_file,
+ (long)file_pos,
+ SEEK_SET);
+ tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", file_pos,
+ __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_block_read_next(tng_data, block,
+ TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(curr_nr == nr)
+ {
+ tng_block_destroy(&block);
+ return(TNG_SUCCESS);
+ }
+
+ file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
+
+ /* Take long steps forward until a long step forward would be too long or
+ * the right frame set is found */
+ while(file_pos > 0 && curr_nr + long_stride_length <= nr)
+ {
+ file_pos = frame_set->long_stride_next_frame_set_file_pos;
+ if(file_pos > 0)
+ {
+ curr_nr += long_stride_length;
+ fseek(tng_data->input_file, (long)file_pos, SEEK_SET);
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_block_read_next(tng_data, block,
+ TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ if(curr_nr == nr)
+ {
+ tng_block_destroy(&block);
+ return(TNG_SUCCESS);
+ }
+ }
+ }
+
+ /* Take medium steps forward until a medium step forward would be too long
+ * or the right frame set is found */
+ while(file_pos > 0 && curr_nr + medium_stride_length <= nr)
+ {
+ file_pos = frame_set->medium_stride_next_frame_set_file_pos;
+ if(file_pos > 0)
+ {
+ curr_nr += medium_stride_length;
+ fseek(tng_data->input_file,
+ (long)file_pos,
+ SEEK_SET);
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_block_read_next(tng_data, block,
+ TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ if(curr_nr == nr)
+ {
+ tng_block_destroy(&block);
+ return(TNG_SUCCESS);
+ }
+ }
+ }
+
+ /* Take one step forward until the right frame set is found */
+ while(file_pos > 0 && curr_nr < nr)
+ {
+ file_pos = frame_set->next_frame_set_file_pos;
+
+ if(file_pos > 0)
+ {
+ ++curr_nr;
+ fseek(tng_data->input_file,
+ (long)file_pos,
+ SEEK_SET);
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_block_read_next(tng_data, block,
+ TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ if(curr_nr == nr)
+ {
+ tng_block_destroy(&block);
+ return(TNG_SUCCESS);
+ }
+ }
+ }
+
+ /* Take long steps backward until a long step backward would be too long
+ * or the right frame set is found */
+ while(file_pos > 0 && curr_nr - long_stride_length >= nr)
+ {
+ file_pos = frame_set->long_stride_prev_frame_set_file_pos;
+ if(file_pos > 0)
+ {
+ curr_nr -= long_stride_length;
+ fseek(tng_data->input_file,
+ (long)file_pos,
+ SEEK_SET);
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_block_read_next(tng_data, block,
+ TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ if(curr_nr == nr)
+ {
+ tng_block_destroy(&block);
+ return(TNG_SUCCESS);
+ }
+ }
+ }
+
+ /* Take medium steps backward until a medium step backward would be too long
+ * or the right frame set is found */
+ while(file_pos > 0 && curr_nr - medium_stride_length >= nr)
+ {
+ file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
+ if(file_pos > 0)
+ {
+ curr_nr -= medium_stride_length;
+ fseek(tng_data->input_file,
+ (long)file_pos,
+ SEEK_SET);
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_block_read_next(tng_data, block,
+ TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ if(curr_nr == nr)
+ {
+ tng_block_destroy(&block);
+ return(TNG_SUCCESS);
+ }
+ }
+ }
+
+ /* Take one step backward until the right frame set is found */
+ while(file_pos > 0 && curr_nr > nr)
+ {
+ file_pos = frame_set->prev_frame_set_file_pos;
+ if(file_pos > 0)
+ {
+ --curr_nr;
+ fseek(tng_data->input_file,
+ (long)file_pos,
+ SEEK_SET);
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_block_read_next(tng_data, block,
+ TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ if(curr_nr == nr)
+ {
+ tng_block_destroy(&block);
+ return(TNG_SUCCESS);
+ }
+ }
+ }
+
+ /* If for some reason the current frame set is not yet found,
+ * take one step forward until the right frame set is found */
+ while(file_pos > 0 && curr_nr < nr)
+ {
+ file_pos = frame_set->next_frame_set_file_pos;
+ if(file_pos > 0)
+ {
+ ++curr_nr;
+ fseek(tng_data->input_file,
+ (long)file_pos,
+ SEEK_SET);
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_block_read_next(tng_data, block,
+ TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ if(curr_nr == nr)
+ {
+ tng_block_destroy(&block);
+ return(TNG_SUCCESS);
+ }
+ }
+ }
+
+ tng_block_destroy(&block);
+ return(TNG_FAILURE);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
+ (tng_trajectory_t tng_data,
+ const int64_t frame)
+{
+ int64_t first_frame, last_frame, n_frames_per_frame_set;
+ int64_t long_stride_length, medium_stride_length;
+ int64_t file_pos, temp_frame, n_frames;
+ tng_trajectory_frame_set_t frame_set;
+ tng_gen_block_t block;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(frame >= 0, "TNG library: frame must be >= 0.");
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ tng_block_init(&block);
+
+ if(tng_data->current_trajectory_frame_set_input_file_pos < 0)
+ {
+ file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
+ fseek(tng_data->input_file,
+ (long)file_pos,
+ SEEK_SET);
+ tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_block_read_next(tng_data, block,
+ TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ }
+
+ first_frame = tng_max_i64(frame_set->first_frame, 0);
+ last_frame = first_frame + frame_set->n_frames - 1;
+ /* Is this the right frame set? */
+ if(first_frame <= frame && frame <= last_frame)
+ {
+ tng_block_destroy(&block);
+ return(TNG_SUCCESS);
+ }
+
+ n_frames_per_frame_set = tng_data->frame_set_n_frames;
+ long_stride_length = tng_data->long_stride_length;
+ medium_stride_length = tng_data->medium_stride_length;
+
+ if(tng_first_frame_nr_of_next_frame_set_get(tng_data, &temp_frame) ==
+ TNG_SUCCESS)
+ {
+ if(temp_frame - first_frame > n_frames_per_frame_set)
+ {
+ n_frames_per_frame_set = temp_frame - first_frame;
+ }
+ }
+
+ tng_num_frames_get(tng_data, &n_frames);
+
+ if(frame >= n_frames)
+ {
+ tng_block_destroy(&block);
+ return(TNG_FAILURE);
+ }
+
+ if(first_frame - frame >= frame ||
+ frame - last_frame >
+ tng_data->n_trajectory_frame_sets * n_frames_per_frame_set - frame)
+ {
+ /* Start from the beginning */
+ if(first_frame - frame >= frame)
+ {
+ file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
+
+ if(file_pos <= 0)
+ {
+ tng_block_destroy(&block);
+ return(TNG_FAILURE);
+ }
+ }
+ /* Start from the end */
+ else if(frame - first_frame > (n_frames - 1) - frame)
+ {
+ file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
+
+ /* If the last frame set position is not set start from the current
+ * frame set, since it will be closer than the first frame set. */
+ }
+ /* Start from current */
+ else
+ {
+ file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
+ }
+
+ if(file_pos > 0)
+ {
+ fseek(tng_data->input_file,
+ (long)file_pos,
+ SEEK_SET);
+ tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_block_read_next(tng_data, block,
+ TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ }
+ }
+
+ first_frame = tng_max_i64(frame_set->first_frame, 0);
+ last_frame = first_frame + frame_set->n_frames - 1;
+
+ if(frame >= first_frame && frame <= last_frame)
+ {
+ tng_block_destroy(&block);
+ return(TNG_SUCCESS);
+ }
+
+ file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
+
+ /* Take long steps forward until a long step forward would be too long or
+ * the right frame set is found */
+ while(file_pos > 0 && first_frame + long_stride_length *
+ n_frames_per_frame_set <= frame)
+ {
+ file_pos = frame_set->long_stride_next_frame_set_file_pos;
+ if(file_pos > 0)
+ {
+ fseek(tng_data->input_file, (long)file_pos, SEEK_SET);
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_block_read_next(tng_data, block,
+ TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ }
+ first_frame = tng_max_i64(frame_set->first_frame, 0);
+ last_frame = first_frame + frame_set->n_frames - 1;
+ if(frame >= first_frame && frame <= last_frame)
+ {
+ tng_block_destroy(&block);
+ return(TNG_SUCCESS);
+ }
+ }
+
+ /* Take medium steps forward until a medium step forward would be too long
+ * or the right frame set is found */
+ while(file_pos > 0 && first_frame + medium_stride_length *
+ n_frames_per_frame_set <= frame)
+ {
+ file_pos = frame_set->medium_stride_next_frame_set_file_pos;
+ if(file_pos > 0)
+ {
+ fseek(tng_data->input_file,
+ (long)file_pos,
+ SEEK_SET);
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_block_read_next(tng_data, block,
+ TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ }
+ first_frame = tng_max_i64(frame_set->first_frame, 0);
+ last_frame = first_frame + frame_set->n_frames - 1;
+ if(frame >= first_frame && frame <= last_frame)
+ {
+ tng_block_destroy(&block);
+ return(TNG_SUCCESS);
+ }
+ }
+
+ /* Take one step forward until the right frame set is found */
+ while(file_pos > 0 && first_frame < frame && last_frame < frame)
+ {
+ file_pos = frame_set->next_frame_set_file_pos;
+ if(file_pos > 0)
+ {
+ fseek(tng_data->input_file,
+ (long)file_pos,
+ SEEK_SET);
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_block_read_next(tng_data, block,
+ TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ }
+ first_frame = tng_max_i64(frame_set->first_frame, 0);
+ last_frame = first_frame + frame_set->n_frames - 1;
+ if(frame >= first_frame && frame <= last_frame)
+ {
+ tng_block_destroy(&block);
+ return(TNG_SUCCESS);
+ }
+ }
+
+ /* Take long steps backward until a long step backward would be too long
+ * or the right frame set is found */
+ while(file_pos > 0 && first_frame - long_stride_length *
+ n_frames_per_frame_set >= frame)
+ {
+ file_pos = frame_set->long_stride_prev_frame_set_file_pos;
+ if(file_pos > 0)
+ {
+ fseek(tng_data->input_file,
+ (long)file_pos,
+ SEEK_SET);
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_block_read_next(tng_data, block,
+ TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ }
+ first_frame = tng_max_i64(frame_set->first_frame, 0);
+ last_frame = first_frame + frame_set->n_frames - 1;
+ if(frame >= first_frame && frame <= last_frame)
+ {
+ tng_block_destroy(&block);
+ return(TNG_SUCCESS);
+ }
+ }
+
+ /* Take medium steps backward until a medium step backward would be too long
+ * or the right frame set is found */
+ while(file_pos > 0 && first_frame - medium_stride_length *
+ n_frames_per_frame_set >= frame)
+ {
+ file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
+ if(file_pos > 0)
+ {
+ fseek(tng_data->input_file,
+ (long)file_pos,
+ SEEK_SET);
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_block_read_next(tng_data, block,
+ TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ }
+ first_frame = tng_max_i64(frame_set->first_frame, 0);
+ last_frame = first_frame + frame_set->n_frames - 1;
+ if(frame >= first_frame && frame <= last_frame)
+ {
+ tng_block_destroy(&block);
+ return(TNG_SUCCESS);
+ }
+ }
+
+ /* Take one step backward until the right frame set is found */
+ while(file_pos > 0 && first_frame > frame && last_frame > frame)
+ {
+ file_pos = frame_set->prev_frame_set_file_pos;
+ if(file_pos > 0)
+ {
+ fseek(tng_data->input_file,
+ (long)file_pos,
+ SEEK_SET);
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_block_read_next(tng_data, block,
+ TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ }
+ first_frame = tng_max_i64(frame_set->first_frame, 0);
+ last_frame = first_frame + frame_set->n_frames - 1;
+ if(frame >= first_frame && frame <= last_frame)
+ {
+ tng_block_destroy(&block);
+ return(TNG_SUCCESS);
+ }
+ }
+
+ /* If for some reason the current frame set is not yet found,
+ * take one step forward until the right frame set is found */
+ while(file_pos > 0 && first_frame < frame && last_frame < frame)
+ {
+ file_pos = frame_set->next_frame_set_file_pos;
+ if(file_pos > 0)
+ {
+ fseek(tng_data->input_file,
+ (long)file_pos,
+ SEEK_SET);
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_block_read_next(tng_data, block,
+ TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ }
+ first_frame = tng_max_i64(frame_set->first_frame, 0);
+ last_frame = first_frame + frame_set->n_frames - 1;
+ if(frame >= first_frame && frame <= last_frame)
+ {
+ tng_block_destroy(&block);
+ return(TNG_SUCCESS);
+ }
+ }
+
+ tng_block_destroy(&block);
+ return(TNG_FAILURE);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_next_frame_set_file_pos_get
+ (const tng_trajectory_t tng_data,
+ const tng_trajectory_frame_set_t frame_set,
+ int64_t *pos)
+{
+ (void)tng_data;
+
+ TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
+ TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
+
+ *pos = frame_set->next_frame_set_file_pos;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_prev_frame_set_file_pos_get
+ (const tng_trajectory_t tng_data,
+ const tng_trajectory_frame_set_t frame_set,
+ int64_t *pos)
+{
+ (void)tng_data;
+
+ TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
+ TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
+
+ *pos = frame_set->prev_frame_set_file_pos;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_frame_range_get
+ (const tng_trajectory_t tng_data,
+ const tng_trajectory_frame_set_t frame_set,
+ int64_t *first_frame,
+ int64_t *last_frame)
+{
+ (void)tng_data;
+
+ TNG_ASSERT(first_frame, "TNG library: first_frame must not be a NULL pointer");
+ TNG_ASSERT(last_frame, "TNG library: last_frame must not be a NULL pointer");
+ TNG_ASSERT(frame_set, "TNG library: frame_set must not be a NULL pointer");
+
+ *first_frame = frame_set->first_frame;
+ *last_frame = *first_frame + frame_set->n_frames - 1;
+
+ return(TNG_SUCCESS);
+}
+
+/** Translate from the particle numbering used in a frame set to the real
+ * particle numbering - used in the molecule description.
+ * @param frame_set is the frame_set containing the mappings to use.
+ * @param local is the index number of the atom in this frame set
+ * @param real is set to the index of the atom in the molecular system.
+ * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
+ * cannot be found.
+ */
+static TNG_INLINE tng_function_status tng_particle_mapping_get_real_particle
+ (const tng_trajectory_frame_set_t frame_set,
+ const int64_t local,
+ int64_t *real)
+{
+ int64_t i, n_blocks = frame_set->n_mapping_blocks, first;
+ tng_particle_mapping_t mapping;
+ if(n_blocks <= 0)
+ {
+ *real = local;
+ return(TNG_SUCCESS);
+ }
+ for(i = 0; i < n_blocks; i++)
+ {
+ mapping = &frame_set->mappings[i];
+ first = mapping->num_first_particle;
+ if(local < first ||
+ local >= first + mapping->n_particles)
+ {
+ continue;
+ }
+ *real = mapping->real_particle_numbers[local-first];
+ return(TNG_SUCCESS);
+ }
+ *real = local;
+ return(TNG_FAILURE);
+}
+
+/** Translate from the real particle numbering to the particle numbering
+ * used in a frame set.
+ * @param frame_set is the frame_set containing the mappings to use.
+ * @param real is the index number of the atom in the molecular system.
+ * @param local is set to the index of the atom in this frame set.
+ * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
+ * cannot be found.
+ */
+/*static TNG_INLINE tng_function_status tng_particle_mapping_get_local_particle
+ (const tng_trajectory_frame_set_t frame_set,
+ const int64_t real,
+ int64_t *local)
+{
+ int64_t i, j, n_blocks = frame_set->n_mapping_blocks;
+ tng_particle_mapping_t mapping;
+ if(n_blocks <= 0)
+ {
+ *local = real;
+ return(TNG_SUCCESS);
+ }
+ for(i = 0; i < n_blocks; i++)
+ {
+ mapping = &frame_set->mappings[i];
+ for(j = mapping->n_particles; j--;)
+ {
+ if(mapping->real_particle_numbers[j] == real)
+ {
+ *local = j;
+ return(TNG_SUCCESS);
+ }
+ }
+ }
+ return(TNG_FAILURE);
+}
+*/
+
+tng_function_status DECLSPECDLLEXPORT tng_file_headers_read
+ (tng_trajectory_t tng_data,
+ const char hash_mode)
+{
+ int cnt = 0, prev_pos = 0;
+ tng_gen_block_t block;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+
+ tng_data->n_trajectory_frame_sets = 0;
+
+ if(tng_input_file_init(tng_data) != TNG_SUCCESS)
+ {
+ return(TNG_CRITICAL);
+ }
+
+ if(!tng_data->input_file_len)
+ {
+ fseek(tng_data->input_file, 0, SEEK_END);
+ tng_data->input_file_len = ftell(tng_data->input_file);
+ fseek(tng_data->input_file, 0, SEEK_SET);
+ }
+
+ tng_block_init(&block);
+ /* Non trajectory blocks (they come before the trajectory
+ * blocks in the file) */
+ while (prev_pos < tng_data->input_file_len &&
+ tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
+ block->id != -1 &&
+ block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ if(tng_block_read_next(tng_data, block,
+ hash_mode) == TNG_SUCCESS)
+ {
+ cnt++;
+ }
+ prev_pos = ftell(tng_data->input_file);
+ }
+
+ /* Go back if a trajectory block was encountered */
+ if(block->id == TNG_TRAJECTORY_FRAME_SET)
+ {
+ fseek(tng_data->input_file, prev_pos, SEEK_SET);
+ }
+
+ tng_block_destroy(&block);
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_file_headers_write
+ (tng_trajectory_t tng_data,
+ const char hash_mode)
+{
+ int i;
+ tng_gen_block_t data_block;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+
+ if(tng_output_file_init(tng_data) != TNG_SUCCESS)
+ {
+ return(TNG_CRITICAL);
+ }
+
+ /* TODO: If there is already frame set data written to this file (e.g. when
+ * appending to an already existing file we might need to move frame sets to
+ * the end of the file. */
+
+ if(tng_general_info_block_write(tng_data, hash_mode)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Error writing general info block of file %s. %s: %d\n",
+ tng_data->input_file_path, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_molecules_block_write(tng_data, hash_mode)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Error writing atom names block of file %s. %s: %d\n",
+ tng_data->input_file_path, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ /* FIXME: Currently writing non-trajectory data blocks here.
+ * Should perhaps be moved. */
+ tng_block_init(&data_block);
+ for(i = 0; i < tng_data->n_data_blocks; i++)
+ {
+ data_block->id = tng_data->non_tr_data[i].block_id;
+ tng_data_block_write(tng_data, data_block,
+ i, hash_mode);
+ }
+
+ for(i = 0; i < tng_data->n_particle_data_blocks; i++)
+ {
+ data_block->id = tng_data->non_tr_particle_data[i].block_id;
+ tng_particle_data_block_write(tng_data, data_block,
+ i, 0, hash_mode);
+ }
+
+ tng_block_destroy(&data_block);
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_block_read_next(tng_trajectory_t tng_data,
+ tng_gen_block_t block,
+ const char hash_mode)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(block, "TNG library: block must be initialised and must not be a NULL pointer.");
+
+ switch(block->id)
+ {
+ case TNG_TRAJECTORY_FRAME_SET:
+ return(tng_frame_set_block_read(tng_data, block, hash_mode));
+ case TNG_PARTICLE_MAPPING:
+ return(tng_trajectory_mapping_block_read(tng_data, block, hash_mode));
+ case TNG_GENERAL_INFO:
+ return(tng_general_info_block_read(tng_data, block, hash_mode));
+ case TNG_MOLECULES:
+ return(tng_molecules_block_read(tng_data, block, hash_mode));
+ default:
+ if(block->id >= TNG_TRAJ_BOX_SHAPE)
+ {
+ return(tng_data_block_contents_read(tng_data, block, hash_mode));
+ }
+ else
+ {
+ /* Skip to the next block */
+ fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
+ return(TNG_FAILURE);
+ }
+ }
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_read
+ (tng_trajectory_t tng_data,
+ const char hash_mode)
+{
+ long file_pos;
+ tng_gen_block_t block;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+
+ if(tng_input_file_init(tng_data) != TNG_SUCCESS)
+ {
+ return(TNG_CRITICAL);
+ }
+
+ file_pos = ftell(tng_data->input_file);
+
+ tng_block_init(&block);
+
+ if(!tng_data->input_file_len)
+ {
+ fseek(tng_data->input_file, 0, SEEK_END);
+ tng_data->input_file_len = ftell(tng_data->input_file);
+ fseek(tng_data->input_file, file_pos, SEEK_SET);
+ }
+
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
+
+ if(tng_block_read_next(tng_data, block,
+ hash_mode) == TNG_SUCCESS)
+ {
+ tng_data->n_trajectory_frame_sets++;
+ file_pos = ftell(tng_data->input_file);
+ /* Read all blocks until next frame set block */
+ stat = tng_block_header_read(tng_data, block);
+ while(file_pos < tng_data->input_file_len &&
+ stat != TNG_CRITICAL &&
+ block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ stat = tng_block_read_next(tng_data, block,
+ hash_mode);
+ if(stat != TNG_CRITICAL)
+ {
+ file_pos = ftell(tng_data->input_file);
+ if(file_pos < tng_data->input_file_len)
+ {
+ stat = tng_block_header_read(tng_data, block);
+ }
+ }
+ }
+ if(stat == TNG_CRITICAL)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(stat);
+ }
+
+ if(block->id == TNG_TRAJECTORY_FRAME_SET)
+ {
+ fseek(tng_data->input_file, file_pos, SEEK_SET);
+ }
+ }
+
+ tng_block_destroy(&block);
+
+ return(TNG_SUCCESS);
+}
+
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_current_only_data_from_block_id
+ (tng_trajectory_t tng_data,
+ const char hash_mode,
+ const int64_t block_id)
+{
+ long file_pos;
+ tng_gen_block_t block;
+ tng_function_status stat;
+ int found_flag = 1;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+
+ if(tng_input_file_init(tng_data) != TNG_SUCCESS)
+ {
+ return(TNG_CRITICAL);
+ }
+
+ file_pos = (long)tng_data->current_trajectory_frame_set_input_file_pos;
+
+ if(file_pos < 0)
+ {
+ /* No current frame set. This means that the first frame set must be
+ * read */
+ found_flag = 0;
+ file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
+ }
+
+ if(file_pos > 0)
+ {
+ fseek(tng_data->input_file,
+ file_pos,
+ SEEK_SET);
+ }
+ else
+ {
+ return(TNG_FAILURE);
+ }
+
+ tng_block_init(&block);
+
+ if(!tng_data->input_file_len)
+ {
+ fseek(tng_data->input_file, 0, SEEK_END);
+ tng_data->input_file_len = ftell(tng_data->input_file);
+ fseek(tng_data->input_file, file_pos, SEEK_SET);
+ }
+
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ /* If the current frame set had already been read skip its block contents */
+ if(found_flag)
+ {
+ fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
+ }
+ /* Otherwiese read the frame set block */
+ else
+ {
+ stat = tng_block_read_next(tng_data, block,
+ hash_mode);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot read frame set block. %s: %d\n", __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(stat);
+ }
+ }
+ file_pos = ftell(tng_data->input_file);
+
+ found_flag = 0;
+
+ /* Read only blocks of the requested ID
+ * until next frame set block */
+ stat = tng_block_header_read(tng_data, block);
+ while(file_pos < tng_data->input_file_len &&
+ stat != TNG_CRITICAL &&
+ block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ if(block->id == block_id)
+ {
+ stat = tng_block_read_next(tng_data, block,
+ hash_mode);
+ if(stat != TNG_CRITICAL)
+ {
+ file_pos = ftell(tng_data->input_file);
+ found_flag = 1;
+ if(file_pos < tng_data->input_file_len)
+ {
+ stat = tng_block_header_read(tng_data, block);
+ }
+ }
+ }
+ else
+ {
+ file_pos += (long)(block->block_contents_size + block->header_contents_size);
+ fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
+ if(file_pos < tng_data->input_file_len)
+ {
+ stat = tng_block_header_read(tng_data, block);
+ }
+ }
+ }
+ if(stat == TNG_CRITICAL)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(stat);
+ }
+
+ if(block->id == TNG_TRAJECTORY_FRAME_SET)
+ {
+ fseek(tng_data->input_file, file_pos, SEEK_SET);
+ }
+
+ tng_block_destroy(&block);
+
+ if(found_flag)
+ {
+ return(TNG_SUCCESS);
+ }
+ else
+ {
+ return(TNG_FAILURE);
+ }
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next
+ (tng_trajectory_t tng_data,
+ const char hash_mode)
+{
+ long file_pos;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+
+ if(tng_input_file_init(tng_data) != TNG_SUCCESS)
+ {
+ return(TNG_CRITICAL);
+ }
+
+ file_pos = (long)tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
+
+ if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
+ {
+ file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
+ }
+
+ if(file_pos > 0)
+ {
+ fseek(tng_data->input_file,
+ file_pos,
+ SEEK_SET);
+ }
+ else
+ {
+ return(TNG_FAILURE);
+ }
+
+ return(tng_frame_set_read(tng_data, hash_mode));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next_only_data_from_block_id
+ (tng_trajectory_t tng_data,
+ const char hash_mode,
+ const int64_t block_id)
+{
+ long file_pos;
+ tng_gen_block_t block;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+
+ if(tng_input_file_init(tng_data) != TNG_SUCCESS)
+ {
+ return(TNG_CRITICAL);
+ }
+
+ file_pos = (long)tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
+
+ if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
+ {
+ file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
+ }
+
+ if(file_pos > 0)
+ {
+ fseek(tng_data->input_file,
+ file_pos,
+ SEEK_SET);
+ }
+ else
+ {
+ return(TNG_FAILURE);
+ }
+
+ tng_block_init(&block);
+
+ if(!tng_data->input_file_len)
+ {
+ fseek(tng_data->input_file, 0, SEEK_END);
+ tng_data->input_file_len = ftell(tng_data->input_file);
+ fseek(tng_data->input_file, file_pos, SEEK_SET);
+ }
+
+ /* Read block headers first to see what block is found. */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
+
+ if(tng_block_read_next(tng_data, block,
+ hash_mode) == TNG_SUCCESS)
+ {
+ stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, hash_mode, block_id);
+ }
+
+ tng_block_destroy(&block);
+
+ return(stat);
+}
+
+tng_function_status tng_frame_set_write(tng_trajectory_t tng_data,
+ const char hash_mode)
+{
+ int i, j;
+ tng_gen_block_t block;
+ tng_trajectory_frame_set_t frame_set;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ if(frame_set->n_written_frames == frame_set->n_frames)
+ {
+ return(TNG_SUCCESS);
+ }
+
+ tng_data->current_trajectory_frame_set_output_file_pos =
+ ftell(tng_data->output_file);
+ tng_data->last_trajectory_frame_set_output_file_pos =
+ tng_data->current_trajectory_frame_set_output_file_pos;
+
+ if(tng_data->current_trajectory_frame_set_output_file_pos <= 0)
+ {
+ return(TNG_FAILURE);
+ }
+
+ if(tng_data->first_trajectory_frame_set_output_file_pos == -1)
+ {
+ tng_data->first_trajectory_frame_set_output_file_pos =
+ tng_data->current_trajectory_frame_set_output_file_pos;
+ }
+
+ tng_block_init(&block);
+
+ if(tng_frame_set_block_write(tng_data, block, hash_mode) != TNG_SUCCESS)
+ {
+ tng_block_destroy(&block);
+ return(TNG_FAILURE);
+ }
+
+ /* Write non-particle data blocks */
+ for(i = 0; i<frame_set->n_data_blocks; i++)
+ {
+ block->id = frame_set->tr_data[i].block_id;
+ tng_data_block_write(tng_data, block, i, hash_mode);
+ }
+ /* Write the mapping blocks and particle data blocks*/
+ if(frame_set->n_mapping_blocks)
+ {
+ for(i = 0; i < frame_set->n_mapping_blocks; i++)
+ {
+ block->id = TNG_PARTICLE_MAPPING;
+ if(frame_set->mappings[i].n_particles > 0)
+ {
+ tng_trajectory_mapping_block_write(tng_data, block, i, hash_mode);
+ for(j = 0; j<frame_set->n_particle_data_blocks; j++)
+ {
+ block->id = frame_set->tr_particle_data[j].block_id;
+ tng_particle_data_block_write(tng_data, block,
+ j, &frame_set->mappings[i],
+ hash_mode);
+ }
+ }
+ }
+ }
+ else
+ {
+ for(i = 0; i<frame_set->n_particle_data_blocks; i++)
+ {
+ block->id = frame_set->tr_particle_data[i].block_id;
+ tng_particle_data_block_write(tng_data, block,
+ i, 0, hash_mode);
+ }
+ }
+
+
+ /* Update pointers in the general info block */
+ stat = tng_header_pointers_update(tng_data, hash_mode);
+
+ if(stat == TNG_SUCCESS)
+ {
+ stat = tng_frame_set_pointers_update(tng_data, hash_mode);
+ }
+
+ tng_block_destroy(&block);
+
+ frame_set->n_unwritten_frames = 0;
+
+ fflush(tng_data->output_file);
+
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_premature_write
+ (tng_trajectory_t tng_data,
+ const char hash_mode)
+{
+ tng_trajectory_frame_set_t frame_set;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ if(frame_set->n_unwritten_frames == 0)
+ {
+ return(TNG_SUCCESS);
+ }
+ frame_set->n_frames = frame_set->n_unwritten_frames;
+
+ return(tng_frame_set_write(tng_data, hash_mode));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_new
+ (tng_trajectory_t tng_data,
+ const int64_t first_frame,
+ const int64_t n_frames)
+{
+ tng_gen_block_t block;
+ tng_trajectory_frame_set_t frame_set;
+ FILE *temp = tng_data->input_file;
+ int64_t curr_pos;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
+ TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ curr_pos = ftell(tng_data->output_file);
+
+ if(curr_pos <= 10)
+ {
+ tng_file_headers_write(tng_data, TNG_USE_HASH);
+ }
+
+ /* Set pointer to previous frame set to the one that was loaded
+ * before.
+ * FIXME: This is a bit risky. If they are not added in order
+ * it will be wrong. */
+ if(tng_data->n_trajectory_frame_sets)
+ {
+ frame_set->prev_frame_set_file_pos =
+ tng_data->current_trajectory_frame_set_output_file_pos;
+ }
+
+ tng_data->current_trajectory_frame_set_output_file_pos =
+ ftell(tng_data->output_file);
+
+ tng_data->n_trajectory_frame_sets++;
+
+ /* Set the medium range pointers */
+ if(tng_data->n_trajectory_frame_sets == tng_data->medium_stride_length + 1)
+ {
+ frame_set->medium_stride_prev_frame_set_file_pos =
+ tng_data->first_trajectory_frame_set_output_file_pos;
+ }
+ else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
+ {
+ /* FIXME: Currently only working if the previous frame set has its
+ * medium stride pointer already set. This might need some fixing. */
+ if(frame_set->medium_stride_prev_frame_set_file_pos != -1 &&
+ frame_set->medium_stride_prev_frame_set_file_pos != 0)
+ {
+ tng_block_init(&block);
+ tng_data->input_file = tng_data->output_file;
+
+ curr_pos = ftell(tng_data->output_file);
+ fseek(tng_data->output_file,
+ (long)frame_set->medium_stride_prev_frame_set_file_pos,
+ SEEK_SET);
+
+ if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
+ __FILE__, __LINE__);
+ tng_data->input_file = temp;
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ /* Read the next frame set from the previous frame set and one
+ * medium stride step back */
+ fseek(tng_data->output_file, (long)block->block_contents_size - 6 *
+ sizeof(int64_t), SEEK_CUR);
+ if(fread(&frame_set->medium_stride_prev_frame_set_file_pos,
+ sizeof(frame_set->medium_stride_prev_frame_set_file_pos),
+ 1, tng_data->output_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
+ tng_data->input_file = temp;
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &frame_set->medium_stride_prev_frame_set_file_pos)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+
+ tng_block_destroy(&block);
+
+ /* Set the long range pointers */
+ if(tng_data->n_trajectory_frame_sets == tng_data->long_stride_length + 1)
+ {
+ frame_set->long_stride_prev_frame_set_file_pos =
+ tng_data->first_trajectory_frame_set_output_file_pos;
+ }
+ else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
+ {
+ /* FIXME: Currently only working if the previous frame set has its
+ * long stride pointer already set. This might need some fixing. */
+ if(frame_set->long_stride_prev_frame_set_file_pos != -1 &&
+ frame_set->long_stride_prev_frame_set_file_pos != 0)
+ {
+ tng_block_init(&block);
+ tng_data->input_file = tng_data->output_file;
+
+ fseek(tng_data->output_file,
+ (long)frame_set->long_stride_prev_frame_set_file_pos,
+ SEEK_SET);
+
+ if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
+ __FILE__, __LINE__);
+ tng_data->input_file = temp;
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ /* Read the next frame set from the previous frame set and one
+ * long stride step back */
+ fseek(tng_data->output_file, (long)block->block_contents_size - 6 *
+ sizeof(int64_t), SEEK_CUR);
+
+ tng_block_destroy(&block);
+
+ if(fread(&frame_set->long_stride_prev_frame_set_file_pos,
+ sizeof(frame_set->long_stride_prev_frame_set_file_pos),
+ 1, tng_data->output_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
+ tng_data->input_file = temp;
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_data->input_endianness_swap_func_64)
+ {
+ if(tng_data->input_endianness_swap_func_64(tng_data,
+ &frame_set->long_stride_prev_frame_set_file_pos)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+
+ }
+ }
+
+ tng_data->input_file = temp;
+ fseek(tng_data->output_file, (long)curr_pos, SEEK_SET);
+ }
+ }
+
+ frame_set->first_frame = first_frame;
+ frame_set->n_frames = n_frames;
+ frame_set->n_written_frames = 0;
+ frame_set->n_unwritten_frames = 0;
+ frame_set->first_frame_time = -1;
+
+ if(tng_data->first_trajectory_frame_set_output_file_pos == -1 ||
+ tng_data->first_trajectory_frame_set_output_file_pos == 0)
+ {
+ tng_data->first_trajectory_frame_set_output_file_pos =
+ tng_data->current_trajectory_frame_set_output_file_pos;
+ }
+ /* FIXME: Should check the frame number instead of the file_pos,
+ * in case frame sets are not in order */
+ if(tng_data->last_trajectory_frame_set_output_file_pos == -1 ||
+ tng_data->last_trajectory_frame_set_output_file_pos == 0 ||
+ tng_data->last_trajectory_frame_set_output_file_pos <
+ tng_data->current_trajectory_frame_set_output_file_pos)
+ {
+ tng_data->last_trajectory_frame_set_output_file_pos =
+ tng_data->current_trajectory_frame_set_output_file_pos;
+ }
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_with_time_new
+ (tng_trajectory_t tng_data,
+ const int64_t first_frame,
+ const int64_t n_frames,
+ const double first_frame_time)
+{
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
+ TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
+ TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
+
+
+ stat = tng_frame_set_new(tng_data, first_frame, n_frames);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ stat = tng_frame_set_first_frame_time_set(tng_data, first_frame_time);
+
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_first_frame_time_set
+ (tng_trajectory_t tng_data,
+ const double first_frame_time)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
+
+ tng_data->current_trajectory_frame_set.first_frame_time = first_frame_time;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_first_frame_nr_of_next_frame_set_get
+ (tng_trajectory_t tng_data,
+ int64_t *frame)
+{
+ long file_pos, next_frame_set_file_pos;
+ tng_gen_block_t block;
+ tng_function_status stat;
+
+ tng_trajectory_frame_set_t frame_set;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
+ TNG_ASSERT(frame, "TNG library: frame must not be a NULL pointer");
+
+ file_pos = ftell(tng_data->input_file);
+
+ if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
+ {
+ next_frame_set_file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
+ }
+ else
+ {
+ frame_set = &tng_data->current_trajectory_frame_set;
+ next_frame_set_file_pos = (long)frame_set->next_frame_set_file_pos;
+ }
+
+ if(next_frame_set_file_pos <= 0)
+ {
+ return(TNG_FAILURE);
+ }
+
+ fseek(tng_data->input_file, (long)next_frame_set_file_pos, SEEK_SET);
+ /* Read block headers first to see that a frame set block is found. */
+ tng_block_init(&block);
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+/* if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
+ {
+ tng_block_read_next(tng_data, block, TNG_USE_HASH);
+ }*/
+ tng_block_destroy(&block);
+
+ if(fread(frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Cannot read first frame of next frame set. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ fseek(tng_data->input_file, file_pos, SEEK_SET);
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_data_block_add
+ (tng_trajectory_t tng_data,
+ const int64_t id,
+ const char *block_name,
+ const char datatype,
+ const char block_type_flag,
+ int64_t n_frames,
+ const int64_t n_values_per_frame,
+ int64_t stride_length,
+ const int64_t codec_id,
+ void *new_data)
+{
+ int i, j, size, len;
+ tng_trajectory_frame_set_t frame_set;
+ tng_non_particle_data_t data;
+ char **first_dim_values;
+ char *new_data_c=new_data;
+ int64_t n_frames_div;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(block_name, "TNG library: block_name must not be a NULL pointer.");
+ TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ if(stride_length <= 0)
+ {
+ stride_length = 1;
+ }
+
+ /* If the block does not exist, create it */
+ if(tng_data_find(tng_data, id, &data) != TNG_SUCCESS)
+ {
+ if(tng_data_block_create(tng_data, block_type_flag) !=
+ TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot create data block. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK)
+ {
+ data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
+ }
+ else
+ {
+ data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
+ }
+ data->block_id = id;
+
+ data->block_name = malloc(strlen(block_name) + 1);
+ if(!data->block_name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
+ (int)strlen(block_name)+1, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ strncpy(data->block_name, block_name, strlen(block_name) + 1);
+
+ data->values = 0;
+ /* FIXME: Memory leak from strings. */
+ data->strings = 0;
+ data->last_retrieved_frame = -1;
+ }
+
+ data->datatype = datatype;
+ data->stride_length = tng_max_i64(stride_length, 1);
+ data->n_values_per_frame = n_values_per_frame;
+ data->n_frames = n_frames;
+ data->codec_id = codec_id;
+ data->compression_multiplier = 1.0;
+ /* FIXME: This can cause problems. */
+ data->first_frame_with_data = frame_set->first_frame;
+
+ switch(datatype)
+ {
+ case TNG_FLOAT_DATA:
+ size = sizeof(float);
+ break;
+ case TNG_INT_DATA:
+ size = sizeof(int64_t);
+ break;
+ case TNG_DOUBLE_DATA:
+ default:
+ size = sizeof(double);
+ break;
+ }
+
+ if(new_data_c)
+ {
+ /* Allocate memory */
+ if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
+ n_values_per_frame) !=
+ TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate data memory. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ if(n_frames > frame_set->n_unwritten_frames)
+ {
+ frame_set->n_unwritten_frames = n_frames;
+ }
+
+ n_frames_div = (n_frames % stride_length) ?
+ n_frames / stride_length + 1:
+ n_frames / stride_length;
+
+ if(datatype == TNG_CHAR_DATA)
+ {
+ for(i = 0; i < n_frames_div; i++)
+ {
+ first_dim_values = data->strings[i];
+ for(j = 0; j < n_values_per_frame; j++)
+ {
+ len = tng_min_i((int)strlen(new_data_c) + 1,
+ TNG_MAX_STR_LEN);
+ if(first_dim_values[j])
+ {
+ free(first_dim_values[j]);
+ }
+ first_dim_values[j] = malloc(len);
+ if(!first_dim_values[j])
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
+ len, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ strncpy(first_dim_values[j],
+ new_data_c, len);
+ new_data_c += len;
+ }
+ }
+ }
+ else
+ {
+ memcpy(data->values, new_data, size * n_frames_div *
+ n_values_per_frame);
+ }
+ }
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_particle_data_block_add
+ (tng_trajectory_t tng_data,
+ const int64_t id,
+ const char *block_name,
+ const char datatype,
+ const char block_type_flag,
+ int64_t n_frames,
+ const int64_t n_values_per_frame,
+ int64_t stride_length,
+ const int64_t num_first_particle,
+ const int64_t n_particles,
+ const int64_t codec_id,
+ void *new_data)
+{
+ int i, size, len;
+ int64_t j, k;
+ int64_t tot_n_particles, n_frames_div;
+ char ***first_dim_values, **second_dim_values;
+ tng_trajectory_frame_set_t frame_set;
+ tng_particle_data_t data;
+ char *new_data_c=new_data;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(block_name, "TNG library: block_name mustnot be a NULL pointer.");
+ TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
+ TNG_ASSERT(num_first_particle >= 0, "TNG library: num_first_particle must be >= 0.");
+ TNG_ASSERT(n_particles >= 0, "TNG library: n_particles must be >= 0.");
+
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ if(stride_length <= 0)
+ {
+ stride_length = 1;
+ }
+
+ /* If the block does not exist, create it */
+ if(tng_particle_data_find(tng_data, id, &data) != TNG_SUCCESS)
+ {
+ if(tng_particle_data_block_create(tng_data, block_type_flag) !=
+ TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK)
+ {
+ data = &frame_set->tr_particle_data[frame_set->
+ n_particle_data_blocks - 1];
+ }
+ else
+ {
+ data = &tng_data->non_tr_particle_data[tng_data->
+ n_particle_data_blocks - 1];
+ }
+ data->block_id = id;
+
+ data->block_name = malloc(strlen(block_name) + 1);
+ if(!data->block_name)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
+ (int)strlen(block_name)+1, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ strncpy(data->block_name, block_name, strlen(block_name) + 1);
+
+ data->datatype = datatype;
+
+ data->values = 0;
+ /* FIXME: Memory leak from strings. */
+ data->strings = 0;
+ data->last_retrieved_frame = -1;
+ }
+
+ data->stride_length = tng_max_i64(stride_length, 1);
+ data->n_values_per_frame = n_values_per_frame;
+ data->n_frames = n_frames;
+ data->codec_id = codec_id;
+ data->compression_multiplier = 1.0;
+ /* FIXME: This can cause problems. */
+ data->first_frame_with_data = frame_set->first_frame;
+
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK && tng_data->var_num_atoms_flag)
+ {
+ tot_n_particles = frame_set->n_particles;
+ }
+ else
+ {
+ tot_n_particles = tng_data->n_particles;
+ }
+
+ /* If data values are supplied add that data to the data block. */
+ if(new_data_c)
+ {
+ /* Allocate memory */
+ if(tng_allocate_particle_data_mem(tng_data, data, n_frames,
+ stride_length, tot_n_particles,
+ n_values_per_frame) !=
+ TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate particle data memory. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ if(n_frames > frame_set->n_unwritten_frames)
+ {
+ frame_set->n_unwritten_frames = n_frames;
+ }
+
+ n_frames_div = (n_frames % stride_length) ?
+ n_frames / stride_length + 1:
+ n_frames / stride_length;
+
+ if(datatype == TNG_CHAR_DATA)
+ {
+ for(i = 0; i < n_frames_div; i++)
+ {
+ first_dim_values = data->strings[i];
+ for(j = num_first_particle; j < num_first_particle + n_particles;
+ j++)
+ {
+ second_dim_values = first_dim_values[j];
+ for(k = 0; k < n_values_per_frame; k++)
+ {
+ len = tng_min_i((int)strlen(new_data_c) + 1,
+ TNG_MAX_STR_LEN);
+ if(second_dim_values[k])
+ {
+ free(second_dim_values[k]);
+ }
+ second_dim_values[k] = malloc(len);
+ if(!second_dim_values[k])
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
+ len, __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ strncpy(second_dim_values[k],
+ new_data_c, len);
+ new_data_c += len;
+ }
+ }
+ }
+ }
+ else
+ {
+ switch(datatype)
+ {
+ case TNG_INT_DATA:
+ size = sizeof(int64_t);
+ break;
+ case TNG_FLOAT_DATA:
+ size = sizeof(float);
+ break;
+ case TNG_DOUBLE_DATA:
+ default:
+ size = sizeof(double);
+ }
+
+ memcpy(data->values, new_data, size * n_frames_div *
+ n_particles * n_values_per_frame);
+ }
+ }
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_data_block_name_get
+ (tng_trajectory_t tng_data,
+ int64_t block_id,
+ char *name,
+ int max_len)
+{
+ int64_t i;
+ tng_trajectory_frame_set_t frame_set;
+ tng_function_status stat;
+ tng_particle_data_t p_data;
+ tng_non_particle_data_t np_data;
+ int block_type = -1;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
+
+ for(i = 0; i < tng_data->n_particle_data_blocks; i++)
+ {
+ p_data = &tng_data->non_tr_particle_data[i];
+ if(p_data->block_id == block_id)
+ {
+ strncpy(name, p_data->block_name, max_len);
+ name[max_len - 1] = '\0';
+ return(TNG_SUCCESS);
+ }
+ }
+ for(i = 0; i < tng_data->n_data_blocks; i++)
+ {
+ np_data = &tng_data->non_tr_data[i];
+ if(np_data->block_id == block_id)
+ {
+ strncpy(name, np_data->block_name, max_len);
+ name[max_len - 1] = '\0';
+ return(TNG_SUCCESS);
+ }
+ }
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ stat = tng_particle_data_find(tng_data, block_id, &p_data);
+ if(stat == TNG_SUCCESS)
+ {
+ block_type = TNG_PARTICLE_BLOCK_DATA;
+ }
+ else
+ {
+ stat = tng_data_find(tng_data, block_id, &np_data);
+ if(stat == TNG_SUCCESS)
+ {
+ block_type = TNG_NON_PARTICLE_BLOCK_DATA;
+ }
+ else
+ {
+ stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ stat = tng_particle_data_find(tng_data, block_id, &p_data);
+ if(stat == TNG_SUCCESS)
+ {
+ block_type = TNG_PARTICLE_BLOCK_DATA;
+ }
+ else
+ {
+ stat = tng_data_find(tng_data, block_id, &np_data);
+ if(stat == TNG_SUCCESS)
+ {
+ block_type = TNG_NON_PARTICLE_BLOCK_DATA;
+ }
+ }
+ }
+ }
+ if(block_type == TNG_PARTICLE_BLOCK_DATA)
+ {
+ for(i = 0; i < frame_set->n_particle_data_blocks; i++)
+ {
+ p_data = &frame_set->tr_particle_data[i];
+ if(p_data->block_id == block_id)
+ {
+ strncpy(name, p_data->block_name, max_len);
+ name[max_len - 1] = '\0';
+ return(TNG_SUCCESS);
+ }
+ }
+ }
+ else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
+ {
+ for(i = 0; i < frame_set->n_data_blocks; i++)
+ {
+ np_data = &frame_set->tr_data[i];
+ if(np_data->block_id == block_id)
+ {
+ strncpy(name, np_data->block_name, max_len);
+ name[max_len - 1] = '\0';
+ return(TNG_SUCCESS);
+ }
+ }
+ }
+
+ return(TNG_FAILURE);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_data_block_dependency_get
+ (tng_trajectory_t tng_data,
+ int64_t block_id,
+ int *block_dependency)
+{
+ int64_t i;
+ tng_function_status stat;
+ tng_particle_data_t p_data;
+ tng_non_particle_data_t np_data;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(block_dependency, "TNG library: block_dependency must not be a NULL pointer.");
+
+ for(i = 0; i < tng_data->n_particle_data_blocks; i++)
+ {
+ p_data = &tng_data->non_tr_particle_data[i];
+ if(p_data->block_id == block_id)
+ {
+ *block_dependency = TNG_PARTICLE_DEPENDENT;
+ return(TNG_SUCCESS);
+ }
+ }
+ for(i = 0; i < tng_data->n_data_blocks; i++)
+ {
+ np_data = &tng_data->non_tr_data[i];
+ if(np_data->block_id == block_id)
+ {
+ *block_dependency = 0;
+ return(TNG_SUCCESS);
+ }
+ }
+
+ stat = tng_particle_data_find(tng_data, block_id, &p_data);
+ if(stat == TNG_SUCCESS)
+ {
+ *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
+ return(TNG_SUCCESS);
+ }
+ else
+ {
+ stat = tng_data_find(tng_data, block_id, &np_data);
+ if(stat == TNG_SUCCESS)
+ {
+ *block_dependency = TNG_FRAME_DEPENDENT;
+ return(TNG_SUCCESS);
+ }
+ else
+ {
+ stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ stat = tng_particle_data_find(tng_data, block_id, &p_data);
+ if(stat == TNG_SUCCESS)
+ {
+ *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
+ return(TNG_SUCCESS);
+ }
+ else
+ {
+ stat = tng_data_find(tng_data, block_id, &np_data);
+ if(stat == TNG_SUCCESS)
+ {
+ *block_dependency = TNG_FRAME_DEPENDENT;
+ return(TNG_SUCCESS);
+ }
+ }
+ }
+ }
+
+ return(TNG_FAILURE);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_data_block_num_values_per_frame_get
+ (tng_trajectory_t tng_data,
+ int64_t block_id,
+ int64_t *n_values_per_frame)
+{
+ int64_t i;
+ tng_function_status stat;
+ tng_particle_data_t p_data;
+ tng_non_particle_data_t np_data;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
+
+ for(i = 0; i < tng_data->n_particle_data_blocks; i++)
+ {
+ p_data = &tng_data->non_tr_particle_data[i];
+ if(p_data->block_id == block_id)
+ {
+ *n_values_per_frame = p_data->n_values_per_frame;
+ return(TNG_SUCCESS);
+ }
+ }
+ for(i = 0; i < tng_data->n_data_blocks; i++)
+ {
+ np_data = &tng_data->non_tr_data[i];
+ if(np_data->block_id == block_id)
+ {
+ *n_values_per_frame = np_data->n_values_per_frame;
+ return(TNG_SUCCESS);
+ }
+ }
+
+ stat = tng_particle_data_find(tng_data, block_id, &p_data);
+ if(stat == TNG_SUCCESS)
+ {
+ *n_values_per_frame = p_data->n_values_per_frame;
+ return(TNG_SUCCESS);
+ }
+ else
+ {
+ stat = tng_data_find(tng_data, block_id, &np_data);
+ if(stat == TNG_SUCCESS)
+ {
+ *n_values_per_frame = np_data->n_values_per_frame;
+ return(TNG_SUCCESS);
+ }
+ else
+ {
+ stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ stat = tng_particle_data_find(tng_data, block_id, &p_data);
+ if(stat == TNG_SUCCESS)
+ {
+ *n_values_per_frame = p_data->n_values_per_frame;
+ return(TNG_SUCCESS);
+ }
+ else
+ {
+ stat = tng_data_find(tng_data, block_id, &np_data);
+ if(stat == TNG_SUCCESS)
+ {
+ *n_values_per_frame = np_data->n_values_per_frame;
+ return(TNG_SUCCESS);
+ }
+ }
+ }
+ }
+
+ return(TNG_FAILURE);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_data_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const int64_t block_id,
+ const void *values,
+ const char hash_mode)
+{
+ int64_t header_pos, file_pos;
+ int64_t output_file_len, n_values_per_frame, size, contents_size;
+ int64_t header_size, temp_first, temp_last;
+ int64_t i, last_frame;
+ long temp_current;
+ tng_gen_block_t block;
+ tng_trajectory_frame_set_t frame_set;
+ FILE *temp = tng_data->input_file;
+ struct tng_non_particle_data data;
+ tng_function_status stat;
+ char dependency, sparse_data, datatype;
+ void *copy;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
+ TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
+
+ if(tng_output_file_init(tng_data) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
+ temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
+ temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
+ tng_data->first_trajectory_frame_set_input_file_pos =
+ tng_data->first_trajectory_frame_set_output_file_pos;
+ tng_data->last_trajectory_frame_set_input_file_pos =
+ tng_data->last_trajectory_frame_set_output_file_pos;
+ tng_data->current_trajectory_frame_set_input_file_pos =
+ tng_data->current_trajectory_frame_set_output_file_pos;
+
+ tng_data->input_file = tng_data->output_file;
+
+ stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ if(stat != TNG_SUCCESS)
+ {
+ last_frame = frame_set->first_frame +
+ frame_set->n_frames - 1;
+ /* If the wanted frame would be in the frame set after the last
+ * frame set create a new frame set. */
+ if(stat == TNG_FAILURE &&
+ last_frame < frame_nr)
+/* (last_frame < frame_nr &&
+ tng_data->current_trajectory_frame_set.first_frame +
+ tng_data->frame_set_n_frames >= frame_nr))*/
+ {
+ if(last_frame + tng_data->frame_set_n_frames < frame_nr)
+ {
+ last_frame = frame_nr - 1;
+ }
+ tng_frame_set_new(tng_data,
+ last_frame+1,
+ tng_data->frame_set_n_frames);
+ file_pos = ftell(tng_data->output_file);
+ fseek(tng_data->output_file, 0, SEEK_END);
+ output_file_len = ftell(tng_data->output_file);
+ fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
+
+ /* Read mapping blocks from the last frame set */
+ tng_block_init(&block);
+
+ stat = tng_block_header_read(tng_data, block);
+ while(file_pos < output_file_len &&
+ stat != TNG_CRITICAL &&
+ block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ if(block->id == TNG_PARTICLE_MAPPING)
+ {
+ tng_trajectory_mapping_block_read(tng_data, block,
+ hash_mode);
+ }
+ else
+ {
+ fseek(tng_data->output_file, (long)block->block_contents_size,
+ SEEK_CUR);
+ }
+ file_pos = ftell(tng_data->output_file);
+ if(file_pos < output_file_len)
+ {
+ stat = tng_block_header_read(tng_data, block);
+ }
+ }
+
+ tng_block_destroy(&block);
+ /* Write the frame set to disk */
+ if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+ }
+ else
+ {
+ tng_data->input_file = temp;
+ tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
+ tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
+ tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
+ return(stat);
+ }
+ }
+
+ tng_block_init(&block);
+
+ file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
+
+ fseek(tng_data->output_file, 0, SEEK_END);
+ output_file_len = ftell(tng_data->output_file);
+ fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
+
+ /* Read past the frame set block first */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ tng_data->input_file = temp;
+
+ tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
+ tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
+ tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
+ return(stat);
+ }
+ fseek(tng_data->output_file, (long)block->block_contents_size,
+ SEEK_CUR);
+
+ /* Read all block headers until next frame set block or
+ * until the wanted block id is found */
+ stat = tng_block_header_read(tng_data, block);
+ while(file_pos < output_file_len &&
+ stat != TNG_CRITICAL &&
+ block->id != block_id &&
+ block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fseek(tng_data->output_file, (long)block->block_contents_size, SEEK_CUR);
+ file_pos = ftell(tng_data->output_file);
+ if(file_pos < output_file_len)
+ {
+ stat = tng_block_header_read(tng_data, block);
+ }
+ }
+ if(stat == TNG_CRITICAL)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ tng_data->input_file = temp;
+ tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
+ tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
+ tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
+ return(stat);
+ }
+
+ contents_size = block->block_contents_size;
+ header_size = block->header_contents_size;
+
+ header_pos = ftell(tng_data->output_file) - header_size;
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ if(fread(&datatype, sizeof(datatype), 1, tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ if(fread(&dependency, sizeof(dependency), 1, tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ data.datatype = datatype;
+
+ if(!(dependency & TNG_FRAME_DEPENDENT) ||
+ (dependency & TNG_PARTICLE_DEPENDENT))
+ {
+ tng_block_destroy(&block);
+ tng_data->input_file = temp;
+
+ tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
+ tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
+ tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
+ return(TNG_FAILURE);
+ }
+
+ if(fread(&sparse_data, sizeof(sparse_data), 1, tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(fread(&data.n_values_per_frame, sizeof(data.n_values_per_frame), 1,
+ tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ &data.n_values_per_frame)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+
+ if(fread(&data.codec_id, sizeof(data.codec_id), 1,
+ tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ &data.codec_id)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+
+ if(data.codec_id != TNG_UNCOMPRESSED)
+ {
+ if(fread(&data.compression_multiplier,
+ sizeof(data.compression_multiplier), 1, tng_data->input_file)
+ == 0)
+ {
+ fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)&data.compression_multiplier)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ }
+ else
+ {
+ data.compression_multiplier = 1;
+ }
+
+ if(sparse_data)
+ {
+ if(fread(&data.first_frame_with_data, sizeof(data.first_frame_with_data),
+ 1, tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ &data.first_frame_with_data)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+
+ if(fread(&data.stride_length, sizeof(data.stride_length),
+ 1, tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ &data.stride_length)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ }
+ else
+ {
+ data.first_frame_with_data = 0;
+ data.stride_length = 1;
+ }
+ data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
+
+ tng_data->input_file = temp;
+
+ tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
+ tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
+ tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
+
+ switch(data.datatype)
+ {
+ case(TNG_INT_DATA):
+ size = sizeof(int64_t);
+ break;
+ case(TNG_FLOAT_DATA):
+ size = sizeof(float);
+ break;
+ case(TNG_DOUBLE_DATA):
+ size = sizeof(double);
+ break;
+ default:
+ fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
+ __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_FAILURE);
+ }
+
+ n_values_per_frame = data.n_values_per_frame;
+
+ file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
+ data.first_frame_with_data)) /
+ data.stride_length;
+ file_pos *= size * n_values_per_frame;
+
+ if(file_pos > contents_size)
+ {
+ fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
+ __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_FAILURE);
+ }
+
+ fseek(tng_data->output_file, (long)file_pos, SEEK_CUR);
+
+ /* If the endianness is not big endian the data needs to be swapped */
+ if((data.datatype == TNG_INT_DATA ||
+ data.datatype == TNG_DOUBLE_DATA) &&
+ tng_data->output_endianness_swap_func_64)
+ {
+ copy = malloc(n_values_per_frame * size);
+ memcpy(copy, values, n_values_per_frame * size);
+ for(i = 0; i < n_values_per_frame; i++)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)copy+i)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ fwrite(copy, n_values_per_frame, size,
+ tng_data->output_file);
+ free(copy);
+ }
+ else if(data.datatype == TNG_FLOAT_DATA &&
+ tng_data->output_endianness_swap_func_32)
+ {
+ copy = malloc(n_values_per_frame * size);
+ memcpy(copy, values, n_values_per_frame * size);
+ for(i = 0; i < n_values_per_frame; i++)
+ {
+ if(tng_data->output_endianness_swap_func_32(tng_data,
+ (int32_t *)copy+i)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ fwrite(copy, n_values_per_frame, size,
+ tng_data->output_file);
+ free(copy);
+ }
+
+ else
+ {
+ fwrite(values, n_values_per_frame, size, tng_data->output_file);
+ }
+
+ fflush(tng_data->output_file);
+
+ /* Update the number of written frames in the frame set. */
+ if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
+ {
+ frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
+ }
+
+ /* If the last frame has been written update the hash */
+ if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
+ data.first_frame_with_data) >=
+ frame_set->n_frames)
+ {
+ tng_md5_hash_update(tng_data, block, header_pos, header_pos +
+ header_size);
+ }
+
+ tng_block_destroy(&block);
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_particle_data_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const int64_t block_id,
+ const int64_t val_first_particle,
+ const int64_t val_n_particles,
+ const void *values,
+ const char hash_mode)
+{
+ int64_t header_pos, file_pos, tot_n_particles;
+ int64_t output_file_len, n_values_per_frame, size, contents_size;
+ int64_t header_size, temp_first, temp_last;
+ int64_t mapping_block_end_pos, num_first_particle, block_n_particles;
+ int64_t i, last_frame;
+ long temp_current;
+ tng_gen_block_t block;
+ tng_trajectory_frame_set_t frame_set;
+ FILE *temp = tng_data->input_file;
+ struct tng_particle_data data;
+ tng_function_status stat;
+ tng_particle_mapping_t mapping;
+ char dependency, sparse_data, datatype;
+ void *copy;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
+ TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
+ TNG_ASSERT(val_first_particle >= 0, "TNG library: val_first_particle must be >= 0.");
+ TNG_ASSERT(val_n_particles >= 0, "TNG library: val_n_particles must be >= 0.");
+
+ if(tng_output_file_init(tng_data) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
+ temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
+ temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
+ tng_data->first_trajectory_frame_set_input_file_pos =
+ tng_data->first_trajectory_frame_set_output_file_pos;
+ tng_data->last_trajectory_frame_set_input_file_pos =
+ tng_data->last_trajectory_frame_set_output_file_pos;
+ tng_data->current_trajectory_frame_set_input_file_pos =
+ tng_data->current_trajectory_frame_set_output_file_pos;
+
+ tng_data->input_file = tng_data->output_file;
+
+ stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ if(stat != TNG_SUCCESS)
+ {
+ last_frame = frame_set->first_frame +
+ frame_set->n_frames - 1;
+/* fprintf(stderr, "TNG library: Frame %"PRId64" not found. Last frame: %"PRId64"\n", frame_nr,
+ last_frame); */
+ /* If the wanted frame would be in the frame set after the last
+ * frame set create a new frame set. */
+ if(stat == TNG_FAILURE &&
+ (last_frame < frame_nr &&
+ last_frame + tng_data->frame_set_n_frames >= frame_nr))
+ {
+ if(last_frame + tng_data->frame_set_n_frames < frame_nr)
+ {
+ last_frame = frame_nr - 1;
+ }
+ tng_frame_set_new(tng_data,
+ last_frame+1,
+ tng_data->frame_set_n_frames);
+
+ file_pos = ftell(tng_data->output_file);
+ fseek(tng_data->output_file, 0, SEEK_END);
+ output_file_len = ftell(tng_data->output_file);
+ fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
+
+ /* Read mapping blocks from the last frame set */
+ tng_block_init(&block);
+
+ stat = tng_block_header_read(tng_data, block);
+ while(file_pos < output_file_len &&
+ stat != TNG_CRITICAL &&
+ block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ if(block->id == TNG_PARTICLE_MAPPING)
+ {
+ tng_trajectory_mapping_block_read(tng_data, block,
+ hash_mode);
+ }
+ else
+ {
+ fseek(tng_data->output_file, (long)block->block_contents_size,
+ SEEK_CUR);
+ }
+ file_pos = ftell(tng_data->output_file);
+ if(file_pos < output_file_len)
+ {
+ stat = tng_block_header_read(tng_data, block);
+ }
+ }
+
+ tng_block_destroy(&block);
+ /* Write the frame set to disk */
+ if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
+ exit(1);
+ }
+ }
+ else
+ {
+ tng_data->input_file = temp;
+ tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
+ tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
+ tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
+ return(stat);
+ }
+ }
+
+
+ tng_block_init(&block);
+
+ file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
+
+ fseek(tng_data->output_file, 0, SEEK_END);
+ output_file_len = ftell(tng_data->output_file);
+ fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
+
+ /* Read past the frame set block first */
+ stat = tng_block_header_read(tng_data, block);
+ if(stat == TNG_CRITICAL)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ tng_data->input_file = temp;
+
+ tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
+ tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
+ tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
+ return(stat);
+ }
+ fseek(tng_data->output_file, (long)block->block_contents_size,
+ SEEK_CUR);
+
+ if(tng_data->var_num_atoms_flag)
+ {
+ tot_n_particles = frame_set->n_particles;
+ }
+ else
+ {
+ tot_n_particles = tng_data->n_particles;
+ }
+
+ if(val_n_particles < tot_n_particles)
+ {
+ mapping_block_end_pos = -1;
+ /* Read all mapping blocks to find the right place to put the data */
+ stat = tng_block_header_read(tng_data, block);
+ while(file_pos < output_file_len &&
+ stat != TNG_CRITICAL &&
+ block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ if(block->id == TNG_PARTICLE_MAPPING)
+ {
+ tng_trajectory_mapping_block_read(tng_data, block, hash_mode);
+ }
+ else
+ {
+ fseek(tng_data->output_file, (long)block->block_contents_size,
+ SEEK_CUR);
+ }
+ file_pos = ftell(tng_data->output_file);
+ if(block->id == TNG_PARTICLE_MAPPING)
+ {
+ mapping = &frame_set->mappings[frame_set->n_mapping_blocks - 1];
+ if(val_first_particle >= mapping->num_first_particle &&
+ val_first_particle < mapping->num_first_particle +
+ mapping->n_particles &&
+ val_first_particle + val_n_particles <=
+ mapping->num_first_particle + mapping->n_particles)
+ {
+ mapping_block_end_pos = file_pos;
+ }
+ }
+ if(file_pos < output_file_len)
+ {
+ stat = tng_block_header_read(tng_data, block);
+ }
+ }
+ if(stat == TNG_CRITICAL)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ tng_data->input_file = temp;
+
+ tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
+ tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
+ tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
+ return(stat);
+ }
+ if(mapping_block_end_pos < 0)
+ {
+ tng_block_destroy(&block);
+ tng_data->input_file = temp;
+
+ tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
+ tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
+ tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
+ return(TNG_FAILURE);
+ }
+ fseek(tng_data->output_file, (long)mapping_block_end_pos, SEEK_SET);
+ }
+
+ /* Read all block headers until next frame set block or
+ * until the wanted block id is found */
+ stat = tng_block_header_read(tng_data, block);
+ while(file_pos < output_file_len &&
+ stat != TNG_CRITICAL &&
+ block->id != block_id &&
+ block->id != TNG_PARTICLE_MAPPING &&
+ block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ fseek(tng_data->output_file, (long)block->block_contents_size, SEEK_CUR);
+ file_pos = ftell(tng_data->output_file);
+ if(file_pos < output_file_len)
+ {
+ stat = tng_block_header_read(tng_data, block);
+ }
+ }
+ if(stat == TNG_CRITICAL)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ tng_data->input_file = temp;
+
+ tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
+ tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
+ tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
+ return(stat);
+ }
+
+ contents_size = block->block_contents_size;
+ header_size = block->header_contents_size;
+
+ header_pos = ftell(tng_data->output_file) - header_size;
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ if(fread(&datatype, sizeof(datatype), 1, tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ data.datatype = datatype;
+
+ if(fread(&dependency, sizeof(dependency), 1, tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(!(dependency & TNG_FRAME_DEPENDENT) ||
+ !(dependency & TNG_PARTICLE_DEPENDENT))
+ {
+ tng_block_destroy(&block);
+ tng_data->input_file = temp;
+
+ tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
+ tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
+ tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
+ return(TNG_FAILURE);
+ }
+
+ if(fread(&sparse_data, sizeof(sparse_data), 1, tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(fread(&data.n_values_per_frame, sizeof(data.n_values_per_frame), 1,
+ tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ &data.n_values_per_frame)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+
+ if(fread(&data.codec_id, sizeof(data.codec_id), 1,
+ tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ &data.codec_id)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+
+ if(data.codec_id != TNG_UNCOMPRESSED)
+ {
+ if(fread(&data.compression_multiplier,
+ sizeof(data.compression_multiplier), 1, tng_data->input_file)
+ == 0)
+ {
+ fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *)&data.compression_multiplier)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ }
+ else
+ {
+ data.compression_multiplier = 1;
+ }
+
+ if(sparse_data)
+ {
+ if(fread(&data.first_frame_with_data,
+ sizeof(data.first_frame_with_data),
+ 1, tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ &data.first_frame_with_data)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+
+ if(fread(&data.stride_length, sizeof(data.stride_length),
+ 1, tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ &data.stride_length)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ }
+ else
+ {
+ data.first_frame_with_data = 0;
+ data.stride_length = 1;
+ }
+ data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
+
+ if(fread(&num_first_particle, sizeof(num_first_particle), 1,
+ tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ &num_first_particle)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+
+ if(fread(&block_n_particles, sizeof(block_n_particles), 1,
+ tng_data->input_file) == 0)
+ {
+ fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_CRITICAL);
+ }
+ if(tng_data->output_endianness_swap_func_64)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ &block_n_particles)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+
+
+ tng_data->input_file = temp;
+
+ tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
+ tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
+ tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
+
+
+ switch(data.datatype)
+ {
+ case(TNG_INT_DATA):
+ size = sizeof(int64_t);
+ break;
+ case(TNG_FLOAT_DATA):
+ size = sizeof(float);
+ break;
+ case(TNG_DOUBLE_DATA):
+ size = sizeof(double);
+ break;
+ default:
+ fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
+ __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_FAILURE);
+ }
+
+ n_values_per_frame = data.n_values_per_frame;
+
+ file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
+ data.first_frame_with_data)) /
+ data.stride_length;
+ file_pos *= block_n_particles * size * n_values_per_frame;
+
+ if(file_pos > contents_size)
+ {
+ fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
+ __LINE__);
+ tng_block_destroy(&block);
+ return(TNG_FAILURE);
+ }
+
+ fseek(tng_data->output_file, (long)file_pos, SEEK_CUR);
+
+ /* If the endianness is not big endian the data needs to be swapped */
+ if((data.datatype == TNG_INT_DATA ||
+ data.datatype == TNG_DOUBLE_DATA) &&
+ tng_data->output_endianness_swap_func_64)
+ {
+ copy = malloc(val_n_particles * n_values_per_frame * size);
+ memcpy(copy, values, val_n_particles * n_values_per_frame * size);
+ for(i = 0; i < val_n_particles * n_values_per_frame; i++)
+ {
+ if(tng_data->output_endianness_swap_func_64(tng_data,
+ (int64_t *) copy+i)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ fwrite(copy, val_n_particles * n_values_per_frame, size,
+ tng_data->output_file);
+ free(copy);
+ }
+ else if(data.datatype == TNG_FLOAT_DATA &&
+ tng_data->output_endianness_swap_func_32)
+ {
+ copy = malloc(val_n_particles * n_values_per_frame * size);
+ memcpy(copy, values, val_n_particles * n_values_per_frame * size);
+ for(i = 0; i < val_n_particles * n_values_per_frame; i++)
+ {
+ if(tng_data->output_endianness_swap_func_32(tng_data,
+ (int32_t *) copy+i)
+ != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ }
+ fwrite(copy, val_n_particles * n_values_per_frame, size,
+ tng_data->output_file);
+ free(copy);
+ }
+
+ else
+ {
+ fwrite(values, val_n_particles * n_values_per_frame, size,
+ tng_data->output_file);
+ }
+ fflush(tng_data->output_file);
+
+ /* Update the number of written frames in the frame set. */
+ if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
+ {
+ frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
+ }
+
+ /* If the last frame has been written update the hash */
+ if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
+ data.first_frame_with_data) >=
+ frame_set->n_frames)
+ {
+ tng_md5_hash_update(tng_data, block, header_pos, header_pos +
+ header_size);
+ }
+
+ tng_block_destroy(&block);
+ return(TNG_SUCCESS);
+}
+
+static tng_function_status tng_data_values_alloc
+ (const tng_trajectory_t tng_data,
+ union data_values ***values,
+ const int64_t n_frames,
+ const int64_t n_values_per_frame,
+ const char type)
+{
+ int64_t i;
+ tng_function_status stat;
+
+ if(n_frames <= 0 || n_values_per_frame <= 0)
+ {
+ return(TNG_FAILURE);
+ }
+
+ if(*values)
+ {
+ stat = tng_data_values_free(tng_data, *values, n_frames,
+ n_values_per_frame,
+ type);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ }
+ *values = malloc(sizeof(union data_values *) * n_frames);
+ if(!*values)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(union data_values **) * n_frames,
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+
+ }
+
+ for(i = n_frames; i--;)
+ {
+ (*values)[i] = malloc(sizeof(union data_values) *
+ n_values_per_frame);
+ if(!(*values)[i])
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(union data_values) * n_values_per_frame,
+ __FILE__, __LINE__);
+ free(values);
+ values = 0;
+ return(TNG_CRITICAL);
+ }
+ }
+ return(TNG_SUCCESS);
+}
+
+/* FIXME: This needs ***values */
+tng_function_status DECLSPECDLLEXPORT tng_data_values_free
+ (const tng_trajectory_t tng_data,
+ union data_values **values,
+ const int64_t n_frames,
+ const int64_t n_values_per_frame,
+ const char type)
+{
+ int64_t i, j;
+ (void)tng_data;
+
+ if(values)
+ {
+ for(i = 0; i < n_frames; i++)
+ {
+ if(values[i])
+ {
+ if(type == TNG_CHAR_DATA)
+ {
+ for(j = n_values_per_frame; j--;)
+ {
+ if(values[i][j].c)
+ {
+ free(values[i][j].c);
+ values[i][j].c = 0;
+ }
+ }
+ }
+ free(values[i]);
+ values[i] = 0;
+ }
+ }
+ free(values);
+ values = 0;
+ }
+
+ return(TNG_SUCCESS);
+}
+
+static tng_function_status tng_particle_data_values_alloc
+ (const tng_trajectory_t tng_data,
+ union data_values ****values,
+ const int64_t n_frames,
+ const int64_t n_particles,
+ const int64_t n_values_per_frame,
+ const char type)
+{
+ int64_t i, j;
+ tng_function_status stat;
+
+ if(n_particles == 0 || n_values_per_frame == 0)
+ {
+ return(TNG_FAILURE);
+ }
+
+ if(*values)
+ {
+ stat = tng_particle_data_values_free(tng_data, *values, n_frames,
+ n_particles, n_values_per_frame,
+ type);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ }
+ *values = malloc(sizeof(union data_values **) * n_frames);
+ if(!*values)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(union data_values **) * n_frames,
+ __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+
+ }
+
+ for(i = n_frames; i--;)
+ {
+ (*values)[i] = malloc(sizeof(union data_values *) *
+ n_particles);
+ if(!(*values)[i])
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(union data_values *) * n_particles,
+ __FILE__, __LINE__);
+ free(*values);
+ *values = 0;
+ return(TNG_CRITICAL);
+ }
+ for(j = n_particles; j--;)
+ {
+ (*values)[i][j] = malloc(sizeof(union data_values) *
+ n_values_per_frame);
+ if(!(*values)[i][j])
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(union data_values *) * n_particles,
+ __FILE__, __LINE__);
+ tng_particle_data_values_free(tng_data, *values, n_frames,
+ n_particles, n_values_per_frame,
+ type);
+ *values = 0;
+ return(TNG_CRITICAL);
+ }
+ }
+ }
+ return(TNG_SUCCESS);
+}
+
+/* FIXME: This needs ****values */
+tng_function_status DECLSPECDLLEXPORT tng_particle_data_values_free
+ (const tng_trajectory_t tng_data,
+ union data_values ***values,
+ const int64_t n_frames,
+ const int64_t n_particles,
+ const int64_t n_values_per_frame,
+ const char type)
+{
+ int64_t i, j, k;
+ (void)tng_data;
+
+ if(values)
+ {
+ for(i = 0; i < n_frames; i++)
+ {
+ if(values[i])
+ {
+ for(j = 0; j < n_particles; j++)
+ {
+ if(type == TNG_CHAR_DATA)
+ {
+ for(k = n_values_per_frame; k--;)
+ {
+ if(values[i][j][k].c)
+ {
+ free(values[i][j][k].c);
+ values[i][j][k].c = 0;
+ }
+ }
+ }
+ free(values[i][j]);
+ values[i][j] = 0;
+ }
+ free(values[i]);
+ values[i] = 0;
+ }
+ }
+ free(values);
+ values = 0;
+ }
+
+ return(TNG_SUCCESS);
+}
+
+
+tng_function_status DECLSPECDLLEXPORT tng_data_get
+ (tng_trajectory_t tng_data,
+ const int64_t block_id,
+ union data_values ***values,
+ int64_t *n_frames,
+ int64_t *n_values_per_frame,
+ char *type)
+{
+ int64_t i, j, file_pos, block_index;
+ int size;
+ size_t len;
+ tng_non_particle_data_t data;
+ tng_trajectory_frame_set_t frame_set;
+ tng_gen_block_t block;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
+ TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
+ TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ block_index = -1;
+ data = 0;
+
+ if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
+ {
+ tng_block_init(&block);
+ file_pos = ftell(tng_data->input_file);
+ /* Read all blocks until next frame set block */
+ stat = tng_block_header_read(tng_data, block);
+ while(file_pos < tng_data->input_file_len &&
+ stat != TNG_CRITICAL &&
+ block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ /* Use hash by default */
+ stat = tng_block_read_next(tng_data, block,
+ TNG_USE_HASH);
+ if(stat != TNG_CRITICAL)
+ {
+ file_pos = ftell(tng_data->input_file);
+ if(file_pos < tng_data->input_file_len)
+ {
+ stat = tng_block_header_read(tng_data, block);
+ }
+ }
+ }
+ tng_block_destroy(&block);
+ if(stat == TNG_CRITICAL)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ return(stat);
+ }
+
+ for(i = frame_set->n_data_blocks; i-- ;)
+ {
+ data = &frame_set->tr_data[i];
+ if(data->block_id == block_id)
+ {
+ block_index = i;
+ break;
+ }
+ }
+ if(block_index < 0)
+ {
+ return(TNG_FAILURE);
+ }
+ }
+
+ *n_frames = tng_max_i64(1, data->n_frames);
+ *n_values_per_frame = data->n_values_per_frame;
+ *type = data->datatype;
+
+ if(*values == 0)
+ {
+ if(tng_data_values_alloc(tng_data, values, *n_frames,
+ *n_values_per_frame,
+ *type)
+ != TNG_SUCCESS)
+ {
+ return(TNG_CRITICAL);
+ }
+ }
+
+ switch(*type)
+ {
+ case TNG_CHAR_DATA:
+ for(i=*n_frames; i--;)
+ {
+ for(j=*n_values_per_frame; j--;)
+ {
+ len = strlen(data->strings[i][j]) + 1;
+ (*values)[i][j].c = malloc(len);
+ strncpy((*values)[i][j].c, data->strings[i][j], len);
+ }
+ }
+ break;
+ case TNG_INT_DATA:
+ size = sizeof(int);
+ for(i=*n_frames; i--;)
+ {
+ for(j=*n_values_per_frame; j--;)
+ {
+ (*values)[i][j].i = *(int *)((char *)data->values + size *
+ (i*(*n_values_per_frame) + j));
+ }
+ }
+ break;
+ case TNG_FLOAT_DATA:
+ size = sizeof(float);
+ for(i=*n_frames; i--;)
+ {
+ for(j=*n_values_per_frame; j--;)
+ {
+ (*values)[i][j].f = *(float *)((char *)data->values + size *
+ (i*(*n_values_per_frame) + j));
+ }
+ }
+ break;
+ case TNG_DOUBLE_DATA:
+ default:
+ size = sizeof(double);
+ for(i=*n_frames; i--;)
+ {
+ for(j=*n_values_per_frame; j--;)
+ {
+ (*values)[i][j].d = *(double *)((char *)data->values + size *
+ (i*(*n_values_per_frame) + j));
+ }
+ }
+ }
+
+ data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status tng_data_vector_get(tng_trajectory_t tng_data,
+ const int64_t block_id,
+ void **values,
+ int64_t *n_frames,
+ int64_t *stride_length,
+ int64_t *n_values_per_frame,
+ char *type)
+{
+ int64_t file_pos, data_size, n_frames_div, block_index;
+ int i, size;
+ tng_non_particle_data_t data;
+ tng_trajectory_frame_set_t frame_set;
+ tng_gen_block_t block;
+ void *temp;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
+ TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
+ TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
+ TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ block_index = -1;
+ data = 0;
+
+ if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
+ {
+ tng_block_init(&block);
+ file_pos = ftell(tng_data->input_file);
+ /* Read all blocks until next frame set block */
+ stat = tng_block_header_read(tng_data, block);
+ while(file_pos < tng_data->input_file_len &&
+ stat != TNG_CRITICAL &&
+ block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ /* Use hash by default */
+ stat = tng_block_read_next(tng_data, block,
+ TNG_USE_HASH);
+ if(stat != TNG_CRITICAL)
+ {
+ file_pos = ftell(tng_data->input_file);
+ if(file_pos < tng_data->input_file_len)
+ {
+ stat = tng_block_header_read(tng_data, block);
+ }
+ }
+ }
+ tng_block_destroy(&block);
+ if(stat == TNG_CRITICAL)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ return(stat);
+ }
+
+ for(i = frame_set->n_data_blocks; i-- ;)
+ {
+ data = &frame_set->tr_data[i];
+ if(data->block_id == block_id)
+ {
+ block_index = i;
+ break;
+ }
+ }
+ if(block_index < 0)
+ {
+ return(TNG_FAILURE);
+ }
+ }
+
+ *type = data->datatype;
+
+ switch(*type)
+ {
+ case TNG_CHAR_DATA:
+ return(TNG_FAILURE);
+ case TNG_INT_DATA:
+ size = sizeof(int64_t);
+ break;
+ case TNG_FLOAT_DATA:
+ size = sizeof(float);
+ break;
+ case TNG_DOUBLE_DATA:
+ default:
+ size = sizeof(double);
+ }
+
+ *n_frames = data->n_frames;
+ *n_values_per_frame = data->n_values_per_frame;
+ *stride_length = data->stride_length;
+ n_frames_div = (*n_frames % *stride_length) ? *n_frames / *stride_length + 1:
+ *n_frames / *stride_length;
+
+ data_size = n_frames_div * size *
+ *n_values_per_frame;
+
+ temp = realloc(*values, data_size);
+ if(!temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ data_size, __FILE__, __LINE__);
+ free(*values);
+ *values = 0;
+ return(TNG_CRITICAL);
+ }
+
+ *values = temp;
+
+ memcpy(*values, data->values, data_size);
+
+ data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_data_interval_get
+ (tng_trajectory_t tng_data,
+ const int64_t block_id,
+ const int64_t start_frame_nr,
+ const int64_t end_frame_nr,
+ const char hash_mode,
+ union data_values ***values,
+ int64_t *n_values_per_frame,
+ char *type)
+{
+ int64_t i, j, n_frames, file_pos, current_frame_pos, first_frame;
+ int64_t block_index;
+ int size;
+ size_t len;
+ tng_non_particle_data_t data;
+ tng_trajectory_frame_set_t frame_set;
+ tng_gen_block_t block;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
+ TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
+ TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
+
+ block_index = -1;
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+ first_frame = frame_set->first_frame;
+
+ stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+
+
+ /* Do not re-read the frame set. */
+ if(first_frame != frame_set->first_frame ||
+ frame_set->n_data_blocks <= 0)
+ {
+ tng_block_init(&block);
+ file_pos = ftell(tng_data->input_file);
+ /* Read all blocks until next frame set block */
+ stat = tng_block_header_read(tng_data, block);
+ while(file_pos < tng_data->input_file_len &&
+ stat != TNG_CRITICAL &&
+ block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ stat = tng_block_read_next(tng_data, block,
+ hash_mode);
+ if(stat != TNG_CRITICAL)
+ {
+ file_pos = ftell(tng_data->input_file);
+ if(file_pos < tng_data->input_file_len)
+ {
+ stat = tng_block_header_read(tng_data, block);
+ }
+ }
+ }
+ tng_block_destroy(&block);
+ if(stat == TNG_CRITICAL)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ return(stat);
+ }
+ }
+
+
+ /* See if there is a data block of this ID.
+ * Start checking the last read frame set */
+ for(i = frame_set->n_data_blocks; i-- ;)
+ {
+ data = &frame_set->tr_data[i];
+ if(data->block_id == block_id)
+ {
+ block_index = i;
+ break;
+ }
+ }
+
+ if(block_index < 0)
+ {
+ fprintf(stderr, "TNG library: Could not find non-particle data block with id %"PRId64". %s: %d\n",
+ block_id, __FILE__, __LINE__);
+ return(TNG_FAILURE);
+ }
+
+ n_frames = end_frame_nr - start_frame_nr + 1;
+ *n_values_per_frame = data->n_values_per_frame;
+ *type = data->datatype;
+
+ if(*values == 0)
+ {
+ if(tng_data_values_alloc(tng_data, values, n_frames,
+ *n_values_per_frame,
+ *type) != TNG_SUCCESS)
+ {
+ return(TNG_CRITICAL);
+ }
+ }
+
+ current_frame_pos = start_frame_nr - frame_set->first_frame;
+ /* It's not very elegant to reuse so much of the code in the different case
+ * statements, but it's unnecessarily slow to have the switch-case block
+ * inside the for loops. */
+ switch(*type)
+ {
+ case TNG_CHAR_DATA:
+ for(i=0; i<n_frames; i++)
+ {
+ if(current_frame_pos == frame_set->n_frames)
+ {
+ stat = tng_frame_set_read_next(tng_data, hash_mode);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ current_frame_pos = 0;
+ }
+ for(j=*n_values_per_frame; j--;)
+ {
+ len = strlen(data->strings[current_frame_pos][j]) + 1;
+ (*values)[i][j].c = malloc(len);
+ strncpy((*values)[i][j].c, data->strings[current_frame_pos][j], len);
+ }
+ current_frame_pos++;
+ }
+ break;
+ case TNG_INT_DATA:
+ size = sizeof(int);
+ for(i=0; i<n_frames; i++)
+ {
+ if(current_frame_pos == frame_set->n_frames)
+ {
+ stat = tng_frame_set_read_next(tng_data, hash_mode);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ current_frame_pos = 0;
+ }
+ for(j=*n_values_per_frame; j--;)
+ {
+ (*values)[i][j].i = *(int *)((char *)data->values + size *
+ (current_frame_pos *
+ (*n_values_per_frame) + j));
+ }
+ current_frame_pos++;
+ }
+ break;
+ case TNG_FLOAT_DATA:
+ size = sizeof(float);
+ for(i=0; i<n_frames; i++)
+ {
+ if(current_frame_pos == frame_set->n_frames)
+ {
+ stat = tng_frame_set_read_next(tng_data, hash_mode);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ current_frame_pos = 0;
+ }
+ for(j=*n_values_per_frame; j--;)
+ {
+ (*values)[i][j].f = *(float *)((char *)data->values + size *
+ (current_frame_pos *
+ (*n_values_per_frame) + j));
+ }
+ current_frame_pos++;
+ }
+ break;
+ case TNG_DOUBLE_DATA:
+ default:
+ size = sizeof(double);
+ for(i=0; i<n_frames; i++)
+ {
+ if(current_frame_pos == frame_set->n_frames)
+ {
+ stat = tng_frame_set_read_next(tng_data, hash_mode);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ current_frame_pos = 0;
+ }
+ for(j=*n_values_per_frame; j--;)
+ {
+ (*values)[i][j].d = *(double *)((char *)data->values + size *
+ (current_frame_pos *
+ (*n_values_per_frame) + j));
+ }
+ current_frame_pos++;
+ }
+ }
+
+ data->last_retrieved_frame = end_frame_nr;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_data_vector_interval_get
+ (tng_trajectory_t tng_data,
+ const int64_t block_id,
+ const int64_t start_frame_nr,
+ const int64_t end_frame_nr,
+ const char hash_mode,
+ void **values,
+ int64_t *stride_length,
+ int64_t *n_values_per_frame,
+ char *type)
+{
+ int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
+ int64_t file_pos, current_frame_pos, data_size, frame_size;
+ int64_t last_frame_pos;
+ int size;
+ tng_trajectory_frame_set_t frame_set;
+ tng_non_particle_data_t np_data;
+ tng_gen_block_t block;
+ void *current_values = 0, *temp;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than the end_frame_nr.");
+ TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
+ TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
+ TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+ first_frame = frame_set->first_frame;
+
+ stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+
+ /* Do not re-read the frame set and only need the requested block. */
+ /* TODO: Test that blocks are read correctly now that not all of them are read at the same time. */
+ stat = tng_data_find(tng_data, block_id, &np_data);
+ if(first_frame != frame_set->first_frame ||
+ stat != TNG_SUCCESS)
+ {
+ tng_block_init(&block);
+ if(stat != TNG_SUCCESS)
+ {
+ fseek(tng_data->input_file,
+ (long)tng_data->current_trajectory_frame_set_input_file_pos,
+ SEEK_SET);
+ stat = tng_block_header_read(tng_data, block);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
+ __FILE__, __LINE__);
+ return(stat);
+ }
+
+ fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
+ }
+ file_pos = ftell(tng_data->input_file);
+ /* Read until next frame set block */
+ stat = tng_block_header_read(tng_data, block);
+ while(file_pos < tng_data->input_file_len &&
+ stat != TNG_CRITICAL &&
+ block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ if(block->id == block_id)
+ {
+ stat = tng_block_read_next(tng_data, block,
+ hash_mode);
+ if(stat != TNG_CRITICAL)
+ {
+ file_pos = ftell(tng_data->input_file);
+ if(file_pos < tng_data->input_file_len)
+ {
+ stat = tng_block_header_read(tng_data, block);
+ }
+ }
+ }
+ else
+ {
+ file_pos += block->block_contents_size + block->header_contents_size;
+ fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
+ if(file_pos < tng_data->input_file_len)
+ {
+ stat = tng_block_header_read(tng_data, block);
+ }
+ }
+ }
+ tng_block_destroy(&block);
+ if(stat == TNG_CRITICAL)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ return(stat);
+ }
+ }
+
+ stat = tng_data_find(tng_data, block_id, &np_data);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+
+ stat = tng_data_vector_get(tng_data, block_id, ¤t_values,
+ &n_frames, stride_length,
+ n_values_per_frame, type);
+
+ if(stat != TNG_SUCCESS)
+ {
+ if(current_values)
+ {
+ free(current_values);
+ }
+ return(stat);
+ }
+
+ if(n_frames == 1 && n_frames < frame_set->n_frames)
+ {
+ tot_n_frames = 1;
+ }
+ else
+ {
+ tot_n_frames = end_frame_nr - start_frame_nr + 1;
+ }
+
+ switch(*type)
+ {
+ case TNG_CHAR_DATA:
+ return(TNG_FAILURE);
+ case TNG_INT_DATA:
+ size = sizeof(int64_t);
+ break;
+ case TNG_FLOAT_DATA:
+ size = sizeof(float);
+ break;
+ case TNG_DOUBLE_DATA:
+ default:
+ size = sizeof(double);
+ }
+
+ n_frames_div = (tot_n_frames % *stride_length) ?
+ tot_n_frames / *stride_length + 1:
+ tot_n_frames / *stride_length;
+ data_size = n_frames_div * size * (*n_values_per_frame);
+
+/* fprintf(stderr, "TNG library: size: %d, n_frames_div: %"PRId64", data_size: %"PRId64"\n",
+ size, n_frames_div, data_size);
+*/
+ temp = realloc(*values, data_size);
+ if(!temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ data_size, __FILE__, __LINE__);
+ free(*values);
+ *values = 0;
+ return(TNG_CRITICAL);
+ }
+
+ *values = temp;
+
+ if( n_frames == 1 && n_frames < frame_set->n_frames)
+ {
+ memcpy(*values, current_values, size * (*n_values_per_frame));
+ }
+ else
+ {
+ current_frame_pos = start_frame_nr - frame_set->first_frame;
+
+ frame_size = size * (*n_values_per_frame);
+
+ last_frame_pos = tng_min_i64(n_frames,
+ end_frame_nr - start_frame_nr);
+
+ n_frames_div = current_frame_pos / *stride_length;
+ n_frames_div_2 = (last_frame_pos % *stride_length) ?
+ last_frame_pos / *stride_length + 1:
+ last_frame_pos / *stride_length;
+ n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
+
+ memcpy(*values, (char *)current_values + n_frames_div * frame_size,
+ n_frames_div_2 * frame_size);
+
+ current_frame_pos += n_frames - current_frame_pos;
+
+ while(current_frame_pos <= end_frame_nr - start_frame_nr)
+ {
+ stat = tng_frame_set_read_next(tng_data, hash_mode);
+ if(stat != TNG_SUCCESS)
+ {
+ if(current_values)
+ {
+ free(current_values);
+ }
+ free(*values);
+ *values = 0;
+ return(stat);
+ }
+
+ stat = tng_data_vector_get(tng_data, block_id, ¤t_values,
+ &n_frames, stride_length,
+ n_values_per_frame, type);
+
+ if(stat != TNG_SUCCESS)
+ {
+ if(current_values)
+ {
+ free(current_values);
+ }
+ free(*values);
+ *values = 0;
+ return(stat);
+ }
+
+ last_frame_pos = tng_min_i64(n_frames,
+ end_frame_nr - current_frame_pos);
+
+ n_frames_div = current_frame_pos / *stride_length;
+ n_frames_div_2 = (last_frame_pos % *stride_length) ?
+ last_frame_pos / *stride_length + 1:
+ last_frame_pos / *stride_length;
+ n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
+
+ memcpy(((char *)*values) + n_frames_div * frame_size,
+ current_values,
+ n_frames_div_2 * frame_size);
+
+ current_frame_pos += n_frames;
+ }
+ }
+
+ if(current_values)
+ {
+ free(current_values);
+ }
+
+ np_data->last_retrieved_frame = end_frame_nr;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_particle_data_get
+ (tng_trajectory_t tng_data,
+ const int64_t block_id,
+ union data_values ****values,
+ int64_t *n_frames,
+ int64_t *n_particles,
+ int64_t *n_values_per_frame,
+ char *type)
+{
+ int64_t i, j, k, mapping, file_pos, i_step, block_index;
+ int size;
+ size_t len;
+ tng_particle_data_t data;
+ tng_trajectory_frame_set_t frame_set;
+ tng_gen_block_t block;
+ char block_type_flag;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
+ TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
+ TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
+ TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ block_index = -1;
+ data = 0;
+
+ if(tng_particle_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
+ {
+ if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
+ {
+ block_type_flag = TNG_TRAJECTORY_BLOCK;
+ }
+ else
+ {
+ block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
+ }
+
+ tng_block_init(&block);
+ file_pos = ftell(tng_data->input_file);
+ /* Read all blocks until next frame set block */
+ stat = tng_block_header_read(tng_data, block);
+ while(file_pos < tng_data->input_file_len &&
+ stat != TNG_CRITICAL &&
+ block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ /* Use hash by default */
+ stat = tng_block_read_next(tng_data, block,
+ TNG_USE_HASH);
+ if(stat != TNG_CRITICAL)
+ {
+ file_pos = ftell(tng_data->input_file);
+ if(file_pos < tng_data->input_file_len)
+ {
+ stat = tng_block_header_read(tng_data, block);
+ }
+ }
+ }
+ tng_block_destroy(&block);
+ if(stat == TNG_CRITICAL)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ return(stat);
+ }
+
+ for(i = frame_set->n_particle_data_blocks; i-- ;)
+ {
+ data = &frame_set->tr_particle_data[i];
+ if(data->block_id == block_id)
+ {
+ block_index = i;
+ block_type_flag = TNG_TRAJECTORY_BLOCK;
+ break;
+ }
+ }
+ if(block_index < 0)
+ {
+ return(TNG_FAILURE);
+ }
+ }
+ else
+ {
+ if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
+ {
+ block_type_flag = TNG_TRAJECTORY_BLOCK;
+ }
+ else
+ {
+ block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
+ }
+ }
+
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
+ tng_data->var_num_atoms_flag)
+ {
+ *n_particles = frame_set->n_particles;
+ }
+ else
+ {
+ *n_particles = tng_data->n_particles;
+ }
+
+ *n_frames = tng_max_i64(1, data->n_frames);
+ *n_values_per_frame = data->n_values_per_frame;
+ *type = data->datatype;
+
+ if(*values == 0)
+ {
+ if(tng_particle_data_values_alloc(tng_data, values, *n_frames,
+ *n_particles, *n_values_per_frame,
+ *type)
+ != TNG_SUCCESS)
+ {
+ return(TNG_CRITICAL);
+ }
+ }
+
+ /* It's not very elegant to reuse so much of the code in the different case
+ * statements, but it's unnecessarily slow to have the switch-case block
+ * inside the for loops. */
+ switch(*type)
+ {
+ case TNG_CHAR_DATA:
+ for(i=*n_frames; i--;)
+ {
+ for(j=*n_particles; j--;)
+ {
+ tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
+ for(k=*n_values_per_frame; k--;)
+ {
+ len = strlen(data->strings[i][j][k]) + 1;
+ (*values)[i][mapping][k].c = malloc(len);
+ strncpy((*values)[i][mapping][k].c,
+ data->strings[i][j][k], len);
+ }
+ }
+ }
+ break;
+ case TNG_INT_DATA:
+ size = sizeof(int);
+ i_step = (*n_particles) * (*n_values_per_frame);
+ for(i=*n_frames; i--;)
+ {
+ for(j=*n_particles; j--;)
+ {
+ tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
+ for(k=*n_values_per_frame; k--;)
+ {
+ (*values)[i][mapping][k].i = *(int *)
+ ((char *)data->values + size *
+ (i * i_step + j *
+ (*n_values_per_frame) + k));
+ }
+ }
+ }
+ break;
+ case TNG_FLOAT_DATA:
+ size = sizeof(float);
+ i_step = (*n_particles) * (*n_values_per_frame);
+ for(i=*n_frames; i--;)
+ {
+ for(j=*n_particles; j--;)
+ {
+ tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
+ for(k=*n_values_per_frame; k--;)
+ {
+ (*values)[i][mapping][k].f = *(float *)
+ ((char *)data->values + size *
+ (i * i_step + j *
+ (*n_values_per_frame) + k));
+ }
+ }
+ }
+ break;
+ case TNG_DOUBLE_DATA:
+ default:
+ size = sizeof(double);
+ i_step = (*n_particles) * (*n_values_per_frame);
+ for(i=*n_frames; i--;)
+ {
+ for(j=*n_particles; j--;)
+ {
+ tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
+ for(k=*n_values_per_frame; k--;)
+ {
+ (*values)[i][mapping][k].d = *(double *)
+ ((char *)data->values + size *
+ (i * i_step + j *
+ (*n_values_per_frame) + k));
+ }
+ }
+ }
+ }
+
+ data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_get
+ (tng_trajectory_t tng_data,
+ const int64_t block_id,
+ void **values,
+ int64_t *n_frames,
+ int64_t *stride_length,
+ int64_t *n_particles,
+ int64_t *n_values_per_frame,
+ char *type)
+{
+ int64_t i, j, mapping, file_pos, i_step, data_size, n_frames_div;
+ int64_t block_index;
+ int size;
+ tng_particle_data_t data;
+ tng_trajectory_frame_set_t frame_set;
+ tng_gen_block_t block;
+ void *temp;
+ char block_type_flag;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
+ TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
+ TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
+ TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ block_index = -1;
+ data = 0;
+
+ if(tng_particle_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
+ {
+ tng_block_init(&block);
+ file_pos = ftell(tng_data->input_file);
+ /* Read all blocks until next frame set block */
+ stat = tng_block_header_read(tng_data, block);
+ while(file_pos < tng_data->input_file_len &&
+ stat != TNG_CRITICAL &&
+ block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ /* Use hash by default */
+ stat = tng_block_read_next(tng_data, block,
+ TNG_USE_HASH);
+ if(stat != TNG_CRITICAL)
+ {
+ file_pos = ftell(tng_data->input_file);
+ if(file_pos < tng_data->input_file_len)
+ {
+ stat = tng_block_header_read(tng_data, block);
+ }
+ }
+ }
+ tng_block_destroy(&block);
+ if(stat == TNG_CRITICAL)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ return(stat);
+ }
+
+ for(i = frame_set->n_particle_data_blocks; i-- ;)
+ {
+ data = &frame_set->tr_particle_data[i];
+ if(data->block_id == block_id)
+ {
+ block_index = i;
+ break;
+ }
+ }
+ if(block_index < 0)
+ {
+ return(TNG_FAILURE);
+ }
+ }
+
+ if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
+ {
+ block_type_flag = TNG_TRAJECTORY_BLOCK;
+ }
+ else
+ {
+ block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
+ }
+
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
+ tng_data->var_num_atoms_flag)
+ {
+ *n_particles = frame_set->n_particles;
+ }
+ else
+ {
+ *n_particles = tng_data->n_particles;
+ }
+
+ *type = data->datatype;
+
+ switch(*type)
+ {
+ case TNG_CHAR_DATA:
+ return(TNG_FAILURE);
+ case TNG_INT_DATA:
+ size = sizeof(int64_t);
+ break;
+ case TNG_FLOAT_DATA:
+ size = sizeof(float);
+ break;
+ case TNG_DOUBLE_DATA:
+ default:
+ size = sizeof(double);
+ }
+
+ *n_frames = tng_max_i64(1, data->n_frames);
+ *n_values_per_frame = data->n_values_per_frame;
+ *stride_length = data->stride_length;
+
+ n_frames_div = (*n_frames % *stride_length) ?
+ *n_frames / *stride_length + 1:
+ *n_frames / *stride_length;
+
+ data_size = n_frames_div * size * (*n_particles) *
+ (*n_values_per_frame);
+
+ temp = realloc(*values, data_size);
+ if(!temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ data_size, __FILE__, __LINE__);
+ free(*values);
+ *values = 0;
+ return(TNG_CRITICAL);
+ }
+
+ *values = temp;
+
+ if(frame_set->n_mapping_blocks <= 0)
+ {
+ memcpy(*values, data->values, data_size);
+ }
+ else
+ {
+ i_step = (*n_particles) * (*n_values_per_frame);
+ for(i = *n_frames; i--;)
+ {
+ for(j = *n_particles; j--;)
+ {
+ tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
+ memcpy(((char *)*values) + size * (i * i_step + mapping *
+ (*n_values_per_frame)),
+ (char *)data->values + size *
+ (i * i_step + j * (*n_values_per_frame)),
+ size * (*n_values_per_frame));
+ }
+ }
+ }
+
+ data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get
+ (tng_trajectory_t tng_data,
+ const int64_t block_id,
+ const int64_t start_frame_nr,
+ const int64_t end_frame_nr,
+ const char hash_mode,
+ union data_values ****values,
+ int64_t *n_particles,
+ int64_t *n_values_per_frame,
+ char *type)
+{
+ int64_t i, j, k, mapping, n_frames, file_pos, current_frame_pos, i_step;
+ int64_t first_frame, block_index;
+ int size;
+ size_t len;
+ tng_particle_data_t data;
+ tng_trajectory_frame_set_t frame_set;
+ tng_gen_block_t block;
+ char block_type_flag;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
+ TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
+ TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
+ TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
+
+ block_index = -1;
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+ first_frame = frame_set->first_frame;
+
+ stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+
+ /* Do not re-read the frame set. */
+ if(first_frame != frame_set->first_frame ||
+ frame_set->n_particle_data_blocks <= 0)
+ {
+ tng_block_init(&block);
+ file_pos = ftell(tng_data->input_file);
+ /* Read all blocks until next frame set block */
+ stat = tng_block_header_read(tng_data, block);
+ while(file_pos < tng_data->input_file_len &&
+ stat != TNG_CRITICAL &&
+ block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ stat = tng_block_read_next(tng_data, block,
+ hash_mode);
+ if(stat != TNG_CRITICAL)
+ {
+ file_pos = ftell(tng_data->input_file);
+ if(file_pos < tng_data->input_file_len)
+ {
+ stat = tng_block_header_read(tng_data, block);
+ }
+ }
+ }
+ tng_block_destroy(&block);
+ if(stat == TNG_CRITICAL)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ return(stat);
+ }
+ }
+
+ /* See if there is already a data block of this ID.
+ * Start checking the last read frame set */
+ for(i = frame_set->n_particle_data_blocks; i-- ;)
+ {
+ data = &frame_set->tr_particle_data[i];
+ if(data->block_id == block_id)
+ {
+ block_index = i;
+ block_type_flag = TNG_TRAJECTORY_BLOCK;
+ break;
+ }
+ }
+
+ if(block_index < 0)
+ {
+ fprintf(stderr, "TNG library: Could not find particle data block with id %"PRId64". %s: %d\n",
+ block_id, __FILE__, __LINE__);
+ return(TNG_FAILURE);
+ }
+
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
+ tng_data->var_num_atoms_flag)
+ {
+ *n_particles = frame_set->n_particles;
+ }
+ else
+ {
+ *n_particles = tng_data->n_particles;
+ }
+
+ n_frames = end_frame_nr - start_frame_nr + 1;
+ *n_values_per_frame = data->n_values_per_frame;
+ *type = data->datatype;
+
+ if(*values == 0)
+ {
+ if(tng_particle_data_values_alloc(tng_data, values, n_frames,
+ *n_particles, *n_values_per_frame,
+ *type)
+ != TNG_SUCCESS)
+ {
+ return(TNG_CRITICAL);
+ }
+ }
+
+ current_frame_pos = start_frame_nr - frame_set->first_frame;
+ /* It's not very elegant to reuse so much of the code in the different case
+ * statements, but it's unnecessarily slow to have the switch-case block
+ * inside the for loops. */
+ switch(*type)
+ {
+ case TNG_CHAR_DATA:
+ for(i=0; i<n_frames; i++)
+ {
+ if(current_frame_pos == frame_set->n_frames)
+ {
+ stat = tng_frame_set_read_next(tng_data, hash_mode);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ current_frame_pos = 0;
+ }
+ for(j=*n_particles; j--;)
+ {
+ tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
+ for(k=*n_values_per_frame; k--;)
+ {
+ len = strlen(data->strings[current_frame_pos][j][k]) + 1;
+ (*values)[i][mapping][k].c = malloc(len);
+ strncpy((*values)[i][mapping][k].c, data->strings[current_frame_pos][j][k], len);
+ }
+ }
+ current_frame_pos++;
+ }
+ break;
+ case TNG_INT_DATA:
+ size = sizeof(int);
+ i_step = (*n_particles) * (*n_values_per_frame);
+ for(i=0; i<n_frames; i++)
+ {
+ if(current_frame_pos == frame_set->n_frames)
+ {
+ stat = tng_frame_set_read_next(tng_data, hash_mode);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ current_frame_pos = 0;
+ }
+ for(j=*n_particles; j--;)
+ {
+ tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
+ for(k=*n_values_per_frame; k--;)
+ {
+ (*values)[i][mapping][k].i = *(int *)
+ ((char *)data->values + size *
+ (current_frame_pos *
+ i_step + j *
+ (*n_values_per_frame) + k));
+ }
+ }
+ current_frame_pos++;
+ }
+ break;
+ case TNG_FLOAT_DATA:
+ size = sizeof(float);
+ i_step = (*n_particles) * (*n_values_per_frame);
+ for(i=0; i<n_frames; i++)
+ {
+ if(current_frame_pos == frame_set->n_frames)
+ {
+ stat = tng_frame_set_read_next(tng_data, hash_mode);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ current_frame_pos = 0;
+ }
+ for(j=*n_particles; j--;)
+ {
+ tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
+ for(k=*n_values_per_frame; k--;)
+ {
+ (*values)[i][mapping][k].f = *(float *)
+ ((char *)data->values + size *
+ (current_frame_pos *
+ i_step + j *
+ (*n_values_per_frame) + k));
+ }
+ }
+ current_frame_pos++;
+ }
+ break;
+ case TNG_DOUBLE_DATA:
+ default:
+ size = sizeof(double);
+ i_step = (*n_particles) * (*n_values_per_frame);
+ for(i=0; i<n_frames; i++)
+ {
+ if(current_frame_pos == frame_set->n_frames)
+ {
+ stat = tng_frame_set_read_next(tng_data, hash_mode);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ current_frame_pos = 0;
+ }
+ for(j=*n_particles; j--;)
+ {
+ tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
+ for(k=*n_values_per_frame; k--;)
+ {
+ (*values)[i][mapping][k].d = *(double *)
+ ((char *)data->values + size *
+ (current_frame_pos *
+ i_step + j *
+ (*n_values_per_frame) + k));
+ }
+ }
+ current_frame_pos++;
+ }
+ }
+
+ data->last_retrieved_frame = end_frame_nr;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_interval_get
+ (tng_trajectory_t tng_data,
+ const int64_t block_id,
+ const int64_t start_frame_nr,
+ const int64_t end_frame_nr,
+ const char hash_mode,
+ void **values,
+ int64_t *n_particles,
+ int64_t *stride_length,
+ int64_t *n_values_per_frame,
+ char *type)
+{
+ int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
+ int64_t file_pos, current_frame_pos, last_frame_pos, data_size, frame_size;
+ int size;
+ tng_trajectory_frame_set_t frame_set;
+ tng_particle_data_t p_data;
+ tng_gen_block_t block;
+ void *current_values = 0, *temp;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
+ TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
+ TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
+ TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
+ TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+ first_frame = frame_set->first_frame;
+
+ stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+
+ /* Do not re-read the frame set and only need the requested block + particle mapping blocks. */
+ /* TODO: Test that blocks are read correctly now that now all of them are read at the same time. */
+ stat = tng_particle_data_find(tng_data, block_id, &p_data);
+ if(first_frame != frame_set->first_frame ||
+ stat != TNG_SUCCESS)
+ {
+ tng_block_init(&block);
+ if(stat != TNG_SUCCESS)
+ {
+ fseek(tng_data->input_file,
+ (long)tng_data->current_trajectory_frame_set_input_file_pos,
+ SEEK_SET);
+ stat = tng_block_header_read(tng_data, block);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
+ __FILE__, __LINE__);
+ return(stat);
+ }
+
+ fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
+ }
+ file_pos = ftell(tng_data->input_file);
+ /* Read until next frame set block */
+ stat = tng_block_header_read(tng_data, block);
+ while(file_pos < tng_data->input_file_len &&
+ stat != TNG_CRITICAL &&
+ block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ if(block->id == block_id || block->id == TNG_PARTICLE_MAPPING)
+ {
+ stat = tng_block_read_next(tng_data, block,
+ hash_mode);
+ if(stat != TNG_CRITICAL)
+ {
+ file_pos = ftell(tng_data->input_file);
+ if(file_pos < tng_data->input_file_len)
+ {
+ stat = tng_block_header_read(tng_data, block);
+ }
+ }
+ }
+ else
+ {
+ file_pos += block->block_contents_size + block->header_contents_size;
+ fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
+ if(file_pos < tng_data->input_file_len)
+ {
+ stat = tng_block_header_read(tng_data, block);
+ }
+ }
+ }
+ tng_block_destroy(&block);
+ if(stat == TNG_CRITICAL)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ return(stat);
+ }
+ }
+ stat = tng_particle_data_find(tng_data, block_id, &p_data);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+
+ stat = tng_particle_data_vector_get(tng_data, block_id, ¤t_values,
+ &n_frames, stride_length, n_particles,
+ n_values_per_frame, type);
+
+ if(stat != TNG_SUCCESS || *n_particles == 0)
+ {
+ if(current_values)
+ {
+ free(current_values);
+ }
+ return(stat);
+ }
+
+ if(n_frames == 1 && n_frames < frame_set->n_frames)
+ {
+ tot_n_frames = 1;
+ }
+ else
+ {
+ tot_n_frames = end_frame_nr - start_frame_nr + 1;
+ }
+
+ switch(*type)
+ {
+ case TNG_CHAR_DATA:
+ return(TNG_FAILURE);
+ case TNG_INT_DATA:
+ size = sizeof(int64_t);
+ break;
+ case TNG_FLOAT_DATA:
+ size = sizeof(float);
+ break;
+ case TNG_DOUBLE_DATA:
+ default:
+ size = sizeof(double);
+ }
+
+ n_frames_div = (tot_n_frames % *stride_length) ?
+ tot_n_frames / *stride_length + 1:
+ tot_n_frames / *stride_length;
+
+ data_size = n_frames_div * size * (*n_particles) *
+ (*n_values_per_frame);
+
+ temp = realloc(*values, data_size);
+ if(!temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ data_size, __FILE__, __LINE__);
+ free(*values);
+ *values = 0;
+ return(TNG_CRITICAL);
+ }
+
+ *values = temp;
+
+ if( n_frames == 1 && n_frames < frame_set->n_frames)
+ {
+ memcpy(*values, current_values, size * (*n_particles) *
+ (*n_values_per_frame));
+ }
+ else
+ {
+ current_frame_pos = start_frame_nr - frame_set->first_frame;
+
+ frame_size = size * (*n_particles) * (*n_values_per_frame);
+
+ last_frame_pos = tng_min_i64(n_frames,
+ end_frame_nr - start_frame_nr);
+
+ n_frames_div = current_frame_pos / *stride_length;
+ n_frames_div_2 = (last_frame_pos % *stride_length) ?
+ last_frame_pos / *stride_length + 1:
+ last_frame_pos / *stride_length;
+ n_frames_div_2 = tng_max_i64(1, n_frames_div_2 + 1);
+
+ memcpy(*values, (char *)current_values + n_frames_div * frame_size,
+ n_frames_div_2 * frame_size);
+
+ current_frame_pos += n_frames - current_frame_pos;
+
+ while(current_frame_pos <= end_frame_nr - start_frame_nr)
+ {
+ stat = tng_frame_set_read_next(tng_data, hash_mode);
+ if(stat != TNG_SUCCESS)
+ {
+ if(current_values)
+ {
+ free(current_values);
+ }
+ free(*values);
+ *values = 0;
+ return(stat);
+ }
+
+ stat = tng_particle_data_vector_get(tng_data, block_id, ¤t_values,
+ &n_frames, stride_length, n_particles,
+ n_values_per_frame, type);
+
+ if(stat != TNG_SUCCESS)
+ {
+ if(current_values)
+ {
+ free(current_values);
+ }
+ free(*values);
+ *values = 0;
+ return(stat);
+ }
+
+ last_frame_pos = tng_min_i64(n_frames,
+ end_frame_nr - current_frame_pos);
+
+ n_frames_div = current_frame_pos / *stride_length;
+ n_frames_div_2 = (last_frame_pos % *stride_length) ?
+ last_frame_pos / *stride_length + 1:
+ last_frame_pos / *stride_length;
+ n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
+
+ memcpy(((char *)*values) + n_frames_div * frame_size,
+ current_values,
+ n_frames_div_2 * frame_size);
+
+ current_frame_pos += n_frames;
+ }
+ }
+
+ if(current_values)
+ {
+ free(current_values);
+ }
+
+ p_data->last_retrieved_frame = end_frame_nr;
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_data_get_stride_length
+ (tng_trajectory_t tng_data,
+ const int64_t block_id,
+ int64_t frame,
+ int64_t *stride_length)
+{
+ tng_function_status stat;
+ tng_non_particle_data_t np_data;
+ tng_particle_data_t p_data;
+ long file_pos;
+ int is_particle_data;
+
+ if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
+ {
+ frame = 0;
+ }
+
+ if(frame >= 0)
+ {
+ stat = tng_frame_set_of_frame_find(tng_data, frame);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ }
+ stat = tng_data_find(tng_data, block_id, &np_data);
+ if(stat != TNG_SUCCESS)
+ {
+ stat = tng_particle_data_find(tng_data, block_id, &p_data);
+ if(stat != TNG_SUCCESS)
+ {
+ stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
+ /* If no specific frame was required read until this data block is found */
+ if(frame < 0)
+ {
+ file_pos = ftell(tng_data->input_file);
+ while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
+ {
+ stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
+ file_pos = ftell(tng_data->input_file);
+ }
+ }
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ stat = tng_data_find(tng_data, block_id, &np_data);
+ if(stat != TNG_SUCCESS)
+ {
+ stat = tng_particle_data_find(tng_data, block_id, &p_data);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ else
+ {
+ is_particle_data = 1;
+ }
+ }
+ else
+ {
+ is_particle_data = 0;
+ }
+ }
+ else
+ {
+ is_particle_data = 1;
+ }
+ }
+ else
+ {
+ is_particle_data = 0;
+ }
+ if(is_particle_data)
+ {
+ *stride_length = p_data->stride_length;
+ }
+ else
+ {
+ *stride_length = np_data->stride_length;
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_time_get_str
+ (const tng_trajectory_t tng_data,
+ char *time)
+{
+ struct tm *time_data;
+ time_t secs;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
+
+ secs = tng_data->time;
+
+ time_data = localtime(&secs); /* Returns a statically allocated variable. */
+ TNG_SNPRINTF(time, TNG_MAX_DATE_STR_LEN,
+ "%4d-%02d-%02d %02d:%02d:%02d",
+ time_data->tm_year+1900, time_data->tm_mon+1, time_data->tm_mday,
+ time_data->tm_hour, time_data->tm_min, time_data->tm_sec);
+
+ return(TNG_SUCCESS);
+}
+
+
+tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_open
+ (const char *filename,
+ const char mode,
+ tng_trajectory_t *tng_data_p)
+{
+ tng_function_status stat;
+
+ TNG_ASSERT(filename, "TNG library: filename must not be a NULL pointer.");
+
+ if(mode != 'r' && mode != 'w' && mode != 'a')
+ {
+ return(TNG_FAILURE);
+ }
+
+ if(tng_trajectory_init(tng_data_p) != TNG_SUCCESS)
+ {
+ tng_trajectory_destroy(tng_data_p);
+ return(TNG_CRITICAL);
+ }
+
+ if(mode == 'r' || mode == 'a')
+ {
+ tng_input_file_set(*tng_data_p, filename);
+
+ /* Read the file headers */
+ tng_file_headers_read(*tng_data_p, TNG_USE_HASH);
+
+ tng_num_frame_sets_get(*tng_data_p, &(*tng_data_p)->n_trajectory_frame_sets);
+ }
+
+ if(mode == 'w')
+ {
+ tng_output_file_set(*tng_data_p, filename);
+ }
+ else if(mode == 'a')
+ {
+ fseek((*tng_data_p)->input_file,
+ (long)(*tng_data_p)->last_trajectory_frame_set_input_file_pos,
+ SEEK_SET);
+
+ stat = tng_frame_set_read(*tng_data_p, TNG_USE_HASH);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot read frame set and related blocks. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+
+ (*tng_data_p)->first_trajectory_frame_set_output_file_pos =
+ (*tng_data_p)->first_trajectory_frame_set_input_file_pos;
+ (*tng_data_p)->last_trajectory_frame_set_output_file_pos =
+ (*tng_data_p)->last_trajectory_frame_set_input_file_pos;
+ (*tng_data_p)->current_trajectory_frame_set_output_file_pos =
+ (*tng_data_p)->current_trajectory_frame_set_input_file_pos;
+ (*tng_data_p)->first_trajectory_frame_set_input_file_pos = -1;
+ (*tng_data_p)->last_trajectory_frame_set_input_file_pos = -1;
+ (*tng_data_p)->current_trajectory_frame_set_input_file_pos = -1;
+ if((*tng_data_p)->input_file)
+ {
+ fclose((*tng_data_p)->input_file);
+ (*tng_data_p)->input_file = 0;
+ }
+ if((*tng_data_p)->input_file_path)
+ {
+ free((*tng_data_p)->input_file_path);
+ (*tng_data_p)->input_file_path = 0;
+ }
+ tng_output_append_file_set(*tng_data_p, filename);
+
+ fseek((*tng_data_p)->output_file, 0, SEEK_END);
+ }
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_close
+ (tng_trajectory_t *tng_data_p)
+{
+ tng_trajectory_frame_set_t frame_set;
+
+ if(tng_data_p == 0)
+ {
+ fprintf(stderr, "TNG library: Empty pointer to trajectory when attempting to close. %s: %d\n",
+ __FILE__, __LINE__);
+ return(TNG_FAILURE);
+ }
+
+ if(*tng_data_p == 0)
+ {
+ return(TNG_SUCCESS);
+ }
+
+ frame_set = &(*tng_data_p)->current_trajectory_frame_set;
+
+ if(frame_set->n_unwritten_frames > 0)
+ {
+ frame_set->n_frames = frame_set->n_unwritten_frames;
+ tng_frame_set_write(*tng_data_p, TNG_USE_HASH);
+ }
+
+ return(tng_trajectory_destroy(tng_data_p));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_time_of_frame_get
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ double *time)
+{
+ int64_t first_frame;
+ tng_trajectory_frame_set_t frame_set;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
+
+ stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot find frame nr %"PRId64". %s: %d\n",
+ frame_nr, __FILE__, __LINE__);
+ return(stat);
+ }
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+ first_frame = frame_set->first_frame;
+
+ if(tng_data->time_per_frame <= 0)
+ {
+ return(TNG_FAILURE);
+ }
+
+ *time = frame_set->first_frame_time + (tng_data->time_per_frame * (frame_nr - first_frame));
+
+ return(TNG_SUCCESS);
+}
+
+/*
+tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecules_get
+ (tng_trajectory_t tng_data,
+ int64_t *n_mols,
+ int64_t **molecule_cnt_list,
+ tng_molecule_t *mols)
+{
+ tng_trajectory_frame_set_t frame_set;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(n_mols, "TNG library: n_mols must not be a NULL pointer.");
+
+ *n_mols = tng_data->n_molecules;
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+ if(tng_data->var_num_atoms_flag && frame_set && frame_set->molecule_cnt_list)
+ {
+ *molecule_cnt_list = frame_set->molecule_cnt_list;
+ }
+ else
+ {
+ *molecule_cnt_list = tng_data->molecule_cnt_list;
+ }
+
+ *mols = tng_data->molecules;
+
+ return(TNG_SUCCESS);
+}
+*/
+/*
+tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecule_add
+ (tng_trajectory_t tng_data,
+ const char *name,
+ const int64_t cnt,
+ tng_molecule_t *mol)
+{
+ tng_function_status stat;
+
+ TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
+ TNG_ASSERT(cnt>=0, "TNG library: cnt must be >= 0");
+
+ stat = tng_molecule_add(tng_data, name, mol);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ stat = tng_molecule_cnt_set(tng_data, *mol, cnt);
+
+ return(stat);
+}
+*/
+tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_get
+ (tng_trajectory_t tng_data,
+ const tng_molecule_t mol,
+ int64_t *n_particles,
+ char ***names,
+ char ***types,
+ char ***res_names,
+ int64_t **res_ids,
+ char ***chain_names,
+ int64_t **chain_ids)
+{
+ tng_atom_t atom;
+ tng_residue_t res;
+ tng_chain_t chain;
+ int64_t i;
+ (void)tng_data;
+
+ *n_particles = mol->n_atoms;
+
+ *names = malloc(sizeof(char *) * *n_particles);
+ *types = malloc(sizeof(char *) * *n_particles);
+ *res_names = malloc(sizeof(char *) * *n_particles);
+ *chain_names = malloc(sizeof(char *) * *n_particles);
+ *res_ids = malloc(sizeof(int64_t) * *n_particles);
+ *chain_ids = malloc(sizeof(int64_t) * *n_particles);
+
+ for(i = 0; i < *n_particles; i++)
+ {
+ atom = &mol->atoms[i];
+ res = atom->residue;
+ chain = res->chain;
+ (*names)[i] = malloc(strlen(atom->name));
+ strcpy(*names[i], atom->name);
+ (*types)[i] = malloc(strlen(atom->atom_type));
+ strcpy(*types[i], atom->atom_type);
+ (*res_names)[i] = malloc(strlen(res->name));
+ strcpy(*res_names[i], res->name);
+ (*chain_names)[i] = malloc(strlen(chain->name));
+ strcpy(*chain_names[i], chain->name);
+ (*res_ids)[i] = res->id;
+ (*chain_ids)[i] = chain->id;
+ }
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_set
+ (tng_trajectory_t tng_data,
+ tng_molecule_t mol,
+ const int64_t n_particles,
+ const char **names,
+ const char **types,
+ const char **res_names,
+ const int64_t *res_ids,
+ const char **chain_names,
+ const int64_t *chain_ids)
+{
+ int64_t i;
+ tng_chain_t chain;
+ tng_residue_t residue;
+ tng_atom_t atom;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(names, "TNG library: names must not be a NULL pointer");
+ TNG_ASSERT(types, "TNG library: types must not be a NULL pointer");
+ TNG_ASSERT(res_names, "TNG library: res_names must not be a NULL pointer");
+ TNG_ASSERT(res_ids, "TNG library: res_ids must not be a NULL pointer");
+ TNG_ASSERT(chain_names, "TNG library: chain_names must not be a NULL pointer");
+ TNG_ASSERT(chain_ids, "TNG library: chain_ids must not be a NULL pointer");
+
+ for(i = 0; i < n_particles; i++)
+ {
+ if(tng_molecule_chain_find(tng_data, mol, chain_names[i], chain_ids[i],
+ &chain) == TNG_FAILURE)
+ {
+ stat = tng_molecule_chain_add(tng_data, mol, chain_names[i],
+ &chain);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ }
+ if(tng_chain_residue_find(tng_data, chain, res_names[i], res_ids[i],
+ &residue) == TNG_FAILURE)
+ {
+ stat = tng_chain_residue_add(tng_data, chain, res_names[i],
+ &residue);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ }
+ stat = tng_residue_atom_add(tng_data, residue, names[i], types[i], &atom);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_pos_read
+ (tng_trajectory_t tng_data,
+ float **positions, int64_t *stride_length)
+{
+ int64_t n_frames, n_particles, n_values_per_frame;
+ char type;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
+ TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
+
+ stat = tng_num_frames_get(tng_data, &n_frames);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+
+ stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
+ 0, n_frames - 1, TNG_USE_HASH,
+ (void **)positions,
+ &n_particles,
+ stride_length,
+ &n_values_per_frame,
+ &type);
+
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_vel_read
+ (tng_trajectory_t tng_data,
+ float **velocities, int64_t *stride_length)
+{
+ int64_t n_frames, n_particles, n_values_per_frame;
+ char type;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
+ TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
+
+ stat = tng_num_frames_get(tng_data, &n_frames);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+
+ stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
+ 0, n_frames - 1, TNG_USE_HASH,
+ (void **)velocities,
+ &n_particles,
+ stride_length,
+ &n_values_per_frame,
+ &type);
+
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_force_read
+ (tng_trajectory_t tng_data,
+ float **forces, int64_t *stride_length)
+{
+ int64_t n_frames, n_particles, n_values_per_frame;
+ char type;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
+ TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
+
+ stat = tng_num_frames_get(tng_data, &n_frames);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+
+ stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
+ 0, n_frames - 1, TNG_USE_HASH,
+ (void **)forces,
+ &n_particles,
+ stride_length,
+ &n_values_per_frame,
+ &type);
+
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read
+ (tng_trajectory_t tng_data,
+ float **box_shape,
+ int64_t *stride_length)
+{
+ int64_t n_frames, n_values_per_frame;
+ char type;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
+ TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
+
+ stat = tng_num_frames_get(tng_data, &n_frames);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+
+ stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
+ 0, n_frames - 1, TNG_USE_HASH,
+ (void **)box_shape,
+ stride_length,
+ &n_values_per_frame,
+ &type);
+
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_particle_data_next_frame_read
+ (tng_trajectory_t tng_data,
+ const int64_t block_id,
+ void **values,
+ char *data_type,
+ int64_t *retrieved_frame_number,
+ double *retrieved_time)
+{
+ tng_trajectory_frame_set_t frame_set;
+ tng_particle_data_t data;
+ tng_function_status stat;
+ int size;
+ int64_t i, data_size, n_particles;
+ void *temp;
+ long file_pos;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
+ TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
+ TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
+ TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ stat = tng_particle_data_find(tng_data, block_id, &data);
+ if(stat != TNG_SUCCESS)
+ {
+ stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
+ file_pos = ftell(tng_data->input_file);
+ while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
+ {
+ stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
+ file_pos = ftell(tng_data->input_file);
+ }
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ stat = tng_particle_data_find(tng_data, block_id, &data);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ }
+ if(data->last_retrieved_frame < 0)
+ {
+ fseek(tng_data->input_file,
+ (long)tng_data->first_trajectory_frame_set_input_file_pos,
+ SEEK_SET);
+ stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+
+ i = data->first_frame_with_data;
+ }
+ else
+ {
+ i = data->last_retrieved_frame + data->stride_length;
+ if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
+ {
+ stat = tng_frame_set_of_frame_find(tng_data, i);
+ if(stat != TNG_SUCCESS)
+ {
+ /* If the frame set search found the frame set after the starting
+ * frame set there is a gap in the frame sets. So, even if the frame
+ * was not found the next frame with data is still in the found
+ * frame set. */
+ if(stat == TNG_CRITICAL)
+ {
+ return(stat);
+ }
+ i = frame_set->first_frame;
+ }
+ }
+ if(data->last_retrieved_frame < frame_set->first_frame)
+ {
+ stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ }
+ }
+ data->last_retrieved_frame = i;
+ *retrieved_frame_number = i;
+ if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
+ {
+ *retrieved_time = frame_set->first_frame_time +
+ (i - frame_set->first_frame) *
+ tng_data->time_per_frame;
+ }
+ else
+ {
+ *retrieved_time = 0;
+ }
+
+ if(data->stride_length > 1)
+ {
+ i = (i - data->first_frame_with_data) / data->stride_length;
+ }
+ else
+ {
+ i = (i - frame_set->first_frame);
+ }
+
+ tng_num_particles_get(tng_data, &n_particles);
+
+ *data_type = data->datatype;
+
+ switch(*data_type)
+ {
+ case TNG_CHAR_DATA:
+ return(TNG_FAILURE);
+ case TNG_INT_DATA:
+ size = sizeof(int64_t);
+ break;
+ case TNG_FLOAT_DATA:
+ size = sizeof(float);
+ break;
+ case TNG_DOUBLE_DATA:
+ default:
+ size = sizeof(double);
+ }
+
+ data_size = size * n_particles * data->n_values_per_frame;
+
+// fprintf(stderr, "TNG library: TEMP: i = %"PRId64", data_size = %"PRId64", size = %d, n_particles = %"PRId64", n_values_per_frame = %"PRId64"\n",
+// i, data_size, size, n_particles, data->n_values_per_frame);
+
+ temp = realloc(*values, data_size);
+ if(!temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ data_size, __FILE__, __LINE__);
+ free(*values);
+ *values = 0;
+ return(TNG_CRITICAL);
+ }
+
+ *values = temp;
+
+ memcpy(*values, (char *)data->values + i * data_size, data_size);
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_non_particle_data_next_frame_read
+ (tng_trajectory_t tng_data,
+ const int64_t block_id,
+ void **values,
+ char *data_type,
+ int64_t *retrieved_frame_number,
+ double *retrieved_time)
+{
+ tng_trajectory_frame_set_t frame_set;
+ tng_non_particle_data_t data;
+ tng_function_status stat;
+ int size;
+ int64_t i, data_size;
+ void *temp;
+ long file_pos;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
+ TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
+ TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
+ TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ stat = tng_data_find(tng_data, block_id, &data);
+ if(stat != TNG_SUCCESS)
+ {
+ stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
+ file_pos = ftell(tng_data->input_file);
+ while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
+ {
+ stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
+ file_pos = ftell(tng_data->input_file);
+ }
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ stat = tng_data_find(tng_data, block_id, &data);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ }
+ if(data->last_retrieved_frame < 0)
+ {
+ fseek(tng_data->input_file,
+ (long)tng_data->first_trajectory_frame_set_input_file_pos,
+ SEEK_SET);
+ stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+
+ i = data->first_frame_with_data;
+ }
+ else
+ {
+ i = data->last_retrieved_frame + data->stride_length;
+ if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
+ {
+ stat = tng_frame_set_of_frame_find(tng_data, i);
+ if(stat != TNG_SUCCESS)
+ {
+ /* If the frame set search found the frame set after the starting
+ * frame set there is a gap in the frame sets. So, even if the frame
+ * was not found the next frame with data is still in the found
+ * frame set. */
+ if(stat == TNG_CRITICAL)
+ {
+ return(stat);
+ }
+ i = frame_set->first_frame;
+ }
+ }
+ if(data->last_retrieved_frame < frame_set->first_frame)
+ {
+ stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ }
+ }
+ data->last_retrieved_frame = i;
+ *retrieved_frame_number = i;
+ if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
+ {
+ *retrieved_time = frame_set->first_frame_time +
+ (i - frame_set->first_frame) *
+ tng_data->time_per_frame;
+ }
+ else
+ {
+ *retrieved_time = 0;
+ }
+
+ if(data->stride_length > 1)
+ {
+ i = (i - data->first_frame_with_data) / data->stride_length;
+ }
+ else
+ {
+ i = (i - frame_set->first_frame);
+ }
+
+ *data_type = data->datatype;
+
+ switch(*data_type)
+ {
+ case TNG_CHAR_DATA:
+ return(TNG_FAILURE);
+ case TNG_INT_DATA:
+ size = sizeof(int64_t);
+ break;
+ case TNG_FLOAT_DATA:
+ size = sizeof(float);
+ break;
+ case TNG_DOUBLE_DATA:
+ default:
+ size = sizeof(double);
+ }
+
+ data_size = size * data->n_values_per_frame;
+
+ temp = realloc(*values, data_size);
+ if(!temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ data_size, __FILE__, __LINE__);
+ free(*values);
+ *values = 0;
+ return(TNG_CRITICAL);
+ }
+
+ *values = temp;
+
+ memcpy(*values, (char *)data->values + i * data_size, data_size);
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_pos_read_range
+ (tng_trajectory_t tng_data,
+ const int64_t first_frame,
+ const int64_t last_frame,
+ float **positions,
+ int64_t *stride_length)
+{
+ int64_t n_particles, n_values_per_frame;
+ char type;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
+ TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
+ TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
+
+ stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
+ first_frame, last_frame,
+ TNG_USE_HASH,
+ (void **)positions,
+ &n_particles,
+ stride_length,
+ &n_values_per_frame,
+ &type);
+
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_vel_read_range
+ (tng_trajectory_t tng_data,
+ const int64_t first_frame,
+ const int64_t last_frame,
+ float **velocities,
+ int64_t *stride_length)
+{
+ int64_t n_particles, n_values_per_frame;
+ char type;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
+ TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
+ TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
+
+ stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
+ first_frame, last_frame,
+ TNG_USE_HASH,
+ (void **)velocities,
+ &n_particles,
+ stride_length,
+ &n_values_per_frame,
+ &type);
+
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_force_read_range
+ (tng_trajectory_t tng_data,
+ const int64_t first_frame,
+ const int64_t last_frame,
+ float **forces,
+ int64_t *stride_length)
+{
+ int64_t n_particles, n_values_per_frame;
+ char type;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
+ TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
+ TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
+
+ stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
+ first_frame, last_frame,
+ TNG_USE_HASH,
+ (void **)forces,
+ &n_particles,
+ stride_length,
+ &n_values_per_frame,
+ &type);
+
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read_range
+ (tng_trajectory_t tng_data,
+ const int64_t first_frame,
+ const int64_t last_frame,
+ float **box_shape,
+ int64_t *stride_length)
+{
+ int64_t n_values_per_frame;
+ char type;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
+ TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
+ TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
+
+ stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
+ first_frame, last_frame,
+ TNG_USE_HASH,
+ (void **)box_shape,
+ stride_length,
+ &n_values_per_frame,
+ &type);
+
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_set
+ (tng_trajectory_t tng_data,
+ const int64_t i,
+ const int64_t n_values_per_frame,
+ const int64_t block_id,
+ const char *block_name,
+ const char particle_dependency,
+ const char compression)
+{
+ tng_trajectory_frame_set_t frame_set;
+ tng_particle_data_t p_data;
+ tng_non_particle_data_t np_data;
+ int64_t n_particles, n_frames;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
+
+ if(i <= 0)
+ {
+ fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
+ i, __FILE__, __LINE__);
+ return(TNG_FAILURE);
+ }
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
+ {
+ n_frames = tng_data->frame_set_n_frames;
+
+ stat = tng_frame_set_new(tng_data, 0, n_frames);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot create frame set. %s: %d\n", __FILE__,
+ __LINE__);
+ return(stat);
+ }
+ }
+ else
+ {
+ n_frames = frame_set->n_frames;
+ }
+
+ if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
+ {
+ tng_num_particles_get(tng_data, &n_particles);
+ if(n_particles <= 0)
+ {
+ return(TNG_FAILURE);
+ }
+
+ if(tng_particle_data_find(tng_data, block_id, &p_data)
+ != TNG_SUCCESS)
+ {
+ stat = tng_particle_data_block_add(tng_data, block_id,
+ block_name,
+ TNG_FLOAT_DATA,
+ TNG_TRAJECTORY_BLOCK,
+ n_frames, n_values_per_frame, i,
+ 0, n_particles,
+ compression, 0);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ p_data = &frame_set->tr_particle_data[frame_set->
+ n_particle_data_blocks - 1];
+ stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
+ i, n_particles,
+ n_values_per_frame);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ }
+ else
+ {
+ if(p_data->stride_length != i)
+ {
+ p_data->stride_length = i;
+ stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
+ i, n_particles,
+ n_values_per_frame);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ }
+ }
+ }
+ else
+ {
+ if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
+ {
+ stat = tng_data_block_add(tng_data, block_id, block_name,
+ TNG_FLOAT_DATA, TNG_TRAJECTORY_BLOCK,
+ n_frames, n_values_per_frame,
+ i, compression, 0);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ np_data = &frame_set->tr_data[frame_set->
+ n_data_blocks - 1];
+ stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
+ i, n_values_per_frame);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ }
+ else
+ {
+ if(np_data->stride_length != i)
+ {
+ np_data->stride_length = i;
+ stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
+ i, n_values_per_frame);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ }
+ }
+ }
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_double_set
+ (tng_trajectory_t tng_data,
+ const int64_t i,
+ const int64_t n_values_per_frame,
+ const int64_t block_id,
+ const char *block_name,
+ const char particle_dependency,
+ const char compression)
+{
+ tng_trajectory_frame_set_t frame_set;
+ tng_particle_data_t p_data;
+ tng_non_particle_data_t np_data;
+ int64_t n_particles, n_frames;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
+
+ if(i <= 0)
+ {
+ fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
+ i, __FILE__, __LINE__);
+ return(TNG_FAILURE);
+ }
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
+ {
+ n_frames = tng_data->frame_set_n_frames;
+
+ stat = tng_frame_set_new(tng_data, 0, n_frames);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot create frame set. %s: %d\n", __FILE__,
+ __LINE__);
+ return(stat);
+ }
+ }
+ else
+ {
+ n_frames = frame_set->n_frames;
+ }
+
+ if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
+ {
+ tng_num_particles_get(tng_data, &n_particles);
+
+ if(n_particles <= 0)
+ {
+ return(TNG_FAILURE);
+ }
+
+ if(tng_particle_data_find(tng_data, block_id, &p_data)
+ != TNG_SUCCESS)
+ {
+ stat = tng_particle_data_block_add(tng_data, block_id,
+ block_name,
+ TNG_DOUBLE_DATA,
+ TNG_TRAJECTORY_BLOCK,
+ n_frames, n_values_per_frame, i,
+ 0, n_particles,
+ compression, 0);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ p_data = &frame_set->tr_particle_data[frame_set->
+ n_particle_data_blocks - 1];
+ stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
+ i, n_particles,
+ n_values_per_frame);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ }
+ else
+ {
+ p_data->stride_length = i;
+ }
+ }
+ else
+ {
+ if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
+ {
+ stat = tng_data_block_add(tng_data, block_id, block_name,
+ TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
+ n_frames, n_values_per_frame,
+ i, compression, 0);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ np_data = &frame_set->tr_data[frame_set->
+ n_data_blocks - 1];
+ stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
+ i, n_values_per_frame);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ }
+ else
+ {
+ np_data->stride_length = i;
+ }
+ }
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_frequency_set
+ (tng_trajectory_t tng_data,
+ const int64_t i,
+ const int64_t n_values_per_frame,
+ const int64_t block_id,
+ const char *block_name,
+ const char particle_dependency,
+ const char compression)
+{
+ fprintf(stderr, "TNG library: Using obsolete function tng_util_generic_write_frequency_set(). "
+ "See documentation. %s: %d", __FILE__, __LINE__);
+ return(tng_util_generic_write_interval_set(tng_data, i, n_values_per_frame,
+ block_id, block_name,
+ particle_dependency,
+ compression));
+}
+tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_set
+ (tng_trajectory_t tng_data,
+ const int64_t i)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
+
+ return(tng_util_generic_write_interval_set(tng_data, i, 3,
+ TNG_TRAJ_POSITIONS,
+ "POSITIONS",
+ TNG_PARTICLE_BLOCK_DATA,
+ TNG_TNG_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_double_set
+ (tng_trajectory_t tng_data,
+ const int64_t i)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
+
+ return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
+ TNG_TRAJ_POSITIONS,
+ "POSITIONS",
+ TNG_PARTICLE_BLOCK_DATA,
+ TNG_TNG_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_frequency_set
+ (tng_trajectory_t tng_data,
+ const int64_t i)
+{
+ fprintf(stderr, "TNG library: Using obsolete function tng_util_pos_write_frequency_set(). "
+ "See documentation. %s: %d", __FILE__, __LINE__);
+ return(tng_util_pos_write_interval_set(tng_data, i));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_set
+ (tng_trajectory_t tng_data,
+ const int64_t i)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
+
+ return(tng_util_generic_write_interval_set(tng_data, i, 3,
+ TNG_TRAJ_VELOCITIES,
+ "VELOCITIES",
+ TNG_PARTICLE_BLOCK_DATA,
+ TNG_TNG_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_double_set
+ (tng_trajectory_t tng_data,
+ const int64_t i)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
+
+ return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
+ TNG_TRAJ_VELOCITIES,
+ "VELOCITIES",
+ TNG_PARTICLE_BLOCK_DATA,
+ TNG_TNG_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_frequency_set
+ (tng_trajectory_t tng_data,
+ const int64_t i)
+{
+ fprintf(stderr, "TNG library: Using obsolete function tng_util_vel_write_frequency_set(). "
+ "See documentation. %s: %d", __FILE__, __LINE__);
+ return(tng_util_vel_write_interval_set(tng_data, i));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_set
+ (tng_trajectory_t tng_data,
+ const int64_t i)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
+
+ return(tng_util_generic_write_interval_set(tng_data, i, 3,
+ TNG_TRAJ_FORCES,
+ "FORCES",
+ TNG_PARTICLE_BLOCK_DATA,
+ TNG_GZIP_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_double_set
+ (tng_trajectory_t tng_data,
+ const int64_t i)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
+
+ return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
+ TNG_TRAJ_FORCES,
+ "FORCES",
+ TNG_PARTICLE_BLOCK_DATA,
+ TNG_GZIP_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_force_write_frequency_set
+ (tng_trajectory_t tng_data,
+ const int64_t i)
+{
+ fprintf(stderr, "TNG library: Using obsolete function tng_util_force_write_frequency_set(). "
+ "See documentation. %s: %d", __FILE__, __LINE__);
+ return(tng_util_force_write_interval_set(tng_data, i));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_set
+ (tng_trajectory_t tng_data,
+ const int64_t i)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
+
+ return(tng_util_generic_write_interval_set(tng_data, i, 9,
+ TNG_TRAJ_BOX_SHAPE,
+ "BOX SHAPE",
+ TNG_NON_PARTICLE_BLOCK_DATA,
+ TNG_GZIP_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_double_set
+ (tng_trajectory_t tng_data,
+ const int64_t i)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
+
+ return(tng_util_generic_write_interval_double_set(tng_data, i, 9,
+ TNG_TRAJ_BOX_SHAPE,
+ "BOX SHAPE",
+ TNG_NON_PARTICLE_BLOCK_DATA,
+ TNG_GZIP_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_frequency_set
+ (tng_trajectory_t tng_data,
+ const int64_t i)
+{
+ fprintf(stderr, "TNG library: Using obsolete function tng_util_box_shape_write_frequency_set(). "
+ "See documentation. %s: %d", __FILE__, __LINE__);
+ return(tng_util_box_shape_write_interval_set(tng_data, i));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_generic_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const float *values,
+ const int64_t n_values_per_frame,
+ const int64_t block_id,
+ const char *block_name,
+ const char particle_dependency,
+ const char compression)
+{
+ tng_trajectory_frame_set_t frame_set;
+ tng_particle_data_t p_data;
+ tng_non_particle_data_t np_data;
+ int64_t n_particles, n_frames, stride_length = 100, frame_pos;
+ int64_t last_frame;
+ int is_first_frame_flag = 0;
+ char block_type_flag;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
+ TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
+
+ if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
+ {
+ tng_num_particles_get(tng_data, &n_particles);
+ TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
+ }
+
+ if(values == 0)
+ {
+ return(TNG_FAILURE);
+ }
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ if(frame_nr < 0)
+ {
+ block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
+ n_frames = stride_length = 1;
+ }
+ else
+ {
+ block_type_flag = TNG_TRAJECTORY_BLOCK;
+
+ if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
+ {
+ stat = tng_frame_set_new(tng_data, 0, tng_data->frame_set_n_frames);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot create frame set. %s: %d\n", __FILE__,
+ __LINE__);
+ return(stat);
+ }
+ }
+ last_frame = frame_set->first_frame +
+ frame_set->n_frames - 1;
+ if(frame_nr > last_frame)
+ {
+ stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot write frame set. %s: %d\n", __FILE__,
+ __LINE__);
+ return(stat);
+ }
+ if(last_frame + tng_data->frame_set_n_frames < frame_nr)
+ {
+ last_frame = frame_nr - 1;
+ }
+ stat = tng_frame_set_new(tng_data, last_frame + 1,
+ tng_data->frame_set_n_frames);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot create frame set. %s: %d\n", __FILE__,
+ __LINE__);
+ return(stat);
+ }
+ }
+ if(frame_set->n_unwritten_frames == 0)
+ {
+ is_first_frame_flag = 1;
+ }
+ frame_set->n_unwritten_frames = frame_nr -
+ frame_set->first_frame + 1;
+
+ n_frames = frame_set->n_frames;
+ }
+
+ if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
+ {
+ if(tng_particle_data_find(tng_data, block_id, &p_data)
+ != TNG_SUCCESS)
+ {
+ stat = tng_particle_data_block_add(tng_data, block_id,
+ block_name,
+ TNG_FLOAT_DATA,
+ block_type_flag,
+ n_frames, n_values_per_frame,
+ stride_length,
+ 0, n_particles,
+ compression, 0);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK)
+ {
+ p_data = &frame_set->tr_particle_data[frame_set->
+ n_particle_data_blocks - 1];
+ }
+ else
+ {
+ p_data = &tng_data->non_tr_particle_data[tng_data->
+ n_particle_data_blocks - 1];
+ }
+ stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
+ stride_length, n_particles,
+ n_values_per_frame);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ }
+
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK)
+ {
+ stride_length = p_data->stride_length;
+
+ if(is_first_frame_flag || p_data->first_frame_with_data < frame_set->first_frame)
+ {
+ p_data->first_frame_with_data = frame_nr;
+ frame_pos = 0;
+ }
+ else
+ {
+ frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
+ }
+
+ memcpy((char *)p_data->values + sizeof(float) * frame_pos * n_particles *
+ n_values_per_frame, values, sizeof(float) *
+ n_particles * n_values_per_frame);
+ }
+ else
+ {
+ memcpy(p_data->values, values, sizeof(float) * n_particles *
+ n_values_per_frame);
+ }
+ }
+ else
+ {
+ if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
+ {
+ stat = tng_data_block_add(tng_data, block_id, block_name,
+ TNG_FLOAT_DATA, block_type_flag,
+ n_frames, n_values_per_frame,
+ stride_length, compression, 0);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK)
+ {
+ np_data = &frame_set->tr_data[frame_set->
+ n_data_blocks - 1];
+ }
+ else
+ {
+ np_data = &tng_data->non_tr_data[tng_data->
+ n_data_blocks - 1];
+ }
+ stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
+ stride_length, n_values_per_frame);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ }
+
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK)
+ {
+ stride_length = np_data->stride_length;
+
+ if(is_first_frame_flag || np_data->first_frame_with_data < frame_set->first_frame)
+ {
+ np_data->first_frame_with_data = frame_nr;
+ frame_pos = 0;
+ }
+ else
+ {
+ frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
+ }
+
+ memcpy((char *)np_data->values + sizeof(float) * frame_pos *
+ n_values_per_frame, values, sizeof(float) *
+ n_values_per_frame);
+ }
+ else
+ {
+ memcpy(np_data->values, values, sizeof(float) * n_values_per_frame);
+ }
+ }
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_generic_double_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double *values,
+ const int64_t n_values_per_frame,
+ const int64_t block_id,
+ const char *block_name,
+ const char particle_dependency,
+ const char compression)
+{
+ tng_trajectory_frame_set_t frame_set;
+ tng_particle_data_t p_data;
+ tng_non_particle_data_t np_data;
+ int64_t n_particles, n_frames, stride_length = 100, frame_pos;
+ int64_t last_frame;
+ int is_first_frame_flag = 0;
+ char block_type_flag;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
+ TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
+
+ if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
+ {
+ tng_num_particles_get(tng_data, &n_particles);
+ TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
+ }
+
+ if(values == 0)
+ {
+ return(TNG_FAILURE);
+ }
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ if(frame_nr < 0)
+ {
+ block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
+ n_frames = stride_length = 1;
+ }
+ else
+ {
+ block_type_flag = TNG_TRAJECTORY_BLOCK;
+
+ n_frames = tng_data->frame_set_n_frames;
+
+ if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
+ {
+ stat = tng_frame_set_new(tng_data, 0, n_frames);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot create frame set. %s: %d\n", __FILE__,
+ __LINE__);
+ return(stat);
+ }
+ }
+ else
+ {
+ n_frames = frame_set->n_frames;
+ }
+ last_frame = frame_set->first_frame +
+ frame_set->n_frames - 1;
+ if(frame_nr > last_frame)
+ {
+ stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot write frame set. %s: %d\n", __FILE__,
+ __LINE__);
+ return(stat);
+ }
+ if(last_frame + tng_data->frame_set_n_frames < frame_nr)
+ {
+ last_frame = frame_nr - 1;
+ }
+ stat = tng_frame_set_new(tng_data, last_frame + 1, n_frames);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot create frame set. %s: %d\n", __FILE__,
+ __LINE__);
+ return(stat);
+ }
+ }
+ if(frame_set->n_unwritten_frames == 0)
+ {
+ is_first_frame_flag = 1;
+ }
+ frame_set->n_unwritten_frames = frame_nr -
+ frame_set->first_frame + 1;
+ }
+
+ if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
+ {
+ if(tng_particle_data_find(tng_data, block_id, &p_data)
+ != TNG_SUCCESS)
+ {
+ stat = tng_particle_data_block_add(tng_data, block_id,
+ block_name,
+ TNG_DOUBLE_DATA,
+ block_type_flag,
+ n_frames, n_values_per_frame,
+ stride_length,
+ 0, n_particles,
+ compression, 0);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK)
+ {
+ p_data = &frame_set->tr_particle_data[frame_set->
+ n_particle_data_blocks - 1];
+ }
+ else
+ {
+ p_data = &tng_data->non_tr_particle_data[tng_data->
+ n_particle_data_blocks - 1];
+ }
+ stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
+ stride_length, n_particles,
+ n_values_per_frame);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ }
+
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK)
+ {
+ stride_length = p_data->stride_length;
+
+ if(is_first_frame_flag)
+ {
+ p_data->first_frame_with_data = frame_nr;
+ frame_pos = 0;
+ }
+ else
+ {
+ frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
+ }
+
+ memcpy((char *)p_data->values + sizeof(double) * frame_pos * n_particles *
+ n_values_per_frame, values, sizeof(double) *
+ n_particles * n_values_per_frame);
+ }
+ else
+ {
+ memcpy(p_data->values, values, sizeof(double) * n_particles *
+ n_values_per_frame);
+ }
+ }
+ else
+ {
+ if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
+ {
+ stat = tng_data_block_add(tng_data, block_id, block_name,
+ TNG_DOUBLE_DATA, block_type_flag,
+ n_frames, n_values_per_frame,
+ stride_length, compression, 0);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK)
+ {
+ np_data = &frame_set->tr_data[frame_set->
+ n_data_blocks - 1];
+ }
+ else
+ {
+ np_data = &tng_data->non_tr_data[tng_data->
+ n_data_blocks - 1];
+ }
+ stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
+ stride_length, n_values_per_frame);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ }
+
+ if(block_type_flag == TNG_TRAJECTORY_BLOCK)
+ {
+ stride_length = np_data->stride_length;
+
+ if(is_first_frame_flag)
+ {
+ np_data->first_frame_with_data = frame_nr;
+ frame_pos = 0;
+ }
+ else
+ {
+ frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
+ }
+
+ memcpy((char *)np_data->values + sizeof(double) * frame_pos *
+ n_values_per_frame, values, sizeof(double) *
+ n_values_per_frame);
+ }
+ else
+ {
+ memcpy(np_data->values, values, sizeof(double) * n_values_per_frame);
+ }
+ }
+
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_pos_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const float *positions)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
+ TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
+
+ return(tng_util_generic_write(tng_data, frame_nr, positions, 3,
+ TNG_TRAJ_POSITIONS, "POSITIONS",
+ TNG_PARTICLE_BLOCK_DATA,
+ TNG_TNG_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_pos_double_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double *positions)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
+ TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
+
+ return(tng_util_generic_double_write(tng_data, frame_nr, positions, 3,
+ TNG_TRAJ_POSITIONS, "POSITIONS",
+ TNG_PARTICLE_BLOCK_DATA,
+ TNG_TNG_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_vel_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const float *velocities)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
+ TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
+
+ return(tng_util_generic_write(tng_data, frame_nr, velocities, 3,
+ TNG_TRAJ_VELOCITIES, "VELOCITIES",
+ TNG_PARTICLE_BLOCK_DATA,
+ TNG_TNG_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_vel_double_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double *velocities)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
+ TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
+
+ return(tng_util_generic_double_write(tng_data, frame_nr, velocities, 3,
+ TNG_TRAJ_VELOCITIES, "VELOCITIES",
+ TNG_PARTICLE_BLOCK_DATA,
+ TNG_TNG_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_force_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const float *forces)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
+ TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
+
+ return(tng_util_generic_write(tng_data, frame_nr, forces, 3,
+ TNG_TRAJ_FORCES, "FORCES",
+ TNG_PARTICLE_BLOCK_DATA,
+ TNG_GZIP_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_force_double_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double *forces)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
+ TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
+
+ return(tng_util_generic_double_write(tng_data, frame_nr, forces, 3,
+ TNG_TRAJ_FORCES, "FORCES",
+ TNG_PARTICLE_BLOCK_DATA,
+ TNG_GZIP_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const float *box_shape)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
+ TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
+
+ return(tng_util_generic_write(tng_data, frame_nr, box_shape, 9,
+ TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
+ TNG_NON_PARTICLE_BLOCK_DATA,
+ TNG_GZIP_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_double_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double *box_shape)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
+ TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
+
+ return(tng_util_generic_double_write(tng_data, frame_nr, box_shape, 9,
+ TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
+ TNG_NON_PARTICLE_BLOCK_DATA,
+ TNG_GZIP_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double time,
+ const float *values,
+ const int64_t n_values_per_frame,
+ const int64_t block_id,
+ const char *block_name,
+ const char particle_dependency,
+ const char compression)
+{
+ tng_trajectory_frame_set_t frame_set;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
+ TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
+ TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
+
+ stat = tng_util_generic_write(tng_data, frame_nr, values, n_values_per_frame,
+ block_id, block_name,
+ particle_dependency,
+ compression);
+
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ /* first_frame_time is -1 when it is not yet set. */
+ if(frame_set->first_frame_time < -0.1)
+ {
+ if(frame_nr > frame_set->first_frame)
+ {
+ stat = tng_frame_set_first_frame_time_set(tng_data,
+ time -
+ (frame_nr -
+ frame_set->first_frame) *
+ tng_data->time_per_frame);
+ }
+ else
+ {
+ stat = tng_frame_set_first_frame_time_set(tng_data, time);
+ }
+ }
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_double_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double time,
+ const double *values,
+ const int64_t n_values_per_frame,
+ const int64_t block_id,
+ const char *block_name,
+ const char particle_dependency,
+ const char compression)
+{
+ tng_trajectory_frame_set_t frame_set;
+ tng_function_status stat;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
+ TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
+ TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
+
+ stat = tng_util_generic_double_write(tng_data, frame_nr, values, n_values_per_frame,
+ block_id, block_name,
+ particle_dependency,
+ compression);
+
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ /* first_frame_time is -1 when it is not yet set. */
+ if(frame_set->first_frame_time < -0.1)
+ {
+ if(frame_nr > frame_set->first_frame)
+ {
+ stat = tng_frame_set_first_frame_time_set(tng_data,
+ time -
+ (frame_nr -
+ frame_set->first_frame) *
+ tng_data->time_per_frame);
+ }
+ else
+ {
+ stat = tng_frame_set_first_frame_time_set(tng_data, time);
+ }
+ }
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double time,
+ const float *positions)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
+ TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
+ TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
+
+ return(tng_util_generic_with_time_write(tng_data, frame_nr, time, positions,
+ 3, TNG_TRAJ_POSITIONS, "POSITIONS",
+ TNG_PARTICLE_BLOCK_DATA,
+ TNG_TNG_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_double_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double time,
+ const double *positions)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
+ TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
+ TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
+
+ return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
+ positions, 3,
+ TNG_TRAJ_POSITIONS,
+ "POSITIONS",
+ TNG_PARTICLE_BLOCK_DATA,
+ TNG_TNG_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double time,
+ const float *velocities)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
+ TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
+ TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
+
+ return(tng_util_generic_with_time_write(tng_data, frame_nr, time,
+ velocities, 3,
+ TNG_TRAJ_VELOCITIES,
+ "VELOCITIES",
+ TNG_PARTICLE_BLOCK_DATA,
+ TNG_TNG_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_double_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double time,
+ const double *velocities)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
+ TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
+ TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
+
+ return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
+ velocities, 3,
+ TNG_TRAJ_VELOCITIES,
+ "VELOCITIES",
+ TNG_PARTICLE_BLOCK_DATA,
+ TNG_TNG_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double time,
+ const float *forces)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
+ TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
+ TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
+
+ return(tng_util_generic_with_time_write(tng_data, frame_nr, time, forces,
+ 3, TNG_TRAJ_FORCES, "FORCES",
+ TNG_PARTICLE_BLOCK_DATA,
+ TNG_GZIP_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_double_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double time,
+ const double *forces)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
+ TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
+ TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
+
+ return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
+ forces, 3,
+ TNG_TRAJ_FORCES, "FORCES",
+ TNG_PARTICLE_BLOCK_DATA,
+ TNG_GZIP_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double time,
+ const float *box_shape)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
+ TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
+ TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
+
+ return(tng_util_generic_with_time_write(tng_data, frame_nr, time, box_shape,
+ 9, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
+ TNG_NON_PARTICLE_BLOCK_DATA,
+ TNG_GZIP_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_double_write
+ (tng_trajectory_t tng_data,
+ const int64_t frame_nr,
+ const double time,
+ const double *box_shape)
+{
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
+ TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
+ TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
+
+ return(tng_util_generic_with_time_double_write(tng_data, frame_nr,
+ time, box_shape, 9,
+ TNG_TRAJ_BOX_SHAPE,
+ "BOX SHAPE",
+ TNG_NON_PARTICLE_BLOCK_DATA,
+ TNG_GZIP_COMPRESSION));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_frame_current_compression_get
+ (tng_trajectory_t tng_data,
+ const int64_t block_id,
+ char *codec_id,
+ float *factor)
+{
+ tng_trajectory_frame_set_t frame_set;
+ tng_particle_data_t p_data;
+ tng_non_particle_data_t np_data;
+ tng_function_status stat;
+ int64_t i;
+ int block_type = -1;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(codec_id, "TNG library: The pointer to the returned codec id must not be a NULL pointer.");
+ TNG_ASSERT(factor, "TNG library: The pointer to the returned multiplication factor must not be a NULL pointer.");
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ stat = tng_particle_data_find(tng_data, block_id, &p_data);
+ if(stat == TNG_SUCCESS)
+ {
+ block_type = TNG_PARTICLE_BLOCK_DATA;
+ }
+ else
+ {
+ stat = tng_data_find(tng_data, block_id, &np_data);
+ if(stat == TNG_SUCCESS)
+ {
+ block_type = TNG_NON_PARTICLE_BLOCK_DATA;
+ }
+ else
+ {
+ stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ stat = tng_particle_data_find(tng_data, block_id, &p_data);
+ if(stat == TNG_SUCCESS)
+ {
+ block_type = TNG_PARTICLE_BLOCK_DATA;
+ }
+ else
+ {
+ stat = tng_data_find(tng_data, block_id, &np_data);
+ if(stat == TNG_SUCCESS)
+ {
+ block_type = TNG_NON_PARTICLE_BLOCK_DATA;
+ }
+ else
+ {
+ return(stat);
+ }
+ }
+ }
+ }
+ if(block_type == TNG_PARTICLE_BLOCK_DATA)
+ {
+ if(p_data->last_retrieved_frame < 0)
+ {
+ i = p_data->first_frame_with_data;
+ }
+ else
+ {
+ i = p_data->last_retrieved_frame;
+ }
+ }
+ else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
+ {
+ if(np_data->last_retrieved_frame < 0)
+ {
+ i = np_data->first_frame_with_data;
+ }
+ else
+ {
+ i = np_data->last_retrieved_frame;
+ }
+ }
+ else
+ {
+ return(TNG_FAILURE);
+ }
+ if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
+ {
+ stat = tng_frame_set_of_frame_find(tng_data, i);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
+ if(stat != TNG_SUCCESS)
+ {
+ fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ }
+ if(block_type == TNG_PARTICLE_BLOCK_DATA)
+ {
+ *codec_id = p_data->codec_id;
+ *factor = p_data->compression_multiplier;
+ }
+ else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
+ {
+ *codec_id = np_data->codec_id;
+ *factor = np_data->compression_multiplier;
+ }
+ return(TNG_SUCCESS);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_next_frame_present_data_blocks_find
+ (tng_trajectory_t tng_data,
+ int64_t current_frame,
+ const int64_t n_requested_data_block_ids,
+ const int64_t *requested_data_block_ids,
+ int64_t *next_frame,
+ int64_t *n_data_blocks_in_next_frame,
+ int64_t **data_block_ids_in_next_frame)
+{
+ tng_trajectory_frame_set_t frame_set;
+ tng_function_status stat;
+ tng_particle_data_t p_data;
+ tng_non_particle_data_t np_data;
+ tng_gen_block_t block;
+ int64_t i, j, block_id, *temp;
+ int64_t data_frame, frame_diff, min_diff;
+ int64_t size, frame_set_file_pos;
+ int found, read_all = 0;
+ long file_pos;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(next_frame, "TNG library: The pointer to the next frame must not be NULL.");
+ TNG_ASSERT(n_data_blocks_in_next_frame, "TNG library: The pointer to n_data_blocks_in_next_frame must not be NULL.");
+ TNG_ASSERT(data_block_ids_in_next_frame, "TNG library: The pointer to the list of data block IDs must not be NULL.");
+
+ if(n_requested_data_block_ids)
+ {
+ TNG_ASSERT(requested_data_block_ids, "TNG library: If the number of requested data blocks is > 0 then the array of data block IDs must not be NULL.");
+ size = sizeof(int64_t) * n_requested_data_block_ids;
+ temp = realloc(*data_block_ids_in_next_frame, size);
+ if(!temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(int64_t) * (*n_data_blocks_in_next_frame),
+ __FILE__, __LINE__);
+ free(*data_block_ids_in_next_frame);
+ *data_block_ids_in_next_frame = 0;
+ return(TNG_CRITICAL);
+ }
+ *data_block_ids_in_next_frame = temp;
+ }
+
+ frame_set = &tng_data->current_trajectory_frame_set;
+
+ current_frame += 1;
+
+ if(current_frame < frame_set->first_frame ||
+ current_frame >= frame_set->first_frame + frame_set->n_frames)
+ {
+ frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
+ stat = tng_frame_set_of_frame_find(tng_data, current_frame);
+ if(stat != TNG_SUCCESS)
+ {
+ /* If the frame set search found the frame set after the starting
+ * frame set there is a gap in the frame sets. So, even if the frame
+ * was not found the next frame with data is still in the found
+ * frame set. */
+ if(stat == TNG_CRITICAL || frame_set->prev_frame_set_file_pos !=
+ frame_set_file_pos)
+ {
+ return(stat);
+ }
+ current_frame = frame_set->first_frame;
+ }
+ }
+
+ if(frame_set->n_particle_data_blocks <= 0 || frame_set->n_data_blocks <= 0)
+ {
+ tng_block_init(&block);
+ file_pos = ftell(tng_data->input_file);
+ /* Read all blocks until next frame set block */
+ stat = tng_block_header_read(tng_data, block);
+ while(file_pos < tng_data->input_file_len &&
+ stat != TNG_CRITICAL &&
+ block->id != TNG_TRAJECTORY_FRAME_SET)
+ {
+ stat = tng_block_read_next(tng_data, block,
+ TNG_USE_HASH);
+ if(stat != TNG_CRITICAL)
+ {
+ file_pos = ftell(tng_data->input_file);
+ if(file_pos < tng_data->input_file_len)
+ {
+ stat = tng_block_header_read(tng_data, block);
+ }
+ }
+ }
+ tng_block_destroy(&block);
+ if(stat == TNG_CRITICAL)
+ {
+ fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
+ file_pos, __FILE__, __LINE__);
+ return(stat);
+ }
+ read_all = 1;
+ }
+
+ min_diff = -1;
+
+ *n_data_blocks_in_next_frame = 0;
+
+ for(i = 0; i < frame_set->n_particle_data_blocks; i++)
+ {
+ p_data = &frame_set->tr_particle_data[i];
+ block_id = p_data->block_id;
+
+ if(n_requested_data_block_ids > 0)
+ {
+ found = 0;
+ for(j = 0; j < n_requested_data_block_ids; j++)
+ {
+ if(block_id == requested_data_block_ids[j])
+ {
+ found = 1;
+ break;
+ }
+ }
+ if(!found)
+ {
+ continue;
+ }
+ }
+
+ if(!read_all && (p_data->last_retrieved_frame < frame_set->first_frame ||
+ p_data->last_retrieved_frame >=
+ frame_set->first_frame + frame_set->n_frames))
+ {
+ stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
+ TNG_USE_HASH, block_id);
+ if(stat == TNG_CRITICAL)
+ {
+ fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ if(stat == TNG_FAILURE)
+ {
+ continue;
+ }
+ }
+ if(frame_set->first_frame != current_frame &&
+ p_data->last_retrieved_frame >= 0)
+ {
+ data_frame = p_data->last_retrieved_frame + p_data->stride_length;
+ }
+ else
+ {
+ data_frame = p_data->first_frame_with_data;
+ }
+ frame_diff = data_frame - current_frame;
+ if(frame_diff < 0)
+ {
+ continue;
+ }
+ if(min_diff == -1 || frame_diff <= min_diff)
+ {
+ if(frame_diff < min_diff)
+ {
+ *n_data_blocks_in_next_frame = 1;
+ }
+ else
+ {
+ *n_data_blocks_in_next_frame += 1;
+ }
+ if(n_requested_data_block_ids <= 0)
+ {
+ size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
+ temp = realloc(*data_block_ids_in_next_frame, size);
+ if(!temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(int64_t) * (*n_data_blocks_in_next_frame),
+ __FILE__, __LINE__);
+ free(*data_block_ids_in_next_frame);
+ *data_block_ids_in_next_frame = 0;
+ return(TNG_CRITICAL);
+ }
+ *data_block_ids_in_next_frame = temp;
+ }
+ else
+ {
+ TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
+ }
+ (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
+
+ min_diff = frame_diff;
+ }
+ }
+ for(i = 0; i < frame_set->n_data_blocks; i++)
+ {
+ np_data = &frame_set->tr_data[i];
+ block_id = np_data->block_id;
+
+ if(n_requested_data_block_ids > 0)
+ {
+ found = 0;
+ for(j = 0; j < n_requested_data_block_ids; j++)
+ {
+ if(block_id == requested_data_block_ids[j])
+ {
+ found = 1;
+ break;
+ }
+ }
+ if(!found)
+ {
+ continue;
+ }
+ }
+
+ if(!read_all && (np_data->last_retrieved_frame < frame_set->first_frame ||
+ np_data->last_retrieved_frame >=
+ frame_set->first_frame + frame_set->n_frames))
+ {
+ stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
+ TNG_USE_HASH, block_id);
+ if(stat == TNG_CRITICAL)
+ {
+ fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
+ __FILE__, __LINE__);
+ return(stat);
+ }
+ if(stat == TNG_FAILURE)
+ {
+ continue;
+ }
+ }
+ if(frame_set->first_frame != current_frame &&
+ np_data->last_retrieved_frame >= 0)
+ {
+ data_frame = np_data->last_retrieved_frame + np_data->stride_length;
+ }
+ else
+ {
+ data_frame = np_data->first_frame_with_data;
+ }
+ frame_diff = data_frame - current_frame;
+ if(frame_diff < 0)
+ {
+ continue;
+ }
+ if(min_diff == -1 || frame_diff <= min_diff)
+ {
+ if(frame_diff < min_diff)
+ {
+ *n_data_blocks_in_next_frame = 1;
+ }
+ else
+ {
+ *n_data_blocks_in_next_frame += 1;
+ }
+ if(n_requested_data_block_ids <= 0)
+ {
+ size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
+ temp = realloc(*data_block_ids_in_next_frame, size);
+ if(!temp)
+ {
+ fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
+ sizeof(int64_t) * (*n_data_blocks_in_next_frame),
+ __FILE__, __LINE__);
+ free(*data_block_ids_in_next_frame);
+ *data_block_ids_in_next_frame = 0;
+ return(TNG_CRITICAL);
+ }
+ *data_block_ids_in_next_frame = temp;
+ }
+ else
+ {
+ TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
+ }
+ (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
+
+ min_diff = frame_diff;
+ }
+ }
+ if(min_diff < 0)
+ {
+ return(TNG_FAILURE);
+ }
+ *next_frame = current_frame + min_diff;
+
+ return(TNG_SUCCESS);
+}
+
+/*
+tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_all_data_block_types_get
+ (tng_trajectory_t tng_data,
+ int64_t *n_data_blocks,
+ int64_t **data_block_ids,
+ char ***data_block_names,
+ int64_t **stride_lengths,
+ int64_t **n_values_per_frame,
+ char **block_types,
+ char **dependencies,
+ char **compressions)
+{
+ tng_gen_block_t block;
+ long orig_file_pos, file_pos;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(n_data_blocks, "TNG library: The pointer to n_data_blocks must not be NULL.");
+ TNG_ASSERT(data_block_ids, "TNG library: The pointer to the list of data block IDs must not be NULL.");
+ TNG_ASSERT(data_block_names, "TNG library: The pointer to the list of data block names must not be NULL.");
+ TNG_ASSERT(stride_lengths, "TNG library: The pointer to the list of stride lengths must not be NULL.");
+
+ orig_file_pos = ftell(tng_data->input_file);
+
+ if(!tng_data->input_file_len)
+ {
+ fseek(tng_data->input_file, 0, SEEK_END);
+ tng_data->input_file_len = ftell(tng_data->input_file);
+ }
+
+ fseek(tng_data->input_file, 0, SEEK_SET);
+ file_pos = 0;
+
+ *n_data_blocks = 0;
+
+ tng_block_init(&block);
+
+ while(file_pos < tng_data->input_file_len &&
+ tng_block_header_read(tng_data, block) != TNG_CRITICAL)
+ {
+ if(block->id > TNG_TRAJECTORY_FRAME_SET)
+ {
+
+ }
+ file_pos += (long)(block->block_contents_size + block->header_contents_size);
+ fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
+ }
+
+ fseek(tng_data->input_file, orig_file_pos, SEEK_SET);
+
+ return(TNG_SUCCESS);
+}
+*/
+tng_function_status DECLSPECDLLEXPORT tng_util_prepare_append_after_frame
+ (tng_trajectory_t tng_data,
+ const int64_t prev_frame)
+{
+ tng_function_status stat;
+ FILE *temp = tng_data->input_file;
+
+ TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
+ TNG_ASSERT(prev_frame >= 0, "TNG library: The previous frame must not be negative.");
+
+ tng_data->input_file = tng_data->output_file;
+
+ stat = tng_frame_set_of_frame_find(tng_data, prev_frame);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+
+ tng_data->current_trajectory_frame_set_output_file_pos =
+ tng_data->current_trajectory_frame_set_input_file_pos;
+
+ tng_data->input_file = temp;
+
+ return(TNG_SUCCESS);
+}
--- /dev/null
+/* This code is part of the tng binary trajectory format.
+ *
+ * VERSION 1.4
+ *
+ * Written by Magnus Lundborg
+ * Copyright (c) 2012-2013, The GROMACS development team.
+ * Check out http://www.gromacs.org for more information.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+#include "../../include/tng_io.h"
+
+/* The following is for calling the library from fortran */
+
+tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_(tng_trajectory_t *tng_data_p)
+{
+ return(tng_trajectory_init(tng_data_p));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy_(tng_trajectory_t *tng_data_p)
+{
+ return(tng_trajectory_destroy(tng_data_p));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_from_src_(tng_trajectory_t src,
+ tng_trajectory_t *dest_p)
+{
+ return(tng_trajectory_init_from_src(src, dest_p));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_input_file_get_(const tng_trajectory_t tng_data,
+ char *file_name, const int max_len)
+{
+ return(tng_input_file_get(tng_data, file_name, max_len));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_input_file_set_(tng_trajectory_t tng_data,
+ const char *file_name, int name_len)
+{
+ char *name = malloc(name_len + 1);
+ tng_function_status stat;
+
+ strncpy(name, file_name, name_len);
+ name[name_len] = 0;
+ stat = tng_input_file_set(tng_data, name);
+ free(name);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_output_file_get_(const tng_trajectory_t tng_data,
+ char *file_name, const int max_len)
+{
+ return(tng_output_file_get(tng_data, file_name, max_len));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_output_file_set_(tng_trajectory_t tng_data,
+ const char *file_name, int name_len)
+{
+ char *name = malloc(name_len + 1);
+ tng_function_status stat;
+
+ strncpy(name, file_name, name_len);
+ name[name_len] = 0;
+ stat = tng_output_file_set(tng_data, name);
+ free(name);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_first_program_name_get_(const tng_trajectory_t tng_data,
+ char *name, const int max_len)
+{
+ return(tng_first_program_name_get(tng_data, name, max_len));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_get_
+ (tng_trajectory_t tng_data, tng_file_endianness *endianness)
+{
+ return(tng_output_file_endianness_get(tng_data, endianness));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_set_
+ (tng_trajectory_t tng_data, const tng_file_endianness *endianness)
+{
+ return(tng_output_file_endianness_set(tng_data, *endianness));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_first_program_name_set_(tng_trajectory_t tng_data,
+ const char *new_name,
+ int name_len)
+{
+ char *name = malloc(name_len + 1);
+ tng_function_status stat;
+
+ strncpy(name, new_name, name_len);
+ name[name_len] = 0;
+ stat = tng_first_program_name_set(tng_data, name);
+ free(name);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_last_program_name_get_(const tng_trajectory_t tng_data,
+ char *name, const int max_len)
+{
+ return(tng_last_program_name_get(tng_data, name, max_len));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_last_program_name_set_(tng_trajectory_t tng_data,
+ const char *new_name,
+ int name_len)
+{
+ char *name = malloc(name_len + 1);
+ tng_function_status stat;
+
+ strncpy(name, new_name, name_len);
+ name[name_len] = 0;
+ stat = tng_last_program_name_set(tng_data, name);
+ free(name);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_first_user_name_get_(const tng_trajectory_t tng_data,
+ char *name, const int max_len)
+{
+ return(tng_first_user_name_get(tng_data, name, max_len));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_first_user_name_set_(tng_trajectory_t tng_data,
+ const char *new_name,
+ int name_len)
+{
+ char *name = malloc(name_len + 1);
+ tng_function_status stat;
+
+ strncpy(name, new_name, name_len);
+ name[name_len] = 0;
+ stat = tng_first_user_name_set(tng_data, name);
+ free(name);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_last_user_name_get_(const tng_trajectory_t tng_data,
+ char *name, const int max_len)
+{
+ return(tng_last_user_name_get(tng_data, name, max_len));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_last_user_name_set_(tng_trajectory_t tng_data,
+ const char *new_name,
+ int name_len)
+{
+ char *name = malloc(name_len + 1);
+ tng_function_status stat;
+
+ strncpy(name, new_name, name_len);
+ name[name_len] = 0;
+ stat = tng_last_user_name_set(tng_data, name);
+ free(name);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_get_(const tng_trajectory_t tng_data,
+ char *name, const int max_len)
+{
+ return(tng_first_computer_name_get(tng_data, name, max_len));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_set_(tng_trajectory_t tng_data,
+ const char *new_name,
+ int name_len)
+{
+ char *name = malloc(name_len + 1);
+ tng_function_status stat;
+
+ strncpy(name, new_name, name_len);
+ name[name_len] = 0;
+ stat = tng_first_computer_name_set(tng_data, name);
+ free(name);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_get_(const tng_trajectory_t tng_data,
+ char *name, const int max_len)
+{
+ return(tng_last_computer_name_get(tng_data, name, max_len));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_set_(tng_trajectory_t tng_data,
+ const char *new_name,
+ int name_len)
+{
+ char *name = malloc(name_len + 1);
+ tng_function_status stat;
+
+ strncpy(name, new_name, name_len);
+ name[name_len] = 0;
+ stat = tng_last_computer_name_set(tng_data, name);
+ free(name);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_first_signature_get_
+ (const tng_trajectory_t tng_data,
+ char *signature, const int max_len)
+{
+ return(tng_first_signature_get(tng_data, signature, max_len));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_first_signature_set_(tng_trajectory_t tng_data,
+ const char *signature,
+ int sign_len)
+{
+ char *sign = malloc(sign_len + 1);
+ tng_function_status stat;
+
+ strncpy(sign, signature, sign_len);
+ sign[sign_len] = 0;
+ stat = tng_first_signature_set(tng_data, sign);
+ free(sign);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_last_signature_get_
+ (const tng_trajectory_t tng_data,
+ char *signature, const int max_len)
+{
+ return(tng_last_signature_get(tng_data, signature, max_len));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_last_signature_set_
+ (tng_trajectory_t tng_data,
+ const char *signature,
+ int sign_len)
+{
+ char *sign = malloc(sign_len + 1);
+ tng_function_status stat;
+
+ strncpy(sign, signature, sign_len);
+ sign[sign_len] = 0;
+ stat = tng_last_signature_set(tng_data, sign);
+ free(sign);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_get_
+ (const tng_trajectory_t tng_data,
+ char *name, const int max_len)
+{
+ return(tng_forcefield_name_get(tng_data, name, max_len));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_set_
+ (tng_trajectory_t tng_data,
+ const char *new_name,
+ int name_len)
+{
+ char *name = malloc(name_len + 1);
+ tng_function_status stat;
+
+ strncpy(name, new_name, name_len);
+ name[name_len] = 0;
+ stat = tng_forcefield_name_set(tng_data, name);
+ free(name);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_get_
+ (const tng_trajectory_t tng_data,
+ int64_t *len)
+{
+ return(tng_medium_stride_length_get(tng_data, len));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_set_
+ (tng_trajectory_t tng_data,
+ const int64_t *len)
+{
+ return(tng_medium_stride_length_set(tng_data, *len));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_get_
+ (const tng_trajectory_t tng_data,
+ int64_t *len)
+{
+ return(tng_long_stride_length_get(tng_data, len));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_set_
+ (tng_trajectory_t tng_data,
+ const int64_t *len)
+{
+ return(tng_long_stride_length_set(tng_data, *len));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_get_
+ (const tng_trajectory_t tng_data,
+ double *time)
+{
+ return(tng_time_per_frame_get(tng_data, time));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_set_
+ (tng_trajectory_t tng_data,
+ const double *time)
+{
+ return(tng_time_per_frame_set(tng_data, *time));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_input_file_len_get_
+ (const tng_trajectory_t tng_data,
+ int64_t *len)
+{
+ return(tng_input_file_len_get(tng_data, len));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_num_frames_get_
+ (const tng_trajectory_t tng_data,
+ int64_t *n)
+{
+ return(tng_num_frames_get(tng_data, n));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_num_particles_get_
+ (const tng_trajectory_t tng_data,
+ int64_t *n)
+{
+ return(tng_num_particles_get(tng_data, n));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_num_molecules_get_
+ (const tng_trajectory_t tng_data,
+ int64_t *n)
+{
+ return(tng_num_molecules_get(tng_data, n));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_get_
+ (const tng_trajectory_t tng_data,
+ int64_t *exp)
+{
+ return(tng_distance_unit_exponential_get(tng_data, exp));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_set_
+ (const tng_trajectory_t tng_data,
+ const int64_t *exp)
+{
+ return(tng_distance_unit_exponential_set(tng_data, *exp));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_get_
+ (const tng_trajectory_t tng_data,
+ int64_t *n)
+{
+ return(tng_num_frames_per_frame_set_get(tng_data, n));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_set_
+ (const tng_trajectory_t tng_data,
+ int64_t *n)
+{
+ return(tng_num_frames_per_frame_set_set(tng_data, *n));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_num_frame_sets_get_
+ (const tng_trajectory_t tng_data,
+ int64_t *n)
+{
+ return(tng_num_frame_sets_get(tng_data, n));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_current_frame_set_get_
+ (tng_trajectory_t tng_data,
+ tng_trajectory_frame_set_t *frame_set_p)
+{
+ return(tng_current_frame_set_get(tng_data, frame_set_p));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find_(tng_trajectory_t tng_data,
+ const int64_t *nr)
+{
+ return(tng_frame_set_nr_find(tng_data, *nr));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find_
+ (tng_trajectory_t tng_data,
+ const int64_t *frame)
+{
+ return(tng_frame_set_of_frame_find(tng_data, *frame));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_next_frame_set_file_pos_get_
+ (const tng_trajectory_t tng_data,
+ const tng_trajectory_frame_set_t frame_set,
+ int64_t *pos)
+{
+ return(tng_frame_set_next_frame_set_file_pos_get(tng_data, frame_set, pos));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_prev_frame_set_file_pos_get_
+ (const tng_trajectory_t tng_data,
+ const tng_trajectory_frame_set_t frame_set,
+ int64_t *pos)
+{
+ return(tng_frame_set_prev_frame_set_file_pos_get(tng_data, frame_set, pos));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_frame_range_get_
+ (const tng_trajectory_t tng_data,
+ const tng_trajectory_frame_set_t frame_set,
+ int64_t *first_frame,
+ int64_t *last_frame)
+{
+ return(tng_frame_set_frame_range_get(tng_data, frame_set, first_frame,
+ last_frame));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_init_(const tng_trajectory_t tng_data,
+ tng_molecule_t molecule)
+{
+ return(tng_molecule_init(tng_data, molecule));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_destroy_
+ (const tng_trajectory_t tng_data,
+ tng_molecule_t molecule)
+{
+ return(tng_molecule_destroy(tng_data, molecule));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_add_(tng_trajectory_t tng_data,
+ const char *name,
+ tng_molecule_t *molecule,
+ int name_len)
+{
+ char *n = malloc(name_len + 1);
+ tng_function_status stat;
+
+ strncpy(n, name, name_len);
+ n[name_len] = 0;
+ stat = tng_molecule_add(tng_data, n, molecule);
+ free(n);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_name_set_(tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ const char *new_name,
+ int name_len)
+{
+ char *name = malloc(name_len + 1);
+ tng_function_status stat;
+
+ strncpy(name, new_name, name_len);
+ name[name_len] = 0;
+ stat = tng_molecule_name_set(tng_data, molecule, name);
+ free(name);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_get_(tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ int64_t *cnt)
+{
+ return(tng_molecule_cnt_get(tng_data, molecule, cnt));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_set_(tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ int64_t *cnt)
+{
+ return(tng_molecule_cnt_set(tng_data, molecule, *cnt));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_find_(tng_trajectory_t tng_data,
+ const char *name,
+ int64_t nr,
+ tng_molecule_t *molecule,
+ int name_len)
+{
+ char *n = malloc(name_len + 1);
+ tng_function_status stat;
+
+ strncpy(n, name, name_len);
+ n[name_len] = 0;
+ stat = tng_molecule_find(tng_data, n, nr, molecule);
+ free(n);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_find_(tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ const char *name,
+ int64_t id,
+ tng_chain_t *chain,
+ int name_len)
+{
+ char *n = malloc(name_len + 1);
+ tng_function_status stat;
+
+ strncpy(n, name, name_len);
+ n[name_len] = 0;
+ stat = tng_molecule_chain_find(tng_data, molecule, n, id, chain);
+ free(n);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_add_(tng_trajectory_t tng_data,
+ tng_molecule_t molecule,
+ const char *name,
+ tng_chain_t *chain,
+ int name_len)
+{
+ char *n = malloc(name_len + 1);
+ tng_function_status stat;
+
+ strncpy(n, name, name_len);
+ n[name_len] = 0;
+ stat = tng_molecule_chain_add(tng_data, molecule, n, chain);
+ free(n);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_chain_name_set_(tng_trajectory_t tng_data,
+ tng_chain_t chain,
+ const char *new_name,
+ int name_len)
+{
+ char *name = malloc(name_len + 1);
+ tng_function_status stat;
+
+ strncpy(name, new_name, name_len);
+ name[name_len] = 0;
+ stat = tng_chain_name_set(tng_data, chain, name);
+ free(name);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_chain_residue_add_(tng_trajectory_t tng_data,
+ tng_chain_t chain,
+ const char *name,
+ tng_residue_t *residue,
+ int name_len)
+{
+ char *n = malloc(name_len + 1);
+ tng_function_status stat;
+
+ strncpy(n, name, name_len);
+ n[name_len] = 0;
+ stat = tng_chain_residue_add(tng_data, chain, n, residue);
+ free(n);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_residue_name_set_(tng_trajectory_t tng_data,
+ tng_residue_t residue,
+ const char *new_name,
+ int name_len)
+{
+ char *name = malloc(name_len + 1);
+ tng_function_status stat;
+
+ strncpy(name, new_name, name_len);
+ name[name_len] = 0;
+ stat = tng_residue_name_set(tng_data, residue, name);
+ free(name);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_residue_atom_add_(tng_trajectory_t tng_data,
+ tng_residue_t residue,
+ const char *atom_name,
+ const char *atom_type,
+ tng_atom_t *atom,
+ int name_len,
+ int type_len)
+{
+ char *name = malloc(name_len + 1);
+ char *type = malloc(type_len + 1);
+ tng_function_status stat;
+
+ strncpy(name, atom_name, name_len);
+ strncpy(type, atom_type, type_len);
+ name[name_len] = 0;
+ type[type_len] = 0;
+ stat = tng_residue_atom_add(tng_data, residue, name, type, atom);
+ free(name);
+ free(type);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_atom_name_set_(tng_trajectory_t tng_data,
+ tng_atom_t atom,
+ const char *new_name,
+ int name_len)
+{
+ char *name = malloc(name_len + 1);
+ tng_function_status stat;
+
+ strncpy(name, new_name, name_len);
+ name[name_len] = 0;
+ stat = tng_atom_name_set(tng_data, atom, name);
+ free(name);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_atom_type_set_(tng_trajectory_t tng_data,
+ tng_atom_t atom,
+ const char *new_type,
+ int type_len)
+{
+ char *type = malloc(type_len + 1);
+ tng_function_status stat;
+
+ strncpy(type, new_type, type_len);
+ type[type_len] = 0;
+ stat = tng_atom_type_set(tng_data, atom, type);
+ free(type);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_molecule_name_of_particle_nr_get_
+ (const tng_trajectory_t tng_data,
+ const int64_t nr,
+ char *name,
+ int max_len)
+{
+ return(tng_molecule_name_of_particle_nr_get(tng_data, nr, name, max_len));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_chain_name_of_particle_nr_get_
+ (const tng_trajectory_t tng_data,
+ const int64_t nr,
+ char *name,
+ int max_len)
+{
+ return(tng_chain_name_of_particle_nr_get(tng_data, nr, name, max_len));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_residue_name_of_particle_nr_get_
+ (const tng_trajectory_t tng_data,
+ const int64_t nr,
+ char *name,
+ int max_len)
+{
+ return(tng_residue_name_of_particle_nr_get(tng_data, nr, name, max_len));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_residue_id_of_particle_nr_get_
+ (const tng_trajectory_t tng_data,
+ const int64_t nr,
+ int64_t *id)
+{
+ return(tng_residue_id_of_particle_nr_get(tng_data, nr, id));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_atom_name_of_particle_nr_get_
+ (const tng_trajectory_t tng_data,
+ const int64_t nr,
+ char *name,
+ int max_len)
+{
+ return(tng_atom_name_of_particle_nr_get(tng_data, nr, name, max_len));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_atom_type_of_particle_nr_get_
+ (const tng_trajectory_t tng_data,
+ const int64_t nr,
+ char *type,
+ int max_len)
+{
+ return(tng_atom_type_of_particle_nr_get(tng_data, nr, type, max_len));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_particle_mapping_add_
+ (tng_trajectory_t tng_data,
+ const int64_t *first_particle_number,
+ const int64_t *n_particles,
+ const int64_t *mapping_table)
+{
+ return(tng_particle_mapping_add(tng_data, *first_particle_number,
+ *n_particles, mapping_table));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_file_headers_read_(tng_trajectory_t tng_data,
+ const char *hash_mode)
+{
+ return(tng_file_headers_read(tng_data, *hash_mode));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_file_headers_write_
+ (tng_trajectory_t tng_data,
+ const char *hash_mode)
+{
+ return(tng_file_headers_write(tng_data, *hash_mode));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_block_read_next_
+ (tng_trajectory_t tng_data,
+ tng_gen_block_t block_data,
+ const char *hash_mode)
+{
+ return(tng_block_read_next(tng_data, block_data, *hash_mode));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next_
+ (tng_trajectory_t tng_data,
+ const char *hash_mode)
+{
+ return(tng_frame_set_read_next(tng_data, *hash_mode));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_write_(tng_trajectory_t tng_data,
+ const char *hash_mode)
+{
+ return(tng_frame_set_write(tng_data, *hash_mode));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_new_(tng_trajectory_t tng_data,
+ const int64_t *first_frame,
+ const int64_t *n_frames)
+{
+ return(tng_frame_set_new(tng_data, *first_frame, *n_frames));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_with_time_new_
+ (tng_trajectory_t tng_data,
+ const int64_t *first_frame,
+ const int64_t *n_frames,
+ const double *first_frame_time)
+{
+ return(tng_frame_set_with_time_new(tng_data, *first_frame, *n_frames,
+ *first_frame_time));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_set_first_frame_time_set_
+ (tng_trajectory_t tng_data,
+ const double *first_frame_time)
+{
+ return(tng_frame_set_first_frame_time_set(tng_data, *first_frame_time));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_data_block_add_
+ (tng_trajectory_t tng_data,
+ const int64_t *id,
+ const char *block_name,
+ const char *datatype,
+ const char *block_type_flag,
+ int64_t *n_frames,
+ const int64_t *n_values_per_frame,
+ const int64_t *stride_length,
+ const int64_t *codec_id,
+ void *new_data,
+ int name_len)
+{
+ char *name = malloc(name_len + 1);
+ tng_function_status stat;
+
+ strncpy(name, block_name, name_len);
+ name[name_len] = 0;
+ stat = tng_data_block_add(tng_data, *id, name, *datatype, *block_type_flag,
+ *n_frames, *n_values_per_frame, *stride_length,
+ *codec_id, new_data);
+ free(name);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_particle_data_block_add_
+ (tng_trajectory_t tng_data,
+ const int64_t *id,
+ const char *block_name,
+ const char *datatype,
+ const char *block_type_flag,
+ int64_t *n_frames,
+ const int64_t *n_values_per_frame,
+ const int64_t *stride_length,
+ const int64_t *first_particle_number,
+ const int64_t *n_particles,
+ const int64_t *codec_id,
+ void *new_data,
+ int name_len)
+{
+ char *name = malloc(name_len + 1);
+ tng_function_status stat;
+
+ strncpy(name, block_name, name_len);
+ name[name_len] = 0;
+ stat = tng_particle_data_block_add(tng_data, *id, name, *datatype,
+ *block_type_flag, *n_frames,
+ *n_values_per_frame, *stride_length,
+ *first_particle_number, *n_particles,
+ *codec_id, new_data);
+ free(name);
+ return(stat);
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_data_write_
+ (tng_trajectory_t tng_data,
+ const int64_t *frame_nr,
+ const int64_t *block_id,
+ const void *data,
+ const char *hash_mode)
+{
+ return(tng_frame_data_write(tng_data, *frame_nr, *block_id, data,
+ *hash_mode));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_frame_particle_data_write_
+ (tng_trajectory_t tng_data,
+ const int64_t *frame_nr,
+ const int64_t *block_id,
+ const int64_t *val_first_particle,
+ const int64_t *val_n_particles,
+ const void *data,
+ const char *hash_mode)
+{
+ return(tng_frame_particle_data_write(tng_data, *frame_nr, *block_id,
+ *val_first_particle, *val_n_particles,
+ data, *hash_mode));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_data_values_free_
+ (const tng_trajectory_t tng_data,
+ union data_values **values,
+ const int64_t *n_frames,
+ const int64_t *n_values_per_frame,
+ const char *type)
+{
+ return(tng_data_values_free(tng_data, values, *n_frames,
+ *n_values_per_frame, *type));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_particle_data_values_free_
+ (const tng_trajectory_t tng_data,
+ union data_values ***values,
+ const int64_t *n_frames,
+ const int64_t *n_particles,
+ const int64_t *n_values_per_frame,
+ const char *type)
+{
+ return(tng_particle_data_values_free(tng_data, values, *n_frames, *n_particles,
+ *n_values_per_frame, *type));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_data_get_
+ (tng_trajectory_t tng_data,
+ const int64_t *block_id,
+ union data_values ***values,
+ int64_t *n_frames,
+ int64_t *n_values_per_frame,
+ char *type)
+{
+ return(tng_data_get(tng_data, *block_id, values, n_frames,
+ n_values_per_frame, type));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_data_interval_get_
+ (tng_trajectory_t tng_data,
+ const int64_t *block_id,
+ const int64_t *start_frame_nr,
+ const int64_t *end_frame_nr,
+ const char *hash_mode,
+ union data_values ***values,
+ int64_t *n_values_per_frame,
+ char *type)
+{
+ return(tng_data_interval_get(tng_data, *block_id, *start_frame_nr,
+ *end_frame_nr, *hash_mode, values,
+ n_values_per_frame, type));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_particle_data_get_
+ (tng_trajectory_t tng_data,
+ const int64_t *block_id,
+ union data_values ****values,
+ int64_t *n_frames,
+ int64_t *n_particles,
+ int64_t *n_values_per_frame,
+ char *type)
+{
+ return(tng_particle_data_get(tng_data, *block_id, values, n_frames,
+ n_particles, n_values_per_frame, type));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get_
+ (tng_trajectory_t tng_data,
+ const int64_t *block_id,
+ const int64_t *start_frame_nr,
+ const int64_t *end_frame_nr,
+ const char *hash_mode,
+ union data_values ****values,
+ int64_t *n_particles,
+ int64_t *n_values_per_frame,
+ char *type)
+{
+ return(tng_particle_data_interval_get(tng_data, *block_id, *start_frame_nr,
+ *end_frame_nr, *hash_mode, values,
+ n_particles, n_values_per_frame,
+ type));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_time_get_str_
+ (const tng_trajectory_t tng_data,
+ char *time, int64_t str_len)
+{
+ return(tng_time_get_str(tng_data, time));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_open_
+ (const char *filename, const char *mode,
+ tng_trajectory_t *tng_data_p)
+{
+ return(tng_util_trajectory_open(filename, *mode, tng_data_p));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_close_
+ (tng_trajectory_t *tng_data_p)
+{
+ return(tng_util_trajectory_close(tng_data_p));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_pos_read_
+ (tng_trajectory_t tng_data,
+ float **positions,
+ int64_t *stride_length)
+{
+ return(tng_util_pos_read(tng_data, positions, stride_length));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_vel_read_
+ (tng_trajectory_t tng_data,
+ float **velocities,
+ int64_t *stride_length)
+{
+ return(tng_util_vel_read(tng_data, velocities, stride_length));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_force_read_
+ (tng_trajectory_t tng_data,
+ float **forces,
+ int64_t *stride_length)
+{
+ return(tng_util_force_read(tng_data, forces, stride_length));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read_
+ (tng_trajectory_t tng_data,
+ float **box_shape,
+ int64_t *stride_length)
+{
+ return(tng_util_box_shape_read(tng_data, box_shape, stride_length));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_pos_read_range_
+ (tng_trajectory_t tng_data,
+ const int64_t *first_frame,
+ const int64_t *last_frame,
+ float **positions,
+ int64_t *stride_length)
+{
+ return(tng_util_pos_read_range(tng_data, *first_frame, *last_frame,
+ positions, stride_length));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_vel_read_range_
+ (tng_trajectory_t tng_data,
+ const int64_t *first_frame,
+ const int64_t *last_frame,
+ float **velocities,
+ int64_t *stride_length)
+{
+ return(tng_util_vel_read_range(tng_data, *first_frame, *last_frame,
+ velocities, stride_length));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_force_read_range_
+ (tng_trajectory_t tng_data,
+ const int64_t *first_frame,
+ const int64_t *last_frame,
+ float **forces,
+ int64_t *stride_length)
+{
+ return(tng_util_force_read_range(tng_data, *first_frame, *last_frame,
+ forces, stride_length));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read_range_
+ (tng_trajectory_t tng_data,
+ const int64_t *first_frame,
+ const int64_t *last_frame,
+ float **box_shape,
+ int64_t *stride_length)
+{
+ return(tng_util_box_shape_read_range(tng_data, *first_frame, *last_frame,
+ box_shape, stride_length));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_frequency_set_
+ (tng_trajectory_t tng_data,
+ const int64_t *f,
+ const int64_t *n_values_per_frame,
+ const int64_t *block_id,
+ const char *block_name,
+ const char *particle_dependency,
+ const char *compression)
+{
+ return(tng_util_generic_write_frequency_set(tng_data, *f,
+ *n_values_per_frame, *block_id,
+ block_name,
+ *particle_dependency,
+ *compression));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_frequency_set_
+ (tng_trajectory_t tng_data,
+ const int64_t *f)
+{
+ return(tng_util_pos_write_frequency_set(tng_data, *f));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_frequency_set_
+ (tng_trajectory_t tng_data,
+ const int64_t *f)
+{
+ return(tng_util_vel_write_frequency_set(tng_data, *f));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_force_write_frequency_set_
+ (tng_trajectory_t tng_data,
+ const int64_t *f)
+{
+ return(tng_util_force_write_frequency_set(tng_data, *f));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_frequency_set_
+ (tng_trajectory_t tng_data,
+ const int64_t *f)
+{
+ return(tng_util_box_shape_write_frequency_set(tng_data, *f));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_
+ (tng_trajectory_t tng_data,
+ const int64_t *frame_nr,
+ const float *values,
+ const int64_t *n_values_per_frame,
+ const int64_t *block_id,
+ const char *block_name,
+ const char *particle_dependency,
+ const char *compression)
+{
+ return(tng_util_generic_write(tng_data, *frame_nr, values,
+ *n_values_per_frame, *block_id, block_name,
+ *particle_dependency, *compression));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_
+ (tng_trajectory_t tng_data,
+ const int64_t *frame_nr,
+ const float *positions)
+{
+ return(tng_util_vel_write(tng_data, *frame_nr, positions));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_
+ (tng_trajectory_t tng_data,
+ const int64_t *frame_nr,
+ const float *velocities)
+{
+ return(tng_util_vel_write(tng_data, *frame_nr, velocities));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_force_write_
+ (tng_trajectory_t tng_data,
+ const int64_t *frame_nr,
+ const float *forces)
+{
+ return(tng_util_force_write(tng_data, *frame_nr, forces));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_
+ (tng_trajectory_t tng_data,
+ const int64_t *frame_nr,
+ const float *box_shape)
+{
+ return(tng_util_box_shape_write(tng_data, *frame_nr, box_shape));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_write_
+ (tng_trajectory_t tng_data,
+ const int64_t *frame_nr,
+ const int64_t *time,
+ const float *positions)
+{
+ return(tng_util_pos_with_time_write(tng_data, *frame_nr, *time,
+ positions));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_write_
+ (tng_trajectory_t tng_data,
+ const int64_t *frame_nr,
+ const int64_t *time,
+ const float *velocities)
+{
+ return(tng_util_vel_with_time_write(tng_data, *frame_nr, *time,
+ velocities));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_write_
+ (tng_trajectory_t tng_data,
+ const int64_t *frame_nr,
+ const int64_t *time,
+ const float *forces)
+{
+ return(tng_util_force_with_time_write(tng_data, *frame_nr, *time,
+ forces));
+}
+
+tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_write_
+ (tng_trajectory_t tng_data,
+ const int64_t *frame_nr,
+ const int64_t *time,
+ const float *box_shape)
+{
+ return(tng_util_box_shape_with_time_write(tng_data, *frame_nr, *time,
+ box_shape));
+}
--- /dev/null
+if(TNG_BUILD_COMPRESSION_TESTS)
+ add_subdirectory(compression)
+endif()
+
+link_directories(${TNG_IO_BINARY_DIR}/src/lib)
+
+add_definitions(-DTNG_EXAMPLE_FILES_DIR="${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/tests/example_files/") # Directory where to find input test files and save output files.
+
+if(TNG_BUILD_TEST)
+ add_executable(tng_testing tng_io_testing.c)
+ target_link_libraries(tng_testing tng_io)
+ if(UNIX)
+ target_link_libraries(tng_testing m)
+ endif()
+
+ if(HAVE_INTTYPES_H)
+ set_property(TARGET tng_testing APPEND PROPERTY COMPILE_DEFINITIONS USE_STD_INTTYPES_H=1)
+ endif()
+
+ file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/../../example_files DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/tests/)
+
+ set_property(TARGET tng_testing PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/tests)
+endif()
+
+if(TNG_BUILD_EXAMPLES)
+ if(TNG_USE_OPENMP AND OPENMP_FOUND)
+
+ add_executable(md_openmp md_openmp.c)
+ target_link_libraries(md_openmp tng_io ${OpenMP_LIBS})
+ if(UNIX)
+ target_link_libraries(md_openmp m)
+ endif()
+ set_property(TARGET md_openmp PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/examples)
+ set_property(TARGET md_openmp APPEND PROPERTY COMPILE_DEFINITIONS TNG_BUILD_OPENMP_EXAMPLES)
+
+
+ add_executable(md_openmp_util md_openmp_util.c)
+ target_link_libraries(md_openmp_util tng_io ${OpenMP_LIBS})
+ if(UNIX)
+ target_link_libraries(md_openmp_util m)
+ endif()
+ set_property(TARGET md_openmp_util PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/examples)
+ set_property(TARGET md_openmp_util APPEND PROPERTY COMPILE_DEFINITIONS TNG_BUILD_OPENMP_EXAMPLES)
+
+ add_executable(tng_parallel_read tng_parallel_read.c)
+ target_link_libraries(tng_parallel_read tng_io)
+ if(UNIX)
+ target_link_libraries(tng_parallel_read m)
+ endif()
+ set_property(TARGET tng_parallel_read PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/examples)
+ set_property(TARGET tng_parallel_read APPEND PROPERTY COMPILE_DEFINITIONS TNG_BUILD_OPENMP_EXAMPLES)
+ endif()
+
+ add_executable(tng_io_read_pos tng_io_read_pos.c)
+ target_link_libraries(tng_io_read_pos tng_io)
+ if(UNIX)
+ target_link_libraries(tng_io_read_pos m)
+ endif()
+ if(HAVE_INTTYPES_H)
+ set_property(TARGET tng_io_read_pos APPEND PROPERTY COMPILE_DEFINITIONS USE_STD_INTTYPES_H=1)
+ endif()
+ set_property(TARGET tng_io_read_pos PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/examples)
+
+ add_executable(tng_io_read_pos_util tng_io_read_pos_util.c)
+ target_link_libraries(tng_io_read_pos_util tng_io)
+ if(UNIX)
+ target_link_libraries(tng_io_read_pos_util m)
+ endif()
+ if(HAVE_INTTYPES_H)
+ set_property(TARGET tng_io_read_pos_util APPEND PROPERTY COMPILE_DEFINITIONS USE_STD_INTTYPES_H=1)
+ endif()
+ set_property(TARGET tng_io_read_pos_util PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/examples)
+
+ if(TNG_BUILD_FORTRAN)
+ # This does not work due to a bug in CMake. Remove lines below if no fortran compiler is found.
+ enable_language(Fortran OPTIONAL)
+ if(${CMAKE_Fortran_COMPILER_WORKS})
+ get_filename_component (Fortran_COMPILER_NAME ${CMAKE_Fortran_COMPILER} NAME)
+ if (Fortran_COMPILER_NAME STREQUAL "gfortran")
+ set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -fcray-pointer ${OpenMP_C_FLAGS} -std=legacy")
+ endif()
+ if(OPENMP_FOUND)
+ add_executable(md_openmp_f md_openmp.f)
+ target_link_libraries(md_openmp_f tng_io ${OpenMP_LIBS})
+ set_property(TARGET md_openmp_f PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/examples)
+ endif()
+ endif()
+ endif()
+endif()
--- /dev/null
+link_directories(${TNG_IO_BINARY_DIR}/src/lib)
+
+add_definitions(-DTNG_COMPRESS_FILES_DIR="${CMAKE_BINARY_DIR}/test_tng_compress_files/") # Directory where to write tng_compress test files.
+
+file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/test_tng_compress_files)
+
+include_directories(${CMAKE_BINARY_DIR}/include/)
+
+set(number 0)
+set(numtests 78)
+
+while( number LESS ${numtests})
+
+math( EXPR number "${number} + 1" )
+
+add_executable(test_tng_compress_gen${number} testsuite.c)
+target_link_libraries(test_tng_compress_gen${number} tng_compress)
+if(UNIX)
+target_link_libraries(test_tng_compress_gen${number} m)
+endif()
+list(APPEND gen${number}_build_definitions GEN)
+list(APPEND gen${number}_build_definitions TESTPARAM="test${number}.h")
+set_target_properties(test_tng_compress_gen${number} PROPERTIES COMPILE_DEFINITIONS "${gen${number}_build_definitions}")
+add_dependencies(test_tng_compress_gen${number} test${number}.h)
+set_property(TARGET test_tng_compress_gen${number} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/compression_tests)
+
+add_executable(test_tng_compress_read${number} testsuite.c)
+target_link_libraries(test_tng_compress_read${number} tng_compress)
+if(UNIX)
+target_link_libraries(test_tng_compress_read${number} m)
+endif()
+list(APPEND read${number}_build_definitions TESTPARAM="test${number}.h")
+set_target_properties(test_tng_compress_read${number} PROPERTIES COMPILE_DEFINITIONS "${read${number}_build_definitions}")
+add_dependencies(test_tng_compress_read${number} test${number}.h)
+set_property(TARGET test_tng_compress_read${number} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/compression_tests)
+
+endwhile()
+
+if(UNIX)
+file(COPY test_tng_compress_write.sh DESTINATION ${CMAKE_BINARY_DIR}/bin/compression_tests)
+file(COPY test_tng_compress_read.sh DESTINATION ${CMAKE_BINARY_DIR}/bin/compression_tests)
+endif()
+if(WIN32)
+file(COPY test_tng_compress_write.bat DESTINATION ${CMAKE_BINARY_DIR}/bin/compression_tests)
+file(COPY test_tng_compress_read.bat DESTINATION ${CMAKE_BINARY_DIR}/bin/compression_tests)
+endif()
--- /dev/null
+#!/bin/sh
+if [ -z "$3" ]; then
+ echo $0 STARTTEST ENDTEST TNGFILEDIR
+else
+ STARTTEST="$1"
+ ENDTEST="$2"
+ TNGFILEDIR="$3"
+ for testnum in $(seq $STARTTEST $ENDTEST); do
+ if [ -r $TNGFILEDIR/test$testnum.tng_compress ]; then
+ grep -v "EXPECTED_FILESIZE" test$testnum.h >tmp$$.h
+ echo "#define EXPECTED_FILESIZE" $(ls -l $TNGFILEDIR/test$testnum.tng_compress |awk '{print $5}'). >>tmp$$.h
+ mv tmp$$.h test$testnum.h
+ fi
+ done
+fi
\ No newline at end of file
--- /dev/null
+#define TESTNAME "Initial coding. Intra frame triple algorithm. Cubic cell."
+#define FILENAME "test1.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 1
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 1
+#define CODINGPARAMETER 0
+#define VELCODING 0
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 2776230.
--- /dev/null
+#define TESTNAME "Coding. Triple intraframe algorithm. Cubic cell."
+#define FILENAME "test10.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 3
+#define CODINGPARAMETER -1
+#define VELCODING 0
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 2728492.
--- /dev/null
+#define TESTNAME "Coding. Triple one-to-one algorithm. Cubic cell."
+#define FILENAME "test11.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 7
+#define CODINGPARAMETER -1
+#define VELCODING 0
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 4293415.
--- /dev/null
+#define TESTNAME "Coding. BWLZH interframe algorithm. Cubic cell."
+#define FILENAME "test12.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 8
+#define CODINGPARAMETER 0
+#define VELCODING 0
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 894421.
--- /dev/null
+#define TESTNAME "Coding. BWLZH intraframe algorithm. Cubic cell."
+#define FILENAME "test13.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 9
+#define CODINGPARAMETER 0
+#define VELCODING 0
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 840246.
--- /dev/null
+#define TESTNAME "Coding. XTC3 algorithm. Cubic cell."
+#define FILENAME "test14.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 10
+#define CODINGPARAMETER 0
+#define VELCODING 0
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 1401016.
--- /dev/null
+#define TESTNAME "Initial coding. Automatic selection of algorithms. Cubic cell."
+#define FILENAME "test15.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 1
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING -1
+#define INITIALCODINGPARAMETER -1
+#define CODING 1
+#define CODINGPARAMETER 0
+#define VELCODING 0
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 2776230.
--- /dev/null
+#define TESTNAME "Coding. Automatic selection of algorithms. Cubic cell."
+#define FILENAME "test16.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING -1
+#define INITIALCODINGPARAMETER -1
+#define CODING -1
+#define CODINGPARAMETER -1
+#define VELCODING 0
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define SPEED 6
+#define EXPECTED_FILESIZE 838168.
--- /dev/null
+#define TESTNAME "Initial coding of velocities. Stopbits one-to-one . Cubic cell."
+#define FILENAME "test17.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 1
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 1
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 1
+#define CODINGPARAMETER 0
+#define INITIALVELCODING 1
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 0
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 7336171.
--- /dev/null
+#define TESTNAME "Initial coding of velocities. Triplet one-to-one. Cubic cell."
+#define FILENAME "test18.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 1
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 1
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 1
+#define CODINGPARAMETER 0
+#define INITIALVELCODING 3
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 0
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 7089695.
--- /dev/null
+#define TESTNAME "Initial coding of velocities. BWLZH one-to-one. Cubic cell."
+#define FILENAME "test19.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 1
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 1
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 1
+#define CODINGPARAMETER 0
+#define INITIALVELCODING 9
+#define INITIALVELCODINGPARAMETER 0
+#define VELCODING 0
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 50
+#define EXPECTED_FILESIZE 208809.
--- /dev/null
+#define TESTNAME "Initial coding. XTC2 algorithm. Cubic cell."
+#define FILENAME "test2.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 1
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 1
+#define CODINGPARAMETER 0
+#define VELCODING 0
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 2796171.
--- /dev/null
+#define TESTNAME "Coding of velocities. Stopbit one-to-one. Cubic cell."
+#define FILENAME "test20.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 1
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 5
+#define CODINGPARAMETER 0
+#define INITIALVELCODING 1
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 1
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 7237102.
--- /dev/null
+#define TESTNAME "Coding of velocities. Triplet inter. Cubic cell."
+#define FILENAME "test21.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 1
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 5
+#define CODINGPARAMETER 0
+#define INITIALVELCODING 1
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 2
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 6214307.
--- /dev/null
+#define TESTNAME "Coding of velocities. Triplet one-to-one. Cubic cell."
+#define FILENAME "test22.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 1
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 5
+#define CODINGPARAMETER 0
+#define INITIALVELCODING 1
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 3
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 6988699.
--- /dev/null
+#define TESTNAME "Coding of velocities. Stopbit interframe. Cubic cell."
+#define FILENAME "test23.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 1
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 5
+#define CODINGPARAMETER 0
+#define INITIALVELCODING 1
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 6
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 6494602.
--- /dev/null
+#define TESTNAME "Coding of velocities. BWLZH interframe. Cubic cell."
+#define FILENAME "test24.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 25
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 1
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 5
+#define CODINGPARAMETER 0
+#define INITIALVELCODING 1
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 8
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 50
+#define EXPECTED_FILESIZE 153520.
--- /dev/null
+#define TESTNAME "Coding of velocities. BWLZH one-to-one. Cubic cell."
+#define FILENAME "test25.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 25
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 1
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 5
+#define CODINGPARAMETER 0
+#define INITIALVELCODING 1
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 9
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 50
+#define EXPECTED_FILESIZE 154753.
--- /dev/null
+#define TESTNAME "XTC2 algorithm. Orthorhombic cell."
+#define FILENAME "test26.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 5
+#define CODINGPARAMETER 0
+#define INITIALVELCODING 1
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 9
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 20000
+#define INTMAX2 10000
+#define INTMAX3 30000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 2861948.
--- /dev/null
+#define TESTNAME "XTC3 algorithm. Orthorhombic cell."
+#define FILENAME "test27.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 10
+#define INITIALCODINGPARAMETER 0
+#define CODING 10
+#define CODINGPARAMETER 0
+#define INITIALVELCODING 1
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 9
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 20000
+#define INTMAX2 10000
+#define INTMAX3 30000
+#define NFRAMES 200
+#define EXPECTED_FILESIZE 282600.
--- /dev/null
+#define TESTNAME "Initial coding. Autoselect algorithm. Repetitive molecule. Cubic cell."
+#define FILENAME "test28.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 1
+#define SCALE 0.1
+#define REGULAR
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING -1
+#define INITIALCODINGPARAMETER -1
+#define CODING 0
+#define CODINGPARAMETER 0
+#define INITIALVELCODING 0
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 0
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 1677619.
--- /dev/null
+#define TESTNAME "Position coding. Autoselect algorithm. Repetitive molecule. Cubic cell."
+#define FILENAME "test29.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define REGULAR
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING -1
+#define INITIALCODINGPARAMETER -1
+#define CODING -1
+#define CODINGPARAMETER -1
+#define INITIALVELCODING 0
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 0
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 228148.
--- /dev/null
+#define TESTNAME "Initial coding. Triplet one-to-one algorithm. Cubic cell."
+#define FILENAME "test3.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 1
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 7
+#define INITIALCODINGPARAMETER -1
+#define CODING 1
+#define CODINGPARAMETER 0
+#define VELCODING 0
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 4356773.
--- /dev/null
+#define TESTNAME "Initial coding. Intra frame triple algorithm. Large system. Cubic cell."
+#define FILENAME "test30.tng_compress"
+#define ALGOTEST
+#define NATOMS 5000000
+#define CHUNKY 1
+#define SCALE 1.
+#define PRECISION 1.
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 1
+#define CODINGPARAMETER -1
+#define VELCODING 4
+#define VELCODINGPARAMETER 0
+#define INTMIN1 -536870911
+#define INTMIN2 -536870911
+#define INTMIN3 -536870911
+#define INTMAX1 536870911
+#define INTMAX2 536870911
+#define INTMAX3 536870911
+#define NFRAMES 10
+#define EXPECTED_FILESIZE 280198420.
--- /dev/null
+#define TESTNAME "Initial coding. XTC2 algorithm. Large system. Cubic cell."
+#define FILENAME "test31.tng_compress"
+#define ALGOTEST
+#define NATOMS 5000000
+#define CHUNKY 1
+#define SCALE 1.
+#define PRECISION 1.
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 1
+#define CODINGPARAMETER -1
+#define VELCODING 4
+#define VELCODINGPARAMETER 0
+#define INTMIN1 -536870911
+#define INTMIN2 -536870911
+#define INTMIN3 -536870911
+#define INTMAX1 536870911
+#define INTMAX2 536870911
+#define INTMAX3 536870911
+#define NFRAMES 10
+#define EXPECTED_FILESIZE 301463456.
--- /dev/null
+#define TESTNAME "Initial coding. XTC3 algorithm. Large system. Cubic cell."
+#define FILENAME "test32.tng_compress"
+#define ALGOTEST
+#define NATOMS 5000000
+#define CHUNKY 1
+#define SCALE 1.
+#define PRECISION 1.
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 10
+#define INITIALCODINGPARAMETER 0
+#define CODING 1
+#define CODINGPARAMETER -1
+#define VELCODING 4
+#define VELCODINGPARAMETER 0
+#define INTMIN1 -536870911
+#define INTMIN2 -536870911
+#define INTMIN3 -536870911
+#define INTMAX1 536870911
+#define INTMAX2 536870911
+#define INTMAX3 536870911
+#define NFRAMES 2
+#define EXPECTED_FILESIZE 31668187.
--- /dev/null
+#define TESTNAME "Initial coding. Intra frame BWLZH algorithm. Large system. Cubic cell."
+#define FILENAME "test33.tng_compress"
+#define ALGOTEST
+#define NATOMS 5000000
+#define CHUNKY 1
+#define SCALE 1.
+#define PRECISION 1.
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 9
+#define INITIALCODINGPARAMETER 0
+#define CODING 1
+#define CODINGPARAMETER -1
+#define VELCODING 4
+#define VELCODINGPARAMETER 0
+#define INTMIN1 -536870911
+#define INTMIN2 -536870911
+#define INTMIN3 -536870911
+#define INTMAX1 536870911
+#define INTMAX2 536870911
+#define INTMAX3 536870911
+#define NFRAMES 2
+#define EXPECTED_FILESIZE 7121047.
--- /dev/null
+#define TESTNAME "Position coding. Stop bits algorithm. Large system. Cubic cell."
+#define FILENAME "test34.tng_compress"
+#define ALGOTEST
+#define NATOMS 5000000
+#define CHUNKY 2
+#define SCALE 1.
+#define PRECISION 1.
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 1
+#define CODINGPARAMETER -1
+#define VELCODING 4
+#define VELCODINGPARAMETER 0
+#define INTMIN1 -536870911
+#define INTMIN2 -536870911
+#define INTMIN3 -536870911
+#define INTMAX1 536870911
+#define INTMAX2 536870911
+#define INTMAX3 536870911
+#define NFRAMES 10
+#define EXPECTED_FILESIZE 250247372.
--- /dev/null
+#define TESTNAME "Position coding. Inter frame triple algorithm. Large system. Cubic cell."
+#define FILENAME "test35.tng_compress"
+#define ALGOTEST
+#define NATOMS 5000000
+#define CHUNKY 2
+#define SCALE 1.
+#define PRECISION 1.
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 2
+#define CODINGPARAMETER -1
+#define VELCODING 4
+#define VELCODINGPARAMETER 0
+#define INTMIN1 -536870911
+#define INTMIN2 -536870911
+#define INTMIN3 -536870911
+#define INTMAX1 536870911
+#define INTMAX2 536870911
+#define INTMAX3 536870911
+#define NFRAMES 10
+#define EXPECTED_FILESIZE 243598962.
--- /dev/null
+#define TESTNAME "Position coding. Intra frame triple algorithm. Large system. Cubic cell."
+#define FILENAME "test36.tng_compress"
+#define ALGOTEST
+#define NATOMS 5000000
+#define CHUNKY 2
+#define SCALE 1.
+#define PRECISION 1.
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 3
+#define CODINGPARAMETER -1
+#define VELCODING 4
+#define VELCODINGPARAMETER 0
+#define INTMIN1 -536870911
+#define INTMIN2 -536870911
+#define INTMIN3 -536870911
+#define INTMAX1 536870911
+#define INTMAX2 536870911
+#define INTMAX3 536870911
+#define NFRAMES 10
+#define EXPECTED_FILESIZE 290800607.
--- /dev/null
+#define TESTNAME "Position coding. XTC2 algorithm. Large system. Cubic cell."
+#define FILENAME "test37.tng_compress"
+#define ALGOTEST
+#define NATOMS 5000000
+#define CHUNKY 2
+#define SCALE 1.
+#define PRECISION 1.
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 5
+#define CODINGPARAMETER 0
+#define VELCODING 4
+#define VELCODINGPARAMETER 0
+#define INTMIN1 -536870911
+#define INTMIN2 -536870911
+#define INTMIN3 -536870911
+#define INTMAX1 536870911
+#define INTMAX2 536870911
+#define INTMAX3 536870911
+#define NFRAMES 10
+#define EXPECTED_FILESIZE 301463256.
--- /dev/null
+#define TESTNAME "Position coding. XTC3 algorithm. Large system. Cubic cell."
+#define FILENAME "test38.tng_compress"
+#define ALGOTEST
+#define NATOMS 5000000
+#define CHUNKY 2
+#define SCALE 1.
+#define PRECISION 1.
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 10
+#define INITIALCODINGPARAMETER 0
+#define CODING 10
+#define CODINGPARAMETER 0
+#define VELCODING 4
+#define VELCODINGPARAMETER 0
+#define INTMIN1 -536870911
+#define INTMIN2 -536870911
+#define INTMIN3 -536870911
+#define INTMAX1 536870911
+#define INTMAX2 536870911
+#define INTMAX3 536870911
+#define NFRAMES 4
+#define EXPECTED_FILESIZE 63482016.
--- /dev/null
+#define TESTNAME "Position coding. Intra frame BWLZH algorithm. Large system. Cubic cell."
+#define FILENAME "test39.tng_compress"
+#define ALGOTEST
+#define NATOMS 5000000
+#define CHUNKY 2
+#define SCALE 1.
+#define PRECISION 1.
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 9
+#define CODINGPARAMETER 0
+#define VELCODING 4
+#define VELCODINGPARAMETER 0
+#define INTMIN1 -536870911
+#define INTMIN2 -536870911
+#define INTMIN3 -536870911
+#define INTMAX1 536870911
+#define INTMAX2 536870911
+#define INTMAX3 536870911
+#define NFRAMES 4
+#define EXPECTED_FILESIZE 67631371.
--- /dev/null
+#define TESTNAME "Initial coding. BWLZH intra algorithm. Cubic cell."
+#define FILENAME "test4.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 1
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 9
+#define INITIALCODINGPARAMETER 0
+#define CODING 1
+#define CODINGPARAMETER 0
+#define VELCODING 0
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 2572043.
--- /dev/null
+#define TESTNAME "Position coding. Inter frame BWLZH algorithm. Large system. Cubic cell."
+#define FILENAME "test40.tng_compress"
+#define ALGOTEST
+#define NATOMS 5000000
+#define CHUNKY 2
+#define SCALE 1.
+#define PRECISION 1.
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 8
+#define CODINGPARAMETER 0
+#define VELCODING 4
+#define VELCODINGPARAMETER 0
+#define INTMIN1 -536870911
+#define INTMIN2 -536870911
+#define INTMIN3 -536870911
+#define INTMAX1 536870911
+#define INTMAX2 536870911
+#define INTMAX3 536870911
+#define NFRAMES 4
+#define EXPECTED_FILESIZE 63822378.
--- /dev/null
+#define TESTNAME "Initial coding. Intra frame triple algorithm. High accuracy. Cubic cell."
+#define FILENAME "test41.tng_compress"
+#define ALGOTEST
+#define NATOMS 100000
+#define CHUNKY 1
+#define SCALE 0.5
+#define PRECISION 1e-8
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 1
+#define CODINGPARAMETER -1
+#define VELCODING 4
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 1610612736
+#define INTMAX2 1610612736
+#define INTMAX3 1610612736
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 53179342.
--- /dev/null
+#define TESTNAME "Initial coding. XTC2 algorithm. High accuracy. Cubic cell."
+#define FILENAME "test42.tng_compress"
+#define ALGOTEST
+#define NATOMS 100000
+#define CHUNKY 1
+#define SCALE 0.5
+#define PRECISION 1e-8
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 1
+#define CODINGPARAMETER -1
+#define VELCODING 4
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 1610612736
+#define INTMAX2 1610612736
+#define INTMAX3 1610612736
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 57283715.
--- /dev/null
+#define TESTNAME "Initial coding. XTC3 algorithm. High accuracy. Cubic cell."
+#define FILENAME "test43.tng_compress"
+#define ALGOTEST
+#define NATOMS 100000
+#define CHUNKY 1
+#define SCALE 0.5
+#define PRECISION 1e-8
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 10
+#define INITIALCODINGPARAMETER 0
+#define CODING 1
+#define CODINGPARAMETER -1
+#define VELCODING 4
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 1610612736
+#define INTMAX2 1610612736
+#define INTMAX3 1610612736
+#define NFRAMES 10
+#define EXPECTED_FILESIZE 3783912.
--- /dev/null
+#define TESTNAME "Initial coding. Intra frame BWLZH algorithm. High accuracy. Cubic cell."
+#define FILENAME "test44.tng_compress"
+#define ALGOTEST
+#define NATOMS 100000
+#define CHUNKY 1
+#define SCALE 0.5
+#define PRECISION 1e-8
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 9
+#define INITIALCODINGPARAMETER 0
+#define CODING 1
+#define CODINGPARAMETER -1
+#define VELCODING 4
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 1610612736
+#define INTMAX2 1610612736
+#define INTMAX3 1610612736
+#define NFRAMES 10
+#define EXPECTED_FILESIZE 1436901.
--- /dev/null
+#define TESTNAME "Position coding. Stop bits algorithm. High accuracy. Cubic cell."
+#define FILENAME "test45.tng_compress"
+#define ALGOTEST
+#define NATOMS 100000
+#define CHUNKY 10
+#define SCALE 0.5
+#define PRECISION 1e-8
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 1
+#define CODINGPARAMETER -1
+#define VELCODING 4
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 1610612736
+#define INTMAX2 1610612736
+#define INTMAX3 1610612736
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 36794379.
--- /dev/null
+#define TESTNAME "Position coding. Inter frame triple algorithm. High accuracy. Cubic cell."
+#define FILENAME "test46.tng_compress"
+#define ALGOTEST
+#define NATOMS 100000
+#define CHUNKY 10
+#define SCALE 0.5
+#define PRECISION 1e-8
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 2
+#define CODINGPARAMETER -1
+#define VELCODING 4
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 1610612736
+#define INTMAX2 1610612736
+#define INTMAX3 1610612736
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 34508770.
--- /dev/null
+#define TESTNAME "Position coding. Intra frame triple algorithm. High accuracy. Cubic cell."
+#define FILENAME "test47.tng_compress"
+#define ALGOTEST
+#define NATOMS 100000
+#define CHUNKY 10
+#define SCALE 0.5
+#define PRECISION 1e-8
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 3
+#define CODINGPARAMETER -1
+#define VELCODING 4
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 1610612736
+#define INTMAX2 1610612736
+#define INTMAX3 1610612736
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 53174711.
--- /dev/null
+#define TESTNAME "Position coding. XTC2 algorithm. High accuracy. Cubic cell."
+#define FILENAME "test48.tng_compress"
+#define ALGOTEST
+#define NATOMS 100000
+#define CHUNKY 10
+#define SCALE 0.5
+#define PRECISION 1e-8
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 5
+#define CODINGPARAMETER 0
+#define VELCODING 4
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 805306368
+#define INTMAX2 805306368
+#define INTMAX3 805306368
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 55638414.
--- /dev/null
+#define TESTNAME "Position coding. XTC3 algorithm. High accuracy. Cubic cell."
+#define FILENAME "test49.tng_compress"
+#define ALGOTEST
+#define NATOMS 100000
+#define CHUNKY 10
+#define SCALE 0.5
+#define PRECISION 1e-8
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 10
+#define CODINGPARAMETER 0
+#define VELCODING 4
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 805306368
+#define INTMAX2 805306368
+#define INTMAX3 805306368
+#define NFRAMES 20
+#define EXPECTED_FILESIZE 3585605.
--- /dev/null
+#define TESTNAME "Initial coding. XTC3 algorithm. Cubic cell."
+#define FILENAME "test5.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 1
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 10
+#define INITIALCODINGPARAMETER 0
+#define CODING 1
+#define CODINGPARAMETER 0
+#define VELCODING 0
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 3346179.
--- /dev/null
+#define TESTNAME "Position coding. Intra frame BWLZH algorithm. High accuracy. Cubic cell."
+#define FILENAME "test50.tng_compress"
+#define ALGOTEST
+#define NATOMS 100000
+#define CHUNKY 10
+#define SCALE 0.5
+#define PRECISION 1e-8
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 9
+#define CODINGPARAMETER 0
+#define VELCODING 4
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 805306368
+#define INTMAX2 805306368
+#define INTMAX3 805306368
+#define NFRAMES 20
+#define EXPECTED_FILESIZE 3143379.
--- /dev/null
+#define TESTNAME "Position coding. Inter frame BWLZH algorithm. High accuracy. Cubic cell."
+#define FILENAME "test51.tng_compress"
+#define ALGOTEST
+#define NATOMS 100000
+#define CHUNKY 10
+#define SCALE 0.5
+#define PRECISION 1e-8
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 8
+#define CODINGPARAMETER 0
+#define VELCODING 4
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 805306368
+#define INTMAX2 805306368
+#define INTMAX3 805306368
+#define NFRAMES 20
+#define EXPECTED_FILESIZE 2897696.
--- /dev/null
+#define TESTNAME "Velocity coding. Stop bits algorithm. High accuracy. Cubic cell."
+#define FILENAME "test52.tng_compress"
+#define ALGOTEST
+#define NATOMS 100000
+#define CHUNKY 10
+#define SCALE 0.5
+#define PRECISION 1e-8
+#define WRITEVEL 1
+#define VELINTMUL 100000
+#define VELPRECISION 1e-8
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 5
+#define CODINGPARAMETER 0
+#define VELCODING 1
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 805306368
+#define INTMAX2 805306368
+#define INTMAX3 805306368
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 173083705.
--- /dev/null
+#define TESTNAME "Velocity coding. Triple algorithm. High accuracy. Cubic cell."
+#define FILENAME "test53.tng_compress"
+#define ALGOTEST
+#define NATOMS 100000
+#define CHUNKY 10
+#define SCALE 0.5
+#define PRECISION 1e-8
+#define WRITEVEL 1
+#define VELINTMUL 100000
+#define VELPRECISION 1e-8
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 5
+#define CODINGPARAMETER 0
+#define VELCODING 3
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 805306368
+#define INTMAX2 805306368
+#define INTMAX3 805306368
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 168548573.
--- /dev/null
+#define TESTNAME "Velocity coding. Interframe triple algorithm. High accuracy. Cubic cell."
+#define FILENAME "test54.tng_compress"
+#define ALGOTEST
+#define NATOMS 100000
+#define CHUNKY 10
+#define SCALE 0.5
+#define PRECISION 1e-8
+#define WRITEVEL 1
+#define VELINTMUL 100000
+#define VELPRECISION 1e-8
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 5
+#define CODINGPARAMETER 0
+#define VELCODING 2
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 805306368
+#define INTMAX2 805306368
+#define INTMAX3 805306368
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 161798573.
--- /dev/null
+#define TESTNAME "Velocity coding. Interframe stop-bits algorithm. High accuracy. Cubic cell."
+#define FILENAME "test55.tng_compress"
+#define ALGOTEST
+#define NATOMS 100000
+#define CHUNKY 10
+#define SCALE 0.5
+#define PRECISION 1e-8
+#define WRITEVEL 1
+#define VELINTMUL 100000
+#define VELPRECISION 1e-8
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 5
+#define CODINGPARAMETER 0
+#define VELCODING 6
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 805306368
+#define INTMAX2 805306368
+#define INTMAX3 805306368
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 166298533.
--- /dev/null
+#define TESTNAME "Velocity coding. Intraframe BWLZH algorithm. High accuracy. Cubic cell."
+#define FILENAME "test56.tng_compress"
+#define ALGOTEST
+#define NATOMS 100000
+#define CHUNKY 10
+#define SCALE 0.5
+#define PRECISION 1e-8
+#define WRITEVEL 1
+#define VELINTMUL 100000
+#define VELPRECISION 1e-8
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 5
+#define CODINGPARAMETER 0
+#define VELCODING 9
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 805306368
+#define INTMAX2 805306368
+#define INTMAX3 805306368
+#define NFRAMES 20
+#define EXPECTED_FILESIZE 23390767.
--- /dev/null
+#define TESTNAME "Velocity coding. Interframe BWLZH algorithm. High accuracy. Cubic cell."
+#define FILENAME "test57.tng_compress"
+#define ALGOTEST
+#define NATOMS 100000
+#define CHUNKY 10
+#define SCALE 0.5
+#define PRECISION 1e-8
+#define WRITEVEL 1
+#define VELINTMUL 100000
+#define VELPRECISION 1e-8
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 5
+#define CODINGPARAMETER 0
+#define VELCODING 8
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 805306368
+#define INTMAX2 805306368
+#define INTMAX3 805306368
+#define NFRAMES 20
+#define EXPECTED_FILESIZE 13817974.
--- /dev/null
+#define TESTNAME "Coding. Test float."
+#define FILENAME "test58.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 1
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 5
+#define CODINGPARAMETER 0
+#define INITIALVELCODING 3
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 3
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define TEST_FLOAT
+#define EXPECTED_FILESIZE 6986313.
--- /dev/null
+#define TESTNAME "Coding. Test write float, read double."
+#define FILENAME "test59.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 1
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 5
+#define CODINGPARAMETER 0
+#define INITIALVELCODING 3
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 3
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#ifdef GEN
+#define TEST_FLOAT
+#endif
+#define EXPECTED_FILESIZE 6986313.
--- /dev/null
+#define TESTNAME "Coding. XTC2 algorithm. Cubic cell."
+#define FILENAME "test6.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 5
+#define CODINGPARAMETER 0
+#define VELCODING 0
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 2736662.
--- /dev/null
+#define TESTNAME "Coding. Test write double, read float."
+#define FILENAME "test60.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 1
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 5
+#define CODINGPARAMETER 0
+#define INITIALVELCODING 3
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 3
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#ifndef GEN
+#define TEST_FLOAT
+#endif
+#define EXPECTED_FILESIZE 6986313.
--- /dev/null
+#define TESTNAME "Coding. Recompression test. Stage 1: Generate"
+#define FILENAME "test61.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 1
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 5
+#define CODINGPARAMETER 0
+#define INITIALVELCODING 3
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 3
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 698801.
--- /dev/null
+#define TESTNAME "Coding. Recompression test. Stage 2: Recompress"
+#define FILENAME "test62.tng_compress"
+#define RECOMPRESS "test61.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 1
+#define VELPRECISION 0.1
+#define INITIALCODING 10
+#define INITIALCODINGPARAMETER 0
+#define CODING 10
+#define CODINGPARAMETER 0
+#define INITIALVELCODING 3
+#define INITIALVELCODINGPARAMETER 0
+#define VELCODING 8
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 151226.
--- /dev/null
+#define TESTNAME "Coding. Read int and convert to double."
+#define FILENAME "test63.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 1
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 5
+#define CODINGPARAMETER 0
+#define INITIALVELCODING 3
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 3
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 100
+#define INTTODOUBLE
+#define EXPECTED_FILESIZE 698801.
--- /dev/null
+#define TESTNAME "Coding. Read int and convert to float."
+#define FILENAME "test64.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 1
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 5
+#define CODINGPARAMETER 0
+#define INITIALVELCODING 3
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 3
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 100
+#define INTTOFLOAT
+#define TEST_FLOAT
+#define EXPECTED_FILESIZE 698801.
--- /dev/null
+#define TESTNAME "Coding. Compress zeros test. positions intra frame triple"
+#define FILENAME "test65.tng_compress"
+#define ALGOTEST
+#define NATOMS 100
+#define CHUNKY 100
+#define SCALE 0.
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 3
+#define CODINGPARAMETER -1
+#define INITIALVELCODING 3
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 3
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 0
+#define INTMAX2 0
+#define INTMAX3 0
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 6315.
--- /dev/null
+#define TESTNAME "Coding. Compress zeros test. positions xtc2"
+#define FILENAME "test66.tng_compress"
+#define ALGOTEST
+#define NATOMS 100
+#define CHUNKY 100
+#define SCALE 0.
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 5
+#define CODINGPARAMETER 0
+#define INITIALVELCODING 3
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 3
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 0
+#define INTMAX2 0
+#define INTMAX3 0
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 4465.
--- /dev/null
+#define TESTNAME "Coding. Compress zeros test. positions triple one-to-one"
+#define FILENAME "test67.tng_compress"
+#define ALGOTEST
+#define NATOMS 100
+#define CHUNKY 100
+#define SCALE 0.
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 7
+#define INITIALCODINGPARAMETER -1
+#define CODING 7
+#define CODINGPARAMETER -1
+#define INITIALVELCODING 3
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 3
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 0
+#define INTMAX2 0
+#define INTMAX3 0
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 6315.
--- /dev/null
+#define TESTNAME "Coding. Compress zeros test. positions BWLZH intra"
+#define FILENAME "test68.tng_compress"
+#define ALGOTEST
+#define NATOMS 100
+#define CHUNKY 100
+#define SCALE 0.
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 9
+#define INITIALCODINGPARAMETER 0
+#define CODING 9
+#define CODINGPARAMETER 0
+#define INITIALVELCODING 3
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 3
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 0
+#define INTMAX2 0
+#define INTMAX3 0
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 321.
--- /dev/null
+#define TESTNAME "Coding. Compress zeros test. positions xtc3"
+#define FILENAME "test69.tng_compress"
+#define ALGOTEST
+#define NATOMS 100
+#define CHUNKY 100
+#define SCALE 0.
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 10
+#define INITIALCODINGPARAMETER 0
+#define CODING 10
+#define CODINGPARAMETER 0
+#define INITIALVELCODING 3
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 3
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 0
+#define INTMAX2 0
+#define INTMAX3 0
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 867.
--- /dev/null
+#define TESTNAME "Coding. Stopbit interframe algorithm. Cubic cell."
+#define FILENAME "test7.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 1
+#define CODINGPARAMETER -1
+#define VELCODING 0
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 2545049.
--- /dev/null
+#define TESTNAME "Coding. Compress zeros test. positions stopbit interframe"
+#define FILENAME "test70.tng_compress"
+#define ALGOTEST
+#define NATOMS 100
+#define CHUNKY 100
+#define SCALE 0.
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 1
+#define CODINGPARAMETER -1
+#define INITIALVELCODING 3
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 3
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 0
+#define INTMAX2 0
+#define INTMAX3 0
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 7548.
--- /dev/null
+#define TESTNAME "Coding. Compress zeros test. positions triple interframe"
+#define FILENAME "test71.tng_compress"
+#define ALGOTEST
+#define NATOMS 100
+#define CHUNKY 100
+#define SCALE 0.
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 2
+#define CODINGPARAMETER -1
+#define INITIALVELCODING 3
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 3
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 0
+#define INTMAX2 0
+#define INTMAX3 0
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 6315.
--- /dev/null
+#define TESTNAME "Coding. Compress zeros test. positions BWLZH inter"
+#define FILENAME "test72.tng_compress"
+#define ALGOTEST
+#define NATOMS 100
+#define CHUNKY 100
+#define SCALE 0.
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 8
+#define CODINGPARAMETER 0
+#define INITIALVELCODING 3
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 3
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 0
+#define INTMAX2 0
+#define INTMAX3 0
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 257.
--- /dev/null
+#define TESTNAME "Coding. Compress zeros test. velocities stopbits one-to-one"
+#define FILENAME "test73.tng_compress"
+#define ALGOTEST
+#define NATOMS 100
+#define CHUNKY 100
+#define SCALE 0.
+#define PRECISION 0.01
+#define WRITEVEL 1
+#define VELPRECISION 0.1
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 3
+#define CODINGPARAMETER -1
+#define INITIALVELCODING 1
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 1
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 0
+#define INTMAX2 0
+#define INTMAX3 0
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 13863.
--- /dev/null
+#define TESTNAME "Coding. Compress zeros test. velocities triplet one-to-one"
+#define FILENAME "test74.tng_compress"
+#define ALGOTEST
+#define NATOMS 100
+#define CHUNKY 100
+#define SCALE 0.
+#define PRECISION 0.01
+#define WRITEVEL 1
+#define VELPRECISION 0.1
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 3
+#define CODINGPARAMETER -1
+#define INITIALVELCODING 3
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 3
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 0
+#define INTMAX2 0
+#define INTMAX3 0
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 12622.
--- /dev/null
+#define TESTNAME "Coding. Compress zeros test. velocities BWLZH one-to-one"
+#define FILENAME "test75.tng_compress"
+#define ALGOTEST
+#define NATOMS 100
+#define CHUNKY 100
+#define SCALE 0.
+#define PRECISION 0.01
+#define WRITEVEL 1
+#define VELPRECISION 0.1
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 3
+#define CODINGPARAMETER -1
+#define INITIALVELCODING 9
+#define INITIALVELCODINGPARAMETER 0
+#define VELCODING 9
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 0
+#define INTMAX2 0
+#define INTMAX3 0
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 6628.
--- /dev/null
+#define TESTNAME "Coding. Compress zeros test. velocities triplet inter"
+#define FILENAME "test76.tng_compress"
+#define ALGOTEST
+#define NATOMS 100
+#define CHUNKY 100
+#define SCALE 0.
+#define PRECISION 0.01
+#define WRITEVEL 1
+#define VELPRECISION 0.1
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 3
+#define CODINGPARAMETER -1
+#define INITIALVELCODING 1
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 2
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 0
+#define INTMAX2 0
+#define INTMAX3 0
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 12630.
--- /dev/null
+#define TESTNAME "Coding. Compress zeros test. velocities stopbits inter"
+#define FILENAME "test77.tng_compress"
+#define ALGOTEST
+#define NATOMS 100
+#define CHUNKY 100
+#define SCALE 0.
+#define PRECISION 0.01
+#define WRITEVEL 1
+#define VELPRECISION 0.1
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 3
+#define CODINGPARAMETER -1
+#define INITIALVELCODING 1
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 6
+#define VELCODINGPARAMETER -1
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 0
+#define INTMAX2 0
+#define INTMAX3 0
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 13863.
--- /dev/null
+#define TESTNAME "Coding. Compress zeros test. velocities BWLZH inter"
+#define FILENAME "test78.tng_compress"
+#define ALGOTEST
+#define NATOMS 100
+#define CHUNKY 100
+#define SCALE 0.
+#define PRECISION 0.01
+#define WRITEVEL 1
+#define VELPRECISION 0.1
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 3
+#define CODINGPARAMETER -1
+#define INITIALVELCODING 1
+#define INITIALVELCODINGPARAMETER -1
+#define VELCODING 8
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 0
+#define INTMAX2 0
+#define INTMAX3 0
+#define NFRAMES 100
+#define EXPECTED_FILESIZE 6572.
--- /dev/null
+#define TESTNAME "Coding. Stopbit interframe algorithm with intraframe compression as initial. Cubic cell."
+#define FILENAME "test8.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 3
+#define INITIALCODINGPARAMETER -1
+#define CODING 1
+#define CODINGPARAMETER -1
+#define VELCODING 0
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 2544876.
--- /dev/null
+#define TESTNAME "Coding. Triple interframe algorithm. Cubic cell."
+#define FILENAME "test9.tng_compress"
+#define ALGOTEST
+#define NATOMS 1000
+#define CHUNKY 100
+#define SCALE 0.1
+#define PRECISION 0.01
+#define WRITEVEL 0
+#define VELPRECISION 0.1
+#define INITIALCODING 5
+#define INITIALCODINGPARAMETER 0
+#define CODING 2
+#define CODINGPARAMETER -1
+#define VELCODING 0
+#define VELCODINGPARAMETER 0
+#define INTMIN1 0
+#define INTMIN2 0
+#define INTMIN3 0
+#define INTMAX1 10000
+#define INTMAX2 10000
+#define INTMAX3 10000
+#define NFRAMES 1000
+#define EXPECTED_FILESIZE 2418212.
--- /dev/null
+@echo off
+setlocal enableextensions enabledelayedexpansion
+SET /A I=0
+:start
+SET /A I+=1
+test_tng_compress_read%I%
+IF "%I%" == "78" (
+ GOTO end
+) ELSE (
+ GOTO start
+)
+:end
+endlocal
--- /dev/null
+#!/bin/sh
+numtests=78
+for x in $(seq 1 $numtests); do
+ ./test_tng_compress_read$x
+done
\ No newline at end of file
--- /dev/null
+@echo off
+setlocal enableextensions enabledelayedexpansion
+SET /A I=0
+:start
+SET /A I+=1
+test_tng_compress_gen%I%
+IF "%I%" == "78" (
+ GOTO end
+) ELSE (
+ GOTO start
+)
+:end
+endlocal
--- /dev/null
+#!/bin/sh
+numtests=78
+for x in $(seq 1 $numtests); do
+ ./test_tng_compress_gen$x
+done
\ No newline at end of file
--- /dev/null
+/* tng compression routines */
+
+/* Only modify testsuite.c
+ *Then* run testsuite.sh to perform the test.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "../../../include/compression/tng_compress.h"
+#include TESTPARAM
+
+#ifdef TEST_FLOAT
+#define REAL float
+#else
+#define REAL double
+#endif
+
+#ifndef TNG_COMPRESS_FILES_DIR
+#define TNG_COMPRESS_FILES_DIR ""
+#endif
+
+#define FUDGE 1.1 /* 10% off target precision is acceptable */
+
+static void keepinbox(int *val)
+{
+ while (val[0]>INTMAX1)
+ val[0]-=(INTMAX1-INTMIN1+1);
+ while (val[0]<INTMIN1)
+ val[0]+=(INTMAX1-INTMIN1+1);
+ while (val[1]>INTMAX2)
+ val[1]-=(INTMAX2-INTMIN2+1);
+ while (val[1]<INTMIN2)
+ val[1]+=(INTMAX2-INTMIN2+1);
+ while (val[2]>INTMAX3)
+ val[2]-=(INTMAX3-INTMIN3+1);
+ while (val[2]<INTMIN3)
+ val[2]+=(INTMAX3-INTMIN3+1);
+}
+
+static int intsintable[128]={
+0 , 3215 , 6423 , 9615 , 12785 , 15923 , 19023 , 22078 ,
+25079 , 28019 , 30892 , 33691 , 36409 , 39039 , 41574 , 44010 ,
+46340 , 48558 , 50659 , 52638 , 54490 , 56211 , 57796 , 59242 ,
+60546 , 61704 , 62713 , 63570 , 64275 , 64825 , 65219 , 65456 ,
+65535 , 65456 , 65219 , 64825 , 64275 , 63570 , 62713 , 61704 ,
+60546 , 59242 , 57796 , 56211 , 54490 , 52638 , 50659 , 48558 ,
+46340 , 44010 , 41574 , 39039 , 36409 , 33691 , 30892 , 28019 ,
+25079 , 22078 , 19023 , 15923 , 12785 , 9615 , 6423 , 3215 ,
+0 , -3215 , -6423 , -9615 , -12785 , -15923 , -19023 , -22078 ,
+-25079 , -28019 , -30892 , -33691 , -36409 , -39039 , -41574 , -44010 ,
+-46340 , -48558 , -50659 , -52638 , -54490 , -56211 , -57796 , -59242 ,
+-60546 , -61704 , -62713 , -63570 , -64275 , -64825 , -65219 , -65456 ,
+-65535 , -65456 , -65219 , -64825 , -64275 , -63570 , -62713 , -61704 ,
+-60546 , -59242 , -57796 , -56211 , -54490 , -52638 , -50659 , -48558 ,
+-46340 , -44010 , -41574 , -39039 , -36409 , -33691 , -30892 , -28019 ,
+-25079 , -22078 , -19023 , -15923 , -12785 , -9615 , -6423 , -3215 ,
+};
+
+static int intsin(int i)
+{
+ int sign=1;
+ if (i<0)
+ {
+ i=0;
+ sign=-1;
+ }
+ return sign*intsintable[i%128];
+}
+
+static int intcos(int i)
+{
+ if (i<0)
+ i=0;
+ return intsin(i+32);
+}
+
+static void molecule(int *target,
+ int *base,
+ int length,
+ int scale, int *direction,
+ int flip,
+ int iframe)
+{
+ int i;
+ for (i=0; i<length; i++)
+ {
+ int ifl=i;
+ if ((i==0) && (flip) && (length>1))
+ ifl=1;
+ else if ((i==1) && (flip) && (length>1))
+ ifl=0;
+ target[ifl*3]=base[0]+(intsin((i+iframe)*direction[0])*scale)/256;
+ target[ifl*3+1]=base[1]+(intcos((i+iframe)*direction[1])*scale)/256;
+ target[ifl*3+2]=base[2]+(intcos((i+iframe)*direction[2])*scale)/256;
+ keepinbox(target+ifl*3);
+ }
+}
+
+#ifndef FRAMESCALE
+#define FRAMESCALE 1
+#endif
+
+static void genibox(int *intbox, int iframe)
+{
+ int molecule_length=1;
+ int molpos[3];
+ int direction[3]={1,1,1};
+ int scale=1;
+ int flip=0;
+ int i=0;
+ molpos[0]=intsin(iframe*FRAMESCALE)/32;
+ molpos[1]=1+intcos(iframe*FRAMESCALE)/32;
+ molpos[2]=2+intsin(iframe*FRAMESCALE)/16;
+ keepinbox(molpos);
+ while (i<NATOMS)
+ {
+ int this_mol_length=molecule_length;
+ int dir;
+#ifdef REGULAR
+ this_mol_length=4;
+ flip=0;
+ scale=1;
+#endif
+ if (i+this_mol_length>NATOMS)
+ this_mol_length=NATOMS-i;
+ /* We must test the large rle as well. This requires special
+ sequencies to get triggered. So insert these from time to
+ time */
+#ifndef REGULAR
+ if ((i%10)==0)
+ {
+ int j;
+ intbox[i*3]=molpos[0];
+ intbox[i*3+1]=molpos[1];
+ intbox[i*3+2]=molpos[2];
+ for (j=1; j<this_mol_length; j++)
+ {
+ intbox[(i+j)*3]=intbox[(i+j-1)*3]+(INTMAX1-INTMIN1+1)/5;
+ intbox[(i+j)*3+1]=intbox[(i+j-1)*3+1]+(INTMAX2-INTMIN2+1)/5;
+ intbox[(i+j)*3+2]=intbox[(i+j-1)*3+2]+(INTMAX3-INTMIN3+1)/5;
+ keepinbox(intbox+(i+j)*3);
+ }
+ }
+ else
+#endif
+ molecule(intbox+i*3,molpos,this_mol_length,scale,direction,flip,iframe*FRAMESCALE);
+ i+=this_mol_length;
+ dir=1;
+ if (intsin(i*3)<0)
+ dir=-1;
+ molpos[0]+=dir*(INTMAX1-INTMIN1+1)/20;
+ dir=1;
+ if (intsin(i*5)<0)
+ dir=-1;
+ molpos[1]+=dir*(INTMAX2-INTMIN2+1)/20;
+ dir=1;
+ if (intsin(i*7)<0)
+ dir=-1;
+ molpos[2]+=dir*(INTMAX3-INTMIN3+1)/20;
+ keepinbox(molpos);
+
+ direction[0]=((direction[0]+1)%7)+1;
+ direction[1]=((direction[1]+1)%3)+1;
+ direction[2]=((direction[2]+1)%6)+1;
+
+ scale++;
+ if (scale>5)
+ scale=1;
+
+ molecule_length++;
+ if (molecule_length>30)
+ molecule_length=1;
+ if (i%9)
+ flip=1-flip;
+ }
+}
+
+static void genivelbox(int *intvelbox, int iframe)
+{
+ int i;
+ for (i=0; i<NATOMS; i++)
+ {
+#ifdef VELINTMUL
+ intvelbox[i*3]=((intsin((i+iframe*FRAMESCALE)*3))/10)*VELINTMUL+i;
+ intvelbox[i*3+1]=1+((intcos((i+iframe*FRAMESCALE)*5))/10)*VELINTMUL+i;
+ intvelbox[i*3+2]=2+((intsin((i+iframe*FRAMESCALE)*7)+intcos((i+iframe*FRAMESCALE)*9))/20)*VELINTMUL+i;
+#else
+ intvelbox[i*3]=((intsin((i+iframe*FRAMESCALE)*3))/10);
+ intvelbox[i*3+1]=1+((intcos((i+iframe*FRAMESCALE)*5))/10);
+ intvelbox[i*3+2]=2+((intsin((i+iframe*FRAMESCALE)*7)+intcos((i+iframe*FRAMESCALE)*9))/20);
+#endif
+ }
+}
+
+#ifndef STRIDE1
+#define STRIDE1 3
+#endif
+
+#ifndef STRIDE2
+#define STRIDE2 3
+#endif
+
+#ifndef GENPRECISION
+#define GENPRECISION PRECISION
+#endif
+
+#ifndef GENVELPRECISION
+#define GENVELPRECISION VELPRECISION
+#endif
+
+static void realbox(int *intbox, REAL *realbox, int stride)
+{
+ int i,j;
+ for (i=0; i<NATOMS; i++)
+ {
+ for (j=0; j<3; j++)
+ realbox[i*stride+j]=(REAL)(intbox[i*3+j]*GENPRECISION*SCALE);
+ for (j=3; j<stride; j++)
+ realbox[i*stride+j]=0.;
+ }
+}
+
+static void realvelbox(int *intbox, REAL *realbox, int stride)
+{
+ int i,j;
+ for (i=0; i<NATOMS; i++)
+ {
+ for (j=0; j<3; j++)
+ realbox[i*stride+j]=(REAL)(intbox[i*3+j]*GENVELPRECISION*SCALE);
+ for (j=3; j<stride; j++)
+ realbox[i*stride+j]=0.;
+ }
+}
+
+static int equalarr(REAL *arr1, REAL *arr2, REAL prec, int len, int itemlen, int stride1, int stride2)
+{
+ REAL maxdiff=0.;
+ int i,j;
+ for (i=0; i<len; i++)
+ {
+ for (j=0; j<itemlen; j++)
+ if (fabs(arr1[i*stride1+j]-arr2[i*stride2+j])>maxdiff)
+ maxdiff=(REAL)fabs(arr1[i*stride1+j]-arr2[i*stride2+j]);
+ }
+#if 0
+ for (i=0; i<len; i++)
+ {
+ for (j=0; j<itemlen; j++)
+ printf("%d %d: %g %g\n",i,j,arr1[i*stride1+j],arr2[i*stride2+j]);
+ }
+#endif
+#if 0
+ fprintf(stderr,"Error is %g. Acceptable error is %g.\n",maxdiff,prec*0.5*FUDGE);
+#endif
+ if (maxdiff>prec*0.5*FUDGE)
+ {
+ return 0;
+ }
+ else
+ return 1;
+}
+
+struct tng_file
+{
+ FILE *f;
+ int natoms;
+ int chunky;
+ REAL precision;
+ REAL velprecision;
+ int initial_coding;
+ int initial_coding_parameter;
+ int coding;
+ int coding_parameter;
+ int initial_velcoding;
+ int initial_velcoding_parameter;
+ int velcoding;
+ int velcoding_parameter;
+ int speed;
+ int nframes;
+ int nframes_delivered;
+ int writevel;
+ REAL *pos;
+ REAL *vel;
+ int *ipos;
+ int *ivel;
+ unsigned int prec_hi, prec_lo;
+ unsigned int velprec_hi, velprec_lo;
+};
+
+static size_t fwrite_int_le(int *x,FILE *f)
+{
+ unsigned char c[4];
+ unsigned int i=(unsigned int)*x;
+ c[0]=(unsigned char)(i&0xFFU);
+ c[1]=(unsigned char)((i>>8)&0xFFU);
+ c[2]=(unsigned char)((i>>16)&0xFFU);
+ c[3]=(unsigned char)((i>>24)&0xFFU);
+ return fwrite(c,1,4,f);
+}
+
+static size_t fread_int_le(int *x,FILE *f)
+{
+ unsigned char c[4];
+ unsigned int i;
+ size_t n=fread(c,1,4,f);
+ if (n)
+ {
+ i=(((unsigned int)c[3])<<24)|(((unsigned int)c[2])<<16)|(((unsigned int)c[1])<<8)|((unsigned int)c[0]);
+ *x=(int)i;
+ }
+ return n;
+}
+
+static struct tng_file *open_tng_file_write(char *filename,
+ int natoms,int chunky,
+ REAL precision,
+ int writevel,
+ REAL velprecision,
+ int initial_coding,
+ int initial_coding_parameter,
+ int coding,
+ int coding_parameter,
+ int initial_velcoding,
+ int initial_velcoding_parameter,
+ int velcoding,
+ int velcoding_parameter,
+ int speed)
+{
+ struct tng_file *tng_file=malloc(sizeof *tng_file);
+ tng_file->pos=NULL;
+ tng_file->vel=NULL;
+ tng_file->ipos=NULL;
+ tng_file->ivel=NULL;
+ tng_file->nframes=0;
+ tng_file->chunky=chunky;
+ tng_file->precision=precision;
+ tng_file->natoms=natoms;
+ tng_file->writevel=writevel;
+ tng_file->velprecision=velprecision;
+ tng_file->initial_coding=initial_coding;
+ tng_file->initial_coding_parameter=initial_coding_parameter;
+ tng_file->coding=coding;
+ tng_file->coding_parameter=coding_parameter;
+ tng_file->initial_velcoding=initial_velcoding;
+ tng_file->initial_velcoding_parameter=initial_velcoding_parameter;
+ tng_file->velcoding=velcoding;
+ tng_file->velcoding_parameter=velcoding_parameter;
+ tng_file->speed=speed;
+ tng_file->pos=malloc(natoms*chunky*3*sizeof *tng_file->pos);
+ tng_file->f=fopen(filename,"wb");
+ if (writevel)
+ tng_file->vel=malloc(natoms*chunky*3*sizeof *tng_file->vel);
+ fwrite_int_le(&natoms,tng_file->f);
+ return tng_file;
+}
+
+static struct tng_file *open_tng_file_write_int(char *filename,
+ int natoms,int chunky,
+ int writevel,
+ int initial_coding,
+ int initial_coding_parameter,
+ int coding,
+ int coding_parameter,
+ int initial_velcoding,
+ int initial_velcoding_parameter,
+ int velcoding,
+ int velcoding_parameter,
+ int speed)
+{
+ struct tng_file *tng_file=malloc(sizeof *tng_file);
+ tng_file->pos=NULL;
+ tng_file->vel=NULL;
+ tng_file->ipos=NULL;
+ tng_file->ivel=NULL;
+ tng_file->nframes=0;
+ tng_file->chunky=chunky;
+ tng_file->natoms=natoms;
+ tng_file->writevel=writevel;
+ tng_file->initial_coding=initial_coding;
+ tng_file->initial_coding_parameter=initial_coding_parameter;
+ tng_file->coding=coding;
+ tng_file->coding_parameter=coding_parameter;
+ tng_file->initial_velcoding=initial_velcoding;
+ tng_file->initial_velcoding_parameter=initial_velcoding_parameter;
+ tng_file->velcoding=velcoding;
+ tng_file->velcoding_parameter=velcoding_parameter;
+ tng_file->speed=speed;
+ tng_file->ipos=malloc(natoms*chunky*3*sizeof *tng_file->ipos);
+ tng_file->f=fopen(filename,"wb");
+ if (writevel)
+ tng_file->ivel=malloc(natoms*chunky*3*sizeof *tng_file->ivel);
+ fwrite_int_le(&natoms,tng_file->f);
+ return tng_file;
+}
+
+static void flush_tng_frames(struct tng_file *tng_file,
+ unsigned long prec_hi, unsigned long prec_lo,
+ unsigned long velprec_hi, unsigned long velprec_lo)
+{
+ int algo[4];
+ char *buf;
+ int nitems;
+
+ /* Make sure these variables are used to avoid compilation warnings */
+ (void)prec_hi;
+ (void)prec_lo;
+ (void)velprec_hi;
+ (void)velprec_lo;
+
+ fwrite_int_le(&tng_file->nframes,tng_file->f);
+ algo[0]=tng_file->initial_coding;
+ algo[1]=tng_file->initial_coding_parameter;
+ algo[2]=tng_file->coding;
+ algo[3]=tng_file->coding_parameter;
+#ifdef RECOMPRESS
+ buf=tng_compress_pos_int(tng_file->ipos,
+ tng_file->natoms,
+ tng_file->nframes,
+ prec_hi,prec_lo,
+ tng_file->speed,algo,&nitems);
+#else /* RECOMPRESS */
+#ifdef TEST_FLOAT
+ buf=tng_compress_pos_float(tng_file->pos,
+ tng_file->natoms,
+ tng_file->nframes,
+ tng_file->precision,
+ tng_file->speed,algo,&nitems);
+#else /* TEST_FLOAT */
+ buf=tng_compress_pos(tng_file->pos,
+ tng_file->natoms,
+ tng_file->nframes,
+ tng_file->precision,
+ tng_file->speed,algo,&nitems);
+#endif /* TEST_FLOAT */
+#endif /* RECOMPRESS */
+ tng_file->initial_coding=algo[0];
+ tng_file->initial_coding_parameter=algo[1];
+ tng_file->coding=algo[2];
+ tng_file->coding_parameter=algo[3];
+ fwrite_int_le(&nitems,tng_file->f);
+ fwrite(buf,1,nitems,tng_file->f);
+ free(buf);
+ if (tng_file->writevel)
+ {
+ algo[0]=tng_file->initial_velcoding;
+ algo[1]=tng_file->initial_velcoding_parameter;
+ algo[2]=tng_file->velcoding;
+ algo[3]=tng_file->velcoding_parameter;
+#ifdef RECOMPRESS
+ buf=tng_compress_vel_int(tng_file->ivel,
+ tng_file->natoms,
+ tng_file->nframes,
+ velprec_hi,velprec_lo,
+ tng_file->speed,algo,&nitems);
+#else /* RECOMPRESS */
+#ifdef TEST_FLOAT
+ buf=tng_compress_vel_float(tng_file->vel,
+ tng_file->natoms,
+ tng_file->nframes,
+ tng_file->velprecision,
+ tng_file->speed,algo,&nitems);
+#else /* TEST_FLOAT */
+ buf=tng_compress_vel(tng_file->vel,
+ tng_file->natoms,
+ tng_file->nframes,
+ tng_file->velprecision,
+ tng_file->speed,algo,&nitems);
+#endif /* TEST_FLOAT */
+#endif /* RECOMPRESS */
+ tng_file->initial_velcoding=algo[0];
+ tng_file->initial_velcoding_parameter=algo[1];
+ tng_file->velcoding=algo[2];
+ tng_file->velcoding_parameter=algo[3];
+ fwrite_int_le(&nitems,tng_file->f);
+ fwrite(buf,1,nitems,tng_file->f);
+ free(buf);
+ }
+ tng_file->nframes=0;
+}
+
+static void write_tng_file(struct tng_file *tng_file,
+ REAL *pos,REAL *vel)
+{
+ memcpy(tng_file->pos+tng_file->nframes*tng_file->natoms*3,pos,tng_file->natoms*3*sizeof *tng_file->pos);
+ if (tng_file->writevel)
+ memcpy(tng_file->vel+tng_file->nframes*tng_file->natoms*3,vel,tng_file->natoms*3*sizeof *tng_file->vel);
+ tng_file->nframes++;
+ if (tng_file->nframes==tng_file->chunky)
+ flush_tng_frames(tng_file,0,0,0,0);
+}
+
+static void write_tng_file_int(struct tng_file *tng_file,
+ int *ipos,int *ivel,
+ unsigned long prec_hi, unsigned long prec_lo,
+ unsigned long velprec_hi, unsigned long velprec_lo)
+{
+ memcpy(tng_file->ipos+tng_file->nframes*tng_file->natoms*3,ipos,tng_file->natoms*3*sizeof *tng_file->ipos);
+ if (tng_file->writevel)
+ memcpy(tng_file->ivel+tng_file->nframes*tng_file->natoms*3,ivel,tng_file->natoms*3*sizeof *tng_file->ivel);
+ tng_file->nframes++;
+ if (tng_file->nframes==tng_file->chunky)
+ flush_tng_frames(tng_file,prec_hi,prec_lo,velprec_hi,velprec_lo);
+ tng_file->prec_hi=prec_hi;
+ tng_file->prec_lo=prec_lo;
+ tng_file->velprec_hi=velprec_hi;
+ tng_file->velprec_lo=velprec_lo;
+}
+
+static void close_tng_file_write(struct tng_file *tng_file)
+{
+ if (tng_file->nframes)
+ flush_tng_frames(tng_file,tng_file->prec_hi,tng_file->prec_lo,tng_file->velprec_hi,tng_file->velprec_lo);
+ fclose(tng_file->f);
+ free(tng_file->pos);
+ free(tng_file->vel);
+ free(tng_file->ipos);
+ free(tng_file->ivel);
+ free(tng_file);
+}
+
+static struct tng_file *open_tng_file_read(char *filename, int writevel)
+{
+ struct tng_file *tng_file=malloc(sizeof *tng_file);
+ tng_file->pos=NULL;
+ tng_file->vel=NULL;
+ tng_file->ipos=NULL;
+ tng_file->ivel=NULL;
+ tng_file->f=fopen(filename,"rb");
+ tng_file->nframes=0;
+ tng_file->nframes_delivered=0;
+ tng_file->writevel=writevel;
+ if (tng_file->f)
+ fread_int_le(&tng_file->natoms,tng_file->f);
+ else
+ {
+ free(tng_file);
+ tng_file=NULL;
+ }
+ return tng_file;
+}
+
+static struct tng_file *open_tng_file_read_int(char *filename, int writevel)
+{
+ struct tng_file *tng_file=malloc(sizeof *tng_file);
+ tng_file->pos=NULL;
+ tng_file->vel=NULL;
+ tng_file->ipos=NULL;
+ tng_file->ivel=NULL;
+ tng_file->f=fopen(filename,"rb");
+ tng_file->nframes=0;
+ tng_file->nframes_delivered=0;
+ tng_file->writevel=writevel;
+ if (tng_file->f)
+ fread_int_le(&tng_file->natoms,tng_file->f);
+ else
+ {
+ free(tng_file);
+ tng_file=NULL;
+ }
+ return tng_file;
+}
+
+static int read_tng_file(struct tng_file *tng_file,
+ REAL *pos,
+ REAL *vel)
+{
+ if (tng_file->nframes==tng_file->nframes_delivered)
+ {
+ int nitems;
+ char *buf;
+ free(tng_file->pos);
+ free(tng_file->vel);
+ if (!fread_int_le(&tng_file->nframes,tng_file->f))
+ return 1;
+ if (!fread_int_le(&nitems,tng_file->f))
+ return 1;
+ buf=malloc(nitems);
+ if (!fread(buf,1,nitems,tng_file->f))
+ {
+ free(buf);
+ return 1;
+ }
+ tng_file->pos=malloc(tng_file->natoms*tng_file->nframes*3*sizeof *tng_file->pos);
+ if (tng_file->writevel)
+ tng_file->vel=malloc(tng_file->natoms*tng_file->nframes*3*sizeof *tng_file->vel);
+#if 0
+ {
+ int natoms, nframes, algo[4];
+ double precision;
+ int ivel;
+ char *initial_coding, *coding;
+ tng_compress_inquire(buf,&ivel,&natoms,&nframes,&precision,algo);
+ initial_coding=tng_compress_initial_pos_algo(algo);
+ coding=tng_compress_pos_algo(algo);
+ printf("ivel=%d natoms=%d nframes=%d precision=%g initial pos=%s pos=%s\n",ivel,natoms,nframes,precision,initial_coding,coding);
+ }
+#endif
+#ifdef TEST_FLOAT
+ tng_compress_uncompress_float(buf,tng_file->pos);
+#else
+ tng_compress_uncompress(buf,tng_file->pos);
+#endif
+ free(buf);
+ if (tng_file->writevel)
+ {
+ if (!fread_int_le(&nitems,tng_file->f))
+ return 1;
+ buf=malloc(nitems);
+ if (!fread(buf,1,nitems,tng_file->f))
+ {
+ free(buf);
+ return 1;
+ }
+#if 0
+ {
+ int natoms, nframes, algo[4];
+ double precision;
+ int ivel;
+ char *initial_coding, *coding;
+ tng_compress_inquire(buf,&ivel,&natoms,&nframes,&precision,algo);
+ initial_coding=tng_compress_initial_vel_algo(algo);
+ coding=tng_compress_vel_algo(algo);
+ printf("ivel=%d natoms=%d nframes=%d precision=%g initial vel=%s vel=%s\n",ivel,natoms,nframes,precision,initial_coding,coding);
+ }
+#endif
+#ifdef TEST_FLOAT
+ tng_compress_uncompress_float(buf,tng_file->vel);
+#else
+ tng_compress_uncompress(buf,tng_file->vel);
+#endif
+ free(buf);
+ }
+ tng_file->nframes_delivered=0;
+ }
+ memcpy(pos,tng_file->pos+tng_file->nframes_delivered*tng_file->natoms*3,tng_file->natoms*3*sizeof *pos);
+ if (tng_file->writevel)
+ memcpy(vel,tng_file->vel+tng_file->nframes_delivered*tng_file->natoms*3,tng_file->natoms*3*sizeof *vel);
+ tng_file->nframes_delivered++;
+ return 0;
+}
+
+static int read_tng_file_int(struct tng_file *tng_file,
+ int *ipos,
+ int *ivel,
+ unsigned long *prec_hi, unsigned long *prec_lo,
+ unsigned long *velprec_hi, unsigned long *velprec_lo)
+{
+ if (tng_file->nframes==tng_file->nframes_delivered)
+ {
+ int nitems;
+ char *buf;
+ free(tng_file->ipos);
+ free(tng_file->ivel);
+ if (!fread_int_le(&tng_file->nframes,tng_file->f))
+ return 1;
+ if (!fread_int_le(&nitems,tng_file->f))
+ return 1;
+ buf=malloc(nitems);
+ if (!fread(buf,1,nitems,tng_file->f))
+ {
+ free(buf);
+ return 1;
+ }
+ tng_file->ipos=malloc(tng_file->natoms*tng_file->nframes*3*sizeof *tng_file->ipos);
+ if (tng_file->writevel)
+ tng_file->ivel=malloc(tng_file->natoms*tng_file->nframes*3*sizeof *tng_file->ivel);
+ tng_compress_uncompress_int(buf,tng_file->ipos,prec_hi,prec_lo);
+ free(buf);
+ if (tng_file->writevel)
+ {
+ if (!fread_int_le(&nitems,tng_file->f))
+ return 1;
+ buf=malloc(nitems);
+ if (!fread(buf,1,nitems,tng_file->f))
+ {
+ free(buf);
+ return 1;
+ }
+ tng_compress_uncompress_int(buf,tng_file->ivel,velprec_hi,velprec_lo);
+ free(buf);
+ }
+ tng_file->nframes_delivered=0;
+ }
+ memcpy(ipos,tng_file->ipos+tng_file->nframes_delivered*tng_file->natoms*3,tng_file->natoms*3*sizeof *ipos);
+ if (tng_file->writevel)
+ memcpy(ivel,tng_file->ivel+tng_file->nframes_delivered*tng_file->natoms*3,tng_file->natoms*3*sizeof *ivel);
+ tng_file->nframes_delivered++;
+ return 0;
+}
+
+static void close_tng_file_read(struct tng_file *tng_file)
+{
+ free(tng_file->vel);
+ free(tng_file->pos);
+ free(tng_file->ivel);
+ free(tng_file->ipos);
+ fclose(tng_file->f);
+ free(tng_file);
+}
+
+
+
+#ifndef EXPECTED_FILESIZE
+#define EXPECTED_FILESIZE 1
+#endif
+
+#ifndef INITIALVELCODING
+#define INITIALVELCODING -1
+#endif
+#ifndef INITIALVELCODINGPARAMETER
+#define INITIALVELCODINGPARAMETER -1
+#endif
+
+#ifndef SPEED
+#define SPEED 5
+#endif
+
+/* Return value 1 means file error.
+ Return value 4 means coding error in coordinates.
+ Return value 5 means coding error in velocities.
+ Return value 9 means filesize seems too off.
+
+ Return value 100+ means test specific error.
+ */
+static int algotest()
+{
+ int i;
+ int *intbox=malloc(NATOMS*3*sizeof *intbox);
+ int *intvelbox=malloc(NATOMS*3*sizeof *intvelbox);
+#ifdef RECOMPRESS
+ unsigned long pos_prec_hi,pos_prec_lo;
+ unsigned long vel_prec_hi,vel_prec_lo;
+#endif
+ REAL *box1=malloc(NATOMS*STRIDE1*sizeof *box1);
+ REAL *velbox1=malloc(NATOMS*STRIDE1*sizeof *velbox1);
+ int startframe=0;
+ int endframe=NFRAMES;
+#ifdef GEN
+ FILE *file;
+ REAL filesize;
+ REAL *box2=0;
+ REAL *velbox2=0;
+#else
+ int readreturn;
+ REAL *box2=malloc(NATOMS*STRIDE2*sizeof *box2);
+ REAL *velbox2=malloc(NATOMS*STRIDE2*sizeof *velbox2);
+#endif
+#ifdef RECOMPRESS
+ void *dumpfile=open_tng_file_write_int(TNG_COMPRESS_FILES_DIR FILENAME,NATOMS,CHUNKY,
+ WRITEVEL,
+ INITIALCODING,
+ INITIALCODINGPARAMETER,CODING,CODINGPARAMETER,
+ INITIALVELCODING,INITIALVELCODINGPARAMETER,
+ VELCODING,VELCODINGPARAMETER,SPEED);
+ void *dumpfile_recompress=open_tng_file_read_int(TNG_COMPRESS_FILES_DIR RECOMPRESS,WRITEVEL);
+ if (!dumpfile_recompress)
+ {
+ free(intbox);
+ free(intvelbox);
+ free(box1);
+ free(velbox1);
+ if(box2)
+ free(box2);
+ if(velbox2)
+ free(velbox2);
+ return 1;
+ }
+#else /* RECOMPRESS */
+#ifdef GEN
+ void *dumpfile=open_tng_file_write(TNG_COMPRESS_FILES_DIR FILENAME,NATOMS,CHUNKY,
+ PRECISION,WRITEVEL,VELPRECISION,
+ INITIALCODING,
+ INITIALCODINGPARAMETER,CODING,CODINGPARAMETER,
+ INITIALVELCODING,INITIALVELCODINGPARAMETER,
+ VELCODING,VELCODINGPARAMETER,SPEED);
+#else
+ void *dumpfile=open_tng_file_read(TNG_COMPRESS_FILES_DIR FILENAME,WRITEVEL);
+#endif
+#endif /* RECOMPRESS */
+ if (!dumpfile)
+ {
+ free(intbox);
+ free(intvelbox);
+ free(box1);
+ free(velbox1);
+ if(box2)
+ free(box2);
+ if(velbox2)
+ free(velbox2);
+ return 1;
+ }
+ for (i=startframe; i<endframe; i++)
+ {
+#ifdef RECOMPRESS
+ unsigned long prec_hi, prec_lo;
+ unsigned long velprec_hi, velprec_lo;
+ if (read_tng_file_int(dumpfile_recompress,intbox,intvelbox,&prec_hi,&prec_lo,&velprec_hi,&velprec_lo))
+ return 1;
+ write_tng_file_int(dumpfile,intbox,intvelbox,prec_hi,prec_lo,velprec_hi,velprec_lo);
+#else /* RECOMPRESS */
+ genibox(intbox,i);
+ realbox(intbox,box1,STRIDE1);
+#if WRITEVEL
+ genivelbox(intvelbox,i);
+ realvelbox(intvelbox,velbox1,STRIDE1);
+#endif
+#ifdef GEN
+ write_tng_file(dumpfile,box1,velbox1);
+#else /* GEN */
+#ifdef INTTOFLOAT
+ {
+ unsigned long prec_hi, prec_lo;
+ unsigned long velprec_hi, velprec_lo;
+ readreturn=read_tng_file_int(dumpfile,intbox,intvelbox,&prec_hi,&prec_lo,&velprec_hi,&velprec_lo);
+ if (!readreturn)
+ {
+ tng_compress_int_to_float(intbox,prec_hi,prec_lo,NATOMS,1,box2);
+#if WRITEVEL
+ tng_compress_int_to_float(intvelbox,velprec_hi,velprec_lo,NATOMS,1,velbox2);
+#endif
+ }
+ }
+#else /* INTTOFLOAT */
+#ifdef INTTODOUBLE
+ {
+ unsigned long prec_hi, prec_lo;
+ unsigned long velprec_hi, velprec_lo;
+ readreturn=read_tng_file_int(dumpfile,intbox,intvelbox,&prec_hi,&prec_lo,&velprec_hi,&velprec_lo);
+ if (!readreturn)
+ {
+ tng_compress_int_to_double(intbox,prec_hi,prec_lo,NATOMS,1,box2);
+#if WRITEVEL
+ tng_compress_int_to_double(intvelbox,velprec_hi,velprec_lo,NATOMS,1,velbox2);
+#endif
+ }
+ }
+#else /* INTTODOUBLE */
+ readreturn=read_tng_file(dumpfile,box2,velbox2);
+#endif /* INTTODOUBLE */
+#endif /* INTTOFLOAT */
+ if (readreturn==1) /* general read error */
+ {
+ free(intbox);
+ free(intvelbox);
+ free(box1);
+ free(velbox1);
+ if(box2)
+ free(box2);
+ if(velbox2)
+ free(velbox2);
+ return 1;
+ }
+#endif /* GEN */
+#ifndef GEN
+ /* Check for equality of boxes. */
+ if (!equalarr(box1,box2,(REAL)PRECISION,NATOMS,3,STRIDE1,STRIDE2))
+ {
+ free(intbox);
+ free(intvelbox);
+ free(box1);
+ free(velbox1);
+ if(box2)
+ free(box2);
+ if(velbox2)
+ free(velbox2);
+ return 4;
+ }
+#if WRITEVEL
+ if (!equalarr(velbox1,velbox2,(REAL)VELPRECISION,NATOMS,3,STRIDE1,STRIDE2))
+ {
+ free(intbox);
+ free(intvelbox);
+ free(box1);
+ free(velbox1);
+ if(box2)
+ free(box2);
+ if(velbox2)
+ free(velbox2);
+ return 5;
+ }
+#endif
+#endif /* GEN */
+#endif /* RECOMPRESS */
+ }
+#ifdef GEN
+ close_tng_file_write(dumpfile);
+#else
+ close_tng_file_read(dumpfile);
+#endif
+#ifdef RECOMPRESS
+ close_tng_file_read(dumpfile_recompress);
+#endif
+#ifdef GEN
+ /* Check against expected filesize for this test. */
+ if (!(file=fopen(TNG_COMPRESS_FILES_DIR FILENAME,"rb")))
+ {
+ fprintf(stderr,"ERROR: Cannot open file "TNG_COMPRESS_FILES_DIR FILENAME"\n");
+ exit(EXIT_FAILURE);
+ }
+ filesize=0;
+ while(1)
+ {
+ char b;
+ if (!fread(&b,1,1,file))
+ break;
+ filesize++;
+ }
+ fclose(file);
+ if (filesize>0)
+ {
+ if ((fabs(filesize-EXPECTED_FILESIZE)/EXPECTED_FILESIZE)>0.05)
+ {
+ free(intvelbox);
+ free(box1);
+ free(velbox1);
+ if(box2)
+ free(box2);
+ if(velbox2)
+ free(velbox2);
+ return 9;
+ }
+ }
+#endif
+ free(intvelbox);
+ free(box1);
+ free(velbox1);
+ if(box2)
+ free(box2);
+ if(velbox2)
+ free(velbox2);
+ return 0;
+}
+
+int main()
+{
+ int testval;
+ if (sizeof(int)<4)
+ {
+ fprintf(stderr,"ERROR: sizeof(int) is too small: %d<4\n",(int)sizeof(int));
+ exit(EXIT_FAILURE);
+ }
+#ifdef GEN
+ printf("Tng compress testsuite generating (writing) test: %s\n",TESTNAME);
+#else
+ printf("Tng compress testsuite running (reading) test: %s\n",TESTNAME);
+#endif
+ testval=algotest();
+ if (testval==0)
+ printf("Passed.\n");
+ else if (testval==1)
+ {
+ printf("ERROR: File error.\n");
+ exit(EXIT_FAILURE);
+ }
+ else if (testval==4)
+ {
+ printf("ERROR: Read coding error in coordinates.\n");
+ exit(EXIT_FAILURE);
+ }
+ else if (testval==5)
+ {
+ printf("ERROR: Read coding error in velocities.\n");
+ exit(EXIT_FAILURE);
+ }
+ else if (testval==9)
+ {
+ printf("ERROR: Generated filesize differs too much.\n");
+ exit(EXIT_FAILURE);
+ }
+ else
+ {
+ printf("ERROR: Unknown error.\n");
+ exit(EXIT_FAILURE);
+ }
+ return 0;
+}
--- /dev/null
+#ifdef TNG_BUILD_OPENMP_EXAMPLES
+
+# include <stdlib.h>
+# include <stdio.h>
+# include <time.h>
+# include <math.h>
+# include <omp.h>
+# include "tng_io.h"
+
+int main ();
+void compute ( int np, int nd, double pos[], double vel[],
+ double mass, double f[], double *pot, double *kin );
+double dist ( int nd, double r1[], double r2[], double dr[] );
+void initialize ( int np, int nd, double box[], int *seed, double pos[],
+ double vel[], double acc[] );
+double r8_uniform_01 ( int *seed );
+void timestamp ( void );
+void update ( int np, int nd, double pos[], double vel[], double f[],
+ double acc[], double mass, double dt );
+
+/******************************************************************************/
+
+int main ()
+
+/******************************************************************************/
+/*
+ Purpose:
+
+ MAIN is the main program for MD_OPENMP.
+
+ Discussion:
+
+ MD implements a simple molecular dynamics simulation.
+
+ The program uses Open MP directives to allow parallel computation.
+
+ The velocity Verlet time integration scheme is used.
+
+ The particles interact with a central pair potential.
+
+ Output of the program is saved in the TNG format, which is why this
+ code is included in the TNG API release.
+
+ Licensing:
+
+ This code is distributed under the GNU LGPL license.
+
+ Modified:
+
+ 8 Jan 2013
+
+ Author:
+
+ Original FORTRAN77 version by Bill Magro.
+ C version by John Burkardt.
+ TNG trajectory output by Magnus Lundborg.
+
+ Parameters:
+
+ None
+*/
+{
+ double *acc;
+ double *box;
+ double *box_shape;
+ double dt = 0.0002;
+ double e0;
+ double *force;
+ int i;
+ double kinetic;
+ double mass = 1.0;
+ int nd = 3;
+ int np = 50;
+ double *pos;
+ double potential;
+ int proc_num;
+ int seed = 123456789;
+ int step;
+ int step_num = 50000;
+ int step_print;
+ int step_print_index;
+ int step_print_num;
+ int step_save;
+ int64_t sparse_save;
+ double *vel;
+ double wtime;
+ tng_trajectory_t traj;
+ tng_molecule_t molecule;
+ tng_chain_t chain;
+ tng_residue_t residue;
+ tng_atom_t atom;
+ int64_t n_frames_per_frame_set;
+ int frames_saved_cnt = 0;
+
+ timestamp ( );
+
+ proc_num = omp_get_num_procs ( );
+
+ acc = ( double * ) malloc ( nd * np * sizeof ( double ) );
+ box = ( double * ) malloc ( nd * sizeof ( double ) );
+ box_shape = (double *) malloc (9 * sizeof (double));
+ force = ( double * ) malloc ( nd * np * sizeof ( double ) );
+ pos = ( double * ) malloc ( nd * np * sizeof ( double ) );
+ vel = ( double * ) malloc ( nd * np * sizeof ( double ) );
+
+ printf ( "\n" );
+ printf ( "MD_OPENMP\n" );
+ printf ( " C/OpenMP version\n" );
+ printf ( "\n" );
+ printf ( " A molecular dynamics program.\n" );
+
+ printf ( "\n" );
+ printf ( " NP, the number of particles in the simulation is %d\n", np );
+ printf ( " STEP_NUM, the number of time steps, is %d\n", step_num );
+ printf ( " DT, the size of each time step, is %f\n", dt );
+
+ printf ( "\n" );
+ printf ( " Number of processors available = %d\n", proc_num );
+ printf ( " Number of threads = %d\n", omp_get_max_threads ( ) );
+
+
+ printf("\n");
+ printf(" Initializing trajectory storage.\n");
+ if(tng_trajectory_init(&traj) != TNG_SUCCESS)
+ {
+ tng_trajectory_destroy(&traj);
+ printf(" Cannot init trajectory.\n");
+ exit(1);
+ }
+#ifdef TNG_EXAMPLE_FILES_DIR
+ tng_output_file_set(traj, TNG_EXAMPLE_FILES_DIR "tng_md_out.tng");
+#else
+ tng_output_file_set(traj, "/tmp/tng_md_out.tng");
+#endif
+
+
+
+ /* Set molecules data */
+ printf(" Creating molecules in trajectory.\n");
+ tng_molecule_add(traj, "water", &molecule);
+ tng_molecule_chain_add(traj, molecule, "W", &chain);
+ tng_chain_residue_add(traj, chain, "WAT", &residue);
+ if(tng_residue_atom_add(traj, residue, "O", "O", &atom) == TNG_CRITICAL)
+ {
+ tng_trajectory_destroy(&traj);
+ printf(" Cannot create molecules.\n");
+ exit(1);
+ }
+ tng_molecule_cnt_set(traj, molecule, np);
+
+
+/*
+ Set the dimensions of the box.
+*/
+ for(i = 0; i < 9; i++)
+ {
+ box_shape[i] = 0.0;
+ }
+ for ( i = 0; i < nd; i++ )
+ {
+ box[i] = 10.0;
+ box_shape[i*nd + i] = box[i];
+ }
+
+
+ /* Add the box shape data block and write the file headers */
+ if(tng_data_block_add(traj, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE", TNG_DOUBLE_DATA,
+ TNG_NON_TRAJECTORY_BLOCK, 1, 9, 1, TNG_UNCOMPRESSED,
+ box_shape) == TNG_CRITICAL ||
+ tng_file_headers_write(traj, TNG_USE_HASH) == TNG_CRITICAL)
+ {
+ free(box_shape);
+ tng_trajectory_destroy(&traj);
+ printf(" Cannot write trajectory headers and box shape.\n");
+ exit(1);
+ }
+ free(box_shape);
+
+ printf ( "\n" );
+ printf ( " Initializing positions, velocities, and accelerations.\n" );
+/*
+ Set initial positions, velocities, and accelerations.
+*/
+ initialize ( np, nd, box, &seed, pos, vel, acc );
+/*
+ Compute the forces and energies.
+*/
+ printf ( "\n" );
+ printf ( " Computing initial forces and energies.\n" );
+
+ compute ( np, nd, pos, vel, mass, force, &potential, &kinetic );
+
+ e0 = potential + kinetic;
+
+ /* Saving frequency */
+ step_save = 500;
+
+ step_print = 0;
+ step_print_index = 0;
+ step_print_num = 10;
+ sparse_save = 100;
+
+/*
+ This is the main time stepping loop:
+ Compute forces and energies,
+ Update positions, velocities, accelerations.
+*/
+ printf(" Every %d steps particle positions, velocities and forces are\n",
+ step_save);
+ printf(" saved to a TNG trajectory file.\n");
+ printf ( "\n" );
+ printf ( " At certain step intervals, we report the potential and kinetic energies.\n" );
+ printf ( " The sum of these energies should be a constant.\n" );
+ printf ( " As an accuracy check, we also print the relative error\n" );
+ printf ( " in the total energy.\n" );
+ printf ( "\n" );
+ printf ( " Step Potential Kinetic (P+K-E0)/E0\n" );
+ printf ( " Energy P Energy K Relative Energy Error\n" );
+ printf ( "\n" );
+
+ step = 0;
+ printf ( " %8d %14f %14f %14e\n",
+ step, potential, kinetic, ( potential + kinetic - e0 ) / e0 );
+ step_print_index++;
+ step_print = ( step_print_index * step_num ) / step_print_num;
+
+ /* Create a frame set for writing data */
+ tng_num_frames_per_frame_set_get(traj, &n_frames_per_frame_set);
+ if(tng_frame_set_new(traj, 0,
+ n_frames_per_frame_set) != TNG_SUCCESS)
+ {
+ printf("Error creating frame set %d. %s: %d\n",
+ i, __FILE__, __LINE__);
+ exit(1);
+ }
+
+ /* Add empty data blocks */
+ if(tng_particle_data_block_add(traj, TNG_TRAJ_POSITIONS,
+ "POSITIONS",
+ TNG_DOUBLE_DATA,
+ TNG_TRAJECTORY_BLOCK,
+ n_frames_per_frame_set, 3,
+ 1, 0, np,
+ TNG_UNCOMPRESSED,
+ 0) != TNG_SUCCESS)
+ {
+ printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ exit(1);
+ }
+ if(tng_particle_data_block_add(traj, TNG_TRAJ_VELOCITIES,
+ "VELOCITIES",
+ TNG_DOUBLE_DATA,
+ TNG_TRAJECTORY_BLOCK,
+ n_frames_per_frame_set, 3,
+ 1, 0, np,
+ TNG_UNCOMPRESSED,
+ 0) != TNG_SUCCESS)
+ {
+ printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ exit(1);
+ }
+ if(tng_particle_data_block_add(traj, TNG_TRAJ_FORCES,
+ "FORCES",
+ TNG_DOUBLE_DATA,
+ TNG_TRAJECTORY_BLOCK,
+ n_frames_per_frame_set, 3,
+ 1, 0, np,
+ TNG_UNCOMPRESSED, 0) != TNG_SUCCESS)
+ {
+ printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ exit(1);
+ }
+
+ /* There is no standard ID for potential energy. Pick one. The
+ potential energy will not be saved every frame - it is sparsely
+ saved. */
+ if(tng_data_block_add(traj, 10101,
+ "POTENTIAL ENERGY",
+ TNG_DOUBLE_DATA,
+ TNG_TRAJECTORY_BLOCK,
+ n_frames_per_frame_set, 1,
+ sparse_save, TNG_UNCOMPRESSED,
+ 0) != TNG_SUCCESS)
+ {
+ printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ exit(1);
+ }
+
+ /* Write the frame set to disk */
+ if(tng_frame_set_write(traj, TNG_USE_HASH) != TNG_SUCCESS)
+ {
+ printf("Error writing frame set. %s: %d\n", __FILE__, __LINE__);
+ exit(1);
+ }
+
+ wtime = omp_get_wtime ( );
+
+ if(tng_frame_particle_data_write(traj, frames_saved_cnt,
+ TNG_TRAJ_POSITIONS, 0, np,
+ pos, TNG_USE_HASH) != TNG_SUCCESS)
+ {
+ printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ exit(1);
+ }
+ if(tng_frame_particle_data_write(traj, frames_saved_cnt,
+ TNG_TRAJ_VELOCITIES, 0, np,
+ vel, TNG_USE_HASH) != TNG_SUCCESS)
+ {
+ printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ exit(1);
+ }
+ if(tng_frame_particle_data_write(traj, frames_saved_cnt,
+ TNG_TRAJ_FORCES, 0, np,
+ force, TNG_USE_HASH) != TNG_SUCCESS)
+ {
+ printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ exit(1);
+ }
+ if(step % (step_save * sparse_save) == 0)
+ {
+ if(tng_frame_data_write(traj, frames_saved_cnt, 10101, &potential,
+ TNG_USE_HASH) != TNG_SUCCESS)
+ {
+ printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ exit(1);
+ }
+ }
+ frames_saved_cnt++;
+
+ for ( step = 1; step < step_num; step++ )
+ {
+ compute ( np, nd, pos, vel, mass, force, &potential, &kinetic );
+
+ if ( step == step_print )
+ {
+ printf ( " %8d %14f %14f %14e\n", step, potential, kinetic,
+ ( potential + kinetic - e0 ) / e0 );
+ step_print_index++;
+ step_print = ( step_print_index * step_num ) / step_print_num;
+ }
+ if(step % step_save == 0)
+ {
+ if(tng_frame_particle_data_write(traj, frames_saved_cnt,
+ TNG_TRAJ_POSITIONS, 0, np,
+ pos, TNG_USE_HASH) != TNG_SUCCESS)
+ {
+ printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ exit(1);
+ }
+ if(tng_frame_particle_data_write(traj, frames_saved_cnt,
+ TNG_TRAJ_VELOCITIES, 0, np,
+ vel, TNG_USE_HASH) != TNG_SUCCESS)
+ {
+ printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ exit(1);
+ }
+ if(tng_frame_particle_data_write(traj, frames_saved_cnt,
+ TNG_TRAJ_FORCES, 0, np,
+ force, TNG_USE_HASH) != TNG_SUCCESS)
+ {
+ printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ exit(1);
+ }
+ if(step % (step_save * sparse_save) == 0)
+ {
+ if(tng_frame_data_write(traj, frames_saved_cnt, 10101, &potential,
+ TNG_USE_HASH) != TNG_SUCCESS)
+ {
+ printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ exit(1);
+ }
+ }
+ frames_saved_cnt++;
+ }
+ update ( np, nd, pos, vel, force, acc, mass, dt );
+ }
+ wtime = omp_get_wtime ( ) - wtime;
+
+ printf ( "\n" );
+ printf ( " Elapsed time for main computation:\n" );
+ printf ( " %f seconds.\n", wtime );
+
+ free ( acc );
+ free ( box );
+ free ( force );
+ free ( pos );
+ free ( vel );
+/*
+ Terminate.
+*/
+ tng_trajectory_destroy(&traj);
+
+ printf ( "\n" );
+ printf ( "MD_OPENMP\n" );
+ printf ( " Normal end of execution.\n" );
+
+ printf ( "\n" );
+ timestamp ( );
+
+ return 0;
+}
+/******************************************************************************/
+
+void compute ( int np, int nd, double pos[], double vel[],
+ double mass, double f[], double *pot, double *kin )
+
+/******************************************************************************/
+/*
+ Purpose:
+
+ COMPUTE computes the forces and energies.
+
+ Discussion:
+
+ The computation of forces and energies is fully parallel.
+
+ The potential function V(X) is a harmonic well which smoothly
+ saturates to a maximum value at PI/2:
+
+ v(x) = ( sin ( min ( x, PI2 ) ) )**2
+
+ The derivative of the potential is:
+
+ dv(x) = 2.0 * sin ( min ( x, PI2 ) ) * cos ( min ( x, PI2 ) )
+ = sin ( 2.0 * min ( x, PI2 ) )
+
+ Licensing:
+
+ This code is distributed under the GNU LGPL license.
+
+ Modified:
+
+ 21 November 2007
+
+ Author:
+
+ Original FORTRAN77 version by Bill Magro.
+ C version by John Burkardt.
+
+ Parameters:
+
+ Input, int NP, the number of particles.
+
+ Input, int ND, the number of spatial dimensions.
+
+ Input, double POS[ND*NP], the position of each particle.
+
+ Input, double VEL[ND*NP], the velocity of each particle.
+
+ Input, double MASS, the mass of each particle.
+
+ Output, double F[ND*NP], the forces.
+
+ Output, double *POT, the total potential energy.
+
+ Output, double *KIN, the total kinetic energy.
+*/
+{
+ double d;
+ double d2;
+ int i;
+ int j;
+ int k;
+ double ke;
+ double pe;
+ double PI2 = 3.141592653589793 / 2.0;
+ double rij[3];
+
+ pe = 0.0;
+ ke = 0.0;
+
+# pragma omp parallel \
+ shared ( f, nd, np, pos, vel ) \
+ private ( i, j, k, rij, d, d2 )
+
+
+# pragma omp for reduction ( + : pe, ke )
+ for ( k = 0; k < np; k++ )
+ {
+/*
+ Compute the potential energy and forces.
+*/
+ for ( i = 0; i < nd; i++ )
+ {
+ f[i+k*nd] = 0.0;
+ }
+
+ for ( j = 0; j < np; j++ )
+ {
+ if ( k != j )
+ {
+ d = dist ( nd, pos+k*nd, pos+j*nd, rij );
+/*
+ Attribute half of the potential energy to particle J.
+*/
+ if ( d < PI2 )
+ {
+ d2 = d;
+ }
+ else
+ {
+ d2 = PI2;
+ }
+
+ pe = pe + 0.5 * pow ( sin ( d2 ), 2 );
+
+ for ( i = 0; i < nd; i++ )
+ {
+ f[i+k*nd] = f[i+k*nd] - rij[i] * sin ( 2.0 * d2 ) / d;
+ }
+ }
+ }
+/*
+ Compute the kinetic energy.
+*/
+ for ( i = 0; i < nd; i++ )
+ {
+ ke = ke + vel[i+k*nd] * vel[i+k*nd];
+ }
+ }
+
+ ke = ke * 0.5 * mass;
+
+ *pot = pe;
+ *kin = ke;
+
+ return;
+}
+/******************************************************************************/
+
+double dist ( int nd, double r1[], double r2[], double dr[] )
+
+/******************************************************************************/
+/*
+ Purpose:
+
+ DIST computes the displacement (and its norm) between two particles.
+
+ Licensing:
+
+ This code is distributed under the GNU LGPL license.
+
+ Modified:
+
+ 21 November 2007
+
+ Author:
+
+ Original FORTRAN77 version by Bill Magro.
+ C version by John Burkardt.
+
+ Parameters:
+
+ Input, int ND, the number of spatial dimensions.
+
+ Input, double R1[ND], R2[ND], the positions of the particles.
+
+ Output, double DR[ND], the displacement vector.
+
+ Output, double D, the Euclidean norm of the displacement.
+*/
+{
+ double d;
+ int i;
+
+ d = 0.0;
+ for ( i = 0; i < nd; i++ )
+ {
+ dr[i] = r1[i] - r2[i];
+ d = d + dr[i] * dr[i];
+ }
+ d = sqrt ( d );
+
+ return d;
+}
+/******************************************************************************/
+
+void initialize ( int np, int nd, double box[], int *seed, double pos[],
+ double vel[], double acc[] )
+
+/******************************************************************************/
+/*
+ Purpose:
+
+ INITIALIZE initializes the positions, velocities, and accelerations.
+
+ Licensing:
+
+ This code is distributed under the GNU LGPL license.
+
+ Modified:
+
+ 21 November 2007
+
+ Author:
+
+ Original FORTRAN77 version by Bill Magro.
+ C version by John Burkardt.
+
+ Parameters:
+
+ Input, int NP, the number of particles.
+
+ Input, int ND, the number of spatial dimensions.
+
+ Input, double BOX[ND], specifies the maximum position
+ of particles in each dimension.
+
+ Input, int *SEED, a seed for the random number generator.
+
+ Output, double POS[ND*NP], the position of each particle.
+
+ Output, double VEL[ND*NP], the velocity of each particle.
+
+ Output, double ACC[ND*NP], the acceleration of each particle.
+*/
+{
+ int i;
+ int j;
+/*
+ Give the particles random positions within the box.
+*/
+ for ( i = 0; i < nd; i++ )
+ {
+ for ( j = 0; j < np; j++ )
+ {
+ pos[i+j*nd] = box[i] * r8_uniform_01 ( seed );
+ }
+ }
+
+ for ( j = 0; j < np; j++ )
+ {
+ for ( i = 0; i < nd; i++ )
+ {
+ vel[i+j*nd] = 0.0;
+ }
+ }
+ for ( j = 0; j < np; j++ )
+ {
+ for ( i = 0; i < nd; i++ )
+ {
+ acc[i+j*nd] = 0.0;
+ }
+ }
+ return;
+}
+/******************************************************************************/
+
+double r8_uniform_01 ( int *seed )
+
+/******************************************************************************/
+/*
+ Purpose:
+
+ R8_UNIFORM_01 is a unit pseudorandom R8.
+
+ Discussion:
+
+ This routine implements the recursion
+
+ seed = 16807 * seed mod ( 2**31 - 1 )
+ unif = seed / ( 2**31 - 1 )
+
+ The integer arithmetic never requires more than 32 bits,
+ including a sign bit.
+
+ Licensing:
+
+ This code is distributed under the GNU LGPL license.
+
+ Modified:
+
+ 11 August 2004
+
+ Author:
+
+ John Burkardt
+
+ Reference:
+
+ Paul Bratley, Bennett Fox, Linus Schrage,
+ A Guide to Simulation,
+ Springer Verlag, pages 201-202, 1983.
+
+ Bennett Fox,
+ Algorithm 647:
+ Implementation and Relative Efficiency of Quasirandom
+ Sequence Generators,
+ ACM Transactions on Mathematical Software,
+ Volume 12, Number 4, pages 362-376, 1986.
+
+ Parameters:
+
+ Input/output, int *SEED, a seed for the random number generator.
+
+ Output, double R8_UNIFORM_01, a new pseudorandom variate, strictly between
+ 0 and 1.
+*/
+{
+ int k;
+ double r;
+
+ k = *seed / 127773;
+
+ *seed = 16807 * ( *seed - k * 127773 ) - k * 2836;
+
+ if ( *seed < 0 )
+ {
+ *seed = *seed + 2147483647;
+ }
+
+ r = ( double ) ( *seed ) * 4.656612875E-10;
+
+ return r;
+}
+/******************************************************************************/
+
+void timestamp ( void )
+
+/******************************************************************************/
+/*
+ Purpose:
+
+ TIMESTAMP prints the current YMDHMS date as a time stamp.
+
+ Example:
+
+ 31 May 2001 09:45:54 AM
+
+ Licensing:
+
+ This code is distributed under the GNU LGPL license.
+
+ Modified:
+
+ 24 September 2003
+
+ Author:
+
+ John Burkardt
+
+ Parameters:
+
+ None
+*/
+{
+# define TIME_SIZE 40
+
+ static char time_buffer[TIME_SIZE];
+ const struct tm *tm;
+ time_t now;
+
+ now = time ( NULL );
+ tm = localtime ( &now );
+
+ strftime ( time_buffer, TIME_SIZE, "%d %B %Y %I:%M:%S %p", tm );
+
+ printf ( "%s\n", time_buffer );
+
+ return;
+# undef TIME_SIZE
+}
+/******************************************************************************/
+
+void update ( int np, int nd, double pos[], double vel[], double f[],
+ double acc[], double mass, double dt )
+
+/******************************************************************************/
+/*
+ Purpose:
+
+ UPDATE updates positions, velocities and accelerations.
+
+ Discussion:
+
+ The time integration is fully parallel.
+
+ A velocity Verlet algorithm is used for the updating.
+
+ x(t+dt) = x(t) + v(t) * dt + 0.5 * a(t) * dt * dt
+ v(t+dt) = v(t) + 0.5 * ( a(t) + a(t+dt) ) * dt
+ a(t+dt) = f(t) / m
+
+ Licensing:
+
+ This code is distributed under the GNU LGPL license.
+
+ Modified:
+
+ 17 April 2009
+
+ Author:
+
+ Original FORTRAN77 version by Bill Magro.
+ C version by John Burkardt.
+
+ Parameters:
+
+ Input, int NP, the number of particles.
+
+ Input, int ND, the number of spatial dimensions.
+
+ Input/output, double POS[ND*NP], the position of each particle.
+
+ Input/output, double VEL[ND*NP], the velocity of each particle.
+
+ Input, double F[ND*NP], the force on each particle.
+
+ Input/output, double ACC[ND*NP], the acceleration of each particle.
+
+ Input, double MASS, the mass of each particle.
+
+ Input, double DT, the time step.
+*/
+{
+ int i;
+ int j;
+ double rmass;
+
+ rmass = 1.0 / mass;
+
+# pragma omp parallel \
+ shared ( acc, dt, f, nd, np, pos, rmass, vel ) \
+ private ( i, j )
+
+# pragma omp for
+ for ( j = 0; j < np; j++ )
+ {
+ for ( i = 0; i < nd; i++ )
+ {
+ pos[i+j*nd] = pos[i+j*nd] + vel[i+j*nd] * dt + 0.5 * acc[i+j*nd] * dt * dt;
+ vel[i+j*nd] = vel[i+j*nd] + 0.5 * dt * ( f[i+j*nd] * rmass + acc[i+j*nd] );
+ acc[i+j*nd] = f[i+j*nd] * rmass;
+ }
+ }
+
+ return;
+}
+
+#endif
--- /dev/null
+ program main
+
+c*********************************************************************72
+c
+cc MAIN is the main program for MD_OPENMP.
+c
+c Discussion:
+c
+c The program implements a simple molecular dynamics simulation.
+c
+c The program uses Open MP directives to allow parallel computation.
+c
+c The velocity Verlet time integration scheme is used.
+c
+c The particles interact with a central pair potential.
+c
+c Output of the program is saved in the TNG format, which is why this
+c code is included in the TNG API release.
+c
+c Licensing:
+c
+c This code is distributed under the GNU LGPL license.
+c
+c Modified:
+c
+c 8 Jan 2013
+c
+c Author:
+c
+c Original FORTRAN90 version by Bill Magro.
+c FORTRAN77 version by John Burkardt.
+c TNG trajectory output by Magnus Lundborg.
+c
+c Parameters:
+c
+c None
+c
+ implicit none
+
+ include 'omp_lib.h'
+
+ integer nd
+ parameter ( nd = 3 )
+ integer np
+ parameter ( np = 250 )
+ integer step_num
+ parameter ( step_num = 1000 )
+
+ double precision acc(nd,np)
+ double precision box(nd)
+ double precision box_shape(9)
+ double precision dt
+ parameter ( dt = 0.0001D+00 )
+ double precision e0
+ double precision force(nd,np)
+ integer i
+ integer id
+ double precision kinetic
+ double precision mass
+ parameter ( mass = 1.0D+00 )
+ double precision pos(nd,np)
+ double precision potential
+ integer proc_num
+ integer seed
+ integer step
+ integer step_print
+ integer step_print_index
+ integer step_print_num
+ integer step_save
+ integer*8 sparse_save
+ integer thread_num
+ double precision vel(nd,np)
+ double precision wtime
+
+c
+c Cray pointers are not standard fortran 77, but must be used to allocate
+c memory properly.
+c
+ pointer (traj_p, traj)
+ pointer (molecule_p, molecule)
+ pointer (chain_p, chain)
+ pointer (residue_p, residue)
+ pointer (atom_p, atom)
+ byte traj
+ byte molecule
+ byte chain
+ byte residue
+ byte atom
+
+c
+c The TNG functions expect 64 bit integers
+c
+ integer*8 n_frames_per_frame_set
+ integer*8 frames_saved_cnt
+ integer*8 tng_n_particles
+
+c
+c These constants are also defined in tng_io.h, but need to
+c set in fortran as well. This can be copied to any fortran
+c source code using the tng_io library.
+c
+ integer*8 TNG_UNCOMPRESSED
+ parameter ( TNG_UNCOMPRESSED = 0)
+ integer TNG_NON_TRAJECTORY_BLOCK
+ parameter ( TNG_NON_TRAJECTORY_BLOCK = 0)
+ integer TNG_TRAJECTORY_BLOCK
+ parameter ( TNG_TRAJECTORY_BLOCK = 1)
+ integer*8 TNG_GENERAL_INFO
+ parameter ( TNG_GENERAL_INFO = 0 )
+ integer*8 TNG_MOLECULES
+ parameter ( TNG_MOLECULES = 1 )
+ integer*8 TNG_TRAJECTORY_FRAME_SET
+ parameter ( TNG_TRAJECTORY_FRAME_SET = 2 )
+ integer*8 TNG_PARTICLE_MAPPING
+ parameter ( TNG_PARTICLE_MAPPING = 3 )
+ integer*8 TNG_TRAJ_BOX_SHAPE
+ parameter ( TNG_TRAJ_BOX_SHAPE = 10000 )
+ integer*8 TNG_TRAJ_POSITIONS
+ parameter ( TNG_TRAJ_POSITIONS = 10001 )
+ integer*8 TNG_TRAJ_VELOCITIES
+ parameter ( TNG_TRAJ_VELOCITIES = 10002 )
+ integer*8 TNG_TRAJ_FORCES
+ parameter ( TNG_TRAJ_FORCES = 10003 )
+ integer TNG_SKIP_HASH
+ parameter ( TNG_SKIP_HASH = 0 )
+ integer TNG_USE_HASH
+ parameter ( TNG_USE_HASH = 1 )
+ integer TNG_CHAR_DATA
+ parameter ( TNG_CHAR_DATA = 0 )
+ integer TNG_INT_DATA
+ parameter ( TNG_INT_DATA = 1 )
+ integer TNG_FLOAT_DATA
+ parameter ( TNG_FLOAT_DATA = 2 )
+ integer TNG_DOUBLE_DATA
+ parameter ( TNG_DOUBLE_DATA = 3 )
+
+ call timestamp ( )
+
+ write ( *, '(a)' ) ' '
+ write ( *, '(a)' ) 'MD_OPENMP'
+ write ( *, '(a)' ) ' FORTRAN77/OpenMP version'
+ write ( *, '(a)' ) ' '
+ write ( *, '(a)' ) ' A molecular dynamics program.'
+ write ( *, '(a)' ) ' '
+ write ( *, '(a,i8)' )
+ & ' NP, the number of particles in the simulation is ', np
+ write ( *, '(a,i8)' )
+ & ' STEP_NUM, the number of time steps, is ', step_num
+ write ( *, '(a,g14.6)' )
+ & ' DT, the size of each time step, is ', dt
+ write ( *, '(a)' ) ' '
+ write ( *, '(a,i8)' )
+ & ' The number of processors = ', omp_get_num_procs ( )
+ write ( *, '(a,i8)' )
+ & ' The number of threads = ', omp_get_max_threads ( )
+
+ write ( *, '(a)' ) ' '
+ write ( *, '(a)' ) ' Initializing trajectory storage.'
+ call tng_trajectory_init(traj_p)
+
+c
+c N.B. The TNG output file should be modified according to needs
+c
+ call tng_output_file_set(traj, "/tmp/tng_md_out_f77.tng")
+
+ write ( *, '(a)' ) ' Creating molecules in trajectory.'
+ tng_n_particles = np
+ call tng_molecule_add(traj, "water", molecule_p)
+ call tng_molecule_chain_add(traj, molecule, "W", chain_p)
+ call tng_chain_residue_add(traj, chain, "WAT", residue_p)
+ call tng_residue_atom_add(traj, residue, "O", "O", atom_p)
+ call tng_molecule_cnt_set(traj, molecule, tng_n_particles)
+c
+c Set the dimensions of the box.
+c
+ do i = 1, 9
+ box_shape(i) = 0.0
+ end do
+ do i = 1, nd
+ box(i) = 10.0D+00
+ box_shape(i*nd + i) = box(i)
+ end do
+
+c
+c Add the box shape data block
+c
+ call tng_data_block_add(traj, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
+ & TNG_DOUBLE_DATA, TNG_NON_TRAJECTORY_BLOCK, int(1, 8),
+ & int(9, 8), int(1, 8), TNG_UNCOMPRESSED, box_shape)
+
+c
+c Write the file headers
+c
+ call tng_file_headers_write(traj, TNG_USE_HASH)
+
+c
+c Set initial positions, velocities, and accelerations.
+c
+ write ( *, '(a)' )
+ & ' Initializing positions, velocities, and accelerations.'
+ seed = 123456789
+ call initialize ( np, nd, box, seed, pos, vel, acc )
+c
+c Compute the forces and energies.
+c
+ write ( *, '(a)' ) ' '
+ write ( *, '(a)' ) ' Computing initial forces and energies.'
+
+ call compute ( np, nd, pos, vel, mass, force, potential,
+ & kinetic )
+
+ e0 = potential + kinetic
+
+c
+c Saving frequency
+c
+ step_save = 5
+
+ step_print = 0
+ step_print_index = 0
+ step_print_num = 10
+ sparse_save = 10
+
+ frames_saved_cnt = 0
+
+c
+c This is the main time stepping loop.
+c
+ write ( *, '(a,i4,a)' ) ' Every', step_save,
+ & ' steps particle positions, velocities and forces are'
+ write ( *, '(a)' ) ' saved to a TNG trajectory file.'
+ write ( *, '(a)' )
+ write ( *, '(a)' )
+ & ' At each step, we report the potential and kinetic energies.'
+ write ( *, '(a)' )
+ & ' The sum of these energies should be a constant.'
+ write ( *, '(a)' )
+ & ' As an accuracy check, we also print the relative error'
+ write ( *, '(a)' ) ' in the total energy.'
+ write ( *, '(a)' ) ' '
+ write ( *, '(a)' )
+ & ' Step Potential Kinetic (P+K-E0)/E0'
+ write ( *, '(a)' )
+ & ' Energy P Energy K ' //
+ & 'Relative Energy Error'
+ write ( *, '(a)' ) ' '
+
+ step = 0
+ write ( *, '(2x,i8,2x,g14.6,2x,g14.6,2x,g14.6)' )
+ & step, potential, kinetic, ( potential + kinetic - e0 ) / e0
+ step_print_index = step_print_index + 1
+ step_print = ( step_print_index * step_num ) / step_print_num
+
+c
+c Create a frame set for writing data
+c
+ call tng_num_frames_per_frame_set_get(traj,
+ & n_frames_per_frame_set)
+ call tng_frame_set_new(traj, int(0, 8), n_frames_per_frame_set)
+
+c
+c Add empty data blocks.
+c
+ call tng_particle_data_block_add(traj, TNG_TRAJ_POSITIONS,
+ & "POSITIONS", TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
+ & n_frames_per_frame_set, int(3, 8), int(1, 8), int(0, 8),
+ & tng_n_particles, TNG_UNCOMPRESSED, %VAL(int(0, 8)))
+
+ call tng_particle_data_block_add(traj, TNG_TRAJ_VELOCITIES,
+ & "VELOCITIES", TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
+ & n_frames_per_frame_set, int(3, 8), int(1, 8), int(0, 8),
+ & tng_n_particles, TNG_UNCOMPRESSED, %VAL(int(0, 8)))
+
+ call tng_particle_data_block_add(traj, TNG_TRAJ_FORCES,
+ & "FORCES", TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
+ & n_frames_per_frame_set, int(3, 8), int(1, 8), int(0, 8),
+ & tng_n_particles, TNG_UNCOMPRESSED, %VAL(int(0, 8)))
+
+c
+c The potential energy data block is saved sparsely.
+c
+ call tng_data_block_add(traj, int(10101, 8),
+ & "POTENTIAL ENERGY", TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
+ & n_frames_per_frame_set, int(1, 8), sparse_save,
+ & TNG_UNCOMPRESSED, %VAL(int(0, 8)))
+
+
+c
+c Write the frame set to disk
+c
+ call tng_frame_set_write(traj, TNG_USE_HASH)
+
+ wtime = omp_get_wtime ( )
+
+ do step = 1, step_num
+
+ call compute ( np, nd, pos, vel, mass, force, potential,
+ & kinetic )
+
+ if ( step .eq. step_print ) then
+
+ write ( *, '(2x,i8,2x,g14.6,2x,g14.6,2x,g14.6)' )
+ & step, potential, kinetic, ( potential + kinetic - e0 ) / e0
+
+ step_print_index = step_print_index + 1
+ step_print = ( step_print_index * step_num ) / step_print_num
+
+ end if
+
+c
+c Output to TNG file at regular intervals, specified by step_save
+c
+ if ( step_save .EQ. 0 .OR. mod(step, step_save) .EQ. 0 ) then
+ call tng_frame_particle_data_write(traj, frames_saved_cnt,
+ & TNG_TRAJ_POSITIONS, int(0, 8), tng_n_particles, pos,
+ & TNG_USE_HASH)
+ call tng_frame_particle_data_write(traj, frames_saved_cnt,
+ & TNG_TRAJ_VELOCITIES, int(0, 8), tng_n_particles, vel,
+ & TNG_USE_HASH)
+ call tng_frame_particle_data_write(traj, frames_saved_cnt,
+ & TNG_TRAJ_FORCES, int(0, 8), tng_n_particles, force,
+ & TNG_USE_HASH)
+ frames_saved_cnt = frames_saved_cnt + 1
+
+ if (mod(step, step_save * sparse_save) .EQ. 0) then
+ call tng_frame_data_write(traj, frames_saved_cnt,
+ & int(10101, 8), potential, TNG_USE_HASH)
+ end if
+
+ end if
+
+ call update ( np, nd, pos, vel, force, acc, mass, dt )
+
+ end do
+
+ wtime = omp_get_wtime ( ) - wtime
+
+ write ( *, '(a)' ) ' '
+ write ( *, '(a)' )
+ & ' Elapsed time for main computation:'
+ write ( *, '(2x,g14.6,a)' ) wtime, ' seconds'
+c
+c Terminate.
+c
+ call tng_trajectory_destroy(traj_p)
+
+ write ( *, '(a)' ) ' '
+ write ( *, '(a)' ) 'MD_OPENMP'
+ write ( *, '(a)' ) ' Normal end of execution.'
+
+ write ( *, '(a)' ) ' '
+ call timestamp ( )
+
+ stop
+ end
+ subroutine compute ( np, nd, pos, vel, mass, f, pot, kin )
+
+c*********************************************************************72
+c
+cc COMPUTE computes the forces and energies.
+c
+c Discussion:
+c
+c The computation of forces and energies is fully parallel.
+c
+c Licensing:
+c
+c This code is distributed under the GNU LGPL license.
+c
+c Modified:
+c
+c 31 July 2009
+c
+c Author:
+c
+c Original FORTRAN90 version by Bill Magro.
+c FORTRAN77 version by John Burkardt.
+c
+c Parameters:
+c
+c Input, integer NP, the number of particles.
+c
+c Input, integer ND, the number of spatial dimensions.
+c
+c Input, double precision POS(ND,NP), the position of each particle.
+c
+c Input, double precision VEL(ND,NP), the velocity of each particle.
+c
+c Input, double precision MASS, the mass of each particle.
+c
+ implicit none
+
+ integer np
+ integer nd
+
+ double precision d
+ double precision d2
+ double precision dv
+ double precision f(nd,np)
+ integer i
+ integer j
+ integer k
+ double precision kin
+ double precision mass
+ double precision PI2
+ parameter ( PI2 = 3.141592653589793D+00 / 2.0D+00 )
+ double precision pos(nd,np)
+ double precision pot
+ double precision rij(nd)
+ double precision v
+ double precision vel(nd,np)
+
+ pot = 0.0D+00
+ kin = 0.0D+00
+
+c$omp parallel
+c$omp& shared ( f, nd, np, pos, vel )
+c$omp& private ( d, d2, i, j, k, rij )
+
+c$omp do reduction ( + : pot, kin )
+ do i = 1, np
+c
+c Compute the potential energy and forces.
+c
+ do k = 1, nd
+ f(k,i) = 0.0D+00
+ end do
+
+ do j = 1, np
+
+ if ( i .ne. j ) then
+
+ call dist ( nd, pos(1,i), pos(1,j), rij, d )
+c
+c Attribute half of the potential energy to particle J.
+c
+ d2 = min ( d, pi2 )
+
+ pot = pot + 0.5D+00 * ( sin ( d2 ) )**2
+
+ do k = 1, nd
+ f(k,i) = f(k,i) - rij(k) * sin ( 2.0D+00 * d2 ) / d
+ end do
+
+ end if
+
+ end do
+c
+c Compute the kinetic energy.
+c
+ do k = 1, nd
+ kin = kin + vel(k,i)**2
+ end do
+
+ end do
+c$omp end do
+
+c$omp end parallel
+
+ kin = kin * 0.5D+00 * mass
+
+ return
+ end
+ subroutine dist ( nd, r1, r2, dr, d )
+
+c*********************************************************************72
+c
+cc DIST computes the displacement (and its norm) between two particles.
+c
+c Licensing:
+c
+c This code is distributed under the GNU LGPL license.
+c
+c Modified:
+c
+c 13 November 2007
+c
+c Author:
+c
+c Original FORTRAN90 version by Bill Magro.
+c FORTRAN77 version by John Burkardt.
+c
+c Parameters:
+c
+c Input, integer ND, the number of spatial dimensions.
+c
+c Input, double precision R1(ND), R2(ND), the positions of the particles.
+c
+c Output, double precision DR(ND), the displacement vector.
+c
+c Output, double precision D, the Euclidean norm of the displacement.
+c
+ implicit none
+
+ integer nd
+
+ double precision d
+ double precision dr(nd)
+ integer i
+ double precision r1(nd)
+ double precision r2(nd)
+
+ do i = 1, nd
+ dr(i) = r1(i) - r2(i)
+ end do
+
+ d = 0.0D+00
+ do i = 1, nd
+ d = d + dr(i)**2
+ end do
+ d = sqrt ( d )
+
+ return
+ end
+ subroutine initialize ( np, nd, box, seed, pos, vel, acc )
+
+c*********************************************************************72
+c
+cc INITIALIZE initializes the positions, velocities, and accelerations.
+c
+c Licensing:
+c
+c This code is distributed under the GNU LGPL license.
+c
+c Modified:
+c
+c 13 November 2007
+c
+c Author:
+c
+c Original FORTRAN90 version by Bill Magro.
+c FORTRAN77 version by John Burkardt.
+c
+c Parameters:
+c
+c Input, integer NP, the number of particles.
+c
+c Input, integer ND, the number of spatial dimensions.
+c
+c Input, double precision BOX(ND), specifies the maximum position
+c of particles in each dimension.
+c
+c Input/output, integer SEED, a seed for the random number generator.
+c
+c Output, double precision POS(ND,NP), the position of each particle.
+c
+c Output, double precision VEL(ND,NP), the velocity of each particle.
+c
+c Output, double precision ACC(ND,NP), the acceleration of each particle.
+c
+ implicit none
+
+ integer np
+ integer nd
+
+ double precision acc(nd,np)
+ double precision box(nd)
+ integer i
+ integer j
+ double precision pos(nd,np)
+ double precision r8_uniform_01
+ integer seed
+ double precision vel(nd,np)
+c
+c Give the particles random positions within the box.
+c
+ do i = 1, nd
+ do j = 1, np
+ pos(i,j) = r8_uniform_01 ( seed )
+ end do
+ end do
+
+c$omp parallel
+c$omp& shared ( acc, box, nd, np, pos, vel )
+c$omp& private ( i, j )
+
+c$omp do
+ do j = 1, np
+ do i = 1, nd
+ pos(i,j) = box(i) * pos(i,j)
+ vel(i,j) = 0.0D+00
+ acc(i,j) = 0.0D+00
+ end do
+ end do
+c$omp end do
+
+c$omp end parallel
+
+ return
+ end
+ function r8_uniform_01 ( seed )
+
+c*********************************************************************72
+c
+cc R8_UNIFORM_01 returns a unit pseudorandom R8.
+c
+c Discussion:
+c
+c This routine implements the recursion
+c
+c seed = 16807 * seed mod ( 2**31 - 1 )
+c r8_uniform_01 = seed / ( 2**31 - 1 )
+c
+c The integer arithmetic never requires more than 32 bits,
+c including a sign bit.
+c
+c If the initial seed is 12345, then the first three computations are
+c
+c Input Output R8_UNIFORM_01
+c SEED SEED
+c
+c 12345 207482415 0.096616
+c 207482415 1790989824 0.833995
+c 1790989824 2035175616 0.947702
+c
+c Licensing:
+c
+c This code is distributed under the GNU LGPL license.
+c
+c Modified:
+c
+c 11 August 2004
+c
+c Author:
+c
+c John Burkardt
+c
+c Reference:
+c
+c Paul Bratley, Bennett Fox, Linus Schrage,
+c A Guide to Simulation,
+c Springer Verlag, pages 201-202, 1983.
+c
+c Pierre L'Ecuyer,
+c Random Number Generation,
+c in Handbook of Simulation,
+c edited by Jerry Banks,
+c Wiley Interscience, page 95, 1998.
+c
+c Bennett Fox,
+c Algorithm 647:
+c Implementation and Relative Efficiency of Quasirandom
+c Sequence Generators,
+c ACM Transactions on Mathematical Software,
+c Volume 12, Number 4, pages 362-376, 1986.
+c
+c Peter Lewis, Allen Goodman, James Miller,
+c A Pseudo-Random Number Generator for the System/360,
+c IBM Systems Journal,
+c Volume 8, pages 136-143, 1969.
+c
+c Parameters:
+c
+c Input/output, integer SEED, the "seed" value, which should NOT be 0.
+c On output, SEED has been updated.
+c
+c Output, double precision R8_UNIFORM_01, a new pseudorandom variate,
+c strictly between 0 and 1.
+c
+ implicit none
+
+ double precision r8_uniform_01
+ integer k
+ integer seed
+
+ if ( seed .eq. 0 ) then
+ write ( *, '(a)' ) ' '
+ write ( *, '(a)' ) 'R8_UNIFORM_01 - Fatal error!'
+ write ( *, '(a)' ) ' Input value of SEED = 0.'
+ stop
+ end if
+
+ k = seed / 127773
+
+ seed = 16807 * ( seed - k * 127773 ) - k * 2836
+
+ if ( seed .lt. 0 ) then
+ seed = seed + 2147483647
+ end if
+c
+c Although SEED can be represented exactly as a 32 bit integer,
+c it generally cannot be represented exactly as a 32 bit real number!
+c
+ r8_uniform_01 = dble ( seed ) * 4.656612875D-10
+
+ return
+ end
+ subroutine timestamp ( )
+
+c*********************************************************************72
+c
+cc TIMESTAMP prints out the current YMDHMS date as a timestamp.
+c
+c Licensing:
+c
+c This code is distributed under the GNU LGPL license.
+c
+c Modified:
+c
+c 12 January 2007
+c
+c Author:
+c
+c John Burkardt
+c
+c Parameters:
+c
+c None
+c
+ implicit none
+
+ character * ( 8 ) ampm
+ integer d
+ character * ( 8 ) date
+ integer h
+ integer m
+ integer mm
+ character * ( 9 ) month(12)
+ integer n
+ integer s
+ character * ( 10 ) time
+ integer y
+
+ save month
+
+ data month /
+ & 'January ', 'February ', 'March ', 'April ',
+ & 'May ', 'June ', 'July ', 'August ',
+ & 'September', 'October ', 'November ', 'December ' /
+
+ call date_and_time ( date, time )
+
+ read ( date, '(i4,i2,i2)' ) y, m, d
+ read ( time, '(i2,i2,i2,1x,i3)' ) h, n, s, mm
+
+ if ( h .lt. 12 ) then
+ ampm = 'AM'
+ else if ( h .eq. 12 ) then
+ if ( n .eq. 0 .and. s .eq. 0 ) then
+ ampm = 'Noon'
+ else
+ ampm = 'PM'
+ end if
+ else
+ h = h - 12
+ if ( h .lt. 12 ) then
+ ampm = 'PM'
+ else if ( h .eq. 12 ) then
+ if ( n .eq. 0 .and. s .eq. 0 ) then
+ ampm = 'Midnight'
+ else
+ ampm = 'AM'
+ end if
+ end if
+ end if
+
+ write ( *,
+ & '(i2,1x,a,1x,i4,2x,i2,a1,i2.2,a1,i2.2,a1,i3.3,1x,a)' )
+ & d, month(m), y, h, ':', n, ':', s, '.', mm, ampm
+
+ return
+ end
+ subroutine update ( np, nd, pos, vel, f, acc, mass, dt )
+
+c*********************************************************************72
+c
+cc UPDATE performs the time integration, using a velocity Verlet algorithm.
+c
+c Discussion:
+c
+c The time integration is fully parallel.
+c
+c Licensing:
+c
+c This code is distributed under the GNU LGPL license.
+c
+c Modified:
+c
+c 13 November 2007
+c
+c Author:
+c
+c Original FORTRAN90 version by Bill Magro.
+c FORTRAN77 version by John Burkardt.
+c
+c Parameters:
+c
+c Input, integer NP, the number of particles.
+c
+c Input, integer ND, the number of spatial dimensions.
+c
+c Input/output, double precision POS(ND,NP), the position of each particle.
+c
+c Input/output, double precision VEL(ND,NP), the velocity of each particle.
+c
+c Input, double precision MASS, the mass of each particle.
+c
+c Input/output, double precision ACC(ND,NP), the acceleration of each
+c particle.
+c
+ implicit none
+
+ integer np
+ integer nd
+
+ double precision acc(nd,np)
+ double precision dt
+ double precision f(nd,np)
+ integer i
+ integer j
+ double precision mass
+ double precision pos(nd,np)
+ double precision rmass
+ double precision vel(nd,np)
+
+ rmass = 1.0D+00 / mass
+
+c$omp parallel
+c$omp& shared ( acc, dt, f, nd, np, pos, rmass, vel )
+c$omp& private ( i, j )
+
+c$omp do
+ do j = 1, np
+ do i = 1, nd
+
+ pos(i,j) = pos(i,j)
+ & + vel(i,j) * dt + 0.5D+00 * acc(i,j) * dt * dt
+
+ vel(i,j) = vel(i,j)
+ & + 0.5D+00 * dt * ( f(i,j) * rmass + acc(i,j) )
+
+ acc(i,j) = f(i,j) * rmass
+
+ end do
+ end do
+c$omp end do
+
+c$omp end parallel
+
+ return
+ end
--- /dev/null
+#ifdef TNG_BUILD_OPENMP_EXAMPLES
+
+# include <stdlib.h>
+# include <stdio.h>
+# include <time.h>
+# include <math.h>
+# include <omp.h>
+# include "tng_io.h"
+
+int main ();
+void compute ( int np, int nd, float pos[], float vel[],
+ float mass, float f[], float *pot, float *kin );
+float dist ( int nd, float r1[], float r2[], float dr[] );
+void initialize ( int np, int nd, float box[], int *seed, float pos[],
+ float vel[], float acc[] );
+float r8_uniform_01 ( int *seed );
+void timestamp ( void );
+void update ( int np, int nd, float pos[], float vel[], float f[],
+ float acc[], float mass, float dt );
+
+/******************************************************************************/
+
+int main ()
+
+/******************************************************************************/
+/*
+ Purpose:
+
+ MAIN is the main program for MD_OPENMP.
+
+ Discussion:
+
+ MD implements a simple molecular dynamics simulation.
+
+ The program uses Open MP directives to allow parallel computation.
+
+ The velocity Verlet time integration scheme is used.
+
+ The particles interact with a central pair potential.
+
+ Output of the program is saved in the TNG format, which is why this
+ code is included in the TNG API release. The high-level API of the
+ TNG API is used where appropriate.
+
+ Licensing:
+
+ This code is distributed under the GNU LGPL license.
+
+ Modified:
+
+ 8 Jan 2013
+
+ Author:
+
+ Original FORTRAN77 version by Bill Magro.
+ C version by John Burkardt.
+ TNG trajectory output by Magnus Lundborg.
+
+ Parameters:
+
+ None
+*/
+{
+ float *acc;
+ float *box;
+ float *box_shape;
+ float dt = 0.0002;
+ float e0;
+ float *force;
+ int i;
+ float kinetic;
+ float mass = 1.0;
+ int nd = 3;
+ int np = 50;
+ float *pos;
+ float potential;
+ int proc_num;
+ int seed = 123456789;
+ int step;
+ int step_num = 50000;
+ int step_print;
+ int step_print_index;
+ int step_print_num;
+ int step_save;
+ float *vel;
+ float wtime;
+ tng_trajectory_t traj;
+ tng_molecule_t molecule;
+ tng_chain_t chain;
+ tng_residue_t residue;
+ tng_atom_t atom;
+
+ timestamp ( );
+
+ proc_num = omp_get_num_procs ( );
+
+ acc = ( float * ) malloc ( nd * np * sizeof ( float ) );
+ box = ( float * ) malloc ( nd * sizeof ( float ) );
+ box_shape = (float *) malloc (9 * sizeof (float));
+ force = ( float * ) malloc ( nd * np * sizeof ( float ) );
+ pos = ( float * ) malloc ( nd * np * sizeof ( float ) );
+ vel = ( float * ) malloc ( nd * np * sizeof ( float ) );
+
+ printf ( "\n" );
+ printf ( "MD_OPENMP\n" );
+ printf ( " C/OpenMP version\n" );
+ printf ( "\n" );
+ printf ( " A molecular dynamics program.\n" );
+
+ printf ( "\n" );
+ printf ( " NP, the number of particles in the simulation is %d\n", np );
+ printf ( " STEP_NUM, the number of time steps, is %d\n", step_num );
+ printf ( " DT, the size of each time step, is %f\n", dt );
+
+ printf ( "\n" );
+ printf ( " Number of processors available = %d\n", proc_num );
+ printf ( " Number of threads = %d\n", omp_get_max_threads ( ) );
+
+
+ printf("\n");
+ printf(" Initializing trajectory storage.\n");
+ /* Initialize the TNG trajectory */
+#ifdef TNG_EXAMPLE_FILES_DIR
+ tng_util_trajectory_open(TNG_EXAMPLE_FILES_DIR "tng_md_out.tng", 'w', &traj);
+#else
+ tng_util_trajectory_open("/tmp/tng_md_out.tng", 'w', &traj);
+#endif
+
+
+
+ /* Set molecules data */
+ /* N.B. This is still not done using utility functions. The low-level API
+ * is used. */
+ printf(" Creating molecules in trajectory.\n");
+ tng_molecule_add(traj, "water", &molecule);
+ tng_molecule_chain_add(traj, molecule, "W", &chain);
+ tng_chain_residue_add(traj, chain, "WAT", &residue);
+ if(tng_residue_atom_add(traj, residue, "O", "O", &atom) == TNG_CRITICAL)
+ {
+ tng_util_trajectory_close(&traj);
+ printf(" Cannot create molecules.\n");
+ exit(1);
+ }
+ tng_molecule_cnt_set(traj, molecule, np);
+
+
+/*
+ Set the dimensions of the box.
+*/
+ for(i = 0; i < 9; i++)
+ {
+ box_shape[i] = 0.0;
+ }
+ for ( i = 0; i < nd; i++ )
+ {
+ box[i] = 10.0;
+ /* box_shape stores 9 values according to the TNG specs */
+ box_shape[i*nd + i] = box[i];
+ }
+
+
+ printf ( "\n" );
+ printf ( " Initializing positions, velocities, and accelerations.\n" );
+/*
+ Set initial positions, velocities, and accelerations.
+*/
+ initialize ( np, nd, box, &seed, pos, vel, acc );
+/*
+ Compute the forces and energies.
+*/
+ printf ( "\n" );
+ printf ( " Computing initial forces and energies.\n" );
+
+ compute ( np, nd, pos, vel, mass, force, &potential, &kinetic );
+
+ e0 = potential + kinetic;
+
+ /* Saving frequency */
+ step_save = 400;
+
+ step_print = 0;
+ step_print_index = 0;
+ step_print_num = 10;
+
+/*
+ This is the main time stepping loop:
+ Compute forces and energies,
+ Update positions, velocities, accelerations.
+*/
+ printf(" Every %d steps box shape, particle positions, velocities and forces are\n",
+ step_save);
+ printf(" saved to a TNG trajectory file.\n");
+ printf ( "\n" );
+ printf ( " At certain step intervals, we report the potential and kinetic energies.\n" );
+ printf ( " The sum of these energies should be a constant.\n" );
+ printf ( " As an accuracy check, we also print the relative error\n" );
+ printf ( " in the total energy.\n" );
+ printf ( "\n" );
+ printf ( " Step Potential Kinetic (P+K-E0)/E0\n" );
+ printf ( " Energy P Energy K Relative Energy Error\n" );
+ printf ( "\n" );
+
+ step = 0;
+ printf ( " %8d %14f %14f %14e\n",
+ step, potential, kinetic, ( potential + kinetic - e0 ) / e0 );
+ step_print_index++;
+ step_print = ( step_print_index * step_num ) / step_print_num;
+
+ /* Set the output frequency of box shape, positions, velocities and forces */
+ if(tng_util_box_shape_write_frequency_set(traj, step_save) != TNG_SUCCESS)
+ {
+ printf("Error setting writing frequency data. %s: %d\n",
+ __FILE__, __LINE__);
+ exit(1);
+ }
+ if(tng_util_pos_write_frequency_set(traj, step_save) != TNG_SUCCESS)
+ {
+ printf("Error setting writing frequency data. %s: %d\n",
+ __FILE__, __LINE__);
+ exit(1);
+ }
+ if(tng_util_vel_write_frequency_set(traj, step_save) != TNG_SUCCESS)
+ {
+ printf("Error setting writing frequency data. %s: %d\n",
+ __FILE__, __LINE__);
+ exit(1);
+ }
+ if(tng_util_force_write_frequency_set(traj, step_save) != TNG_SUCCESS)
+ {
+ printf("Error setting writing frequency data. %s: %d\n",
+ __FILE__, __LINE__);
+ exit(1);
+ }
+
+ /* Write the first frame of box shape, positions, velocities and forces */
+ if(tng_util_box_shape_write(traj, 0, box_shape) != TNG_SUCCESS)
+ {
+ printf("Error writing box shape. %s: %d\n",
+ __FILE__, __LINE__);
+ exit(1);
+ }
+ if(tng_util_pos_write(traj, 0, pos) != TNG_SUCCESS)
+ {
+ printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ exit(1);
+ }
+ if(tng_util_vel_write(traj, 0, vel) != TNG_SUCCESS)
+ {
+ printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ exit(1);
+ }
+ if(tng_util_force_write(traj, 0, force) != TNG_SUCCESS)
+ {
+ printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ exit(1);
+ }
+
+ wtime = omp_get_wtime ( );
+
+ for ( step = 1; step < step_num; step++ )
+ {
+ compute ( np, nd, pos, vel, mass, force, &potential, &kinetic );
+
+ if ( step == step_print )
+ {
+ printf ( " %8d %14f %14f %14e\n", step, potential, kinetic,
+ ( potential + kinetic - e0 ) / e0 );
+ step_print_index++;
+ step_print = ( step_print_index * step_num ) / step_print_num;
+ }
+ if(step % step_save == 0)
+ {
+ /* Write box shape, positions, velocities and forces */
+ if(tng_util_box_shape_write(traj, step, box_shape) != TNG_SUCCESS)
+ {
+ printf("Error writing box shape. %s: %d\n",
+ __FILE__, __LINE__);
+ exit(1);
+ }
+ if(tng_util_pos_write(traj, step, pos) != TNG_SUCCESS)
+ {
+ printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ break;
+ }
+ if(tng_util_vel_write(traj, step, vel) != TNG_SUCCESS)
+ {
+ printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ break;
+ }
+ if(tng_util_force_write(traj, step, force) != TNG_SUCCESS)
+ {
+ printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ break;
+ }
+ }
+ update ( np, nd, pos, vel, force, acc, mass, dt );
+ }
+ wtime = omp_get_wtime ( ) - wtime;
+
+ printf ( "\n" );
+ printf ( " Elapsed time for main computation:\n" );
+ printf ( " %f seconds.\n", wtime );
+
+ free ( acc );
+ free ( box );
+ free ( box_shape );
+ free ( force );
+ free ( pos );
+ free ( vel );
+
+ /* Close the TNG output. */
+ tng_util_trajectory_close(&traj);
+
+ printf ( "\n" );
+ printf ( "MD_OPENMP\n" );
+ printf ( " Normal end of execution.\n" );
+
+ printf ( "\n" );
+ timestamp ( );
+
+ return 0;
+}
+/******************************************************************************/
+
+void compute ( int np, int nd, float pos[], float vel[],
+ float mass, float f[], float *pot, float *kin )
+
+/******************************************************************************/
+/*
+ Purpose:
+
+ COMPUTE computes the forces and energies.
+
+ Discussion:
+
+ The computation of forces and energies is fully parallel.
+
+ The potential function V(X) is a harmonic well which smoothly
+ saturates to a maximum value at PI/2:
+
+ v(x) = ( sin ( min ( x, PI2 ) ) )**2
+
+ The derivative of the potential is:
+
+ dv(x) = 2.0 * sin ( min ( x, PI2 ) ) * cos ( min ( x, PI2 ) )
+ = sin ( 2.0 * min ( x, PI2 ) )
+
+ Licensing:
+
+ This code is distributed under the GNU LGPL license.
+
+ Modified:
+
+ 21 November 2007
+
+ Author:
+
+ Original FORTRAN77 version by Bill Magro.
+ C version by John Burkardt.
+
+ Parameters:
+
+ Input, int NP, the number of particles.
+
+ Input, int ND, the number of spatial dimensions.
+
+ Input, float POS[ND*NP], the position of each particle.
+
+ Input, float VEL[ND*NP], the velocity of each particle.
+
+ Input, float MASS, the mass of each particle.
+
+ Output, float F[ND*NP], the forces.
+
+ Output, float *POT, the total potential energy.
+
+ Output, float *KIN, the total kinetic energy.
+*/
+{
+ float d;
+ float d2;
+ int i;
+ int j;
+ int k;
+ float ke;
+ float pe;
+ float PI2 = 3.141592653589793 / 2.0;
+ float rij[3];
+
+ pe = 0.0;
+ ke = 0.0;
+
+# pragma omp parallel \
+ shared ( f, nd, np, pos, vel ) \
+ private ( i, j, k, rij, d, d2 )
+
+
+# pragma omp for reduction ( + : pe, ke )
+ for ( k = 0; k < np; k++ )
+ {
+/*
+ Compute the potential energy and forces.
+*/
+ for ( i = 0; i < nd; i++ )
+ {
+ f[i+k*nd] = 0.0;
+ }
+
+ for ( j = 0; j < np; j++ )
+ {
+ if ( k != j )
+ {
+ d = dist ( nd, pos+k*nd, pos+j*nd, rij );
+/*
+ Attribute half of the potential energy to particle J.
+*/
+ if ( d < PI2 )
+ {
+ d2 = d;
+ }
+ else
+ {
+ d2 = PI2;
+ }
+
+ pe = pe + 0.5 * pow ( sin ( d2 ), 2 );
+
+ for ( i = 0; i < nd; i++ )
+ {
+ f[i+k*nd] = f[i+k*nd] - rij[i] * sin ( 2.0 * d2 ) / d;
+ }
+ }
+ }
+/*
+ Compute the kinetic energy.
+*/
+ for ( i = 0; i < nd; i++ )
+ {
+ ke = ke + vel[i+k*nd] * vel[i+k*nd];
+ }
+ }
+
+ ke = ke * 0.5 * mass;
+
+ *pot = pe;
+ *kin = ke;
+
+ return;
+}
+/******************************************************************************/
+
+float dist ( int nd, float r1[], float r2[], float dr[] )
+
+/******************************************************************************/
+/*
+ Purpose:
+
+ DIST computes the displacement (and its norm) between two particles.
+
+ Licensing:
+
+ This code is distributed under the GNU LGPL license.
+
+ Modified:
+
+ 21 November 2007
+
+ Author:
+
+ Original FORTRAN77 version by Bill Magro.
+ C version by John Burkardt.
+
+ Parameters:
+
+ Input, int ND, the number of spatial dimensions.
+
+ Input, float R1[ND], R2[ND], the positions of the particles.
+
+ Output, float DR[ND], the displacement vector.
+
+ Output, float D, the Euclidean norm of the displacement.
+*/
+{
+ float d;
+ int i;
+
+ d = 0.0;
+ for ( i = 0; i < nd; i++ )
+ {
+ dr[i] = r1[i] - r2[i];
+ d = d + dr[i] * dr[i];
+ }
+ d = sqrt ( d );
+
+ return d;
+}
+/******************************************************************************/
+
+void initialize ( int np, int nd, float box[], int *seed, float pos[],
+ float vel[], float acc[] )
+
+/******************************************************************************/
+/*
+ Purpose:
+
+ INITIALIZE initializes the positions, velocities, and accelerations.
+
+ Licensing:
+
+ This code is distributed under the GNU LGPL license.
+
+ Modified:
+
+ 21 November 2007
+
+ Author:
+
+ Original FORTRAN77 version by Bill Magro.
+ C version by John Burkardt.
+
+ Parameters:
+
+ Input, int NP, the number of particles.
+
+ Input, int ND, the number of spatial dimensions.
+
+ Input, float BOX[ND], specifies the maximum position
+ of particles in each dimension.
+
+ Input, int *SEED, a seed for the random number generator.
+
+ Output, float POS[ND*NP], the position of each particle.
+
+ Output, float VEL[ND*NP], the velocity of each particle.
+
+ Output, float ACC[ND*NP], the acceleration of each particle.
+*/
+{
+ int i;
+ int j;
+/*
+ Give the particles random positions within the box.
+*/
+ for ( i = 0; i < nd; i++ )
+ {
+ for ( j = 0; j < np; j++ )
+ {
+ pos[i+j*nd] = box[i] * r8_uniform_01 ( seed );
+ }
+ }
+
+ for ( j = 0; j < np; j++ )
+ {
+ for ( i = 0; i < nd; i++ )
+ {
+ vel[i+j*nd] = 0.0;
+ }
+ }
+ for ( j = 0; j < np; j++ )
+ {
+ for ( i = 0; i < nd; i++ )
+ {
+ acc[i+j*nd] = 0.0;
+ }
+ }
+ return;
+}
+/******************************************************************************/
+
+float r8_uniform_01 ( int *seed )
+
+/******************************************************************************/
+/*
+ Purpose:
+
+ R8_UNIFORM_01 is a unit pseudorandom R8.
+
+ Discussion:
+
+ This routine implements the recursion
+
+ seed = 16807 * seed mod ( 2**31 - 1 )
+ unif = seed / ( 2**31 - 1 )
+
+ The integer arithmetic never requires more than 32 bits,
+ including a sign bit.
+
+ Licensing:
+
+ This code is distributed under the GNU LGPL license.
+
+ Modified:
+
+ 11 August 2004
+
+ Author:
+
+ John Burkardt
+
+ Reference:
+
+ Paul Bratley, Bennett Fox, Linus Schrage,
+ A Guide to Simulation,
+ Springer Verlag, pages 201-202, 1983.
+
+ Bennett Fox,
+ Algorithm 647:
+ Implementation and Relative Efficiency of Quasirandom
+ Sequence Generators,
+ ACM Transactions on Mathematical Software,
+ Volume 12, Number 4, pages 362-376, 1986.
+
+ Parameters:
+
+ Input/output, int *SEED, a seed for the random number generator.
+
+ Output, float R8_UNIFORM_01, a new pseudorandom variate, strictly between
+ 0 and 1.
+*/
+{
+ int k;
+ float r;
+
+ k = *seed / 127773;
+
+ *seed = 16807 * ( *seed - k * 127773 ) - k * 2836;
+
+ if ( *seed < 0 )
+ {
+ *seed = *seed + 2147483647;
+ }
+
+ r = ( float ) ( *seed ) * 4.656612875E-10;
+
+ return r;
+}
+/******************************************************************************/
+
+void timestamp ( void )
+
+/******************************************************************************/
+/*
+ Purpose:
+
+ TIMESTAMP prints the current YMDHMS date as a time stamp.
+
+ Example:
+
+ 31 May 2001 09:45:54 AM
+
+ Licensing:
+
+ This code is distributed under the GNU LGPL license.
+
+ Modified:
+
+ 24 September 2003
+
+ Author:
+
+ John Burkardt
+
+ Parameters:
+
+ None
+*/
+{
+# define TIME_SIZE 40
+
+ static char time_buffer[TIME_SIZE];
+ const struct tm *tm;
+ time_t now;
+
+ now = time ( NULL );
+ tm = localtime ( &now );
+
+ strftime ( time_buffer, TIME_SIZE, "%d %B %Y %I:%M:%S %p", tm );
+
+ printf ( "%s\n", time_buffer );
+
+ return;
+# undef TIME_SIZE
+}
+/******************************************************************************/
+
+void update ( int np, int nd, float pos[], float vel[], float f[],
+ float acc[], float mass, float dt )
+
+/******************************************************************************/
+/*
+ Purpose:
+
+ UPDATE updates positions, velocities and accelerations.
+
+ Discussion:
+
+ The time integration is fully parallel.
+
+ A velocity Verlet algorithm is used for the updating.
+
+ x(t+dt) = x(t) + v(t) * dt + 0.5 * a(t) * dt * dt
+ v(t+dt) = v(t) + 0.5 * ( a(t) + a(t+dt) ) * dt
+ a(t+dt) = f(t) / m
+
+ Licensing:
+
+ This code is distributed under the GNU LGPL license.
+
+ Modified:
+
+ 17 April 2009
+
+ Author:
+
+ Original FORTRAN77 version by Bill Magro.
+ C version by John Burkardt.
+
+ Parameters:
+
+ Input, int NP, the number of particles.
+
+ Input, int ND, the number of spatial dimensions.
+
+ Input/output, float POS[ND*NP], the position of each particle.
+
+ Input/output, float VEL[ND*NP], the velocity of each particle.
+
+ Input, float F[ND*NP], the force on each particle.
+
+ Input/output, float ACC[ND*NP], the acceleration of each particle.
+
+ Input, float MASS, the mass of each particle.
+
+ Input, float DT, the time step.
+*/
+{
+ int i;
+ int j;
+ float rmass;
+
+ rmass = 1.0 / mass;
+
+# pragma omp parallel \
+ shared ( acc, dt, f, nd, np, pos, rmass, vel ) \
+ private ( i, j )
+
+# pragma omp for
+ for ( j = 0; j < np; j++ )
+ {
+ for ( i = 0; i < nd; i++ )
+ {
+ pos[i+j*nd] = pos[i+j*nd] + vel[i+j*nd] * dt + 0.5 * acc[i+j*nd] * dt * dt;
+ vel[i+j*nd] = vel[i+j*nd] + 0.5 * dt * ( f[i+j*nd] * rmass + acc[i+j*nd] );
+ acc[i+j*nd] = f[i+j*nd] * rmass;
+ }
+ }
+
+
+ return;
+}
+
+#endif
--- /dev/null
+/* This code is part of the tng binary trajectory format.
+ *
+ * VERSION 1.0
+ *
+ * Written by Magnus Lundborg
+ * Copyright (c) 2012-2013, The GROMACS development team.
+ * check out http://www.gromacs.org for more information.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+#ifdef USE_STD_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "../../include/tng_io.h"
+
+int main(int argc, char **argv)
+{
+ tng_trajectory_t traj;
+ union data_values ***positions = 0; /* A 3-dimensional array to be populated */
+ int64_t n_particles, n_values_per_frame, n_frames, tot_n_frames;
+ char data_type;
+ int i, j;
+ int particle = 0;
+ /* Set a default frame range */
+ int first_frame = 0, last_frame = 50;
+ char atom_name[64], res_name[64], chain_name[64];
+
+ if(argc <= 1)
+ {
+ printf("No file specified\n");
+ printf("Usage:\n");
+ printf("tng_io_read_pos <tng_file> [particle number = %d] "
+ "[first_frame = %d] [last_frame = %d]\n",
+ particle, first_frame, last_frame);
+ exit(1);
+ }
+
+ /* A reference must be passed to allocate memory */
+ if(tng_trajectory_init(&traj) != TNG_SUCCESS)
+ {
+ tng_trajectory_destroy(&traj);
+ exit(1);
+ }
+ tng_input_file_set(traj, argv[1]);
+
+ /* Read the file headers */
+ tng_file_headers_read(traj, TNG_USE_HASH);
+
+ if(argc >= 3)
+ {
+ particle = strtol(argv[2], 0, 10);
+ if(argc >= 4)
+ {
+ first_frame = strtol(argv[3], 0, 10);
+ if(argc >= 5)
+ {
+ last_frame = strtol(argv[4], 0, 10);
+ }
+ }
+ }
+
+ if(tng_num_frames_get(traj, &tot_n_frames) != TNG_SUCCESS)
+ {
+ printf("Cannot determine the number of frames in the file\n");
+ tng_trajectory_destroy(&traj);
+ exit(1);
+ }
+
+ printf("%"PRId64" frames in file\n", tot_n_frames);
+
+ if(last_frame > tot_n_frames - 1)
+ {
+ last_frame = tot_n_frames - 1;
+ }
+
+ n_frames = last_frame - first_frame + 1;
+
+ if(tng_atom_name_of_particle_nr_get(traj, particle, atom_name,
+ sizeof(atom_name)) ==
+ TNG_SUCCESS &&
+ tng_residue_name_of_particle_nr_get(traj, particle, res_name,
+ sizeof(res_name)) ==
+ TNG_SUCCESS &&
+ tng_chain_name_of_particle_nr_get(traj, particle, chain_name,
+ sizeof(chain_name)) ==
+ TNG_SUCCESS)
+ {
+ printf("Particle: %s (%s: %s)\n", atom_name, chain_name, res_name);
+ }
+ else
+ {
+ printf("Particle name not found\n");
+ }
+
+ /* Get the positions of all particles in the requested frame range.
+ The positions are stored in the positions array.
+ N.B. No proper error checks. */
+ if(tng_particle_data_interval_get(traj, TNG_TRAJ_POSITIONS, first_frame,
+ last_frame, TNG_USE_HASH, &positions, &n_particles, &n_values_per_frame,
+ &data_type) == TNG_SUCCESS)
+ {
+ if(particle >= n_particles)
+ {
+ printf("Chosen particle out of range. Only %"PRId64" particles in trajectory.\n", n_particles);
+ }
+ else
+ {
+ /* Print the positions of the wanted particle (zero based) */
+ for(i=0; i<n_frames; i++)
+ {
+ printf("%d", first_frame + i);
+ for(j=0; j<n_values_per_frame; j++)
+ {
+ switch(data_type)
+ {
+ case TNG_INT_DATA:
+ printf("\t%"PRId64"", positions[i][particle][j].i);
+ break;
+ case TNG_FLOAT_DATA:
+ printf("\t%f", positions[i][particle][j].f);
+ break;
+ case TNG_DOUBLE_DATA:
+ printf("\t%f", positions[i][particle][j].d);
+ break;
+ default:
+ break;
+ }
+ printf("\n");
+ }
+ }
+ }
+ }
+ else
+ {
+ printf("Cannot read positions\n");
+ }
+
+ /* Free memory */
+ if(positions)
+ {
+ tng_particle_data_values_free(traj, positions, n_frames, n_particles,
+ n_values_per_frame, data_type);
+ }
+ tng_trajectory_destroy(&traj);
+
+ return(0);
+}
--- /dev/null
+/* This code is part of the tng binary trajectory format.
+ *
+ * The high-level API of the TNG API is used where appropriate.
+ *
+ * VERSION 1.0
+ *
+ * Written by Magnus Lundborg
+ * Copyright (c) 2012-2013, The GROMACS development team.
+ * Check out http://www.gromacs.org for more information.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+#ifdef USE_STD_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "../../include/tng_io.h"
+
+int main(int argc, char **argv)
+{
+ tng_trajectory_t traj;
+ /* Assume that the data is stored as floats. The data is placed in 1-D
+ * arrays */
+ float *positions = 0, *box_shape = 0;
+ int64_t n_particles, n_frames, tot_n_frames, stride_length, i, j;
+ /* Set a default frame range */
+ int first_frame = 0, last_frame = 5000, n_strides;
+
+ if(argc <= 1)
+ {
+ printf("No file specified\n");
+ printf("Usage:\n");
+ printf("tng_io_read_pos_util <tng_file> "
+ "[first_frame = %d] [last_frame = %d]\n",
+ first_frame, last_frame);
+ exit(1);
+ }
+
+ /* A reference must be passed to allocate memory */
+ tng_util_trajectory_open(argv[1], 'r', &traj);
+
+ if(argc >= 3)
+ {
+ first_frame = strtol(argv[2], 0, 10);
+ if(argc >= 4)
+ {
+ last_frame = strtol(argv[3], 0, 10);
+ }
+ }
+
+ if(tng_num_frames_get(traj, &tot_n_frames) != TNG_SUCCESS)
+ {
+ printf("Cannot determine the number of frames in the file\n");
+ tng_util_trajectory_close(&traj);
+ exit(1);
+ }
+
+ if(tng_num_particles_get(traj, &n_particles) != TNG_SUCCESS)
+ {
+ printf("Cannot determine the number of particles in the file\n");
+ tng_util_trajectory_close(&traj);
+ exit(1);
+ }
+
+ printf("%"PRId64" frames in file\n", tot_n_frames);
+
+ if(last_frame > tot_n_frames - 1)
+ {
+ last_frame = tot_n_frames - 1;
+ }
+
+
+ n_frames = last_frame - first_frame + 1;
+
+ if(tng_util_box_shape_read(traj, &box_shape, &stride_length) ==
+ TNG_SUCCESS)
+ {
+ printf("Simulation box shape: ");
+ for(i=0; i < 9; i++)
+ {
+ printf("%f ", box_shape[i]);
+ }
+ printf("\n");
+ }
+ else
+ {
+ printf("Simulation box shape not set in the file (or could not be read)\n");
+ }
+
+ n_strides = (n_frames % stride_length) ? n_frames / stride_length + 1:
+ n_frames / stride_length;
+
+ /* Get the positions of all particles in the requested frame range.
+ * The positions are stored in the positions array.
+ * N.B. No proper error checks. */
+ if(tng_util_pos_read_range(traj, 0, last_frame, &positions, &stride_length)
+ == TNG_SUCCESS)
+ {
+ /* Print the positions of the wanted particle (zero based) */
+ for(i=0; i < n_strides; i++)
+ {
+ printf("\nFrame %"PRId64":\n", first_frame + i*stride_length);
+ for(j=0; j < n_particles; j++)
+ {
+ printf("Atom nr: %"PRId64"", j);
+ printf("\t%f", positions[i*n_particles*3+j*3]);
+ printf("\t%f", positions[i*n_particles*3+j*3+1]);
+ printf("\t%f", positions[i*n_particles*3+j*3+2]);
+ printf("\n");
+ }
+ }
+ }
+ else
+ {
+ printf("Cannot read positions\n");
+ }
+
+ /* Free memory */
+ if(positions)
+ {
+ free(positions);
+ }
+ if(box_shape)
+ {
+ free(box_shape);
+ }
+ tng_util_trajectory_close(&traj);
+
+ return(0);
+}
--- /dev/null
+/* This code is part of the tng binary trajectory format.
+ *
+ * VERSION 1.0
+ *
+ * Written by Magnus Lundborg
+ * Copyright (c) 2012-2013, The GROMACS development team.
+ * Check out http://www.gromacs.org for more information.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+#ifdef USE_STD_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include "../../include/tng_io.h"
+
+static tng_function_status tng_test_setup_molecules(tng_trajectory_t traj)
+{
+ tng_molecule_t molecule;
+ tng_chain_t chain;
+ tng_residue_t residue;
+ tng_atom_t atom;
+ int64_t cnt;
+
+ tng_molecule_add(traj, "water", &molecule);
+ tng_molecule_chain_add(traj, molecule, "W", &chain);
+ tng_chain_residue_add(traj, chain, "WAT", &residue);
+ if(tng_residue_atom_add(traj, residue, "O", "O", &atom) == TNG_CRITICAL)
+ {
+ return(TNG_CRITICAL);
+ }
+ if(tng_residue_atom_add(traj, residue, "HO1", "H", &atom) == TNG_CRITICAL)
+ {
+ return(TNG_CRITICAL);
+ }
+ if(tng_residue_atom_add(traj, residue, "HO2", "H", &atom) == TNG_CRITICAL)
+ {
+ return(TNG_CRITICAL);
+ }
+ tng_molecule_cnt_set(traj, molecule, 200);
+ tng_molecule_cnt_get(traj, molecule, &cnt);
+/* printf("Created %"PRId64" %s molecules.\n", cnt, molecule->name); */
+
+/* traj->molecule_cnt_list[traj->n_molecules-1] = 5;
+// tng_molecule_name_set(traj, &traj->molecules[1], "ligand");
+// tng_molecule_name_set(traj, &traj->molecules[2], "water");
+// tng_molecule_name_set(traj, &traj->molecules[3], "dummy");
+// traj->molecules[0].id = 0;
+// traj->molecules[1].id = 1;
+// traj->molecules[2].id = 2;
+// traj->molecules[3].id = 3;
+
+// if(tng_add_atom_to_molecule(traj, &traj->molecules[0], "atom1", "type1") == TNG_CRITICAL)
+// {
+// return(TNG_CRITICAL);
+// }
+// if(tng_add_atom_to_molecule(traj, &traj->molecules[0], "atom2", "type1") == TNG_CRITICAL)
+// {
+// return(TNG_CRITICAL);
+// }
+// if(tng_add_atom_to_molecule(traj, &traj->molecules[0], "atom3", "type1") == TNG_CRITICAL)
+// {
+// return(TNG_CRITICAL);
+// }
+// if(tng_add_atom_to_molecule(traj, &traj->molecules[0], "atom4", "type2") == TNG_CRITICAL)
+// {
+// return(TNG_CRITICAL);
+// }
+// if(tng_add_atom_to_molecule(traj, &traj->molecules[0], "atom5", "type2") == TNG_CRITICAL)
+// {
+// return(TNG_CRITICAL);
+// }
+// if(tng_add_atom_to_molecule(traj, &traj->molecules[0], "atom6", "type2") == TNG_CRITICAL)
+// {
+// return(TNG_CRITICAL);
+// }
+// if(tng_add_atom_to_molecule(traj, &traj->molecules[0], "atom7", "type3") == TNG_CRITICAL)
+// {
+// return(TNG_CRITICAL);
+// }
+// if(tng_add_atom_to_molecule(traj, &traj->molecules[1], "C1", "C") == TNG_CRITICAL)
+// {
+// return(TNG_CRITICAL);
+// }
+// if(tng_add_atom_to_molecule(traj, &traj->molecules[1], "O1", "O") == TNG_CRITICAL)
+// {
+// return(TNG_CRITICAL);
+// }
+// if(tng_add_atom_to_molecule(traj, &traj->molecules[1], "H11", "H") == TNG_CRITICAL)
+// {
+// return(TNG_CRITICAL);
+// }
+// if(tng_add_atom_to_molecule(traj, &traj->molecules[1], "H12", "H") == TNG_CRITICAL)
+// {
+// return(TNG_CRITICAL);
+// }
+// if(tng_add_atom_to_molecule(traj, &traj->molecules[1], "H13", "H") == TNG_CRITICAL)
+// {
+// return(TNG_CRITICAL);
+// }
+*/
+ return(TNG_SUCCESS);
+}
+
+static tng_function_status tng_test_read_and_write_file
+ (tng_trajectory_t traj)
+{
+ tng_function_status stat;
+
+ stat = tng_file_headers_read(traj, TNG_USE_HASH);
+ if(stat == TNG_CRITICAL)
+ {
+ return(stat);
+ }
+ stat = tng_file_headers_write(traj, TNG_USE_HASH);
+ if(stat == TNG_CRITICAL)
+ {
+ return(stat);
+ }
+
+ while(stat == TNG_SUCCESS)
+ {
+ stat = tng_frame_set_read_next(traj, TNG_USE_HASH);
+ if(stat != TNG_SUCCESS)
+ {
+ return(stat);
+ }
+ stat = tng_frame_set_write(traj, TNG_USE_HASH);
+ }
+
+ return(stat);
+}
+
+static tng_function_status tng_test_write_and_read_traj(tng_trajectory_t *traj)
+{
+ int i, j, k, nr, cnt;
+ float *data, *molpos, *charges;
+ int64_t mapping[300], n_particles, n_frames_per_frame_set, tot_n_mols;
+// int64_t frame_nr;
+ double box_shape[9];
+ char atom_type[16], annotation[128];
+ tng_function_status stat = TNG_SUCCESS;
+
+ tng_medium_stride_length_set(*traj, 10);
+ tng_long_stride_length_set(*traj, 100);
+
+ /* Create molecules */
+ if(tng_test_setup_molecules(*traj) == TNG_CRITICAL)
+ {
+ return(TNG_CRITICAL);
+ }
+
+ /* Set the box shape */
+ box_shape[1] = box_shape[2] = box_shape[3] = box_shape[5] = box_shape[6] =
+ box_shape[7] = 0;
+ box_shape[0] = 150.0;
+ box_shape[4] = 145.5;
+ box_shape[8] = 155.5;
+ if(tng_data_block_add(*traj, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE", TNG_DOUBLE_DATA,
+ TNG_NON_TRAJECTORY_BLOCK, 1, 9, 1, TNG_UNCOMPRESSED,
+ box_shape) == TNG_CRITICAL)
+ {
+ tng_trajectory_destroy(traj);
+ printf("Cannot write trajectory box shape.\n");
+ exit(1);
+ }
+
+ /* Set partial charges (treat the water as TIP3P. */
+ tng_num_particles_get(*traj, &n_particles);
+ charges = malloc(sizeof(float) * n_particles);
+ for(i = 0; i < n_particles; i++)
+ {
+ stat = tng_atom_type_of_particle_nr_get(*traj, i, atom_type,
+ sizeof(atom_type));
+ if(stat == TNG_CRITICAL)
+ {
+ break;
+ }
+ if(atom_type[0] == 'O')
+ {
+ charges[i] = -0.834;
+ }
+ else if(atom_type[0] == 'H')
+ {
+ charges[i] = 0.417;
+ }
+ }
+ if(stat == TNG_CRITICAL)
+ {
+ free(charges);
+ printf("Failed setting partial charges.\n");
+ return(TNG_CRITICAL);
+ }
+
+ stat = tng_particle_data_block_add(*traj, TNG_TRAJ_PARTIAL_CHARGES, "PARTIAL CHARGES",
+ TNG_FLOAT_DATA, TNG_NON_TRAJECTORY_BLOCK,
+ 1, 1, 1, 0, n_particles,
+ TNG_UNCOMPRESSED, charges);
+ free(charges);
+ if(stat != TNG_SUCCESS)
+ {
+ printf("Failed adding partial charges\n");
+ return(TNG_CRITICAL);
+ }
+
+
+ /* Generate a custom annotation data block */
+ strcpy(annotation, "This trajectory was generated from tng_io_testing. "
+ "It is not a real MD trajectory.");
+ if(tng_data_block_add(*traj, 10100, "DETAILS", TNG_CHAR_DATA,
+ TNG_NON_TRAJECTORY_BLOCK, 1, 1, 1, TNG_UNCOMPRESSED,
+ annotation) != TNG_SUCCESS)
+ {
+ printf("Failed adding details annotation data block.\n");
+ return(TNG_CRITICAL);
+ }
+
+ /* Write file headers (includes non trajectory data blocks */
+ if(tng_file_headers_write(*traj, TNG_SKIP_HASH) == TNG_CRITICAL)
+ {
+ printf("Cannot write file headers.\n");
+ }
+
+
+ tng_num_frames_per_frame_set_get(*traj, &n_frames_per_frame_set);
+
+ data = malloc(sizeof(float) * n_particles *
+ n_frames_per_frame_set * 3);
+ if(!data)
+ {
+ printf("Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+ tng_num_molecules_get(*traj, &tot_n_mols);
+ molpos = malloc(sizeof(float) * tot_n_mols * 3);
+
+ /* Set initial coordinates */
+ for(i = 0; i < tot_n_mols; i++)
+ {
+ nr = i * 3;
+ /* Somewhat random coordinates (between 0 and 100),
+ * but not specifying a random seed */
+ molpos[nr] = 100.0 * rand() / (RAND_MAX + 1.0);
+ molpos[nr+1] = 100.0 * rand() / (RAND_MAX + 1.0);
+ molpos[nr+2] = 100.0 * rand() / (RAND_MAX + 1.0);
+ }
+
+ /* Generate 200 frame sets - each with 100 frames (by default) */
+ for(i = 0; i < 200; i++)
+ {
+ cnt = 0;
+ for(j = 0; j < n_frames_per_frame_set; j++)
+ {
+ for(k = 0; k < tot_n_mols; k++)
+ {
+ nr = k * 3;
+ /* Move -1 to 1 */
+ molpos[nr] += 2 * (rand() / (RAND_MAX + 1.0)) - 1;
+ molpos[nr+1] += 2 * (rand() / (RAND_MAX + 1.0)) - 1;
+ molpos[nr+2] += 2 * (rand() / (RAND_MAX + 1.0)) - 1;
+
+ data[cnt++] = molpos[nr];
+ data[cnt++] = molpos[nr + 1];
+ data[cnt++] = molpos[nr + 2];
+ data[cnt++] = molpos[nr] + 1;
+ data[cnt++] = molpos[nr + 1] + 1;
+ data[cnt++] = molpos[nr + 2] + 1;
+ data[cnt++] = molpos[nr] - 1;
+ data[cnt++] = molpos[nr + 1] - 1;
+ data[cnt++] = molpos[nr + 2] - 1;
+ }
+ }
+ if(tng_frame_set_new(*traj, i * n_frames_per_frame_set,
+ n_frames_per_frame_set) != TNG_SUCCESS)
+ {
+ printf("Error creating frame set %d. %s: %d\n",
+ i, __FILE__, __LINE__);
+ free(molpos);
+ free(data);
+ return(TNG_CRITICAL);
+ }
+
+ tng_frame_set_particle_mapping_free(*traj);
+
+ /* Setup particle mapping. Use 4 different mapping blocks with arbitrary
+ * mappings. */
+ for(k=0; k<150; k++)
+ {
+ mapping[k]=k;
+ }
+ if(tng_particle_mapping_add(*traj, 0, 150, mapping) != TNG_SUCCESS)
+ {
+ printf("Error creating particle mapping. %s: %d\n",
+ __FILE__, __LINE__);
+ free(molpos);
+ free(data);
+ return(TNG_CRITICAL);
+ }
+ for(k=0; k<150; k++)
+ {
+ mapping[k]=599-k;
+ }
+ if(tng_particle_mapping_add(*traj, 150, 150, mapping) != TNG_SUCCESS)
+ {
+ printf("Error creating particle mapping. %s: %d\n",
+ __FILE__, __LINE__);
+ free(molpos);
+ free(data);
+ return(TNG_CRITICAL);
+ }
+ for(k=0; k<150; k++)
+ {
+ mapping[k]=k+150;
+ }
+ if(tng_particle_mapping_add(*traj, 300, 150, mapping) != TNG_SUCCESS)
+ {
+ printf("Error creating particle mapping. %s: %d\n",
+ __FILE__, __LINE__);
+ free(molpos);
+ free(data);
+ return(TNG_CRITICAL);
+ }
+ for(k=0; k<150; k++)
+ {
+ mapping[k]=449-k;
+ }
+ if(tng_particle_mapping_add(*traj, 450, 150, mapping) != TNG_SUCCESS)
+ {
+ printf("Error creating particle mapping. %s: %d\n",
+ __FILE__, __LINE__);
+ free(molpos);
+ free(data);
+ return(TNG_CRITICAL);
+ }
+
+ /* Add the positions in a data block */
+ if(tng_particle_data_block_add(*traj, TNG_TRAJ_POSITIONS,
+ "POSITIONS",
+ TNG_FLOAT_DATA,
+ TNG_TRAJECTORY_BLOCK,
+ n_frames_per_frame_set, 3,
+ 1, 0, n_particles,
+/* TNG_UNCOMPRESSED, */
+ TNG_GZIP_COMPRESSION,
+ data) != TNG_SUCCESS)
+ {
+ printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ free(molpos);
+ free(data);
+ return(TNG_CRITICAL);
+ }
+ /* Write the frame set */
+ if(tng_frame_set_write(*traj, TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ printf("Error writing frame set. %s: %d\n", __FILE__, __LINE__);
+ free(molpos);
+ free(data);
+ return(TNG_CRITICAL);
+ }
+ }
+
+ /* Write two more frame sets one frame at a time */
+
+ /* Make a new frame set - if always using the same mapping blocks
+ * it is not necessary to explicitly add a new frame set - it will
+ * be added automatically when adding data for a frame */
+/* if(tng_frame_set_new(*traj, i * n_frames_per_frame_set,
+ n_frames_per_frame_set) != TNG_SUCCESS)
+ {
+ printf("Error creating frame set %d. %s: %d\n",
+ i, __FILE__, __LINE__);
+ free(molpos);
+ free(data);
+ return(TNG_CRITICAL);
+ }
+
+ frame_nr = i * n_frames_per_frame_set;
+
+ for(k=0; k<300; k++)
+ {
+ mapping[k]=k;
+ }
+ *//* Just use two particle mapping blocks in this frame set *//*
+ if(tng_particle_mapping_add(*traj, 0, 300, mapping) != TNG_SUCCESS)
+ {
+ printf("Error creating particle mapping. %s: %d\n",
+ __FILE__, __LINE__);
+ free(molpos);
+ free(data);
+ return(TNG_CRITICAL);
+ }
+ for(k=0; k<300; k++)
+ {
+ mapping[k]=599-k;
+ }
+ if(tng_particle_mapping_add(*traj, 300, 300, mapping) != TNG_SUCCESS)
+ {
+ printf("Error creating particle mapping. %s: %d\n",
+ __FILE__, __LINE__);
+ free(molpos);
+ free(data);
+ return(TNG_CRITICAL);
+ }
+
+ *//* Add the data block to the current frame set *//*
+ if(tng_particle_data_block_add(*traj, TNG_TRAJ_POSITIONS,
+ "POSITIONS",
+ TNG_FLOAT_DATA,
+ TNG_TRAJECTORY_BLOCK,
+ n_frames_per_frame_set, 3,
+ 1, 0, n_particles,
+ TNG_UNCOMPRESSED,
+ 0) != TNG_SUCCESS)
+ {
+ printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ free(molpos);
+ free(data);
+ return(TNG_CRITICAL);
+ }
+
+ *//* Write the frame set to disk *//*
+ if(tng_frame_set_write(*traj, TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ printf("Error writing frame set. %s: %d\n", __FILE__, __LINE__);
+ free(molpos);
+ free(data);
+ return(TNG_CRITICAL);
+ }
+
+ *//* Write particle data to disk - one frame at a time *//*
+ for(i = 0; i < n_frames_per_frame_set * 2; i++)
+ {
+ for(j = 0; j < 2; j++)
+ {
+ cnt = 0;
+ for(k = 0; k < tot_n_mols/2; k++)
+ {
+ nr = k * 3;
+ *//* Move -1 to 1 *//*
+ molpos[nr] += 2 * (rand() / (RAND_MAX + 1.0)) - 1;
+ molpos[nr+1] += 2 * (rand() / (RAND_MAX + 1.0)) - 1;
+ molpos[nr+2] += 2 * (rand() / (RAND_MAX + 1.0)) - 1;
+
+ data[cnt++] = molpos[nr];
+ data[cnt++] = molpos[nr + 1];
+ data[cnt++] = molpos[nr + 2];
+ data[cnt++] = molpos[nr] + 1;
+ data[cnt++] = molpos[nr + 1] + 1;
+ data[cnt++] = molpos[nr + 2] + 1;
+ data[cnt++] = molpos[nr] - 1;
+ data[cnt++] = molpos[nr + 1] - 1;
+ data[cnt++] = molpos[nr + 2] - 1;
+ }
+ if(tng_frame_particle_data_write(*traj, frame_nr + i,
+ TNG_TRAJ_POSITIONS, j * 300, 300,
+ data, TNG_SKIP_HASH) != TNG_SUCCESS)
+ {
+ printf("Error adding data. %s: %d\n", __FILE__, __LINE__);
+ free(molpos);
+ free(data);
+ return(TNG_CRITICAL);
+ }
+ }
+ }
+*/
+ free(molpos);
+ free(data);
+
+ tng_trajectory_destroy(traj);
+ tng_trajectory_init(traj);
+#ifdef TNG_EXAMPLE_FILES_DIR
+ tng_input_file_set(*traj, TNG_EXAMPLE_FILES_DIR "tng_test.tng");
+#else
+ tng_input_file_set(*traj, "/tmp/tng_test.tng");
+#endif
+
+ stat = tng_file_headers_read(*traj, TNG_SKIP_HASH);
+
+ while(stat == TNG_SUCCESS)
+ {
+ stat = tng_frame_set_read_next(*traj, TNG_SKIP_HASH);
+ }
+
+ return(stat);
+}
+
+/* This test relies on knowing that the box shape is stored as double */
+tng_function_status tng_test_get_box_data(tng_trajectory_t traj)
+{
+ int64_t n_frames, n_values_per_frame;
+ union data_values **values = 0;
+ char type;
+
+ if(tng_data_get(traj, TNG_TRAJ_BOX_SHAPE, &values, &n_frames,
+ &n_values_per_frame, &type) != TNG_SUCCESS)
+ {
+ printf("Failed getting box shape. %s: %d\n", __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+/*
+// int64_t i, j;
+// printf("Box shape:");
+// for(i=0; i<n_frames; i++)
+// {
+// for(j=0; j<n_values_per_frame; j++)
+// {
+// printf("\t%f", (values[i][j]).d);
+// }
+// printf("\n");
+// }
+*/
+ tng_data_values_free(traj, values, n_frames, n_values_per_frame, type);
+
+ return(TNG_SUCCESS);
+}
+
+/* This test relies on knowing that the positions are stored as float
+ * and that the data is not sparse (i.e. as many frames in the data
+ * as in the frame set */
+tng_function_status tng_test_get_positions_data(tng_trajectory_t traj)
+{
+ int64_t n_frames, n_particles, n_values_per_frame;
+ union data_values ***values = 0;
+ char type;
+
+ if(tng_particle_data_get(traj, TNG_TRAJ_POSITIONS, &values, &n_frames,
+ &n_particles, &n_values_per_frame, &type) !=
+ TNG_SUCCESS)
+ {
+ printf("Failed getting particle positions. %s: %d\n", __FILE__, __LINE__);
+ return(TNG_CRITICAL);
+ }
+
+/*
+// int64_t i, j, k;
+// struct tng_trajectory_frame_set *frame_set =
+// &traj->current_trajectory_frame_set;
+// for(i = 0; i<n_frames; i++)
+// {
+// printf("Frame %"PRId64"\n", frame_set->first_frame + i);
+// for(j = 0; j<n_particles; j++)
+// {
+// printf("Particle %"PRId64":", j);
+// for(k=0; k<n_values_per_frame; k++)
+// {
+// printf("\t%f", (values[i][j][k]).f);
+// }
+// printf("\n");
+// }
+// }
+*/
+ tng_particle_data_values_free(traj, values, n_frames, n_particles,
+ n_values_per_frame, type);
+
+ values = 0;
+
+ tng_particle_data_interval_get(traj, TNG_TRAJ_POSITIONS, 11000, 11499,
+ TNG_SKIP_HASH, &values, &n_particles,
+ &n_values_per_frame, &type);
+
+ /* Here the particle positions can be printed */
+
+ tng_particle_data_values_free(traj, values, 500, n_particles,
+ n_values_per_frame, type);
+
+ return(TNG_SUCCESS);
+}
+
+int main()
+{
+ tng_trajectory_t traj;
+ tng_function_status stat;
+ char time_str[TNG_MAX_DATE_STR_LEN];
+
+ if(tng_trajectory_init(&traj) != TNG_SUCCESS)
+ {
+ tng_trajectory_destroy(&traj);
+ printf("Test Init trajectory:\t\t\t\tFailed. %s: %d.\n",
+ __FILE__, __LINE__);
+ exit(1);
+ }
+ printf("Test Init trajectory:\t\t\t\tSucceeded.\n");
+
+ tng_time_get_str(traj, time_str);
+
+ printf("Creation time: %s\n", time_str);
+
+#ifdef TNG_EXAMPLE_FILES_DIR
+ tng_input_file_set(traj, TNG_EXAMPLE_FILES_DIR "tng_example.tng");
+ tng_output_file_set(traj, TNG_EXAMPLE_FILES_DIR "tng_example_out.tng");
+#else
+ tng_input_file_set(traj, "tng_example.tng");
+ tng_output_file_set(traj, "/tmp/tng_example_out.tng");
+#endif
+
+
+ if(tng_test_read_and_write_file(traj) == TNG_CRITICAL)
+ {
+ printf("Test Read and write file:\t\t\tFailed. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ else
+ {
+ printf("Test Read and write file:\t\t\tSucceeded.\n");
+ }
+
+ if(tng_test_get_box_data(traj) != TNG_SUCCESS)
+ {
+ printf("Test Get data:\t\t\t\t\tFailed. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ else
+ {
+ printf("Test Get data:\t\t\t\t\tSucceeded.\n");
+ }
+
+ if(tng_trajectory_destroy(&traj) == TNG_CRITICAL ||
+ tng_trajectory_init(&traj) == TNG_CRITICAL)
+ {
+ printf("Test Destroy and init trajectory:\t\tFailed. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ else
+ {
+ printf("Test Destroy and init trajectory:\t\tSucceeded.\n");
+ }
+
+
+#ifdef TNG_EXAMPLE_FILES_DIR
+ tng_output_file_set(traj, TNG_EXAMPLE_FILES_DIR "tng_test.tng");
+#else
+ tng_output_file_set(traj, "/tmp/tng_test.tng");
+#endif
+
+ if(tng_test_write_and_read_traj(&traj) == TNG_CRITICAL)
+ {
+ printf("Test Write and read file:\t\t\tFailed. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ else
+ {
+ printf("Test Write and read file:\t\t\tSucceeded.\n");
+ }
+
+ if(tng_test_get_positions_data(traj) != TNG_SUCCESS)
+ {
+ printf("Test Get particle data:\t\t\t\tFailed. %s: %d\n",
+ __FILE__, __LINE__);
+ }
+ else
+ {
+ printf("Test Get particle data:\t\t\t\tSucceeded.\n");
+ }
+
+ if(tng_trajectory_destroy(&traj) == TNG_CRITICAL)
+ {
+ printf("Test Destroy trajectory:\t\t\tFailed. %s: %d.\n",
+ __FILE__, __LINE__);
+ exit(1);
+ }
+ else
+ {
+ printf("Test Destroy trajectory:\t\t\tSucceeded.\n");
+ }
+
+
+#ifdef TNG_EXAMPLE_FILES_DIR
+ stat = tng_util_trajectory_open(TNG_EXAMPLE_FILES_DIR "tng_test.tng", 'r', &traj);
+#else
+ stat = tng_util_trajectory_open("/tmp/tng_test.tng", 'r', &traj);
+#endif
+ if(stat != TNG_SUCCESS)
+ {
+ printf("Test Utility function open:\t\t\tFailed. %s: %d.\n",
+ __FILE__, __LINE__);
+ exit(1);
+ }
+ else
+ {
+ printf("Test Utility function open:\t\t\tSucceeded.\n");
+ }
+
+ stat = tng_util_trajectory_close(&traj);
+ if(stat != TNG_SUCCESS)
+ {
+ printf("Test Utility function close:\t\t\tFailed. %s: %d.\n",
+ __FILE__, __LINE__);
+ exit(1);
+ }
+ else
+ {
+ printf("Test Utility function close:\t\t\tSucceeded.\n");
+ }
+
+ printf("Tests finished\n");
+
+ exit(0);
+}
--- /dev/null
+#ifdef TNG_BUILD_OPENMP_EXAMPLES
+
+/* This code is part of the tng binary trajectory format.
+ *
+ * VERSION 1.0
+ *
+ * Written by Magnus Lundborg
+ * Copyright (c) 2012-2013, The GROMACS development team.
+ * Check out http://www.gromacs.org for more information.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the Revised BSD License.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "../../include/tng_io.h"
+
+
+/* N.B. this code is for testing parallel reading of trajectory frame sets. The
+ * performance is not improved very much and is to a large extent limited by
+ * disk i/o. It can however be used as inspiration for writing parallel code
+ * using the TNG library. The code is NOT fully tested and may behave strangely. */
+
+int main(int argc, char **argv)
+{
+ tng_trajectory_t traj, local_traj = 0;
+ union data_values ***local_positions = 0; // A 3-dimensional array to be populated
+ union data_values **particle_pos = 0;
+ int64_t n_particles, n_values_per_frame, n_frame_sets, n_frames;
+ int64_t n_frames_per_frame_set, tot_n_frames = 0;
+ char data_type;
+ int i, j, fail;
+ int64_t particle = 0, local_first_frame, local_last_frame;
+ char atom_name[64], res_name[64];
+ tng_trajectory_frame_set_t frame_set = 0;
+
+ if(argc <= 1)
+ {
+ printf("No file specified\n");
+ printf("Usage:\n");
+ printf("tng_parallel_read <tng_file> [particle number = %"PRId64"]\n",
+ particle);
+ exit(1);
+ }
+
+ // A reference must be passed to allocate memory
+ if(tng_trajectory_init(&traj) != TNG_SUCCESS)
+ {
+ tng_trajectory_destroy(&traj);
+ exit(1);
+ }
+ tng_input_file_set(traj, argv[1]);
+
+ tng_current_frame_set_get(traj, &frame_set);
+
+ // Read the file headers
+ tng_file_headers_read(traj, TNG_USE_HASH);
+
+ if(argc >= 3)
+ {
+ particle = strtoll(argv[2], 0, 10);
+ }
+
+ tng_num_frame_sets_get(traj, &n_frame_sets);
+ tng_num_frames_per_frame_set_get(traj, &n_frames_per_frame_set);
+
+ particle_pos = malloc(sizeof(union data_values *) * n_frame_sets *
+ n_frames_per_frame_set);
+ for(i = n_frame_sets * n_frames_per_frame_set; i--;)
+ {
+ /* Assume 3 values per frame even if it's not determined yet */
+ particle_pos[i] = malloc(sizeof(union data_values) * 3);
+ }
+
+ printf("%"PRId64" frame sets\n", n_frame_sets);
+
+ if(tng_atom_name_of_particle_nr_get(traj, particle, atom_name,
+ sizeof(atom_name)) ==
+ TNG_SUCCESS &&
+ tng_residue_name_of_particle_nr_get(traj, particle, res_name,
+ sizeof(res_name)) ==
+ TNG_SUCCESS)
+ {
+ printf("Particle: %s (%s)\n", atom_name, res_name);
+ }
+ else
+ {
+ printf("Particle name not found\n");
+ }
+
+ fail = 0;
+
+#pragma omp parallel \
+private (n_frames, n_particles, n_values_per_frame, \
+ local_first_frame, local_last_frame, j, fail) \
+firstprivate (local_traj, local_positions, frame_set)\
+shared(data_type, traj, n_frame_sets, particle_pos, particle, i, tot_n_frames)\
+default(none)
+{
+ /* Each tng_trajectory_t keeps its own file pointers and i/o positions.
+ * Therefore there must be a copy for each thread. */
+ tng_trajectory_init_from_src(traj, &local_traj);
+#pragma omp for
+ for(i = 0; i < n_frame_sets; i++)
+ {
+ if(tng_frame_set_nr_find(local_traj, i) != TNG_SUCCESS)
+ {
+ printf("FAILED finding frame set %d!\n", i);
+ tot_n_frames = 0;
+ fail = 1;
+ }
+ if(tng_particle_data_get(local_traj, TNG_TRAJ_POSITIONS, &local_positions,
+ &n_frames, &n_particles, &n_values_per_frame,
+ &data_type) != TNG_SUCCESS)
+ {
+ printf("FAILED getting particle data\n");
+ tot_n_frames = 0;
+ fail = 1;
+ }
+ if(!fail)
+ {
+ tng_current_frame_set_get(local_traj, &frame_set);
+ tng_frame_set_frame_range_get(local_traj, frame_set, &local_first_frame, &local_last_frame);
+ // printf("Frame %"PRId64"-%"PRId64":\n", local_first_frame, local_last_frame);
+ // printf("%"PRId64" %"PRId64" %"PRId64"\n", n_frames, n_particles, n_values_per_frame);
+ tot_n_frames += n_frames;
+ for(j = 0; j < n_frames; j++)
+ {
+ particle_pos[local_first_frame + j][0] = local_positions[j][particle][0];
+ particle_pos[local_first_frame + j][1] = local_positions[j][particle][1];
+ particle_pos[local_first_frame + j][2] = local_positions[j][particle][2];
+ }
+ }
+ }
+
+ // Free memory
+ if(local_positions)
+ {
+ tng_particle_data_values_free(local_traj, local_positions, n_frames, n_particles,
+ n_values_per_frame, data_type);
+ }
+ tng_trajectory_destroy(&local_traj);
+}
+ switch(data_type)
+ {
+ case TNG_INT_DATA:
+ for(j = 0; j < tot_n_frames; j++)
+ {
+ printf("\t%"PRId64"\t%"PRId64"\t%"PRId64"\n", particle_pos[j][0].i,
+ particle_pos[j][1].i, particle_pos[j][2].i);
+ }
+ break;
+ case TNG_FLOAT_DATA:
+ for(j = 0; j < tot_n_frames; j++)
+ {
+ printf("\t%f\t%f\t%f\n", particle_pos[j][0].f,
+ particle_pos[j][1].f, particle_pos[j][2].f);
+ }
+ break;
+ case TNG_DOUBLE_DATA:
+ for(j = 0; j < tot_n_frames; j++)
+ {
+ printf("\t%f\t%f\t%f\n", particle_pos[j][0].d,
+ particle_pos[j][1].d, particle_pos[j][2].d);
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Free more memory */
+ for(i = n_frame_sets * n_frames_per_frame_set; i--;)
+ {
+ free(particle_pos[i]);
+ }
+ free(particle_pos);
+
+ tng_trajectory_destroy(&traj);
+
+ return(0);
+}
+
+#endif
target_link_libraries(libgromacs ${GMX_GPU_LIBRARIES}
${GMX_EXTRA_LIBRARIES}
+ ${GMX_TNG_LIBRARIES}
${FFT_LIBRARIES} ${LINEAR_ALGEBRA_LIBRARIES}
${XML_LIBRARIES} ${GSL_LIBRARIES}
${THREAD_LIB} ${GMX_SHARED_LINKER_FLAGS})
#
# This file is part of the GROMACS molecular simulation package.
#
-# Copyright (c) 2013, by the GROMACS development team, led by
+# Copyright (c) 2013,2014, by the GROMACS development team, led by
# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
# and including many others, as listed in the AUTHORS file in the
# top-level source directory and at http://www.gromacs.org.
)
gmx_install_headers(fileio ${FILEIO_PUBLIC_HEADERS})
+# These files include tng_io.h from the TNG library. That header needs to know
+# whether inttypes.h exists or not.
+include(CheckIncludeFiles)
+check_include_file(inttypes.h HAVE_INTTYPES_H)
+if(HAVE_INTTYPES_H)
+ set_property(SOURCE tngio.cpp APPEND PROPERTY COMPILE_DEFINITIONS USE_STD_INTTYPES_H)
+ set_property(SOURCE tngio_for_tools.cpp APPEND PROPERTY COMPILE_DEFINITIONS USE_STD_INTTYPES_H)
+endif()
+
if (BUILD_TESTING)
-# add_subdirectory(tests)
+ add_subdirectory(tests)
endif (BUILD_TESTING)
enum
{
- eftASC, eftBIN, eftXDR, eftGEN, eftNR
+ eftASC, eftBIN, eftXDR, eftTNG, eftGEN, eftNR
};
/* To support multiple file types with one general (eg TRX) we have
#ifdef USE_XDR
efXTC, efTRR, efCPT,
#endif
- efTRJ, efGRO, efG96, efPDB, efG87
+ efTRJ, efGRO, efG96, efPDB, efG87, efTNG
};
#define NTRXS asize(trxs)
+static const int trcompressed[] =
+{
+#ifdef USE_XDR
+ efXTC,
+#endif
+ efTNG
+};
+#define NTRCOMPRESSED asize(trcompressed)
+
static const int tros[] =
{
#ifdef USE_XDR
efXTC, efTRR,
#endif
- efTRJ, efGRO, efG96, efPDB, efG87
+ efTRJ, efGRO, efG96, efPDB, efG87, efTNG
};
#define NTROS asize(tros)
#ifdef USE_XDR
efTRR, efCPT,
#endif
- efTRJ
+ efTRJ, efTNG
};
#define NTRNS asize(trns)
{
{ eftASC, ".mdp", "grompp", "-f", "grompp input file with MD parameters" },
{ eftGEN, ".???", "traj", "-f",
- "Trajectory: xtc trr trj gro g96 pdb cpt", NTRXS, trxs },
+ "Trajectory: tng xtc trr trj gro g96 pdb cpt", NTRXS, trxs },
{ eftGEN, ".???", "trajout", "-f",
- "Trajectory: xtc trr trj gro g96 pdb", NTROS, tros },
+ "Trajectory: tng xtc trr trj gro g96 pdb", NTROS, tros },
{ eftGEN, ".???", "traj", NULL,
- "Full precision trajectory: trr trj cpt", NTRNS, trns },
+ "Full precision trajectory: tng trr trj cpt", NTRNS, trns },
{ eftXDR, ".trr", "traj", NULL, "Trajectory in portable xdr format" },
{ eftBIN, ".trj", "traj", NULL, "Trajectory file (architecture specific)" },
+ { eftGEN, ".???", "traj_comp", NULL,
+ "Compressed trajectory (tng format or portable xdr format): tng xtc", NTRCOMPRESSED, trcompressed},
{ eftXDR, ".xtc", "traj", NULL,
- "Compressed trajectory (portable xdr format)" },
+ "Compressed trajectory (portable xdr format): xtc" },
+ { eftTNG, ".tng", "traj", NULL,
+ "Trajectory file (tng format)" },
{ eftASC, ".g87", "gtraj", NULL, "Gromos-87 ASCII trajectory format" },
{ eftXDR, ".edr", "ener", NULL, "Energy file"},
{ eftGEN, ".???", "conf", "-c", "Structure file: gro g96 pdb tpr etc.",
return "Binary";
case eftXDR:
return "XDR portable";
+ case eftTNG:
+ return "TNG";
case eftGEN:
return "";
default:
/* this enum should correspond to the array deffile in gmxlib/filenm.c */
enum {
efMDP,
- efTRX, efTRO, efTRN, efTRR, efTRJ, efXTC, efG87,
+ efTRX, efTRO, efTRN, efTRR, efTRJ, efCOMPRESSED, efXTC, efTNG, efG87,
efEDR,
efSTX, efSTO, efGRO, efG96, efPDB, efBRK, efENT, efESP, efPQR, efXYZ,
efCPT,
/* These simple lists define the I/O type for these files */
static const int ftpXDR[] =
-{ efTPR, efTRR, efEDR, efXTC, efMTX, efCPT };
+{ efTPR, efTRR, efEDR, efXTC, efTNG, efMTX, efCPT };
static const int ftpASC[] =
{ efTPA, efGRO, efPDB };
static const int ftpBIN[] =
-{ efTPB, efTRJ };
+{ efTPB, efTRJ, efTNG };
#ifdef HAVE_XML
static const int ftpXML[] =
{ efXML};
gmx_open(fn);
}
}
+ if (fn2ftp(fn) == efTNG)
+ {
+ gmx_incons("gmx_fio_open may not be used to open TNG files");
+ }
/* Open the file */
fio->fp = ffopen(fn, newmode);
/* We don't want two processes operating on the list at the same time */
tMPI_Thread_mutex_lock(&open_file_mutex);
+ if (fio->iFTP == efTNG)
+ {
+ gmx_incons("gmx_fio_close should not be called on a TNG file");
+ }
gmx_fio_lock(fio);
/* first remove it from the list */
gmx_fio_remove(fio);
#include "mdoutf.h"
#include "gromacs/legacyheaders/xvgr.h"
-#include "trnio.h"
-#include "xtcio.h"
#include "gromacs/legacyheaders/mdrun.h"
#include "gromacs/legacyheaders/smalloc.h"
+#include "gromacs/legacyheaders/mvdata.h"
+#include "gromacs/legacyheaders/domdec.h"
+#include "trnio.h"
+#include "xtcio.h"
+#include "tngio.h"
+#include "trajectory_writing.h"
+#include "checkpoint.h"
+
+struct gmx_mdoutf {
+ t_fileio *fp_trn;
+ t_fileio *fp_xtc;
+ tng_trajectory_t tng;
+ tng_trajectory_t tng_low_prec;
+ int x_compression_precision; /* only used by XTC output */
+ ener_file_t fp_ene;
+ const char *fn_cpt;
+ gmx_bool bKeepAndNumCPT;
+ int eIntegrator;
+ gmx_bool bExpanded;
+ int elamstats;
+ int simulation_part;
+ FILE *fp_dhdl;
+ FILE *fp_field;
+ int natoms_global;
+ int natoms_x_compressed;
+ gmx_groups_t *groups; /* for compressed position writing */
+};
+
-gmx_mdoutf_t *init_mdoutf(int nfile, const t_filenm fnm[], int mdrun_flags,
- const t_commrec *cr, const t_inputrec *ir,
- gmx_mtop_t *top_global,
- const output_env_t oenv)
+gmx_mdoutf_t init_mdoutf(int nfile, const t_filenm fnm[], int mdrun_flags,
+ const t_commrec *cr, const t_inputrec *ir,
+ gmx_mtop_t *top_global,
+ const output_env_t oenv)
{
- gmx_mdoutf_t *of;
+ gmx_mdoutf_t of;
char filemode[3];
gmx_bool bAppendFiles;
int i;
snew(of, 1);
- of->fp_trn = NULL;
- of->fp_ene = NULL;
- of->fp_xtc = NULL;
- of->fp_dhdl = NULL;
- of->fp_field = NULL;
+ of->fp_trn = NULL;
+ of->fp_ene = NULL;
+ of->fp_xtc = NULL;
+ of->tng = NULL;
+ of->tng_low_prec = NULL;
+ of->fp_dhdl = NULL;
+ of->fp_field = NULL;
of->eIntegrator = ir->eI;
of->bExpanded = ir->bExpanded;
of->elamstats = ir->expandedvals->elamstats;
of->simulation_part = ir->simulation_part;
+ of->x_compression_precision = ir->x_compression_precision;
if (MASTER(cr))
{
#endif
)
{
- of->fp_trn = open_trn(ftp2fn(efTRN, nfile, fnm), filemode);
+ const char *filename;
+ filename = ftp2fn(efTRN, nfile, fnm);
+ switch (fn2ftp(filename))
+ {
+ case efTRR:
+ case efTRN:
+ of->fp_trn = open_trn(filename, filemode);
+ break;
+ case efTNG:
+ gmx_tng_open(filename, filemode[0], &of->tng);
+ if (filemode[0] == 'w')
+ {
+ gmx_tng_prepare_md_writing(of->tng, top_global, ir);
+ }
+ break;
+ default:
+ gmx_incons("Invalid full precision file format");
+ }
}
if (EI_DYNAMICS(ir->eI) &&
- ir->nstxtcout > 0)
+ ir->nstxout_compressed > 0)
{
- of->fp_xtc = open_xtc(ftp2fn(efXTC, nfile, fnm), filemode);
- of->xtc_prec = ir->xtcprec;
+ const char *filename;
+ filename = ftp2fn(efCOMPRESSED, nfile, fnm);
+ switch (fn2ftp(filename))
+ {
+ case efXTC:
+ of->fp_xtc = open_xtc(filename, filemode);
+ break;
+ case efTNG:
+ gmx_tng_open(filename, filemode[0], &of->tng_low_prec);
+ if (filemode[0] == 'w')
+ {
+ gmx_tng_prepare_low_prec_writing(of->tng_low_prec, top_global, ir);
+ }
+ break;
+ default:
+ gmx_incons("Invalid reduced precision file format");
+ }
}
if (EI_DYNAMICS(ir->eI) || EI_ENERGY_MINIMIZATION(ir->eI))
{
groups, and how to look up later which ones they are. */
of->natoms_global = top_global->natoms;
of->groups = &top_global->groups;
- of->natoms_xtc = 0;
+ of->natoms_x_compressed = 0;
for (i = 0; (i < top_global->natoms); i++)
{
- if (ggrpnr(of->groups, egcXTC, i) == 0)
+ if (ggrpnr(of->groups, egcCompressedX, i) == 0)
{
- of->natoms_xtc++;
+ of->natoms_x_compressed++;
}
}
}
return of;
}
-void done_mdoutf(gmx_mdoutf_t *of)
+FILE *mdoutf_get_fp_field(gmx_mdoutf_t of)
+{
+ return of->fp_field;
+}
+
+ener_file_t mdoutf_get_fp_ene(gmx_mdoutf_t of)
+{
+ return of->fp_ene;
+}
+
+FILE *mdoutf_get_fp_dhdl(gmx_mdoutf_t of)
+{
+ return of->fp_dhdl;
+}
+
+static void moveit(t_commrec *cr, rvec xx[])
+{
+ if (!xx)
+ {
+ return;
+ }
+
+ move_rvecs(cr, FALSE, FALSE, xx, NULL, (cr->nnodes-cr->npmenodes)-1, NULL);
+}
+
+void mdoutf_write_to_trajectory_files(FILE *fplog, t_commrec *cr,
+ gmx_mdoutf_t of,
+ int mdof_flags,
+ gmx_mtop_t *top_global,
+ gmx_int64_t step, double t,
+ t_state *state_local, t_state *state_global,
+ rvec *f_local, rvec *f_global)
+{
+ rvec *local_v;
+ rvec *global_v;
+
+#define MX(xvf) moveit(cr, xvf)
+
+ /* MRS -- defining these variables is to manage the difference
+ * between half step and full step velocities, but there must be a better way . . . */
+
+ local_v = state_local->v;
+ global_v = state_global->v;
+
+ if (DOMAINDECOMP(cr))
+ {
+ if (mdof_flags & MDOF_CPT)
+ {
+ dd_collect_state(cr->dd, state_local, state_global);
+ }
+ else
+ {
+ if (mdof_flags & (MDOF_X | MDOF_X_COMPRESSED))
+ {
+ dd_collect_vec(cr->dd, state_local, state_local->x,
+ state_global->x);
+ }
+ if (mdof_flags & MDOF_V)
+ {
+ dd_collect_vec(cr->dd, state_local, local_v,
+ global_v);
+ }
+ }
+ if (mdof_flags & MDOF_F)
+ {
+ dd_collect_vec(cr->dd, state_local, f_local, f_global);
+ }
+ }
+ else
+ {
+ if (mdof_flags & MDOF_CPT)
+ {
+ /* All pointers in state_local are equal to state_global,
+ * but we need to copy the non-pointer entries.
+ */
+ state_global->lambda = state_local->lambda;
+ state_global->veta = state_local->veta;
+ state_global->vol0 = state_local->vol0;
+ copy_mat(state_local->box, state_global->box);
+ copy_mat(state_local->boxv, state_global->boxv);
+ copy_mat(state_local->svir_prev, state_global->svir_prev);
+ copy_mat(state_local->fvir_prev, state_global->fvir_prev);
+ copy_mat(state_local->pres_prev, state_global->pres_prev);
+ }
+ if (cr->nnodes > 1)
+ {
+ /* Particle decomposition, collect the data on the master node */
+ if (mdof_flags & MDOF_CPT)
+ {
+ if (state_local->flags & (1<<estX))
+ {
+ MX(state_global->x);
+ }
+ if (state_local->flags & (1<<estV))
+ {
+ MX(state_global->v);
+ }
+ if (state_local->flags & (1<<estSDX))
+ {
+ MX(state_global->sd_X);
+ }
+ if (state_global->nrngi > 1)
+ {
+ if (state_local->flags & (1<<estLD_RNG))
+ {
+#ifdef GMX_MPI
+ MPI_Gather(state_local->ld_rng,
+ state_local->nrng*sizeof(state_local->ld_rng[0]), MPI_BYTE,
+ state_global->ld_rng,
+ state_local->nrng*sizeof(state_local->ld_rng[0]), MPI_BYTE,
+ MASTERRANK(cr), cr->mpi_comm_mygroup);
+#endif
+ }
+ if (state_local->flags & (1<<estLD_RNGI))
+ {
+#ifdef GMX_MPI
+ MPI_Gather(state_local->ld_rngi,
+ sizeof(state_local->ld_rngi[0]), MPI_BYTE,
+ state_global->ld_rngi,
+ sizeof(state_local->ld_rngi[0]), MPI_BYTE,
+ MASTERRANK(cr), cr->mpi_comm_mygroup);
+#endif
+ }
+ }
+ }
+ else
+ {
+ if (mdof_flags & (MDOF_X | MDOF_X_COMPRESSED))
+ {
+ MX(state_global->x);
+ }
+ if (mdof_flags & MDOF_V)
+ {
+ MX(global_v);
+ }
+ }
+ if (mdof_flags & MDOF_F)
+ {
+ MX(f_global);
+ }
+ }
+ }
+
+ if (MASTER(cr))
+ {
+ if (mdof_flags & MDOF_CPT)
+ {
+ fflush_tng(of->tng);
+ fflush_tng(of->tng_low_prec);
+ write_checkpoint(of->fn_cpt, of->bKeepAndNumCPT,
+ fplog, cr, of->eIntegrator, of->simulation_part,
+ of->bExpanded, of->elamstats, step, t, state_global);
+ }
+
+ if (mdof_flags & (MDOF_X | MDOF_V | MDOF_F))
+ {
+ if (of->fp_trn)
+ {
+ fwrite_trn(of->fp_trn, step, t, state_local->lambda[efptFEP],
+ state_local->box, top_global->natoms,
+ (mdof_flags & MDOF_X) ? state_global->x : NULL,
+ (mdof_flags & MDOF_V) ? global_v : NULL,
+ (mdof_flags & MDOF_F) ? f_global : NULL);
+ if (gmx_fio_flush(of->fp_trn) != 0)
+ {
+ gmx_file("Cannot write trajectory; maybe you are out of disk space?");
+ }
+ }
+
+ gmx_fwrite_tng(of->tng, FALSE, step, t, state_local->lambda[efptFEP],
+ (const rvec *) state_local->box,
+ top_global->natoms,
+ (mdof_flags & MDOF_X) ? (const rvec *) state_global->x : NULL,
+ (mdof_flags & MDOF_V) ? (const rvec *) global_v : NULL,
+ (mdof_flags & MDOF_F) ? (const rvec *) f_global : NULL);
+ }
+ if (mdof_flags & MDOF_X_COMPRESSED)
+ {
+ rvec *xxtc = NULL;
+
+ if (of->natoms_x_compressed == of->natoms_global)
+ {
+ /* We are writing the positions of all of the atoms to
+ the compressed output */
+ xxtc = state_global->x;
+ }
+ else
+ {
+ /* We are writing the positions of only a subset of
+ the atoms to the compressed output, so we have to
+ make a copy of the subset of coordinates. */
+ int i, j;
+
+ snew(xxtc, of->natoms_x_compressed);
+ for (i = 0, j = 0; (i < of->natoms_x_compressed); i++)
+ {
+ if (ggrpnr(of->groups, egcCompressedX, i) == 0)
+ {
+ copy_rvec(state_global->x[i], xxtc[j++]);
+ }
+ }
+ }
+ if (write_xtc(of->fp_xtc, of->natoms_x_compressed, step, t,
+ state_local->box, xxtc, of->x_compression_precision) == 0)
+ {
+ gmx_fatal(FARGS, "XTC error - maybe you are out of disk space?");
+ }
+ gmx_fwrite_tng(of->tng_low_prec,
+ TRUE,
+ step,
+ t,
+ state_local->lambda[efptFEP],
+ (const rvec *) state_local->box,
+ of->natoms_x_compressed,
+ (const rvec *) xxtc,
+ NULL,
+ NULL);
+ if (of->natoms_x_compressed != of->natoms_global)
+ {
+ sfree(xxtc);
+ }
+ }
+ }
+}
+
+void done_mdoutf(gmx_mdoutf_t of)
{
if (of->fp_ene != NULL)
{
{
gmx_fio_fclose(of->fp_field);
}
+ gmx_tng_close(&of->tng);
+ gmx_tng_close(&of->tng_low_prec);
sfree(of);
}
#ifndef GMX_FILEIO_MDOUTF_H
#define GMX_FILEIO_MDOUTF_H
-#include "filenm.h"
#include <stdio.h>
#include "../legacyheaders/types/simple.h"
+#include "../legacyheaders/types/topology.h"
+#include "../legacyheaders/types/inputrec.h"
+#include "../legacyheaders/types/oenv.h"
+#include "../legacyheaders/network.h"
+#include "filenm.h"
#include "enxio.h"
-#include "gmxfio.h"
-typedef struct {
- t_fileio *fp_trn;
- t_fileio *fp_xtc;
- int xtc_prec;
- ener_file_t fp_ene;
- const char *fn_cpt;
- gmx_bool bKeepAndNumCPT;
- int eIntegrator;
- gmx_bool bExpanded;
- int elamstats;
- int simulation_part;
- FILE *fp_dhdl;
- FILE *fp_field;
- int natoms_global;
- int natoms_xtc;
- gmx_groups_t *groups; /* for XTC writing */
-} gmx_mdoutf_t;
+typedef struct gmx_mdoutf *gmx_mdoutf_t;
-gmx_mdoutf_t *init_mdoutf(int nfile, const t_filenm fnm[],
- int mdrun_flags,
- const t_commrec *cr, const t_inputrec *ir,
- gmx_mtop_t *top_global,
- const output_env_t oenv);
-/* Returns a pointer to a data structure with all output file pointers
+/*! \brief Allocate and initialize object to manager trajectory writing output
+ *
+ * Returns a pointer to a data structure with all output file pointers
* and names required by mdrun.
*/
+gmx_mdoutf_t init_mdoutf(int nfile,
+ const t_filenm fnm[],
+ int mdrun_flags,
+ const t_commrec *cr,
+ const t_inputrec *ir,
+ gmx_mtop_t *mtop,
+ const output_env_t oenv);
+
+/*! \brief Getter for file pointer */
+FILE *mdoutf_get_fp_field(gmx_mdoutf_t of);
+
+/*! \brief Getter for file pointer */
+ener_file_t mdoutf_get_fp_ene(gmx_mdoutf_t of);
-void done_mdoutf(gmx_mdoutf_t *of);
-/* Close all open output files and free the of pointer */
+/*! \brief Getter for file pointer */
+FILE *mdoutf_get_fp_dhdl(gmx_mdoutf_t of);
+
+/*! \brief Close all open output files and free the of pointer */
+void done_mdoutf(gmx_mdoutf_t of);
+
+/*! \brief Routine that writes trajectory-like frames.
+ *
+ * Writes data to trn, xtc and/or checkpoint. What is written is
+ * determined by the mdof_flags defined below. Data is collected to
+ * the master node only when necessary.
+ */
+void mdoutf_write_to_trajectory_files(FILE *fplog, t_commrec *cr,
+ gmx_mdoutf_t of,
+ int mdof_flags,
+ gmx_mtop_t *top_global,
+ gmx_int64_t step, double t,
+ t_state *state_local, t_state *state_global,
+ rvec *f_local, rvec *f_global);
-#define MDOF_X (1<<0)
-#define MDOF_V (1<<1)
-#define MDOF_F (1<<2)
-#define MDOF_XTC (1<<3)
-#define MDOF_CPT (1<<4)
+#define MDOF_X (1<<0)
+#define MDOF_V (1<<1)
+#define MDOF_F (1<<2)
+#define MDOF_X_COMPRESSED (1<<3)
+#define MDOF_CPT (1<<4)
#endif /* GMX_FILEIO_MDOUTF_H */
--- /dev/null
+#
+# This file is part of the GROMACS molecular simulation package.
+#
+# Copyright (c) 2013,2014, by the GROMACS development team, led by
+# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+# and including many others, as listed in the AUTHORS file in the
+# top-level source directory and at http://www.gromacs.org.
+#
+# GROMACS is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1
+# of the License, or (at your option) any later version.
+#
+# GROMACS 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with GROMACS; if not, see
+# http://www.gnu.org/licenses, or write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# If you want to redistribute modifications to GROMACS, please
+# consider that scientific software is very special. Version
+# control is crucial - bugs must be traceable. We will be happy to
+# consider code for inclusion in the official distribution, but
+# derived work must not be called official GROMACS. Details are found
+# in the README & COPYING files - if they are missing, get the
+# official version at http://www.gromacs.org.
+#
+# To help us fund GROMACS development, we humbly ask that you cite
+# the research papers on the package. Check out http://www.gromacs.org.
+
+if(GMX_USE_TNG)
+ gmx_add_unit_test(FileIOTests fileio-test
+ tngio.cpp)
+endif()
--- /dev/null
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2013, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Tests for file I/O routines
+ *
+ * \author Mark Abraham <mark.j.abraham@gmail.com>
+ * \ingroup module_fileio
+ */
+#include <gtest/gtest.h>
+#include <string>
+
+#include "../tngio.h"
+#include "../tngio_for_tools.h"
+#include "testutils/testfilemanager.h"
+#include "gromacs/utility/path.h"
+
+namespace
+{
+
+class TngTest : public ::testing::Test
+{
+ public:
+ TngTest()
+ {
+ }
+ gmx::test::TestFileManager fileManager_;
+};
+
+TEST_F(TngTest, CanOpenTngFile)
+{
+ tng_trajectory_t tng;
+ gmx_tng_open(fileManager_.getInputFilePath("spc2-traj.tng").c_str(),
+ 'r',
+ &tng);
+ gmx_tng_close(&tng);
+}
+
+TEST_F(TngTest, CloseBeforeOpenIsNotFatal)
+{
+ tng_trajectory_t tng = NULL;
+ gmx_tng_close(&tng);
+}
+
+} // namespace
--- /dev/null
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2013, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#include "tngio.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef GMX_USE_TNG
+#include "../../external/tng_io/include/tng_io.h"
+#endif
+
+#include "gromacs/legacyheaders/copyrite.h"
+#include "gromacs/legacyheaders/gmx_fatal.h"
+#include "gromacs/legacyheaders/main.h"
+#include "gromacs/legacyheaders/physics.h"
+#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/programinfo.h"
+#include "gromacs/math/utilities.h"
+#include "gmxfio.h"
+
+static const char *modeToVerb(char mode)
+{
+ switch (mode)
+ {
+ case 'r':
+ return "reading";
+ break;
+ case 'w':
+ return "writing";
+ break;
+ case 'a':
+ return "appending";
+ break;
+ default:
+ gmx_fatal(FARGS, "Invalid file opening mode %c", mode);
+ return "";
+ }
+}
+
+void gmx_tng_open(const char *filename,
+ char mode,
+ tng_trajectory_t *tng)
+{
+#ifdef GMX_USE_TNG
+ /* First check whether we have to make a backup,
+ * only for writing, not for read or append.
+ */
+ if (mode == 'w')
+ {
+#ifndef GMX_FAHCORE
+ /* only make backups for normal gromacs */
+ make_backup(filename);
+#endif
+ }
+
+ /* tng must not be pointing at already allocated memory.
+ * Memory will be allocated by tng_util_trajectory_open() and must
+ * later on be freed by tng_util_trajectory_close(). */
+ if (TNG_SUCCESS != tng_util_trajectory_open(filename, mode, tng))
+ {
+ /* TNG does return more than one degree of error, but there is
+ no use case for GROMACS handling the non-fatal errors
+ gracefully. */
+ gmx_fatal(FARGS,
+ "%s while opening %s for %s",
+ gmx_strerror("file"),
+ filename,
+ modeToVerb(mode));
+ }
+
+ if (mode == 'w' || mode == 'a')
+ {
+ /* FIXME in TNG: When adding data to the header, subsequent blocks might get
+ * overwritten. This could be solved by moving the first trajectory
+ * frame set(s) to the end of the file. Could that cause other problems,
+ * e.g. when continuing a simulation? */
+ char hostname[256];
+ gmx_gethostname(hostname, 256);
+ if (mode == 'w')
+ {
+ tng_first_computer_name_set(*tng, hostname);
+ }
+/* TODO: This should be implemented when the above fixme is done (adding data to
+ * the header). */
+// else
+// {
+// tng_last_computer_name_set(*tng, hostname);
+// }
+
+ char programInfo[256];
+ const char *precisionString = "";
+#ifdef GMX_DOUBLE
+ precisionString = " (double precision)";
+#endif
+ sprintf(programInfo, "%.100s, %.128s%.24s", gmx::ProgramInfo::getInstance().displayName().c_str(),
+ GromacsVersion(), precisionString);
+ if (mode == 'w')
+ {
+ tng_first_program_name_set(*tng, programInfo);
+ }
+/* TODO: This should be implemented when the above fixme is done (adding data to
+ * the header). */
+// else
+// {
+// tng_last_program_name_set(*tng, programInfo);
+// }
+
+#ifdef HAVE_UNISTD_H
+ char username[256];
+ getlogin_r(username, 256);
+ if (mode == 'w')
+ {
+ tng_first_user_name_set(*tng, username);
+ }
+/* TODO: This should be implemented when the above fixme is done (adding data to
+ * the header). */
+// else
+// {
+// tng_last_user_name_set(*tng, username);
+// }
+#endif
+ }
+#else
+ gmx_file("GROMACS was compiled without TNG support, cannot handle this file type");
+ GMX_UNUSED_VALUE(filename);
+ GMX_UNUSED_VALUE(mode);
+ GMX_UNUSED_VALUE(tng);
+#endif
+}
+
+void gmx_tng_close(tng_trajectory_t *tng)
+{
+ /* We have to check that tng is set because
+ * tng_util_trajectory_close wants to return a NULL in it, and
+ * gives a fatal error if it is NULL. */
+#ifdef GMX_USE_TNG
+ if (tng)
+ {
+ tng_util_trajectory_close(tng);
+ }
+#else
+ GMX_UNUSED_VALUE(tng);
+#endif
+}
+
+#ifdef GMX_USE_TNG
+static void addTngMoleculeFromTopology(tng_trajectory_t tng,
+ const char *moleculeName,
+ const t_atoms *atoms,
+ gmx_int64_t numMolecules,
+ tng_molecule_t *tngMol)
+{
+ if (tng_molecule_add(tng, moleculeName, tngMol) != TNG_SUCCESS)
+ {
+ gmx_file("Cannot add molecule to TNG molecular system.");
+ }
+
+ /* FIXME: The TNG atoms should contain mass and atomB info (for free
+ * energy calculations), i.e. in when it's available in TNG (2.0). */
+ for (int atomIt = 0; atomIt < atoms->nr; atomIt++)
+ {
+ const t_atom *at = &atoms->atom[atomIt];
+ /* FIXME: Currently the TNG API can only add atoms belonging to a
+ * residue and chain. Wait for TNG 2.0*/
+ if (atoms->nres > 0)
+ {
+ const t_resinfo *resInfo = &atoms->resinfo[at->resind];
+ char chainName[2] = {resInfo->chainid, 0};
+ tng_chain_t tngChain = NULL;
+ tng_residue_t tngRes = NULL;
+ tng_atom_t tngAtom = NULL;
+
+ if (tng_molecule_chain_find (tng, *tngMol, chainName,
+ (gmx_int64_t)-1, &tngChain) !=
+ TNG_SUCCESS)
+ {
+ tng_molecule_chain_add (tng, *tngMol, chainName,
+ &tngChain);
+ }
+
+ /* FIXME: When TNG supports both residue index and residue
+ * number the latter should be used. Wait for TNG 2.0*/
+ if (tng_chain_residue_find(tng, tngChain, *resInfo->name,
+ at->resind + 1, &tngRes)
+ != TNG_SUCCESS)
+ {
+ tng_chain_residue_add(tng, tngChain, *resInfo->name, &tngRes);
+ }
+ tng_residue_atom_add(tng, tngRes, *(atoms->atomname[atomIt]), *(atoms->atomtype[atomIt]), &tngAtom);
+ }
+ }
+ tng_molecule_cnt_set(tng, *tngMol, numMolecules);
+}
+
+void gmx_tng_add_mtop(tng_trajectory_t tng,
+ const gmx_mtop_t *mtop)
+{
+ int i, j;
+ const t_ilist *ilist;
+ tng_bond_t tngBond;
+
+ if (!mtop)
+ {
+ /* No topology information available to add. */
+ return;
+ }
+
+ for (int molIt = 0; molIt < mtop->nmolblock; molIt++)
+ {
+ tng_molecule_t tngMol = NULL;
+ const gmx_moltype_t *molType =
+ &mtop->moltype[mtop->molblock[molIt].type];
+
+ /* Add a molecule to the TNG trajectory with the same name as the
+ * current molecule. */
+ addTngMoleculeFromTopology(tng,
+ *(molType->name),
+ &molType->atoms,
+ mtop->molblock[molIt].nmol,
+ &tngMol);
+
+ /* Bonds have to be deduced from interactions (constraints etc). Different
+ * interactions have different sets of parameters. */
+ /* Constraints are specified using two atoms */
+ for (i = 0; i < F_NRE; i++)
+ {
+ if (IS_CHEMBOND(i))
+ {
+ ilist = &molType->ilist[i];
+ if (ilist)
+ {
+ j = 1;
+ while (j < ilist->nr)
+ {
+ tng_molecule_bond_add(tng, tngMol, ilist->iatoms[j], ilist->iatoms[j+1], &tngBond);
+ j += 3;
+ }
+ }
+ }
+ }
+ /* Settle is described using three atoms */
+ ilist = &molType->ilist[F_SETTLE];
+ if (ilist)
+ {
+ j = 1;
+ while (j < ilist->nr)
+ {
+ tng_molecule_bond_add(tng, tngMol, ilist->iatoms[j], ilist->iatoms[j+1], &tngBond);
+ tng_molecule_bond_add(tng, tngMol, ilist->iatoms[j], ilist->iatoms[j+2], &tngBond);
+ j += 4;
+ }
+ }
+ }
+}
+
+/*! \libinternal \brief Compute greatest common divisor of n1 and n2
+ * if they are positive.
+ *
+ * If only one of n1 and n2 is positive, then return it.
+ * If neither n1 or n2 is positive, then return -1. */
+static int
+greatest_common_divisor_if_positive(int n1, int n2)
+{
+ if (0 >= n1)
+ {
+ return (0 >= n2) ? -1 : n2;
+ }
+ if (0 >= n2)
+ {
+ return n1;
+ }
+
+ /* We have a non-trivial greatest common divisor to compute. */
+ return gmx_greatest_common_divisor(n1, n2);
+}
+
+/* By default try to write 100 frames (of actual output) in each frame set.
+ * This number is the number of outputs of the most frequently written data
+ * type per frame set.
+ * TODO for 5.1: Verify that 100 frames per frame set is efficient for most
+ * setups regarding compression efficiency and compression time. Make this
+ * a hidden command-line option? */
+const int defaultFramesPerFrameSet = 100;
+
+/*! \libinternal \brief Set the number of frames per frame
+ * set according to output intervals.
+ * The default is that 100 frames are written of the data
+ * that is written most often. */
+static void tng_set_frames_per_frame_set(tng_trajectory_t tng,
+ const gmx_bool bUseLossyCompression,
+ const t_inputrec *ir)
+{
+ int gcd = -1;
+
+ /* Set the number of frames per frame set to contain at least
+ * defaultFramesPerFrameSet of the lowest common denominator of
+ * the writing interval of positions and velocities. */
+ /* FIXME after 5.0: consider nstenergy also? */
+ if (bUseLossyCompression)
+ {
+ gcd = ir->nstxout_compressed;
+ }
+ else
+ {
+ gcd = greatest_common_divisor_if_positive(ir->nstxout, ir->nstvout);
+ gcd = greatest_common_divisor_if_positive(gcd, ir->nstfout);
+ }
+ if (0 >= gcd)
+ {
+ return;
+ }
+
+ tng_num_frames_per_frame_set_set(tng, gcd * defaultFramesPerFrameSet);
+}
+
+/*! \libinternal \brief Set the data-writing intervals, and number of
+ * frames per frame set */
+static void set_writing_intervals(tng_trajectory_t tng,
+ const gmx_bool bUseLossyCompression,
+ const t_inputrec *ir)
+{
+ /* Define pointers to specific writing functions depending on if we
+ * write float or double data */
+ typedef tng_function_status (*set_writing_interval_func_pointer)(tng_trajectory_t,
+ const gmx_int64_t,
+ const gmx_int64_t,
+ const gmx_int64_t,
+ const char*,
+ const char,
+ const char);
+#ifdef GMX_DOUBLE
+ set_writing_interval_func_pointer set_writing_interval = tng_util_generic_write_interval_double_set;
+#else
+ set_writing_interval_func_pointer set_writing_interval = tng_util_generic_write_interval_set;
+#endif
+ int xout, vout, fout;
+// int gcd = -1, lowest = -1;
+ char compression;
+
+ tng_set_frames_per_frame_set(tng, bUseLossyCompression, ir);
+
+ if (bUseLossyCompression)
+ {
+ xout = ir->nstxout_compressed;
+ vout = 0;
+ fout = 0;
+ compression = TNG_TNG_COMPRESSION;
+ }
+ else
+ {
+ xout = ir->nstxout;
+ vout = ir->nstvout;
+ fout = ir->nstfout;
+ compression = TNG_GZIP_COMPRESSION;
+ }
+ if (xout)
+ {
+ set_writing_interval(tng, xout, 3, TNG_TRAJ_POSITIONS,
+ "POSITIONS", TNG_PARTICLE_BLOCK_DATA,
+ compression);
+ /* The design of TNG makes it awkward to try to write a box
+ * with multiple periodicities, which might be co-prime. Since
+ * the use cases for the box with a frame consisting only of
+ * velocities seem low, for now we associate box writing with
+ * position writing. */
+ set_writing_interval(tng, xout, 9, TNG_TRAJ_BOX_SHAPE,
+ "BOX SHAPE", TNG_NON_PARTICLE_BLOCK_DATA,
+ TNG_GZIP_COMPRESSION);
+ /* TODO: if/when we write energies to TNG also, reconsider how
+ * and when box information is written, because GROMACS
+ * behaviour pre-5.0 was to write the box with every
+ * trajectory frame and every energy frame, and probably
+ * people depend on this. */
+
+ /* TODO: If we need to write lambda values at steps when
+ * positions (or other data) are not also being written, then
+ * code in mdoutf.c will need to match however that is
+ * organized here. */
+ set_writing_interval(tng, xout, 1, TNG_GMX_LAMBDA,
+ "LAMBDAS", TNG_NON_PARTICLE_BLOCK_DATA,
+ TNG_GZIP_COMPRESSION);
+
+ /* FIXME: gcd and lowest currently not used. */
+// gcd = greatest_common_divisor_if_positive(gcd, xout);
+// if (lowest < 0 || xout < lowest)
+// {
+// lowest = xout;
+// }
+ }
+ if (vout)
+ {
+ set_writing_interval(tng, ir->nstvout, 3, TNG_TRAJ_VELOCITIES,
+ "VELOCITIES", TNG_PARTICLE_BLOCK_DATA,
+ compression);
+
+ /* FIXME: gcd and lowest currently not used. */
+// gcd = greatest_common_divisor_if_positive(gcd, vout);
+// if (lowest < 0 || vout < lowest)
+// {
+// lowest = vout;
+// }
+ }
+ if (fout)
+ {
+ set_writing_interval(tng, ir->nstfout, 3, TNG_TRAJ_FORCES,
+ "FORCES", TNG_PARTICLE_BLOCK_DATA,
+ TNG_GZIP_COMPRESSION);
+
+ /* FIXME: gcd and lowest currently not used. */
+// gcd = greatest_common_divisor_if_positive(gcd, fout);
+// if (lowest < 0 || fout < lowest)
+// {
+// lowest = fout;
+// }
+ }
+ /* FIXME: See above. gcd interval for lambdas is disabled. */
+// if (gcd > 0)
+// {
+// /* Lambdas written at an interval of the lowest common denominator
+// * of other output */
+// set_writing_interval(tng, gcd, 1, TNG_GMX_LAMBDA,
+// "LAMBDAS", TNG_NON_PARTICLE_BLOCK_DATA,
+// TNG_GZIP_COMPRESSION);
+//
+// if (gcd < lowest / 10)
+// {
+// gmx_warning("The lowest common denominator of trajectory output is "
+// "every %d step(s), whereas the shortest output interval "
+// "is every %d steps.", gcd, lowest);
+// }
+// }
+}
+#endif
+
+void gmx_tng_prepare_md_writing(tng_trajectory_t tng,
+ const gmx_mtop_t *mtop,
+ const t_inputrec *ir)
+{
+#ifdef GMX_USE_TNG
+ gmx_tng_add_mtop(tng, mtop);
+ set_writing_intervals(tng, FALSE, ir);
+ tng_time_per_frame_set(tng, ir->delta_t * PICO);
+#else
+ GMX_UNUSED_VALUE(tng);
+ GMX_UNUSED_VALUE(mtop);
+ GMX_UNUSED_VALUE(ir);
+#endif
+}
+
+#ifdef GMX_USE_TNG
+/* Create a TNG molecule representing the selection groups
+ * to write */
+static void add_selection_groups(tng_trajectory_t tng,
+ const gmx_mtop_t *mtop)
+{
+ const gmx_moltype_t *molType;
+ const t_atoms *atoms;
+ const t_atom *at;
+ const t_resinfo *resInfo;
+ const t_ilist *ilist;
+ int nAtoms = 0, i = 0, j, molIt, atomIt, nameIndex;
+ int atom_offset = 0;
+ tng_molecule_t mol, iterMol;
+ tng_chain_t chain;
+ tng_residue_t res;
+ tng_atom_t atom;
+ tng_bond_t tngBond;
+ gmx_int64_t nMols;
+ char *groupName;
+
+ /* The name of the TNG molecule containing the selection group is the
+ * same as the name of the selection group. */
+ nameIndex = *mtop->groups.grps[egcCompressedX].nm_ind;
+ groupName = *mtop->groups.grpname[nameIndex];
+
+ tng_molecule_alloc(tng, &mol);
+ tng_molecule_name_set(tng, mol, groupName);
+ tng_molecule_chain_add(tng, mol, "", &chain);
+ for (molIt = 0; molIt < mtop->nmoltype; molIt++)
+ {
+ molType = &mtop->moltype[mtop->molblock[molIt].type];
+
+ atoms = &molType->atoms;
+
+ for (j = 0; j < mtop->molblock[molIt].nmol; j++)
+ {
+ bool bAtomsAdded = FALSE;
+ for (atomIt = 0; atomIt < atoms->nr; atomIt++, i++)
+ {
+ char *res_name;
+ int res_id;
+
+ if (ggrpnr(&mtop->groups, egcCompressedX, i) != 0)
+ {
+ continue;
+ }
+ at = &atoms->atom[atomIt];
+ if (atoms->nres > 0)
+ {
+ resInfo = &atoms->resinfo[at->resind];
+ /* FIXME: When TNG supports both residue index and residue
+ * number the latter should be used. */
+ res_name = *resInfo->name;
+ res_id = at->resind + 1;
+ }
+ else
+ {
+ res_name = (char *)"";
+ res_id = 0;
+ }
+ if (tng_chain_residue_find(tng, chain, res_name, res_id, &res)
+ != TNG_SUCCESS)
+ {
+ /* Since there is ONE chain for selection groups do not keep the
+ * original residue IDs - otherwise there might be conflicts. */
+ tng_chain_residue_add(tng, chain, res_name, &res);
+ }
+ tng_residue_atom_w_id_add(tng, res, *(atoms->atomname[atomIt]),
+ *(atoms->atomtype[atomIt]),
+ atom_offset + atomIt, &atom);
+ nAtoms++;
+ bAtomsAdded = TRUE;
+ }
+ /* Add bonds. */
+ if (bAtomsAdded)
+ {
+ for (int k = 0; k < F_NRE; k++)
+ {
+ if (IS_CHEMBOND(k))
+ {
+ ilist = &molType->ilist[k];
+ if (ilist)
+ {
+ int l = 1;
+ while (l < ilist->nr)
+ {
+ int atom1, atom2;
+ atom1 = ilist->iatoms[l] + atom_offset;
+ atom2 = ilist->iatoms[l+1] + atom_offset;
+ if (ggrpnr(&mtop->groups, egcCompressedX, atom1) == 0 &&
+ ggrpnr(&mtop->groups, egcCompressedX, atom2) == 0)
+ {
+ tng_molecule_bond_add(tng, mol, ilist->iatoms[l],
+ ilist->iatoms[l+1], &tngBond);
+ }
+ l += 3;
+ }
+ }
+ }
+ }
+ /* Settle is described using three atoms */
+ ilist = &molType->ilist[F_SETTLE];
+ if (ilist)
+ {
+ int l = 1;
+ while (l < ilist->nr)
+ {
+ int atom1, atom2, atom3;
+ atom1 = ilist->iatoms[l] + atom_offset;
+ atom2 = ilist->iatoms[l+1] + atom_offset;
+ atom3 = ilist->iatoms[l+2] + atom_offset;
+ if (ggrpnr(&mtop->groups, egcCompressedX, atom1) == 0)
+ {
+ if (ggrpnr(&mtop->groups, egcCompressedX, atom2) == 0)
+ {
+ tng_molecule_bond_add(tng, mol, atom1,
+ atom2, &tngBond);
+ }
+ if (ggrpnr(&mtop->groups, egcCompressedX, atom3) == 0)
+ {
+ tng_molecule_bond_add(tng, mol, atom1,
+ atom3, &tngBond);
+ }
+ }
+ l += 4;
+ }
+ }
+ }
+ atom_offset += atoms->nr;
+ }
+ }
+ if (nAtoms != i)
+ {
+ tng_molecule_existing_add(tng, &mol);
+ tng_molecule_cnt_set(tng, mol, 1);
+ tng_num_molecule_types_get(tng, &nMols);
+ for (gmx_int64_t k = 0; k < nMols; k++)
+ {
+ tng_molecule_of_index_get(tng, k, &iterMol);
+ if (iterMol == mol)
+ {
+ continue;
+ }
+ tng_molecule_cnt_set(tng, iterMol, 0);
+ }
+ }
+ else
+ {
+ tng_molecule_free(tng, &mol);
+ }
+}
+#endif
+
+void gmx_tng_set_compression_precision(tng_trajectory_t tng,
+ real prec)
+{
+#ifdef GMX_USE_TNG
+ tng_compression_precision_set(tng, 1.0/prec);
+#else
+ GMX_UNUSED_VALUE(tng);
+ GMX_UNUSED_VALUE(prec);
+#endif
+}
+
+void gmx_tng_prepare_low_prec_writing(tng_trajectory_t tng,
+ const gmx_mtop_t *mtop,
+ const t_inputrec *ir)
+{
+#ifdef GMX_USE_TNG
+ gmx_tng_add_mtop(tng, mtop);
+ add_selection_groups(tng, mtop);
+ set_writing_intervals(tng, TRUE, ir);
+ tng_time_per_frame_set(tng, ir->delta_t * PICO);
+ gmx_tng_set_compression_precision(tng, ir->x_compression_precision);
+#else
+ GMX_UNUSED_VALUE(tng);
+ GMX_UNUSED_VALUE(mtop);
+ GMX_UNUSED_VALUE(ir);
+#endif
+}
+
+void gmx_fwrite_tng(tng_trajectory_t tng,
+ const gmx_bool bUseLossyCompression,
+ int step,
+ real elapsedPicoSeconds,
+ real lambda,
+ const rvec *box,
+ int nAtoms,
+ const rvec *x,
+ const rvec *v,
+ const rvec *f)
+{
+#ifdef GMX_USE_TNG
+ typedef tng_function_status (*write_data_func_pointer)(tng_trajectory_t,
+ const gmx_int64_t,
+ const double,
+ const real*,
+ const gmx_int64_t,
+ const gmx_int64_t,
+ const char*,
+ const char,
+ const char);
+#ifdef GMX_DOUBLE
+ static write_data_func_pointer write_data = tng_util_generic_with_time_double_write;
+#else
+ static write_data_func_pointer write_data = tng_util_generic_with_time_write;
+#endif
+ double elapsedSeconds = elapsedPicoSeconds * PICO;
+ gmx_int64_t nParticles;
+ char compression;
+
+
+ if (!tng)
+ {
+ /* This function might get called when the type of the
+ compressed trajectory is actually XTC. So we exit and move
+ on. */
+ return;
+ }
+
+ tng_num_particles_get(tng, &nParticles);
+ if (nAtoms != (int)nParticles)
+ {
+ tng_implicit_num_particles_set(tng, nAtoms);
+ }
+
+ if (bUseLossyCompression)
+ {
+ compression = TNG_TNG_COMPRESSION;
+ }
+ else
+ {
+ compression = TNG_GZIP_COMPRESSION;
+ }
+
+ /* The writing is done using write_data, which writes float or double
+ * depending on the GROMACS compilation. */
+ if (x)
+ {
+ GMX_ASSERT(box, "Need a non-NULL box if positions are written");
+
+ if (write_data(tng, step, elapsedSeconds,
+ reinterpret_cast<const real *>(x),
+ 3, TNG_TRAJ_POSITIONS, "POSITIONS",
+ TNG_PARTICLE_BLOCK_DATA,
+ compression) != TNG_SUCCESS)
+ {
+ gmx_file("Cannot write TNG trajectory frame; maybe you are out of disk space?");
+ }
+ /* TNG-MF1 compression only compresses positions and velocities. Use lossless
+ * compression for box shape regardless of output mode */
+ if (write_data(tng, step, elapsedSeconds,
+ reinterpret_cast<const real *>(box),
+ 9, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
+ TNG_NON_PARTICLE_BLOCK_DATA,
+ TNG_GZIP_COMPRESSION) != TNG_SUCCESS)
+ {
+ gmx_file("Cannot write TNG trajectory frame; maybe you are out of disk space?");
+ }
+ }
+
+ if (v)
+ {
+ if (write_data(tng, step, elapsedSeconds,
+ reinterpret_cast<const real *>(v),
+ 3, TNG_TRAJ_VELOCITIES, "VELOCITIES",
+ TNG_PARTICLE_BLOCK_DATA,
+ compression) != TNG_SUCCESS)
+ {
+ gmx_file("Cannot write TNG trajectory frame; maybe you are out of disk space?");
+ }
+ }
+
+ if (f)
+ {
+ /* TNG-MF1 compression only compresses positions and velocities. Use lossless
+ * compression for forces regardless of output mode */
+ if (write_data(tng, step, elapsedSeconds,
+ reinterpret_cast<const real *>(f),
+ 3, TNG_TRAJ_FORCES, "FORCES",
+ TNG_PARTICLE_BLOCK_DATA,
+ TNG_GZIP_COMPRESSION) != TNG_SUCCESS)
+ {
+ gmx_file("Cannot write TNG trajectory frame; maybe you are out of disk space?");
+ }
+ }
+
+ /* TNG-MF1 compression only compresses positions and velocities. Use lossless
+ * compression for lambdas regardless of output mode */
+ if (write_data(tng, step, elapsedSeconds,
+ reinterpret_cast<const real *>(&lambda),
+ 1, TNG_GMX_LAMBDA, "LAMBDAS",
+ TNG_NON_PARTICLE_BLOCK_DATA,
+ TNG_GZIP_COMPRESSION) != TNG_SUCCESS)
+ {
+ gmx_file("Cannot write TNG trajectory frame; maybe you are out of disk space?");
+ }
+#else
+ GMX_UNUSED_VALUE(tng);
+ GMX_UNUSED_VALUE(bUseLossyCompression);
+ GMX_UNUSED_VALUE(step);
+ GMX_UNUSED_VALUE(elapsedPicoSeconds);
+ GMX_UNUSED_VALUE(lambda);
+ GMX_UNUSED_VALUE(box);
+ GMX_UNUSED_VALUE(nAtoms);
+ GMX_UNUSED_VALUE(x);
+ GMX_UNUSED_VALUE(v);
+ GMX_UNUSED_VALUE(f);
+#endif
+}
+
+void fflush_tng(tng_trajectory_t tng)
+{
+#ifdef GMX_USE_TNG
+ if (!tng)
+ {
+ return;
+ }
+ tng_frame_set_premature_write(tng, TNG_USE_HASH);
+#else
+ GMX_UNUSED_VALUE(tng);
+#endif
+}
+
+float gmx_tng_get_time_of_final_frame(tng_trajectory_t tng)
+{
+#ifdef GMX_USE_TNG
+ gmx_int64_t nFrames;
+ double time;
+ float fTime;
+
+ tng_num_frames_get(tng, &nFrames);
+ tng_util_time_of_frame_get(tng, nFrames - 1, &time);
+
+ fTime = time / PICO;
+ return fTime;
+#else
+ GMX_UNUSED_VALUE(tng);
+ return -1.0;
+#endif
+}
--- /dev/null
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2013, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+
+#ifndef GMX_FILEIO_TNGIO_H
+#define GMX_FILEIO_TNGIO_H
+
+#include "gromacs/legacyheaders/typedefs.h"
+#include "../../external/tng_io/include/tng_io_fwd.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if 0
+}
+#endif
+
+/*! \brief Open a TNG trajectory file
+ *
+ * \param filename Name of file to open
+ * \param mode Can be set to 'r', 'w' or 'a' for reading, writing or appending respectively.
+ * \param tng_data_p Pointer to an allocated tng_trajectory_t into which a handle to a TNG trajectory will be stored.
+ *
+ * Handles all I/O errors internally via fatal error
+ */
+void gmx_tng_open(const char *filename,
+ char mode,
+ tng_trajectory_t *tng_data_p);
+
+/*! \brief Finish writing a TNG trajectory file */
+void gmx_tng_close(tng_trajectory_t *tng);
+
+/*!\brief Add molecular topology information to TNG output (if
+ * available)
+ *
+ * \param tng Valid handle to a TNG trajectory
+ * \param mtop Pointer to a topology (can be NULL)
+ */
+void gmx_tng_add_mtop(tng_trajectory_t tng,
+ const gmx_mtop_t *mtop);
+
+/*! \brief Do all TNG preparation for full-precision whole-system
+ * trajectory writing during MD simulations.
+ *
+ * \param tng Valid handle to a TNG trajectory
+ * \param mtop Global topology
+ * \param ir Input settings (for writing frequencies)
+ */
+void gmx_tng_prepare_md_writing(tng_trajectory_t tng,
+ const gmx_mtop_t *mtop,
+ const t_inputrec *ir);
+
+/*! \brief Set the default compression precision for TNG writing
+ *
+ * \param tng Valid handle to a TNG trajectory
+ * \param prec GROMACS-style precision setting (i.e. 1000 for 3 digits of precision) */
+void gmx_tng_set_compression_precision(tng_trajectory_t tng,
+ real prec);
+
+/*! \brief Do all TNG preparation for low-precision selection-based
+ * trajectory writing during MD simulations.
+ *
+ * \param tng Valid handle to a TNG trajectory
+ * \param mtop Global topology
+ * \param ir Input settings (for writing frequencies)
+ */
+void gmx_tng_prepare_low_prec_writing(tng_trajectory_t tng,
+ const gmx_mtop_t *mtop,
+ const t_inputrec *ir);
+
+/*! \brief Write a frame to a TNG file
+ *
+ * \param tng Valid handle to a TNG trajectory
+ * \param bUseLossyCompression Whether to use lossy compression
+ * \param step MD step number
+ * \param elapsedPicoSeconds Elapsed MD time
+ * \param lambda Free-energy lambda value
+ * \param box Simulation box
+ * \param nAtoms Number of atoms (i.e. vector lengths)
+ * \param x Vector of position coordinates
+ * \param v Vector of elocities
+ * \param f Vector of forces
+ *
+ * The pointers tng, x, v, f may be NULL, which triggers not writing
+ * (that component). box can only be NULL if x is also NULL. */
+void gmx_fwrite_tng(tng_trajectory_t tng,
+ const gmx_bool bUseLossyCompression,
+ int step,
+ real elapsedPicoSeconds,
+ real lambda,
+ const rvec *box,
+ int nAtoms,
+ const rvec *x,
+ const rvec *v,
+ const rvec *f);
+
+/*! \brief Write the current frame set to disk. Perform compression
+ * etc.
+ *
+ * \param tng Valid handle to a TNG trajectory
+ */
+void fflush_tng(tng_trajectory_t tng);
+
+/*! \brief Get the time (in picoseconds) of the final frame in the
+ * trajectory.
+ *
+ * \param tng Valid handle to a TNG trajectory
+ */
+float gmx_tng_get_time_of_final_frame(tng_trajectory_t tng);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GMX_FILEIO_TNGIO_H */
--- /dev/null
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2013, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#include "tngio_for_tools.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <vector>
+
+#include "tngio.h"
+#include "trx.h"
+
+#ifdef GMX_USE_TNG
+#include "../../external/tng_io/include/tng_io.h"
+#endif
+
+#include "gromacs/utility/common.h"
+#include "gromacs/legacyheaders/types/atoms.h"
+#include "gromacs/legacyheaders/smalloc.h"
+#include "gromacs/legacyheaders/physics.h"
+#include "gromacs/legacyheaders/gmx_fatal.h"
+#include "gromacs/tools/dump.h"
+
+void gmx_prepare_tng_writing(const char *filename,
+ char mode,
+ tng_trajectory_t *input,
+ tng_trajectory_t *output,
+ int nAtoms,
+ const gmx_mtop_t *mtop,
+ const atom_id *index,
+ const char *indexGroupName)
+{
+#ifdef GMX_USE_TNG
+ /* FIXME after 5.0: Currently only standard block types are read */
+ const int defaultNumIds = 5;
+ static gmx_int64_t fallbackIds[defaultNumIds] =
+ {
+ TNG_TRAJ_BOX_SHAPE, TNG_TRAJ_POSITIONS,
+ TNG_TRAJ_VELOCITIES, TNG_TRAJ_FORCES,
+ TNG_GMX_LAMBDA
+ };
+ static char fallbackNames[defaultNumIds][32] =
+ {
+ "BOX SHAPE", "POSITIONS", "VELOCITIES",
+ "FORCES", "LAMBDAS"
+ };
+
+
+ gmx_tng_open(filename, mode, output);
+
+ /* Do we have an input file in TNG format? If so, then there's
+ more data we can copy over, rather than having to improvise. */
+ if (*input)
+ {
+ /* Set parameters (compression, time per frame, molecule
+ * information, number of frames per frame set and writing
+ * intervals of positions, box shape and lambdas) of the
+ * output tng container based on their respective values int
+ * the input tng container */
+ double time, compression_precision;
+ gmx_int64_t n_frames_per_frame_set, interval = -1;
+
+ tng_compression_precision_get(*input, &compression_precision);
+ tng_compression_precision_set(*output, compression_precision);
+ // TODO make this configurable in a future version
+ char compression_type = TNG_TNG_COMPRESSION;
+
+ tng_molecule_system_copy(*input, *output);
+
+ tng_time_per_frame_get(*input, &time);
+ tng_time_per_frame_set(*output, time);
+
+ tng_num_frames_per_frame_set_get(*input, &n_frames_per_frame_set);
+ tng_num_frames_per_frame_set_set(*output, n_frames_per_frame_set);
+
+ for (int i = 0; i < defaultNumIds; i++)
+ {
+ if (tng_data_get_stride_length(*input, fallbackIds[i], -1, &interval)
+ == TNG_SUCCESS)
+ {
+ switch (fallbackIds[i])
+ {
+ case TNG_TRAJ_POSITIONS:
+ case TNG_TRAJ_VELOCITIES:
+ tng_util_generic_write_interval_set(*output, interval, 3, fallbackIds[i],
+ fallbackNames[i], TNG_PARTICLE_BLOCK_DATA,
+ compression_type);
+ break;
+ case TNG_TRAJ_FORCES:
+ tng_util_generic_write_interval_set(*output, interval, 3, fallbackIds[i],
+ fallbackNames[i], TNG_PARTICLE_BLOCK_DATA,
+ TNG_GZIP_COMPRESSION);
+ break;
+ case TNG_TRAJ_BOX_SHAPE:
+ tng_util_generic_write_interval_set(*output, interval, 9, fallbackIds[i],
+ fallbackNames[i], TNG_NON_PARTICLE_BLOCK_DATA,
+ TNG_GZIP_COMPRESSION);
+ break;
+ case TNG_GMX_LAMBDA:
+ tng_util_generic_write_interval_set(*output, interval, 1, fallbackIds[i],
+ fallbackNames[i], TNG_NON_PARTICLE_BLOCK_DATA,
+ TNG_GZIP_COMPRESSION);
+ default:
+ continue;
+ }
+ }
+ }
+
+ }
+ else
+ {
+ /* TODO after trjconv is modularized: fix this so the user can
+ change precision when they are doing an operation where
+ this makes sense, and not otherwise.
+
+ char compression = bUseLossyCompression ? TNG_TNG_COMPRESSION : TNG_GZIP_COMPRESSION;
+ gmx_tng_set_compression_precision(*output, ndec2prec(nDecimalsOfPrecision));
+ */
+ gmx_tng_add_mtop(*output, mtop);
+ tng_num_frames_per_frame_set_set(*output, 1);
+ }
+
+ if (index && nAtoms > 0)
+ {
+ gmx_tng_setup_atom_subgroup(*output, nAtoms, index, indexGroupName);
+ }
+
+ /* If for some reason there are more requested atoms than there are atoms in the
+ * molecular system create a number of implicit atoms (without atom data) to
+ * compensate for that. */
+ if (nAtoms >= 0)
+ {
+ tng_implicit_num_particles_set(*output, nAtoms);
+ }
+#else
+ GMX_UNUSED_VALUE(filename);
+ GMX_UNUSED_VALUE(mode);
+ GMX_UNUSED_VALUE(input);
+ GMX_UNUSED_VALUE(output);
+ GMX_UNUSED_VALUE(nAtoms);
+#endif
+}
+
+void gmx_write_tng_from_trxframe(tng_trajectory_t output,
+ t_trxframe *frame,
+ int natoms)
+{
+#ifdef GMX_USE_TNG
+ if (frame->step > 0)
+ {
+ double timePerFrame = frame->time * PICO / frame->step;
+ tng_time_per_frame_set(output, timePerFrame);
+ }
+ if (natoms < 0)
+ {
+ natoms = frame->natoms;
+ }
+ gmx_fwrite_tng(output,
+ TRUE,
+ frame->step,
+ frame->time,
+ 0,
+ (const rvec *) frame->box,
+ natoms,
+ (const rvec *) frame->x,
+ (const rvec *) frame->v,
+ (const rvec *) frame->f);
+#else
+ GMX_UNUSED_VALUE(output);
+ GMX_UNUSED_VALUE(frame);
+#endif
+}
+
+#ifdef GMX_USE_TNG
+static void
+convert_array_to_real_array(void *from,
+ real *to,
+ const float fact,
+ const int nAtoms,
+ const int nValues,
+ const char datatype)
+{
+ int i, j;
+
+ switch (datatype)
+ {
+ case TNG_FLOAT_DATA:
+ if (sizeof(real) == sizeof(float))
+ {
+ if (fact == 1)
+ {
+ memcpy(to, from, nValues * sizeof(real) * nAtoms);
+ }
+ else
+ {
+ for (i = 0; i < nAtoms; i++)
+ {
+ for (j = 0; j < nValues; j++)
+ {
+ to[i*nValues+j] = (real)((float *)from)[i*nValues+j] * fact;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < nAtoms; i++)
+ {
+ for (j = 0; j < nValues; j++)
+ {
+ to[i*nValues+j] = (real)((float *)from)[i*nValues+j] * fact;
+ }
+ }
+ }
+ break;
+ case TNG_INT_DATA:
+ for (i = 0; i < nAtoms; i++)
+ {
+ for (j = 0; j < nValues; j++)
+ {
+ to[i*nValues+j] = (real)((gmx_int64_t *)from)[i*nValues+j] * fact;
+ }
+ }
+ break;
+ case TNG_DOUBLE_DATA:
+ if (sizeof(real) == sizeof(double))
+ {
+ if (fact == 1)
+ {
+ memcpy(to, from, nValues * sizeof(real) * nAtoms);
+ }
+ else
+ {
+ for (i = 0; i < nAtoms; i++)
+ {
+ for (j = 0; j < nValues; j++)
+ {
+ to[i*nValues+j] = (real)((double *)from)[i*nValues+j] * fact;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < nAtoms; i++)
+ {
+ for (j = 0; j < nValues; j++)
+ {
+ to[i*nValues+j] = (real)((double *)from)[i*nValues+j] * fact;
+ }
+ }
+ }
+ break;
+ default:
+ gmx_incons("Illegal datatype when converting values to a real array!");
+ return;
+ }
+ return;
+}
+
+static real getDistanceScaleFactor(tng_trajectory_t in)
+{
+ gmx_int64_t exp = -1;
+ real distanceScaleFactor;
+
+ // TODO Hopefully, TNG 2.0 will do this kind of thing for us
+ tng_distance_unit_exponential_get(in, &exp);
+
+ // GROMACS expects distances in nm
+ switch (exp)
+ {
+ case 9:
+ distanceScaleFactor = NANO/NANO;
+ break;
+ case 10:
+ distanceScaleFactor = NANO/ANGSTROM;
+ break;
+ default:
+ distanceScaleFactor = pow(10.0, exp + 9.0);
+ }
+
+ return distanceScaleFactor;
+}
+#endif
+
+void gmx_tng_setup_atom_subgroup(tng_trajectory_t tng,
+ const int nind,
+ const atom_id *ind,
+ const char *name)
+{
+#ifdef GMX_USE_TNG
+ gmx_int64_t nAtoms, cnt, nMols;
+ tng_molecule_t mol, iterMol;
+ tng_chain_t chain;
+ tng_residue_t res;
+ tng_atom_t atom;
+ tng_function_status stat;
+
+ tng_num_particles_get(tng, &nAtoms);
+
+ if (nAtoms == nind)
+ {
+ return;
+ }
+
+ stat = tng_molecule_find(tng, name, -1, &mol);
+ if (stat == TNG_SUCCESS)
+ {
+ tng_molecule_num_atoms_get(tng, mol, &nAtoms);
+ tng_molecule_cnt_get(tng, mol, &cnt);
+ if (nAtoms == nind)
+ {
+ stat = TNG_SUCCESS;
+ }
+ else
+ {
+ stat = TNG_FAILURE;
+ }
+ }
+ if (stat == TNG_FAILURE)
+ {
+ /* The indexed atoms are added to one separate molecule. */
+ tng_molecule_alloc(tng, &mol);
+ tng_molecule_name_set(tng, mol, name);
+ tng_molecule_chain_add(tng, mol, "", &chain);
+
+ for (int i = 0; i < nind; i++)
+ {
+ char temp_name[256], temp_type[256];
+
+ /* Try to retrieve the residue name of the atom */
+ stat = tng_residue_name_of_particle_nr_get(tng, ind[i], temp_name, 256);
+ if (stat != TNG_SUCCESS)
+ {
+ temp_name[0] = '\0';
+ }
+ /* Check if the molecule of the selection already contains this residue */
+ if (tng_chain_residue_find(tng, chain, temp_name, -1, &res)
+ != TNG_SUCCESS)
+ {
+ tng_chain_residue_add(tng, chain, temp_name, &res);
+ }
+ /* Try to find the original name and type of the atom */
+ stat = tng_atom_name_of_particle_nr_get(tng, ind[i], temp_name, 256);
+ if (stat != TNG_SUCCESS)
+ {
+ temp_name[0] = '\0';
+ }
+ stat = tng_atom_type_of_particle_nr_get(tng, ind[i], temp_type, 256);
+ if (stat != TNG_SUCCESS)
+ {
+ temp_type[0] = '\0';
+ }
+ tng_residue_atom_w_id_add(tng, res, temp_name, temp_type, ind[i], &atom);
+ }
+ tng_molecule_existing_add(tng, &mol);
+ }
+ /* Set the count of the molecule containing the selected atoms to 1 and all
+ * other molecules to 0 */
+ tng_molecule_cnt_set(tng, mol, 1);
+ tng_num_molecule_types_get(tng, &nMols);
+ for (gmx_int64_t k = 0; k < nMols; k++)
+ {
+ tng_molecule_of_index_get(tng, k, &iterMol);
+ if (iterMol == mol)
+ {
+ continue;
+ }
+ tng_molecule_cnt_set(tng, iterMol, 0);
+ }
+#else
+ GMX_UNUSED_VALUE(tng);
+ GMX_UNUSED_VALUE(nind);
+ GMX_UNUSED_VALUE(ind);
+ GMX_UNUSED_VALUE(name);
+#endif
+}
+
+/* TODO: If/when TNG acquires the ability to copy data blocks without
+ * uncompressing them, then this implemenation should be reconsidered.
+ * Ideally, gmx trjconv -f a.tng -o b.tng -b 10 -e 20 would be fast
+ * and lose no information. */
+gmx_bool gmx_read_next_tng_frame(tng_trajectory_t input,
+ t_trxframe *fr,
+ gmx_int64_t *requestedIds,
+ int numRequestedIds)
+{
+#ifdef GMX_USE_TNG
+ gmx_bool bOK = TRUE;
+ tng_function_status stat;
+ gmx_int64_t numberOfAtoms = -1, frameNumber = -1;
+ gmx_int64_t nBlocks, blockId, *blockIds = NULL;
+ char datatype = -1, codecId;
+ void *values = NULL;
+ double frameTime = -1.0;
+ int size, blockDependency;
+ float prec;
+ const int defaultNumIds = 5;
+ static gmx_int64_t fallbackRequestedIds[defaultNumIds] =
+ {
+ TNG_TRAJ_BOX_SHAPE, TNG_TRAJ_POSITIONS,
+ TNG_TRAJ_VELOCITIES, TNG_TRAJ_FORCES,
+ TNG_GMX_LAMBDA
+ };
+
+
+ fr->bStep = FALSE;
+ fr->bTime = FALSE;
+ fr->bLambda = FALSE;
+ fr->bAtoms = FALSE;
+ fr->bPrec = FALSE;
+ fr->bX = FALSE;
+ fr->bV = FALSE;
+ fr->bF = FALSE;
+ fr->bBox = FALSE;
+
+ /* If no specific IDs were requested read all block types that can
+ * currently be interpreted */
+ if (!requestedIds || numRequestedIds == 0)
+ {
+ numRequestedIds = defaultNumIds;
+ requestedIds = fallbackRequestedIds;
+ }
+
+ stat = tng_num_particles_get(input, &numberOfAtoms);
+ if (stat != TNG_SUCCESS)
+ {
+ gmx_file("Cannot determine number of atoms from TNG file.");
+ }
+ fr->natoms = numberOfAtoms;
+
+ if (!gmx_get_tng_data_block_types_of_next_frame(input,
+ fr->step,
+ numRequestedIds,
+ requestedIds,
+ &frameNumber,
+ &nBlocks,
+ &blockIds))
+ {
+ return FALSE;
+ }
+
+ if (nBlocks == 0)
+ {
+ return FALSE;
+ }
+
+ for (gmx_int64_t i = 0; i < nBlocks; i++)
+ {
+ blockId = blockIds[i];
+ tng_data_block_dependency_get(input, blockId, &blockDependency);
+ if (blockDependency & TNG_PARTICLE_DEPENDENT)
+ {
+ stat = tng_util_particle_data_next_frame_read(input,
+ blockId,
+ &values,
+ &datatype,
+ &frameNumber,
+ &frameTime);
+ }
+ else
+ {
+ stat = tng_util_non_particle_data_next_frame_read(input,
+ blockId,
+ &values,
+ &datatype,
+ &frameNumber,
+ &frameTime);
+ }
+ if (stat == TNG_CRITICAL)
+ {
+ gmx_file("Cannot read positions from TNG file.");
+ return FALSE;
+ }
+ else if (stat == TNG_FAILURE)
+ {
+ continue;
+ }
+ switch (blockId)
+ {
+ case TNG_TRAJ_BOX_SHAPE:
+ switch (datatype)
+ {
+ case TNG_INT_DATA:
+ size = sizeof(gmx_int64_t);
+ break;
+ case TNG_FLOAT_DATA:
+ size = sizeof(float);
+ break;
+ case TNG_DOUBLE_DATA:
+ size = sizeof(double);
+ break;
+ default:
+ size = 0; /* Just to make the compiler happy. */
+ gmx_incons("Illegal datatype of box shape values!");
+ }
+ for (int i = 0; i < DIM; i++)
+ {
+ convert_array_to_real_array((char *)(values) + size * i * DIM,
+ (real *) fr->box[i],
+ getDistanceScaleFactor(input),
+ 1,
+ DIM,
+ datatype);
+ }
+ fr->bBox = TRUE;
+ break;
+ case TNG_TRAJ_POSITIONS:
+ srenew(fr->x, fr->natoms);
+ convert_array_to_real_array(values,
+ (real *) fr->x,
+ getDistanceScaleFactor(input),
+ fr->natoms,
+ DIM,
+ datatype);
+ fr->bX = TRUE;
+ tng_util_frame_current_compression_get(input, blockId, &codecId, &prec);
+ /* This must be updated if/when more lossy compression methods are added */
+ if (codecId == TNG_TNG_COMPRESSION)
+ {
+ fr->prec = prec;
+ fr->bPrec = TRUE;
+ }
+ break;
+ case TNG_TRAJ_VELOCITIES:
+ srenew(fr->v, fr->natoms);
+ convert_array_to_real_array(values,
+ (real *) fr->v,
+ getDistanceScaleFactor(input),
+ fr->natoms,
+ DIM,
+ datatype);
+ fr->bV = TRUE;
+ tng_util_frame_current_compression_get(input, blockId, &codecId, &prec);
+ /* This must be updated if/when more lossy compression methods are added */
+ if (codecId == TNG_TNG_COMPRESSION)
+ {
+ fr->prec = prec;
+ fr->bPrec = TRUE;
+ }
+ break;
+ case TNG_TRAJ_FORCES:
+ srenew(fr->f, fr->natoms);
+ convert_array_to_real_array(values,
+ (real *) fr->f,
+ getDistanceScaleFactor(input),
+ fr->natoms,
+ DIM,
+ datatype);
+ fr->bF = TRUE;
+ break;
+ case TNG_GMX_LAMBDA:
+ switch (datatype)
+ {
+ case TNG_FLOAT_DATA:
+ fr->lambda = (*(float *)values);
+ break;
+ case TNG_DOUBLE_DATA:
+ fr->lambda = (*(double *)values);
+ break;
+ default:
+ gmx_incons("Illegal datatype lambda value!");
+ }
+ fr->bLambda = TRUE;
+ break;
+ default:
+ gmx_warning("Illegal block type! Currently GROMACS tools can only handle certain data types. Skipping block.");
+ }
+ /* values does not have to be freed before reading next frame. It will
+ * be reallocated if it is not NULL. */
+ }
+
+ fr->step = (int) frameNumber;
+ fr->bStep = TRUE;
+ // Convert the time to ps
+ fr->time = frameTime / PICO;
+ fr->bTime = TRUE;
+
+ /* values must be freed before leaving this function */
+ sfree(values);
+
+ return bOK;
+#else
+ GMX_UNUSED_VALUE(input);
+ GMX_UNUSED_VALUE(fr);
+ GMX_UNUSED_VALUE(requestedIds);
+ return FALSE;
+#endif
+}
+
+void gmx_print_tng_molecule_system(tng_trajectory_t input,
+ FILE *stream)
+{
+#ifdef GMX_USE_TNG
+ gmx_int64_t nMolecules, nChains, nResidues, nAtoms, *molCntList;
+ tng_molecule_t molecule;
+ tng_chain_t chain;
+ tng_residue_t residue;
+ tng_atom_t atom;
+ char str[256], varNAtoms;
+
+ tng_num_molecule_types_get(input, &nMolecules);
+ tng_molecule_cnt_list_get(input, &molCntList);
+ /* Can the number of particles change in the trajectory or is it constant? */
+ tng_num_particles_variable_get(input, &varNAtoms);
+
+ for (gmx_int64_t i = 0; i < nMolecules; i++)
+ {
+ tng_molecule_of_index_get(input, i, &molecule);
+ tng_molecule_name_get(input, molecule, str, 256);
+ if (varNAtoms == TNG_CONSTANT_N_ATOMS)
+ {
+ if ((int)molCntList[i] == 0)
+ {
+ continue;
+ }
+ fprintf(stream, "Molecule: %s, count: %d\n", str, (int)molCntList[i]);
+ }
+ else
+ {
+ fprintf(stream, "Molecule: %s\n", str);
+ }
+ tng_molecule_num_chains_get(input, molecule, &nChains);
+ if (nChains > 0)
+ {
+ for (gmx_int64_t j = 0; j < nChains; j++)
+ {
+ tng_molecule_chain_of_index_get(input, molecule, j, &chain);
+ tng_chain_name_get(input, chain, str, 256);
+ fprintf(stream, "\tChain: %s\n", str);
+ tng_chain_num_residues_get(input, chain, &nResidues);
+ for (gmx_int64_t k = 0; k < nResidues; k++)
+ {
+ tng_chain_residue_of_index_get(input, chain, k, &residue);
+ tng_residue_name_get(input, residue, str, 256);
+ fprintf(stream, "\t\tResidue: %s\n", str);
+ tng_residue_num_atoms_get(input, residue, &nAtoms);
+ for (gmx_int64_t l = 0; l < nAtoms; l++)
+ {
+ tng_residue_atom_of_index_get(input, residue, l, &atom);
+ tng_atom_name_get(input, atom, str, 256);
+ fprintf(stream, "\t\t\tAtom: %s", str);
+ tng_atom_type_get(input, atom, str, 256);
+ fprintf(stream, " (%s)\n", str);
+ }
+ }
+ }
+ }
+ /* It is possible to have a molecule without chains, in which case
+ * residues in the molecule can be iterated through without going
+ * through chains. */
+ else
+ {
+ tng_molecule_num_residues_get(input, molecule, &nResidues);
+ if (nResidues > 0)
+ {
+ for (gmx_int64_t k = 0; k < nResidues; k++)
+ {
+ tng_molecule_residue_of_index_get(input, molecule, k, &residue);
+ tng_residue_name_get(input, residue, str, 256);
+ fprintf(stream, "\t\tResidue: %s\n", str);
+ tng_residue_num_atoms_get(input, residue, &nAtoms);
+ for (gmx_int64_t l = 0; l < nAtoms; l++)
+ {
+ tng_residue_atom_of_index_get(input, residue, l, &atom);
+ tng_atom_name_get(input, atom, str, 256);
+ fprintf(stream, "\t\t\tAtom: %s", str);
+ tng_atom_type_get(input, atom, str, 256);
+ fprintf(stream, " (%s)\n", str);
+ }
+ }
+ }
+ else
+ {
+ tng_molecule_num_atoms_get(input, molecule, &nAtoms);
+ for (gmx_int64_t l = 0; l < nAtoms; l++)
+ {
+ tng_molecule_atom_of_index_get(input, molecule, l, &atom);
+ tng_atom_name_get(input, atom, str, 256);
+ fprintf(stream, "\t\t\tAtom: %s", str);
+ tng_atom_type_get(input, atom, str, 256);
+ fprintf(stream, " (%s)\n", str);
+ }
+ }
+ }
+ }
+#else
+ GMX_UNUSED_VALUE(input);
+ GMX_UNUSED_VALUE(stream);
+#endif
+}
+
+gmx_bool gmx_get_tng_data_block_types_of_next_frame(tng_trajectory_t input,
+ int frame,
+ int nRequestedIds,
+ gmx_int64_t *requestedIds,
+ gmx_int64_t *nextFrame,
+ gmx_int64_t *nBlocks,
+ gmx_int64_t **blockIds)
+{
+#ifdef GMX_USE_TNG
+ tng_function_status stat;
+
+ stat = tng_util_trajectory_next_frame_present_data_blocks_find(input, frame,
+ nRequestedIds, requestedIds,
+ nextFrame,
+ nBlocks, blockIds);
+
+ if (stat == TNG_CRITICAL)
+ {
+ gmx_file("Cannot read TNG file. Cannot find data blocks of next frame.");
+ }
+ else if (stat == TNG_FAILURE)
+ {
+ return FALSE;
+ }
+ return TRUE;
+#else
+ GMX_UNUSED_VALUE(input);
+ GMX_UNUSED_VALUE(frame);
+ GMX_UNUSED_VALUE(nRequestedIds);
+ GMX_UNUSED_VALUE(requestedIds);
+ GMX_UNUSED_VALUE(nextFrame);
+ GMX_UNUSED_VALUE(nBlocks);
+ GMX_UNUSED_VALUE(blockIds);
+ return FALSE;
+#endif
+}
+
+gmx_bool gmx_get_tng_data_next_frame_of_block_type(tng_trajectory_t input,
+ gmx_int64_t blockId,
+ real **values,
+ gmx_int64_t *frameNumber,
+ double *frameTime,
+ gmx_int64_t *nValuesPerFrame,
+ gmx_int64_t *nAtoms,
+ real *prec,
+ char *name,
+ int maxLen,
+ gmx_bool *bOK)
+{
+#ifdef GMX_USE_TNG
+ tng_function_status stat;
+ char datatype = -1, codecId;
+ int blockDependency;
+ void *data = 0;
+ float localPrec;
+
+ stat = tng_data_block_name_get(input, blockId, name, maxLen);
+ if (stat != TNG_SUCCESS)
+ {
+ gmx_file("Cannot read next frame of TNG file");
+ }
+ stat = tng_data_block_dependency_get(input, blockId, &blockDependency);
+ if (stat != TNG_SUCCESS)
+ {
+ gmx_file("Cannot read next frame of TNG file");
+ }
+ if (blockDependency & TNG_PARTICLE_DEPENDENT)
+ {
+ tng_num_particles_get(input, nAtoms);
+ stat = tng_util_particle_data_next_frame_read(input,
+ blockId,
+ &data,
+ &datatype,
+ frameNumber,
+ frameTime);
+ }
+ else
+ {
+ *nAtoms = 1; /* There are not actually any atoms, but it is used for
+ allocating memory */
+ stat = tng_util_non_particle_data_next_frame_read(input,
+ blockId,
+ &data,
+ &datatype,
+ frameNumber,
+ frameTime);
+ }
+ if (stat == TNG_CRITICAL)
+ {
+ gmx_file("Cannot read next frame of TNG file");
+ }
+ if (stat == TNG_FAILURE)
+ {
+ *bOK = TRUE;
+ return FALSE;
+ }
+
+ stat = tng_data_block_num_values_per_frame_get(input, blockId, nValuesPerFrame);
+ if (stat != TNG_SUCCESS)
+ {
+ gmx_file("Cannot read next frame of TNG file");
+ }
+ snew(*values, sizeof(real) * *nValuesPerFrame * *nAtoms);
+ convert_array_to_real_array(data,
+ *values,
+ getDistanceScaleFactor(input),
+ *nAtoms,
+ *nValuesPerFrame,
+ datatype);
+
+ tng_util_frame_current_compression_get(input, blockId, &codecId, &localPrec);
+
+ /* This must be updated if/when more lossy compression methods are added */
+ if (codecId != TNG_TNG_COMPRESSION)
+ {
+ *prec = -1.0;
+ }
+ else
+ {
+ *prec = localPrec;
+ }
+
+ *bOK = TRUE;
+ return TRUE;
+#else
+ GMX_UNUSED_VALUE(input);
+ GMX_UNUSED_VALUE(blockId);
+ GMX_UNUSED_VALUE(values);
+ GMX_UNUSED_VALUE(frameNumber);
+ GMX_UNUSED_VALUE(frameTime);
+ GMX_UNUSED_VALUE(nValuesPerFrame);
+ GMX_UNUSED_VALUE(nAtoms);
+ GMX_UNUSED_VALUE(prec);
+ GMX_UNUSED_VALUE(name);
+ GMX_UNUSED_VALUE(maxLen);
+ GMX_UNUSED_VALUE(bOK);
+ return FALSE;
+#endif
+}
+
+void list_tng_for_gmx_dump(const char *fn, gmx_bool bXVG)
+{
+#ifdef GMX_USE_TNG
+ tng_trajectory_t tng;
+ gmx_int64_t nframe = 0;
+ gmx_int64_t i, *block_ids = NULL, step, ndatablocks;
+ gmx_int64_t pos_block_id = TNG_TRAJ_POSITIONS;
+ gmx_bool bOK;
+
+ gmx_tng_open(fn, 'r', &tng);
+ gmx_print_tng_molecule_system(tng, stdout);
+
+ bOK = gmx_get_tng_data_block_types_of_next_frame(tng, -1,
+ bXVG ? 1 : 0,
+ bXVG ? &pos_block_id : NULL,
+ &step, &ndatablocks,
+ &block_ids);
+ do
+ {
+ for (i = 0; i < ndatablocks; i++)
+ {
+ double frame_time;
+ real prec, *values = NULL;
+ gmx_int64_t n_values_per_frame, n_atoms;
+ char block_name[STRLEN];
+
+ gmx_get_tng_data_next_frame_of_block_type(tng, block_ids[i], &values,
+ &step, &frame_time,
+ &n_values_per_frame, &n_atoms,
+ &prec,
+ block_name, STRLEN, &bOK);
+ if (!bOK)
+ {
+ /* Can't write any output because we don't know what
+ arrays are valid. */
+ fprintf(stderr, "\nWARNING: Incomplete frame at time %g, will not write output\n", frame_time);
+ list_tng_inner(fn, (0 == i), bXVG, values, step, frame_time,
+ n_values_per_frame, n_atoms, prec, nframe, block_name);
+ }
+ }
+ nframe++;
+ }
+ while (gmx_get_tng_data_block_types_of_next_frame(tng, step,
+ bXVG ? 1 : 0,
+ bXVG ? &pos_block_id : NULL,
+ &step,
+ &ndatablocks,
+ &block_ids));
+
+ if (block_ids)
+ {
+ sfree(block_ids);
+ }
+
+ gmx_tng_close(&tng);
+#else
+ GMX_UNUSED_VALUE(fn);
+ GMX_UNUSED_VALUE(bXVG);
+#endif
+}
--- /dev/null
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2013, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+
+#ifndef GMX_FILEIO_TNGIO_FOR_TOOLS_H
+#define GMX_FILEIO_TNGIO_FOR_TOOLS_H
+
+#include "gromacs/legacyheaders/typedefs.h"
+#include "../../external/tng_io/include/tng_io_fwd.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if 0
+}
+#endif
+
+/*! \brief Prepare to write TNG output from trajectory conversion tools */
+void gmx_prepare_tng_writing(const char *filename,
+ char mode,
+ tng_trajectory_t *in,
+ tng_trajectory_t *out,
+ int nAtoms,
+ const gmx_mtop_t *mtop,
+ const atom_id *index,
+ const char *indexGroupName);
+
+/*! \brief Write a trxframe to a TNG file
+ *
+ * \param natoms Number of atoms to actually write
+ *
+ * The natoms field in frame is the number of atoms in the system. The
+ * parameter natoms supports writing an index-group subset of the
+ * atoms.
+ */
+void gmx_write_tng_from_trxframe(tng_trajectory_t output,
+ t_trxframe *frame,
+ int natoms);
+
+/*! \brief Creates a molecule containing only the indexed atoms and sets
+ * the number of all other molecules to 0. Works similar to a
+ * selection group. */
+void gmx_tng_setup_atom_subgroup(tng_trajectory_t tng,
+ const int nind,
+ const atom_id *ind,
+ const char *name);
+
+/*! \brief Read the first/next TNG frame. */
+gmx_bool gmx_read_next_tng_frame(tng_trajectory_t input,
+ t_trxframe *fr,
+ gmx_int64_t *requestedIds,
+ int numRequestedIds);
+
+/*! \brief Print the molecule system to stream */
+void gmx_print_tng_molecule_system(tng_trajectory_t input,
+ FILE *stream);
+
+/*! \brief Get a list of block IDs present in the next frame with data. */
+gmx_bool gmx_get_tng_data_block_types_of_next_frame(tng_trajectory_t input,
+ int frame,
+ int nRequestedIds,
+ gmx_int64_t *requestedIds,
+ gmx_int64_t *nextFrame,
+ gmx_int64_t *nBlocks,
+ gmx_int64_t **blockIds);
+
+/*! \brief Get data of the next frame with data from the data block
+ * with the specified block ID. */
+gmx_bool gmx_get_tng_data_next_frame_of_block_type(tng_trajectory_t input,
+ gmx_int64_t blockId,
+ real **values,
+ gmx_int64_t *frameNumber,
+ double *frameTime,
+ gmx_int64_t *nValuesPerFrame,
+ gmx_int64_t *nAtoms,
+ real *prec,
+ char *name,
+ int maxLen,
+ gmx_bool *bOK);
+
+/*! \brief Implements TNG file reading for gmxdump. */
+void list_tng_for_gmx_dump(const char *fn,
+ gmx_bool bXVG);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
gmx_fio_do_int(fio, ir->nstvout);
gmx_fio_do_int(fio, ir->nstfout);
gmx_fio_do_int(fio, ir->nstenergy);
- gmx_fio_do_int(fio, ir->nstxtcout);
+ gmx_fio_do_int(fio, ir->nstxout_compressed);
if (file_version >= 59)
{
gmx_fio_do_double(fio, ir->init_t);
gmx_fio_do_real(fio, rdum);
ir->delta_t = rdum;
}
- gmx_fio_do_real(fio, ir->xtcprec);
+ gmx_fio_do_real(fio, ir->x_compression_precision);
if (file_version < 19)
{
gmx_fio_do_int(fio, idum);
#include "gromacs/timing/wallcycle.h"
void
-do_trajectory_writing(FILE *fplog,
- t_commrec *cr,
- int nfile,
- const t_filenm fnm[],
- gmx_int64_t step,
- gmx_int64_t step_rel,
- double t,
- t_inputrec *ir,
- t_state *state,
- t_state *state_global,
- gmx_mtop_t *top_global,
- t_forcerec *fr,
- gmx_update_t upd,
- gmx_mdoutf_t *outf,
- t_mdebin *mdebin,
- gmx_ekindata_t *ekind,
- rvec *f,
- rvec *f_global,
- gmx_wallcycle_t wcycle,
- gmx_rng_t mcrng,
- int *nchkpt,
- gmx_bool bCPT,
- gmx_bool bRerunMD,
- gmx_bool bLastStep,
- gmx_bool bDoConfOut,
- gmx_bool bSumEkinhOld
- )
+do_md_trajectory_writing(FILE *fplog,
+ t_commrec *cr,
+ int nfile,
+ const t_filenm fnm[],
+ gmx_int64_t step,
+ gmx_int64_t step_rel,
+ double t,
+ t_inputrec *ir,
+ t_state *state,
+ t_state *state_global,
+ gmx_mtop_t *top_global,
+ t_forcerec *fr,
+ gmx_update_t upd,
+ gmx_mdoutf_t outf,
+ t_mdebin *mdebin,
+ gmx_ekindata_t *ekind,
+ rvec *f,
+ rvec *f_global,
+ gmx_wallcycle_t wcycle,
+ gmx_rng_t mcrng,
+ int *nchkpt,
+ gmx_bool bCPT,
+ gmx_bool bRerunMD,
+ gmx_bool bLastStep,
+ gmx_bool bDoConfOut,
+ gmx_bool bSumEkinhOld
+ )
{
int mdof_flags;
{
mdof_flags |= MDOF_F;
}
- if (do_per_step(step, ir->nstxtcout))
+ if (do_per_step(step, ir->nstxout_compressed))
{
- mdof_flags |= MDOF_XTC;
+ mdof_flags |= MDOF_X_COMPRESSED;
}
if (bCPT)
{
update_energyhistory(&state_global->enerhist, mdebin);
}
}
- write_traj(fplog, cr, outf, mdof_flags,
- step, t, state, state_global, f, f_global);
+ mdoutf_write_to_trajectory_files(fplog, cr, outf, mdof_flags, top_global,
+ step, t, state, state_global, f, f_global);
if (bCPT)
{
(*nchkpt)++;
bDoConfOut && MASTER(cr) &&
!bRerunMD)
{
- /* x and v have been collected in write_traj,
+ /* x and v have been collected in mdoutf_write_to_trajectory_files,
* because a checkpoint file will always be written
* at the last step.
*/
#include "../legacyheaders/update.h"
#include "../legacyheaders/mdebin.h"
+/*! \brief Wrapper routine for writing trajectories during mdrun
+ *
+ * This routine does communication (e.g. collecting distributed coordinates)
+ */
void
-do_trajectory_writing(FILE *fplog,
- t_commrec *cr,
- int nfile,
- const t_filenm fnm[],
- gmx_int64_t step,
- gmx_int64_t step_rel,
- double t,
- t_inputrec *ir,
- t_state *state,
- t_state *state_global,
- gmx_mtop_t *top_global,
- t_forcerec *fr,
- gmx_update_t upd,
- gmx_mdoutf_t *outf,
- t_mdebin *mdebin,
- gmx_ekindata_t *ekind,
- rvec *f,
- rvec *f_global,
- gmx_wallcycle_t wcycle,
- gmx_rng_t mcrng,
- int *nchkpt,
- gmx_bool bCPT,
- gmx_bool bRerunMD,
- gmx_bool bLastStep,
- gmx_bool bDoConfOut,
- gmx_bool bSumEkinhOld
- );
-/* Wrapper routine for trajectory writing */
+do_md_trajectory_writing(FILE *fplog,
+ t_commrec *cr,
+ int nfile,
+ const t_filenm fnm[],
+ gmx_int64_t step,
+ gmx_int64_t step_rel,
+ double t,
+ t_inputrec *ir,
+ t_state *state,
+ t_state *state_global,
+ gmx_mtop_t *top_global,
+ t_forcerec *fr,
+ gmx_update_t upd,
+ gmx_mdoutf_t outf,
+ t_mdebin *mdebin,
+ gmx_ekindata_t *ekind,
+ rvec *f,
+ rvec *f_global,
+ gmx_wallcycle_t wcycle,
+ gmx_rng_t mcrng,
+ int *nchkpt,
+ gmx_bool bCPT,
+ gmx_bool bRerunMD,
+ gmx_bool bLastStep,
+ gmx_bool bDoConfOut,
+ gmx_bool bSumEkinhOld
+ );
-void write_traj(FILE *fplog, t_commrec *cr,
- gmx_mdoutf_t *of,
- int mdof_flags,
- gmx_int64_t step, double t,
- t_state *state_local, t_state *state_global,
- rvec *f_local, rvec *f_global);
-/* Routine that writes frames to trn, xtc and/or checkpoint.
- * What is written is determined by the mdof_flags defined above.
- * Data is collected to the master node only when necessary.
- */
#endif /* GMX_FILEIO_TRAJECTORY_WRITING_H */
+++ /dev/null
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2013,2014, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
- * and including many others, as listed in the AUTHORS file in the
- * top-level source directory and at http://www.gromacs.org.
- *
- * GROMACS is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * GROMACS 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with GROMACS; if not, see
- * http://www.gnu.org/licenses, or write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * If you want to redistribute modifications to GROMACS, please
- * consider that scientific software is very special. Version
- * control is crucial - bugs must be traceable. We will be happy to
- * consider code for inclusion in the official distribution, but
- * derived work must not be called official GROMACS. Details are found
- * in the README & COPYING files - if they are missing, get the
- * official version at http://www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the research papers on the package. Check out http://www.gromacs.org.
- */
-
-#include "trajectory_writing.h"
-#include "gromacs/legacyheaders/mvdata.h"
-#include "gromacs/legacyheaders/domdec.h"
-#include "checkpoint.h"
-#include "trnio.h"
-#include "xtcio.h"
-#include "gromacs/legacyheaders/smalloc.h"
-
-static void moveit(t_commrec *cr, rvec xx[])
-{
- if (!xx)
- {
- return;
- }
-
- move_rvecs(cr, FALSE, FALSE, xx, NULL, (cr->nnodes-cr->npmenodes)-1, NULL);
-}
-
-void write_traj(FILE *fplog, t_commrec *cr,
- gmx_mdoutf_t *of,
- int mdof_flags,
- gmx_int64_t step, double t,
- t_state *state_local, t_state *state_global,
- rvec *f_local, rvec *f_global)
-{
- rvec *local_v;
- rvec *global_v;
-
-#define MX(xvf) moveit(cr, xvf)
-
- /* MRS -- defining these variables is to manage the difference
- * between half step and full step velocities, but there must be a better way . . . */
-
- local_v = state_local->v;
- global_v = state_global->v;
-
- if (DOMAINDECOMP(cr))
- {
- if (mdof_flags & MDOF_CPT)
- {
- dd_collect_state(cr->dd, state_local, state_global);
- }
- else
- {
- if (mdof_flags & (MDOF_X | MDOF_XTC))
- {
- dd_collect_vec(cr->dd, state_local, state_local->x,
- state_global->x);
- }
- if (mdof_flags & MDOF_V)
- {
- dd_collect_vec(cr->dd, state_local, local_v,
- global_v);
- }
- }
- if (mdof_flags & MDOF_F)
- {
- dd_collect_vec(cr->dd, state_local, f_local, f_global);
- }
- }
- else
- {
- if (mdof_flags & MDOF_CPT)
- {
- /* All pointers in state_local are equal to state_global,
- * but we need to copy the non-pointer entries.
- */
- state_global->lambda = state_local->lambda;
- state_global->veta = state_local->veta;
- state_global->vol0 = state_local->vol0;
- copy_mat(state_local->box, state_global->box);
- copy_mat(state_local->boxv, state_global->boxv);
- copy_mat(state_local->svir_prev, state_global->svir_prev);
- copy_mat(state_local->fvir_prev, state_global->fvir_prev);
- copy_mat(state_local->pres_prev, state_global->pres_prev);
- }
- if (cr->nnodes > 1)
- {
- /* Particle decomposition, collect the data on the master node */
- if (mdof_flags & MDOF_CPT)
- {
- if (state_local->flags & (1<<estX))
- {
- MX(state_global->x);
- }
- if (state_local->flags & (1<<estV))
- {
- MX(state_global->v);
- }
- if (state_local->flags & (1<<estSDX))
- {
- MX(state_global->sd_X);
- }
- if (state_global->nrngi > 1)
- {
- if (state_local->flags & (1<<estLD_RNG))
- {
-#ifdef GMX_MPI
- MPI_Gather(state_local->ld_rng,
- state_local->nrng*sizeof(state_local->ld_rng[0]), MPI_BYTE,
- state_global->ld_rng,
- state_local->nrng*sizeof(state_local->ld_rng[0]), MPI_BYTE,
- MASTERRANK(cr), cr->mpi_comm_mygroup);
-#endif
- }
- if (state_local->flags & (1<<estLD_RNGI))
- {
-#ifdef GMX_MPI
- MPI_Gather(state_local->ld_rngi,
- sizeof(state_local->ld_rngi[0]), MPI_BYTE,
- state_global->ld_rngi,
- sizeof(state_local->ld_rngi[0]), MPI_BYTE,
- MASTERRANK(cr), cr->mpi_comm_mygroup);
-#endif
- }
- }
- }
- else
- {
- if (mdof_flags & (MDOF_X | MDOF_XTC))
- {
- MX(state_global->x);
- }
- if (mdof_flags & MDOF_V)
- {
- MX(global_v);
- }
- }
- if (mdof_flags & MDOF_F)
- {
- MX(f_global);
- }
- }
- }
-
- if (MASTER(cr))
- {
- if (mdof_flags & MDOF_CPT)
- {
- write_checkpoint(of->fn_cpt, of->bKeepAndNumCPT,
- fplog, cr, of->eIntegrator, of->simulation_part,
- of->bExpanded, of->elamstats, step, t, state_global);
- }
-
- if (mdof_flags & (MDOF_X | MDOF_V | MDOF_F))
- {
- fwrite_trn(of->fp_trn, step, t, state_local->lambda[efptFEP],
- state_local->box, of->natoms_global,
- (mdof_flags & MDOF_X) ? state_global->x : NULL,
- (mdof_flags & MDOF_V) ? global_v : NULL,
- (mdof_flags & MDOF_F) ? f_global : NULL);
- if (gmx_fio_flush(of->fp_trn) != 0)
- {
- gmx_file("Cannot write trajectory; maybe you are out of disk space?");
- }
- }
- if (mdof_flags & MDOF_XTC)
- {
- rvec *xxtc = NULL;
-
- if (of->natoms_xtc == of->natoms_global)
- {
- /* We are writing all the atoms to XTC output */
- xxtc = state_global->x;
- }
- else
- {
- /* We are writing only a subset of the atoms to XTC
- output, so we have to make a copy of the subset of
- coordinates. */
- int i, j;
-
- snew(xxtc, of->natoms_xtc);
- for (i = 0, j = 0; ((i < of->natoms_global) &&
- (j < of->natoms_xtc)); i++)
- {
- if (ggrpnr(of->groups, egcXTC, i) == 0)
- {
- copy_rvec(state_global->x[i], xxtc[j++]);
- }
- }
- }
- if (write_xtc(of->fp_xtc, of->natoms_xtc, step, t,
- state_local->box, xxtc, of->xtc_prec) == 0)
- {
- gmx_fatal(FARGS, "XTC error - maybe you are out of disk space?");
- }
- if (of->natoms_xtc != of->natoms_global)
- {
- sfree(xxtc);
- }
- }
- }
-}
#include "trxio.h"
#include "tpxio.h"
#include "trnio.h"
+#include "tngio.h"
+#include "tngio_for_tools.h"
#include "names.h"
#include "vec.h"
#include "futil.h"
struct t_trxstatus
{
- int __frame;
- t_trxframe *xframe;
- int nxframe;
- t_fileio *fio;
- eFileFormat eFF;
- int NATOMS;
- double DT, BOX[3];
- gmx_bool bReadBox;
- char *persistent_line; /* Persistent line for reading g96 trajectories */
+ int __frame;
+ t_trxframe *xframe;
+ int nxframe;
+ t_fileio *fio;
+ tng_trajectory_t tng;
+ eFileFormat eFF;
+ int NATOMS;
+ double DT, BOX[3];
+ gmx_bool bReadBox;
+ char *persistent_line; /* Persistent line for reading g96 trajectories */
};
/* utility functions */
status->fio = NULL;
status->__frame = -1;
status->persistent_line = NULL;
+ status->tng = NULL;
}
return (int)(log(prec)/log(10.0)+0.5);
}
+real ndec2prec(int ndec)
+{
+ return pow(10.0, ndec);
+}
t_fileio *trx_get_fileio(t_trxstatus *status)
{
return status->fio;
}
-
+tng_trajectory_t trx_get_tng(t_trxstatus *status)
+{
+ return status->tng;
+}
void clear_trxframe(t_trxframe *fr, gmx_bool bFirst)
{
- fr->not_ok = 0;
- fr->bTitle = FALSE;
- fr->bStep = FALSE;
- fr->bTime = FALSE;
- fr->bLambda = FALSE;
+ fr->not_ok = 0;
+ fr->bTitle = FALSE;
+ fr->bStep = FALSE;
+ fr->bTime = FALSE;
+ fr->bLambda = FALSE;
fr->bFepState = FALSE;
- fr->bAtoms = FALSE;
- fr->bPrec = FALSE;
- fr->bX = FALSE;
- fr->bV = FALSE;
- fr->bF = FALSE;
- fr->bBox = FALSE;
+ fr->bAtoms = FALSE;
+ fr->bPrec = FALSE;
+ fr->bX = FALSE;
+ fr->bV = FALSE;
+ fr->bF = FALSE;
+ fr->bBox = FALSE;
if (bFirst)
{
- fr->flags = 0;
- fr->bDouble = FALSE;
- fr->natoms = -1;
- fr->t0 = 0;
- fr->tpf = 0;
- fr->tppf = 0;
- fr->title = NULL;
- fr->step = 0;
- fr->time = 0;
- fr->lambda = 0;
+ fr->flags = 0;
+ fr->bDouble = FALSE;
+ fr->natoms = -1;
+ fr->t0 = 0;
+ fr->tpf = 0;
+ fr->tppf = 0;
+ fr->title = NULL;
+ fr->step = 0;
+ fr->time = 0;
+ fr->lambda = 0;
fr->fep_state = 0;
- fr->atoms = NULL;
- fr->prec = 0;
- fr->x = NULL;
- fr->v = NULL;
- fr->f = NULL;
+ fr->atoms = NULL;
+ fr->prec = 0;
+ fr->x = NULL;
+ fr->v = NULL;
+ fr->f = NULL;
clear_mat(fr->box);
fr->bPBC = FALSE;
fr->ePBC = -1;
{
char title[STRLEN];
rvec *xout = NULL, *vout = NULL, *fout = NULL;
- int i;
+ int i, ftp = -1;
real prec;
if (fr->bPrec)
prec = 1000.0;
}
- switch (gmx_fio_getftp(status->fio))
+ if (status->tng)
+ {
+ ftp = efTNG;
+ }
+ else if (status->fio)
+ {
+ ftp = gmx_fio_getftp(status->fio);
+ }
+ else
+ {
+ gmx_incons("No input file available");
+ }
+
+ switch (ftp)
{
case efTRJ:
case efTRR:
+ case efTNG:
break;
default:
if (!fr->bX)
{
gmx_fatal(FARGS, "Need coordinates to write a %s trajectory",
- ftp2ext(gmx_fio_getftp(status->fio)));
+ ftp2ext(ftp));
}
break;
}
- switch (gmx_fio_getftp(status->fio))
+ switch (ftp)
{
case efTRJ:
case efTRR:
+ case efTNG:
if (fr->bV)
{
snew(vout, nind);
break;
}
- switch (gmx_fio_getftp(status->fio))
+ switch (ftp)
{
+ case efTNG:
+ gmx_write_tng_from_trxframe(status->tng, fr, nind);
+ break;
case efXTC:
write_xtc(status->fio, nind, fr->step, fr->time, fr->box, xout, prec);
break;
if (!fr->bAtoms)
{
gmx_fatal(FARGS, "Can not write a %s file without atom names",
- ftp2ext(gmx_fio_getftp(status->fio)));
+ ftp2ext(ftp));
}
sprintf(title, "frame t= %.3f", fr->time);
- if (gmx_fio_getftp(status->fio) == efGRO)
+ if (ftp == efGRO)
{
write_hconf_indexed_p(gmx_fio_getfp(status->fio), title, fr->atoms, nind, ind,
prec2ndec(prec),
break;
default:
gmx_fatal(FARGS, "Sorry, write_trxframe_indexed can not write %s",
- ftp2ext(gmx_fio_getftp(status->fio)));
+ ftp2ext(ftp));
break;
}
- switch (gmx_fio_getftp(status->fio))
+ switch (ftp)
{
case efTRN:
case efTRJ:
case efTRR:
+ case efTNG:
if (vout)
{
sfree(vout);
return 0;
}
+void trjtools_gmx_prepare_tng_writing(const char *filename,
+ char filemode,
+ t_trxstatus *in,
+ t_trxstatus **out,
+ const char *infile,
+ const int natoms,
+ const gmx_mtop_t *mtop,
+ const atom_id *index,
+ const char *index_group_name)
+{
+ if (filemode != 'w' && filemode != 'a')
+ {
+ gmx_incons("Sorry, can only prepare for TNG output.");
+ }
+
+ if (*out == NULL)
+ {
+ snew((*out), 1);
+ }
+ status_init(*out);
+
+ if (in != NULL)
+ {
+ gmx_prepare_tng_writing(filename,
+ filemode,
+ &in->tng,
+ &(*out)->tng,
+ natoms,
+ mtop,
+ index,
+ index_group_name);
+ }
+ else if (efTNG == fn2ftp(infile))
+ {
+ tng_trajectory_t tng_in;
+ gmx_tng_open(infile, 'r', &tng_in);
+
+ gmx_prepare_tng_writing(filename,
+ filemode,
+ &tng_in,
+ &(*out)->tng,
+ natoms,
+ mtop,
+ index,
+ index_group_name);
+ }
+}
+
+void write_tng_frame(t_trxstatus *status,
+ t_trxframe *frame)
+{
+ gmx_write_tng_from_trxframe(status->tng, frame, -1);
+}
+
int write_trxframe(t_trxstatus *status, t_trxframe *fr, gmx_conect gc)
{
char title[STRLEN];
prec = 1000.0;
}
+ if (status->tng)
+ {
+ gmx_tng_set_compression_precision(status->tng, prec);
+ write_tng_frame(status, fr);
+
+ return 0;
+ }
+
switch (gmx_fio_getftp(status->fio))
{
case efTRJ:
void close_trx(t_trxstatus *status)
{
- gmx_fio_close(status->fio);
+ gmx_tng_close(&status->tng);
+ if (status->fio)
+ {
+ gmx_fio_close(status->fio);
+ }
sfree(status);
}
int ct;
gmx_bool bOK, bRet, bMissingData = FALSE, bSkip = FALSE;
int dummy = 0;
+ int ftp;
bRet = FALSE;
pt = fr->time;
fr->tppf = fr->tpf;
fr->tpf = fr->time;
- switch (gmx_fio_getftp(status->fio))
+ if (status->tng)
+ {
+ /* Special treatment for TNG files */
+ ftp = efTNG;
+ }
+ else
+ {
+ ftp = gmx_fio_getftp(status->fio);
+ }
+ switch (ftp)
{
case efTRJ:
case efTRR:
fr->not_ok = DATA_NOT_OK;
}
break;
+ case efTNG:
+ bRet = gmx_read_next_tng_frame(status->tng, fr, NULL, 0);
+ break;
case efPDB:
bRet = pdb_next_x(status, gmx_fio_getfp(status->fio), fr);
break;
int read_first_frame(const output_env_t oenv, t_trxstatus **status,
const char *fn, t_trxframe *fr, int flags)
{
- t_fileio *fio;
- gmx_bool bFirst, bOK;
- int dummy = 0;
+ t_fileio *fio;
+ gmx_bool bFirst, bOK;
+ int dummy = 0;
+ int ftp = fn2ftp(fn);
+ gmx_int64_t *tng_ids;
clear_trxframe(fr, TRUE);
fr->flags = flags;
(*status)->nxframe = 1;
initcount(*status);
- fio = (*status)->fio = gmx_fio_open(fn, "r");
- switch (gmx_fio_getftp(fio))
+ if (efTNG == ftp)
+ {
+ /* Special treatment for TNG files */
+ gmx_tng_open(fn, 'r', &(*status)->tng);
+ }
+ else
+ {
+ fio = (*status)->fio = gmx_fio_open(fn, "r");
+ }
+ switch (ftp)
{
case efTRJ:
case efTRR:
}
bFirst = FALSE;
break;
+ case efTNG:
+ fr->step = -1;
+ if (!gmx_read_next_tng_frame((*status)->tng, fr, NULL, 0))
+ {
+ fr->not_ok = DATA_NOT_OK;
+ fr->natoms = 0;
+ printincomp(*status, fr);
+ }
+ else
+ {
+ printcount(*status, oenv, fr->time, FALSE);
+ }
+ bFirst = FALSE;
+ break;
case efPDB:
pdb_first_x(*status, gmx_fio_getfp(fio), fr);
if (fr->natoms)
void close_trj(t_trxstatus *status)
{
- gmx_fio_close(status->fio);
+ gmx_tng_close(&status->tng);
+ if (status->fio)
+ {
+ gmx_fio_close(status->fio);
+ }
+
/* The memory in status->xframe is lost here,
* but the read_first_x/read_next_x functions are deprecated anyhow.
* read_first_frame/read_next_frame and close_trx should be used.
#include "pdbio.h"
#include "../legacyheaders/oenv.h"
#include "gmxfio.h"
+#include "../../external/tng_io/include/tng_io_fwd.h"
#ifdef __cplusplus
extern "C" {
int prec2ndec(real prec);
/* Convert precision in 1/(nm) to number of decimal places */
+/*! \brief Convert number of decimal places to trajectory precision in
+ * 1/(nm) */
+real ndec2prec(int ndec);
+
void clear_trxframe(t_trxframe *fr, gmx_bool bFirst);
/* Set all content gmx_booleans to FALSE.
* When bFirst = TRUE, set natoms=-1, all pointers to NULL
* atoms can be NULL for file types which don't need atom names.
*/
+void trjtools_gmx_prepare_tng_writing(const char *filename,
+ char filemode,
+ t_trxstatus *in,
+ t_trxstatus **out,
+ const char *infile,
+ const int natoms,
+ const gmx_mtop_t *mtop,
+ const atom_id *index,
+ const char *index_group_name);
+/* Sets up *out for writing TNG. If *in != NULL and contains a TNG trajectory
+ * some data, e.g. molecule system, will be copied over from *in to *out.
+ * If *in == NULL a file name (infile) of a TNG file can be provided instead
+ * and used for copying data to *out.
+ * If there is no TNG input natoms is used to create "implicit atoms" (no atom
+ * or molecular data present). If natoms == -1 the number of atoms are
+ * not known (or there is already a TNG molecule system to copy, in which case
+ * natoms is not required anyhow). If an group of indexed atoms are written
+ * natoms must be the length of index. index_group_name is the name of the
+ * index group.
+ */
+
+/*! \brief Write a trxframe to the TNG file in status.
+ *
+ * This function is needed because both t_trxstatus and
+ * tng_trajectory_t are encapsulated, so client trajectory-writing
+ * code with a t_trxstatus can't just call the TNG writing
+ * function. */
+void write_tng_frame(t_trxstatus *status,
+ t_trxframe *fr);
+
void close_trx(t_trxstatus *status);
/* Close trj file as opened with read_first_x, read_frist_frame
* or open_trx. Identical to close_trj.
t_trxstatus *open_trx(const char *outfile, const char *filemode);
/* Open a TRX file and return an allocated status pointer */
-/* get a fileio from a trxstatus */
t_fileio *trx_get_fileio(t_trxstatus *status);
+/* get a fileio from a trxstatus */
+tng_trajectory_t trx_get_tng(t_trxstatus *status);
+/* get a tng trajectory container from a trxstatus */
gmx_bool bRmod_fd(double a, double b, double c, gmx_bool bDouble);
/* Returns TRUE when (a - b) MOD c = 0, using a margin which is slightly
gmx_bool bDum;
int bOK;
+ if (!fio)
+ {
+ /* This means the fio object is not being used, e.g. because
+ we are actually writing TNG output. We still have to return
+ a pseudo-success value, to keep some callers happy. */
+ return 1;
+ }
+
xd = gmx_fio_getxdr(fio);
/* write magic number and xtc identidier */
if (xtc_header(xd, &magic_number, &natoms, &step, &time, FALSE, &bDum) == 0)
read_tpxheader(tpr, &tpxh, TRUE, &version, &generation);
if (tpxh.natoms != natoms)
{
- gmx_fatal(FARGS, "tpr (%d atoms) and xtc (%d atoms) do not match!",
+ gmx_fatal(FARGS, "tpr (%d atoms) and trajectory (%d atoms) do not match!",
tpxh.natoms, natoms);
}
ePBC = read_tpx(tpr, NULL, NULL, &natoms, NULL, NULL, NULL, mtop);
#include "gromacs/fileio/tpxio.h"
#include "gromacs/fileio/trxio.h"
#include "rmpbc.h"
-#include "gromacs/fileio/xtcio.h"
#include "gmx_ana.h"
"For a system of 32,000 atoms and a 50 ns trajectory, the SDF can be generated ",
"in about 30 minutes, with most of the time dedicated to the two runs through ",
"[TT]trjconv[tt] that are required to center everything properly. ",
- "This also takes a whole bunch of space (3 copies of the [TT].xtc[tt] file). ",
+ "This also takes a whole bunch of space (3 copies of the trajectory file). ",
"Still, the pictures are pretty and very informative when the fitted selection is properly made. ",
"3-4 atoms in a widely mobile group (like a free amino acid in solution) works ",
"well, or select the protein backbone in a stable folded structure to get the SDF ",
"Cartesian coordinate. To do that, simply omit the preliminary [gmx-trjconv] steps. \n",
"USAGE: \n",
"1. Use [gmx-make_ndx] to create a group containing the atoms around which you want the SDF \n",
- "2. [TT]gmx trjconv -s a.tpr -f a.xtc -o b.xtc -boxcenter tric -ur compact -pbc none[tt] \n",
- "3. [TT]gmx trjconv -s a.tpr -f b.xtc -o c.xtc -fit rot+trans[tt] \n",
- "4. run [THISMODULE] on the [TT].xtc[tt] output of step #3. \n",
+ "2. [TT]gmx trjconv -s a.tpr -f a.tng -o b.tng -boxcenter tric -ur compact -pbc none[tt] \n",
+ "3. [TT]gmx trjconv -s a.tpr -f b.tng -o c.tng -fit rot+trans[tt] \n",
+ "4. run [THISMODULE] on the [TT]c.tng[tt] output of step #3. \n",
"5. Load [TT]grid.cube[tt] into VMD and view as an isosurface. \n",
"[BB]Note[bb] that systems such as micelles will require [TT]gmx trjconv -pbc cluster[tt] between steps 1 and 2\n",
"WARNINGS:[BR]",
#include "gromacs/fileio/tpxio.h"
#include "gromacs/fileio/trxio.h"
#include "gromacs/fileio/trnio.h"
+#include "gromacs/fileio/tngio.h"
+#include "gromacs/fileio/tngio_for_tools.h"
#include "gromacs/commandline/pargs.h"
#include "gromacs/fileio/futil.h"
#include "gromacs/fileio/pdbio.h"
};
#define npargs asize(pa)
int ftpin, i, frame, frame_out, step = 0, trjout = 0;
- t_trxstatus *status;
+ t_trxstatus *status, *trxout = NULL;
rvec *x, *v;
real t_corr;
t_trxframe fr, frout;
char **fnms, **fnms_out, *in_file, *out_file;
int n_append;
- t_trxstatus *trxout = NULL;
gmx_bool bNewFile, bIndex, bWrite;
int earliersteps, nfile_in, nfile_out, *cont_type, last_ok_step;
real *readtime, *timest, *settime;
atom_id *index = NULL, imax;
char *grpname;
real **val = NULL, *t = NULL, dt_remd;
- int n, nset;
+ int n, nset, ftpout = -1, prevEndStep = 0, filetype;
gmx_bool bOK;
gmx_off_t fpos;
output_env_t oenv;
gmx_fatal(FARGS, "You have specified %d files and %d entries in the demux table", nfile_in, nset);
}
+ ftpin = fn2ftp(fnms[0]);
+
+ for (i = 1; i < nfile_in; i++)
+ {
+ if (ftpin != fn2ftp(fnms[i]))
+ {
+ gmx_fatal(FARGS, "All input files must be of the same format");
+ }
+ }
+
nfile_out = opt2fns(&fnms_out, "-o", NFILE, fnm);
if (!nfile_out)
{
* This has to be done after sorting etc.
*/
out_file = fnms_out[0];
+ ftpout = fn2ftp(out_file);
n_append = -1;
for (i = 0; ((i < nfile_in) && (n_append == -1)); i++)
{
if (n_append == -1)
{
- trxout = open_trx(out_file, "w");
+ if (ftpout == efTNG)
+ {
+ if (bIndex)
+ {
+ trjtools_gmx_prepare_tng_writing(out_file, 'w', NULL, &trxout,
+ fnms[0], isize, NULL, index, grpname);
+ }
+ else
+ {
+ trjtools_gmx_prepare_tng_writing(out_file, 'w', NULL, &trxout,
+ fnms[0], -1, NULL, NULL, NULL);
+ }
+ }
+ else
+ {
+ trxout = open_trx(out_file, "w");
+ }
memset(&frout, 0, sizeof(frout));
}
else
"If the trajectories have an overlap and have not been written binary \n"
"reproducible this will produce an incorrect trajectory!\n\n");
+ filetype = gmx_fio_getftp(stfio);
/* Fails if last frame is incomplete
* We can't do anything about it without overwriting
* */
- if (gmx_fio_getftp(stfio) == efXTC)
+ if (filetype == efXTC)
{
lasttime =
xdr_xtc_get_last_frame_time(gmx_fio_getfp(stfio),
gmx_fatal(FARGS, "Error reading last frame. Maybe seek not supported." );
}
}
+ else if (filetype == efTNG)
+ {
+ tng_trajectory_t tng = trx_get_tng(status);
+ if (!tng)
+ {
+ gmx_fatal(FARGS, "Error opening TNG file.");
+ }
+ lasttime = gmx_tng_get_time_of_final_frame(tng);
+ fr.time = lasttime;
+ }
else
{
while (read_next_frame(oenv, status, &fr))
/* set the next time from the last frame in previous file */
if (i > 0)
{
+ /* When writing TNG the step determine which frame to write. Use an
+ * offset to be able to increase steps properly when changing files. */
+ if (ftpout == efTNG)
+ {
+ prevEndStep = frout.step;
+ }
+
if (frame_out >= 0)
{
if (cont_type[i] == TIME_CONTINUE)
frout = fr;
/* set the new time by adding the correct calculated above */
frout.time += t_corr;
+ if (ftpout == efTNG)
+ {
+ frout.step += prevEndStep;
+ }
/* quit if we have reached the end of what should be written */
if ((end > 0) && (frout.time > end+GMX_REAL_EPS))
{
#include "gromacs/fileio/tpxio.h"
#include "gromacs/fileio/trxio.h"
#include "gromacs/fileio/trnio.h"
+#include "gromacs/fileio/tngio_for_tools.h"
#include "gromacs/commandline/pargs.h"
#include "gromacs/fileio/futil.h"
#include "gromacs/fileio/pdbio.h"
}
#endif
+/*! \brief Read a full molecular topology if useful and available.
+ *
+ * If the input trajectory file is not in TNG format, and the output
+ * file is in TNG format, then we want to try to read a full topology
+ * (if available), so that we can write molecule information to the
+ * output file. The full topology provides better molecule information
+ * than is available from the normal t_topology data used by GROMACS
+ * tools.
+ *
+ * Also, the t_topology is only read under (different) particular
+ * conditions. If both apply, then a .tpr file might be read
+ * twice. Trying to fix this redundancy while trjconv is still an
+ * all-purpose tool does not seem worthwhile.
+ *
+ * Because of the way gmx_prepare_tng_writing is implemented, the case
+ * where the input TNG file has no molecule information will never
+ * lead to an output TNG file having molecule information. Since
+ * molecule information will generally be present if the input TNG
+ * file was written by a GROMACS tool, this seems like reasonable
+ * behaviour. */
+static gmx_mtop_t *read_mtop_for_tng(const char *tps_file,
+ const char *input_file,
+ const char *output_file)
+{
+ gmx_mtop_t *mtop = NULL;
+
+ if (fn2bTPX(tps_file) &&
+ efTNG != fn2ftp(input_file) &&
+ efTNG == fn2ftp(output_file))
+ {
+ int temp_natoms = -1;
+ snew(mtop, 1);
+ read_tpx(tps_file, NULL, NULL, &temp_natoms,
+ NULL, NULL, NULL, mtop);
+ }
+
+ return mtop;
+}
+
int gmx_trjconv(int argc, char *argv[])
{
const char *desc[] = {
FILE *out = NULL;
t_trxstatus *trxout = NULL;
- t_trxstatus *status;
+ t_trxstatus *trxin;
int ftp, ftpin = 0, file_nr;
t_trxframe fr, frout;
int flags;
int m, i, d, frame, outframe, natoms, nout, ncent, nre, newstep = 0, model_nr;
#define SKIP 10
t_topology top;
+ gmx_mtop_t *mtop = NULL;
gmx_conect gc = NULL;
int ePBC = -1;
t_atoms *atoms = NULL, useatoms;
{
}
+ mtop = read_mtop_for_tng(top_file, in_file, out_file);
+
/* Determine whether to read a topology */
bTPS = (ftp2bSet(efTPS, NFILE, fnm) ||
bRmPBC || bReset || bPBCcomMol || bCluster ||
else
{
/* no index file, so read natoms from TRX */
- if (!read_first_frame(oenv, &status, in_file, &fr, TRX_DONT_SKIP))
+ if (!read_first_frame(oenv, &trxin, in_file, &fr, TRX_DONT_SKIP))
{
gmx_fatal(FARGS, "Could not read a frame from %s", in_file);
}
natoms = fr.natoms;
- close_trj(status);
+ close_trj(trxin);
sfree(fr.x);
snew(index, natoms);
for (i = 0; i < natoms; i++)
}
/* open trx file for reading */
- bHaveFirstFrame = read_first_frame(oenv, &status, in_file, &fr, flags);
+ bHaveFirstFrame = read_first_frame(oenv, &trxin, in_file, &fr, flags);
if (fr.bPrec)
{
fprintf(stderr, "\nPrecision of %s is %g (nm)\n", in_file, 1/fr.prec);
tzero = fr.time;
}
+ bCopy = FALSE;
+ if (bIndex)
+ {
+ /* check if index is meaningful */
+ for (i = 0; i < nout; i++)
+ {
+ if (index[i] >= natoms)
+ {
+ gmx_fatal(FARGS,
+ "Index[%d] %d is larger than the number of atoms in the\n"
+ "trajectory file (%d). There is a mismatch in the contents\n"
+ "of your -f, -s and/or -n files.", i, index[i]+1, natoms);
+ }
+ bCopy = bCopy || (i != index[i]);
+ }
+ }
+
/* open output for writing */
if ((bAppend) && (gmx_fexist(out_file)))
{
}
switch (ftp)
{
+ case efTNG:
+ trjtools_gmx_prepare_tng_writing(out_file,
+ filemode[0],
+ trxin,
+ &trxout,
+ NULL,
+ nout,
+ mtop,
+ index,
+ grpnm);
+ break;
case efXTC:
case efG87:
case efTRR:
out = ffopen(out_file, filemode);
}
break;
+ default:
+ gmx_incons("Illegal output file format");
}
- bCopy = FALSE;
- if (bIndex)
- {
- /* check if index is meaningful */
- for (i = 0; i < nout; i++)
- {
- if (index[i] >= natoms)
- {
- gmx_fatal(FARGS,
- "Index[%d] %d is larger than the number of atoms in the\n"
- "trajectory file (%d). There is a mismatch in the contents\n"
- "of your -f, -s and/or -n files.", i, index[i]+1, natoms);
- }
- bCopy = bCopy || (i != index[i]);
- }
- }
if (bCopy)
{
snew(xmem, nout);
switch (ftp)
{
+ case efTNG:
+ write_tng_frame(trxout, &frout);
+ // TODO when trjconv behaves better: work how to read and write lambda
+ break;
case efTRJ:
case efTRR:
case efG87:
}
}
frame++;
- bHaveNextFrame = read_next_frame(oenv, status, &fr);
+ bHaveNextFrame = read_next_frame(oenv, trxin, &fr);
}
while (!(bTDump && bDumpFrame) && bHaveNextFrame);
}
}
fprintf(stderr, "\n");
- close_trj(status);
+ close_trj(trxin);
sfree(outf_base);
if (bRmPBC)
}
}
+ sfree(mtop);
+
do_view(oenv, out_file, NULL);
return 0;
/* mdrun: */
{ efTPX, NULL, NULL, ffREAD },
{ efTRN, "-o", NULL, ffWRITE },
- { efXTC, "-x", NULL, ffOPTWR },
+ { efCOMPRESSED, "-x", NULL, ffOPTWR },
{ efCPT, "-cpi", NULL, ffOPTRD },
{ efCPT, "-cpo", NULL, ffOPTWR },
{ efSTO, "-c", "confout", ffWRITE },
#include "gromacs/gmxana/gmx_ana.h"
#include "testutils/integrationtests.h"
#include "testutils/cmdlinetest.h"
+#include "gromacs/utility/arrayref.h"
namespace
{
-//! Test fixture for gmx traj
-typedef gmx::test::IntegrationTestFixture GmxTrajTest;
-
-class GmxTrajTestNoFatalError : public GmxTrajTest
+class GmxTraj : public gmx::test::IntegrationTestFixture,
+ public ::testing::WithParamInterface<const char *>
{
public:
- GmxTrajTestNoFatalError() : groFileName(fileManager_.getInputFilePath("spc2.gro")),
- xvgFileName(fileManager_.getTemporaryFilePath("spc2.xvg"))
+ GmxTraj() : groFileName(fileManager_.getInputFilePath("spc2.gro")),
+ xvgFileName(fileManager_.getTemporaryFilePath("spc2.xvg"))
{
}
caller.addOption("-s", groFileName);
caller.addOption("-ox", xvgFileName);
- std::string inputTrajectoryFileName = fileManager_.getInputFilePath(fileName).c_str();
+ std::string inputTrajectoryFileName = fileManager_.getInputFilePath(fileName);
caller.addOption("-f", inputTrajectoryFileName);
redirectStringToStdin("0\n");
std::string xvgFileName;
};
-/* There are fancy ways to use "value-parameterized tests" to reduce
- * the duplication below, but for the handful of file formats we care
- * about, the code would probably get longer (and need fancy template
- * stuff, too).
- */
-
/* TODO These tests are actually not very effective, because gmx-traj
* can only return 0 or exit via gmx_fatal() (which currently also
* exits the test binary). So, "no XDR/TNG support in the binary"
* leads to the reading test appearing to pass. Still, no fatal error
* and no segfault is useful information while modifying such code. */
-TEST_F(GmxTrajTestNoFatalError, TRRFile)
-{
- runTest("spc2-traj.trr");
-}
-TEST_F(GmxTrajTestNoFatalError, XTCFile)
+TEST_P(GmxTraj, WithDifferentInputFormats)
{
- runTest("spc2-traj.xtc");
+ runTest(GetParam());
}
-TEST_F(GmxTrajTestNoFatalError, GROFile)
-{
- runTest("spc2-traj.gro");
-}
+// ==
-TEST_F(GmxTrajTestNoFatalError, PDBFile)
+class TrjconvWithIndexGroupSubset : public gmx::test::IntegrationTestFixture,
+ public ::testing::WithParamInterface<const char *>
{
- runTest("spc2-traj.pdb");
-}
+ public:
+ int runTest(const char *fileName)
+ {
+ gmx::test::CommandLine caller;
+ caller.append("trjconv");
-TEST_F(GmxTrajTestNoFatalError, G96File)
-{
- runTest("spc2-traj.g96");
-}
+ caller.addOption("-s", fileManager_.getInputFilePath("spc2.gro"));
+
+ std::string inputTrajectoryFileName = fileManager_.getInputFilePath(fileName);
+ caller.addOption("-f", inputTrajectoryFileName);
-// .g87 file reading has been broken since at least v4.5
-// proposed on gmx-developers for removing that support
-TEST_F(GmxTrajTestNoFatalError, DISABLED_G87File)
+ std::string ndxFileName = fileManager_.getInputFilePath("spc2.ndx");
+ caller.addOption("-n", ndxFileName);
+
+ caller.addOption("-o", fileManager_.getTemporaryFilePath("spc-traj.tng"));
+
+ redirectStringToStdin("SecondWaterMolecule\n");
+
+ /* TODO Ideally, we would then check that the output file
+ has only 3 of the 6 atoms (which it does), but the
+ infrastructure for doing that automatically is still
+ being built. This would also fix the TODO below. */
+ return gmx_trjconv(caller.argc(), caller.argv());
+ }
+};
+/* TODO These tests are actually not very effective, because trjconv
+ * can only return 0 or exit via gmx_fatal() (which currently also
+ * exits the test binary). So, "no XDR/TNG support in the binary"
+ * leads to the reading test appearing to pass. Still, no fatal error
+ * and no segfault is useful information while modifying such code. */
+
+TEST_P(TrjconvWithIndexGroupSubset, WithDifferentInputFormats)
{
- redirectStringToStdin("0\n4\n6\n0.0\n");
- runTest("spc2-traj.g87");
+ runTest(GetParam());
}
+// ==
+
+/*! \brief Helper array of input files present in the source repo
+ * database. These all have two identical frames of two SPC water
+ * molecules, which were generated via trjconv from the .gro
+ * version. */
+const char *trajectoryFileNames[] = {
+ "spc2-traj.trr",
+#ifdef GMX_USE_TNG
+ "spc2-traj.tng",
+#endif
+ "spc2-traj.xtc",
+ "spc2-traj.gro",
+ "spc2-traj.pdb",
+ "spc2-traj.g96"
+};
+// .g87 and .xyz file reading has been broken (and awkwardly
+// interactive) since at least v4.5 proposed on gmx-developers for
+// removing that support, so not testing it
+
+#ifdef __INTEL_COMPILER
+#pragma warning( disable : 177 )
+#endif
+
+INSTANTIATE_TEST_CASE_P(NoFatalErrorWhenWritingFrom,
+ GmxTraj,
+ ::testing::ValuesIn(gmx::ArrayRef<const char*>(trajectoryFileNames)));
+
+INSTANTIATE_TEST_CASE_P(NoFatalErrorWhenWritingFrom,
+ TrjconvWithIndexGroupSubset,
+ ::testing::ValuesIn(gmx::ArrayRef<const char*>(trajectoryFileNames)));
+
} // namespace
--- /dev/null
+[ System ]
+ 1 2 3 4 5 6
+[ FirstWaterMolecule ]
+ 1 2 3
+[ SecondWaterMolecule ]
+ 4 5 6
const char *gtypes[egcNR+1] = {
"T-Coupling", "Energy Mon.", "Acceleration", "Freeze",
- "User1", "User2", "VCM", "XTC", "Or. Res. Fit", "QMMM", NULL
+ "User1", "User2", "VCM", "Compressed X", "Or. Res. Fit", "QMMM", NULL
};
const char *esimtemp_names[esimtempNR+1] = {
}
+void pr_rvecs_of_dim(FILE *fp, int indent, const char *title, rvec vec[], int n, int dim)
+{
+ const char *fshort = "%12.5e";
+ const char *flong = "%15.8e";
+ const char *format;
+ int i, j;
+
+ if (getenv("LONGFORMAT") != NULL)
+ {
+ format = flong;
+ }
+ else
+ {
+ format = fshort;
+ }
+
+ if (available(fp, vec, indent, title))
+ {
+ indent = pr_title_nxn(fp, indent, title, n, dim);
+ for (i = 0; i < n; i++)
+ {
+ (void) pr_indent(fp, indent);
+ (void) fprintf(fp, "%s[%5d]={", title, i);
+ for (j = 0; j < dim; j++)
+ {
+ if (j != 0)
+ {
+ (void) fprintf(fp, ", ");
+ }
+ (void) fprintf(fp, format, vec[i][j]);
+ }
+ (void) fprintf(fp, "}\n");
+ }
+ }
+}
+
void pr_reals(FILE *fp, int indent, const char *title, real *vec, int n)
{
int i;
}
}
+void pr_reals_of_dim(FILE *fp, int indent, const char *title, real *vec, int n, int dim)
+{
+ int i, j;
+ const char *fshort = "%12.5e";
+ const char *flong = "%15.8e";
+ const char *format;
+
+ if (getenv("LONGFORMAT") != NULL)
+ {
+ format = flong;
+ }
+ else
+ {
+ format = fshort;
+ }
+
+ if (available(fp, vec, indent, title))
+ {
+ indent = pr_title_nxn(fp, indent, title, n, dim);
+ for (i = 0; i < n; i++)
+ {
+ (void) pr_indent(fp, indent);
+ (void) fprintf(fp, "%s[%5d]={", title, i);
+ for (j = 0; j < dim; j++)
+ {
+ if (j != 0)
+ {
+ (void) fprintf(fp, ", ");
+ }
+ (void) fprintf(fp, format, vec[i * dim + j]);
+ }
+ (void) fprintf(fp, "}\n");
+ }
+ }
+}
+
static void pr_int(FILE *fp, int indent, const char *title, int i)
{
pr_indent(fp, indent);
PI("nstfout", ir->nstfout);
PI("nstcalcenergy", ir->nstcalcenergy);
PI("nstenergy", ir->nstenergy);
- PI("nstxtcout", ir->nstxtcout);
+ PI("nstxout_compressed", ir->nstxout_compressed);
PR("init-t", ir->init_t);
PR("delta-t", ir->delta_t);
- PR("xtcprec", ir->xtcprec);
+ PR("x_compression_precision", ir->x_compression_precision);
PR("fourierspacing", ir->fourier_spacing);
PI("nkx", ir->nkx);
PI("nky", ir->nky);
nstx = div_nsteps(nsteps, ir->nstxout);
nstv = div_nsteps(nsteps, ir->nstvout);
nstf = div_nsteps(nsteps, ir->nstfout);
- nstxtc = div_nsteps(nsteps, ir->nstxtcout);
- if (ir->nstxtcout > 0)
+ nstxtc = div_nsteps(nsteps, ir->nstxout_compressed);
+ if (ir->nstxout_compressed > 0)
{
for (i = 0; i < natoms; i++)
{
- if (groups->grpnr[egcXTC] == NULL || groups->grpnr[egcXTC][i] == 0)
+ if (groups->grpnr[egcCompressedX] == NULL || groups->grpnr[egcCompressedX][i] == 0)
{
nxtcatoms++;
}
{
char tcgrps[STRLEN], tau_t[STRLEN], ref_t[STRLEN],
acc[STRLEN], accgrps[STRLEN], freeze[STRLEN], frdim[STRLEN],
- energy[STRLEN], user1[STRLEN], user2[STRLEN], vcm[STRLEN], xtc_grps[STRLEN],
+ energy[STRLEN], user1[STRLEN], user2[STRLEN], vcm[STRLEN], x_compressed_groups[STRLEN],
couple_moltype[STRLEN], orirefitgrp[STRLEN], egptable[STRLEN], egpexcl[STRLEN],
wall_atomtype[STRLEN], wall_density[STRLEN], deform[STRLEN], QMMM[STRLEN];
char fep_lambda[efptNR][STRLEN];
REPL_TYPE("unconstrained-start", "continuation");
REPL_TYPE("foreign-lambda", "fep-lambdas");
REPL_TYPE("verlet-buffer-drift", "verlet-buffer-tolerance");
+ REPL_TYPE("nstxtcout", "nstxout-compressed");
+ REPL_TYPE("xtc-grps", "compressed-x-grps");
+ REPL_TYPE("xtc-precision", "compressed-x-precision");
CCTYPE ("VARIOUS PREPROCESSING OPTIONS");
CTYPE ("Preprocessor information: use cpp syntax.");
ITYPE ("nstcalcenergy", ir->nstcalcenergy, 100);
ITYPE ("nstenergy", ir->nstenergy, 1000);
CTYPE ("Output frequency and precision for .xtc file");
- ITYPE ("nstxtcout", ir->nstxtcout, 0);
- RTYPE ("xtc-precision", ir->xtcprec, 1000.0);
- CTYPE ("This selects the subset of atoms for the .xtc file. You can");
- CTYPE ("select multiple groups. By default all atoms will be written.");
- STYPE ("xtc-grps", is->xtc_grps, NULL);
+ ITYPE ("nstxout-compressed", ir->nstxout_compressed, 0);
+ RTYPE ("compressed-x-precision", ir->x_compression_precision, 1000.0);
+ CTYPE ("This selects the subset of atoms for the compressed");
+ CTYPE ("trajectory file. You can select multiple groups. By");
+ CTYPE ("default, all atoms will be written.");
+ STYPE ("compressed-x-grps", is->x_compressed_groups, NULL);
CTYPE ("Selection of energy groups");
STYPE ("energygrps", is->energy, NULL);
nuser = str_nelem(is->user2, MAXPTR, ptr1);
do_numbering(natoms, groups, nuser, ptr1, grps, gnames, egcUser2,
restnm, egrptpALL_GENREST, bVerbose, wi);
- nuser = str_nelem(is->xtc_grps, MAXPTR, ptr1);
- do_numbering(natoms, groups, nuser, ptr1, grps, gnames, egcXTC,
+ nuser = str_nelem(is->x_compressed_groups, MAXPTR, ptr1);
+ do_numbering(natoms, groups, nuser, ptr1, grps, gnames, egcCompressedX,
restnm, egrptpONE, bVerbose, wi);
nofg = str_nelem(is->orirefitgrp, MAXPTR, ptr1);
do_numbering(natoms, groups, nofg, ptr1, grps, gnames, egcORFIT,
#include <stdio.h>
#include "typedefs.h"
-#include "sim_util.h"
+#include "../math/gmxcomplex.h"
+#include "../timing/walltime_accounting.h"
+#include "../legacyheaders/network.h"
#ifdef __cplusplus
extern "C" {
t_nrnb *nrnb, gmx_mtop_t *mtop,
gmx_update_t *upd,
int nfile, const t_filenm fnm[],
- gmx_mdoutf_t **outf, t_mdebin **mdebin,
+ gmx_mdoutf_t *outf, t_mdebin **mdebin,
tensor force_vir, tensor shake_vir,
rvec mu_tot,
gmx_bool *bSimAnn, t_vcm **vcm, unsigned long Flags);
void pr_ivecs(FILE *fp, int indent, const char *title, ivec vec[], int n, gmx_bool bShowNumbers);
void pr_bvec(FILE *fp, int indent, const char *title, gmx_bool vec[], int n, gmx_bool bShowNnumbers);
void pr_rvec(FILE *fp, int indent, const char *title, real vec[], int n, gmx_bool bShowNumbers);
+void pr_rvecs_of_dim(FILE *fp, int indent, const char *title, rvec vec[], int n, int dim);
void pr_dvec(FILE *fp, int indent, const char *title, double vec[], int n, gmx_bool bShowNumbers);
void pr_rvecs(FILE *fp, int indent, const char *title, rvec vec[], int n);
void pr_rvecs_len(FILE *fp, int indent, const char *title, rvec vec[], int n);
void pr_reals(FILE *fp, int indent, const char *title, real vec[], int n);
void pr_doubles(FILE *fp, int indent, const char *title, double *vec, int n);
+void pr_reals_of_dim(FILE *fp, int indent, const char *title, real *vec, int n, int dim);
void pr_block(FILE *fp, int indent, const char *title, t_block *block, gmx_bool bShowNumbers);
void pr_blocka(FILE *fp, int indent, const char *title, t_blocka *block, gmx_bool bShowNumbers);
void pr_ilist(FILE *fp, int indent, const char *title,
#include "simple.h"
+#include "enums.h"
#include "../sysstuff.h"
#ifdef __cplusplus
} t_adress;
typedef struct {
- int eI; /* Integration method */
- gmx_int64_t nsteps; /* number of steps to be taken */
- int simulation_part; /* Used in checkpointing to separate chunks */
- gmx_int64_t init_step; /* start at a stepcount >0 (used w. tpbconv) */
- int nstcalcenergy; /* frequency of energy calc. and T/P coupl. upd. */
- int cutoff_scheme; /* group or verlet cutoffs */
- int ns_type; /* which ns method should we use? */
- int nstlist; /* number of steps before pairlist is generated */
- int ndelta; /* number of cells per rlong */
- int nstcomm; /* number of steps after which center of mass */
+ int eI; /* Integration method */
+ gmx_int64_t nsteps; /* number of steps to be taken */
+ int simulation_part; /* Used in checkpointing to separate chunks */
+ gmx_int64_t init_step; /* start at a stepcount >0 (used w. tpbconv) */
+ int nstcalcenergy; /* frequency of energy calc. and T/P coupl. upd. */
+ int cutoff_scheme; /* group or verlet cutoffs */
+ int ns_type; /* which ns method should we use? */
+ int nstlist; /* number of steps before pairlist is generated */
+ int ndelta; /* number of cells per rlong */
+ int nstcomm; /* number of steps after which center of mass */
/* motion is removed */
- int comm_mode; /* Center of mass motion removal algorithm */
- int nstcheckpoint; /* checkpointing frequency */
- int nstlog; /* number of steps after which print to logfile */
- int nstxout; /* number of steps after which X is output */
- int nstvout; /* id. for V */
- int nstfout; /* id. for F */
- int nstenergy; /* number of steps after which energies printed */
- int nstxtcout; /* id. for compressed trj (.xtc) */
- double init_t; /* initial time (ps) */
- double delta_t; /* time step (ps) */
- real xtcprec; /* precision of xtc file */
- real fourier_spacing; /* requested fourier_spacing, when nk? not set */
- int nkx, nky, nkz; /* number of k vectors in each spatial dimension*/
- /* for fourier methods for long range electrost.*/
- int pme_order; /* interpolation order for PME */
- real ewald_rtol; /* Real space tolerance for Ewald, determines */
- /* the real/reciprocal space relative weight */
- real ewald_rtol_lj; /* Real space tolerance for LJ-Ewald */
- int ewald_geometry; /* normal/3d ewald, or pseudo-2d LR corrections */
- real epsilon_surface; /* Epsilon for PME dipole correction */
- gmx_bool bOptFFT; /* optimize the fft plan at start */
- int ljpme_combination_rule; /* Type of combination rule in LJ-PME */
- int ePBC; /* Type of periodic boundary conditions */
- int bPeriodicMols; /* Periodic molecules */
- gmx_bool bContinuation; /* Continuation run: starting state is correct */
- int etc; /* temperature coupling */
- int nsttcouple; /* interval in steps for temperature coupling */
- gmx_bool bPrintNHChains; /* whether to print nose-hoover chains */
- int epc; /* pressure coupling */
- int epct; /* pressure coupling type */
- int nstpcouple; /* interval in steps for pressure coupling */
- real tau_p; /* pressure coupling time (ps) */
- tensor ref_p; /* reference pressure (kJ/(mol nm^3)) */
- tensor compress; /* compressability ((mol nm^3)/kJ) */
- int refcoord_scaling; /* How to scale absolute reference coordinates */
- rvec posres_com; /* The COM of the posres atoms */
- rvec posres_comB; /* The B-state COM of the posres atoms */
- int andersen_seed; /* Random seed for Andersen thermostat (obsolete) */
- real verletbuf_tol; /* Per atom pair energy drift tolerance (kJ/mol/ps/atom) for list buffer */
- real rlist; /* short range pairlist cut-off (nm) */
- real rlistlong; /* long range pairlist cut-off (nm) */
- int nstcalclr; /* Frequency of evaluating direct space long-range interactions */
- real rtpi; /* Radius for test particle insertion */
- int coulombtype; /* Type of electrostatics treatment */
- int coulomb_modifier; /* Modify the Coulomb interaction */
- real rcoulomb_switch; /* Coulomb switch range start (nm) */
- real rcoulomb; /* Coulomb cutoff (nm) */
- real epsilon_r; /* relative dielectric constant */
- real epsilon_rf; /* relative dielectric constant of the RF */
- int implicit_solvent; /* No (=explicit water), or GBSA solvent models */
- int gb_algorithm; /* Algorithm to use for calculation Born radii */
- int nstgbradii; /* Frequency of updating Generalized Born radii */
- real rgbradii; /* Cutoff for GB radii calculation */
- real gb_saltconc; /* Salt concentration (M) for GBSA models */
- real gb_epsilon_solvent; /* dielectric coeff. of implicit solvent */
- real gb_obc_alpha; /* 1st scaling factor for Bashford-Case GB */
- real gb_obc_beta; /* 2nd scaling factor for Bashford-Case GB */
- real gb_obc_gamma; /* 3rd scaling factor for Bashford-Case GB */
- real gb_dielectric_offset; /* Dielectric offset for Still/HCT/OBC */
- int sa_algorithm; /* Algorithm for SA part of GBSA */
- real sa_surface_tension; /* Energy factor for SA part of GBSA */
- int vdwtype; /* Type of Van der Waals treatment */
- int vdw_modifier; /* Modify the VdW interaction */
- real rvdw_switch; /* Van der Waals switch range start (nm) */
- real rvdw; /* Van der Waals cutoff (nm) */
- int eDispCorr; /* Perform Long range dispersion corrections */
- real tabext; /* Extension of the table beyond the cut-off, *
- * as well as the table length for 1-4 interac. */
- real shake_tol; /* tolerance for shake */
- int efep; /* free energy calculations */
- t_lambda *fepvals; /* Data for the FEP state */
- gmx_bool bSimTemp; /* Whether to do simulated tempering */
- t_simtemp *simtempvals; /* Variables for simulated tempering */
- gmx_bool bExpanded; /* Whether expanded ensembles are used */
- t_expanded *expandedvals; /* Expanded ensemble parameters */
- int eDisre; /* Type of distance restraining */
- real dr_fc; /* force constant for ta_disre */
- int eDisreWeighting; /* type of weighting of pairs in one restraints */
- gmx_bool bDisreMixed; /* Use comb of time averaged and instan. viol's */
- int nstdisreout; /* frequency of writing pair distances to enx */
- real dr_tau; /* time constant for memory function in disres */
- real orires_fc; /* force constant for orientational restraints */
- real orires_tau; /* time constant for memory function in orires */
- int nstorireout; /* frequency of writing tr(SD) to enx */
- real dihre_fc; /* force constant for dihedral restraints (obsolete) */
- real em_stepsize; /* The stepsize for updating */
- real em_tol; /* The tolerance */
- int niter; /* Number of iterations for convergence of */
- /* steepest descent in relax_shells */
- real fc_stepsize; /* Stepsize for directional minimization */
- /* in relax_shells */
- int nstcgsteep; /* number of steps after which a steepest */
- /* descents step is done while doing cg */
- int nbfgscorr; /* Number of corrections to the hessian to keep */
- int eConstrAlg; /* Type of constraint algorithm */
- int nProjOrder; /* Order of the LINCS Projection Algorithm */
- real LincsWarnAngle; /* If bond rotates more than %g degrees, warn */
- int nLincsIter; /* Number of iterations in the final Lincs step */
- gmx_bool bShakeSOR; /* Use successive overrelaxation for shake */
- real bd_fric; /* Friction coefficient for BD (amu/ps) */
- int ld_seed; /* Random seed for SD and BD */
- int nwall; /* The number of walls */
- int wall_type; /* The type of walls */
- real wall_r_linpot; /* The potentail is linear for r<=wall_r_linpot */
- int wall_atomtype[2]; /* The atom type for walls */
- real wall_density[2]; /* Number density for walls */
- real wall_ewald_zfac; /* Scaling factor for the box for Ewald */
- int ePull; /* Type of pulling: no, umbrella or constraint */
- t_pull *pull; /* The data for center of mass pulling */
- gmx_bool bRot; /* Calculate enforced rotation potential(s)? */
- t_rot *rot; /* The data for enforced rotation potentials */
- real cos_accel; /* Acceleration for viscosity calculation */
- tensor deform; /* Triclinic deformation velocities (nm/ps) */
- int userint1; /* User determined parameters */
+ int comm_mode; /* Center of mass motion removal algorithm */
+ int nstcheckpoint; /* checkpointing frequency */
+ int nstlog; /* number of steps after which print to logfile */
+ int nstxout; /* number of steps after which X is output */
+ int nstvout; /* id. for V */
+ int nstfout; /* id. for F */
+ int nstenergy; /* number of steps after which energies printed */
+ int nstxout_compressed; /* id. for compressed trj (.xtc,.tng) */
+ double init_t; /* initial time (ps) */
+ double delta_t; /* time step (ps) */
+ real x_compression_precision; /* precision of x in compressed trajectory file */
+ real fourier_spacing; /* requested fourier_spacing, when nk? not set */
+ int nkx, nky, nkz; /* number of k vectors in each spatial dimension*/
+ /* for fourier methods for long range electrost.*/
+ int pme_order; /* interpolation order for PME */
+ real ewald_rtol; /* Real space tolerance for Ewald, determines */
+ /* the real/reciprocal space relative weight */
+ real ewald_rtol_lj; /* Real space tolerance for LJ-Ewald */
+ int ewald_geometry; /* normal/3d ewald, or pseudo-2d LR corrections */
+ real epsilon_surface; /* Epsilon for PME dipole correction */
+ gmx_bool bOptFFT; /* optimize the fft plan at start */
+ int ljpme_combination_rule; /* Type of combination rule in LJ-PME */
+ int ePBC; /* Type of periodic boundary conditions */
+ int bPeriodicMols; /* Periodic molecules */
+ gmx_bool bContinuation; /* Continuation run: starting state is correct */
+ int etc; /* temperature coupling */
+ int nsttcouple; /* interval in steps for temperature coupling */
+ gmx_bool bPrintNHChains; /* whether to print nose-hoover chains */
+ int epc; /* pressure coupling */
+ int epct; /* pressure coupling type */
+ int nstpcouple; /* interval in steps for pressure coupling */
+ real tau_p; /* pressure coupling time (ps) */
+ tensor ref_p; /* reference pressure (kJ/(mol nm^3)) */
+ tensor compress; /* compressability ((mol nm^3)/kJ) */
+ int refcoord_scaling; /* How to scale absolute reference coordinates */
+ rvec posres_com; /* The COM of the posres atoms */
+ rvec posres_comB; /* The B-state COM of the posres atoms */
+ int andersen_seed; /* Random seed for Andersen thermostat (obsolete) */
+ real verletbuf_tol; /* Per atom pair energy drift tolerance (kJ/mol/ps/atom) for list buffer */
+ real rlist; /* short range pairlist cut-off (nm) */
+ real rlistlong; /* long range pairlist cut-off (nm) */
+ int nstcalclr; /* Frequency of evaluating direct space long-range interactions */
+ real rtpi; /* Radius for test particle insertion */
+ int coulombtype; /* Type of electrostatics treatment */
+ int coulomb_modifier; /* Modify the Coulomb interaction */
+ real rcoulomb_switch; /* Coulomb switch range start (nm) */
+ real rcoulomb; /* Coulomb cutoff (nm) */
+ real epsilon_r; /* relative dielectric constant */
+ real epsilon_rf; /* relative dielectric constant of the RF */
+ int implicit_solvent; /* No (=explicit water), or GBSA solvent models */
+ int gb_algorithm; /* Algorithm to use for calculation Born radii */
+ int nstgbradii; /* Frequency of updating Generalized Born radii */
+ real rgbradii; /* Cutoff for GB radii calculation */
+ real gb_saltconc; /* Salt concentration (M) for GBSA models */
+ real gb_epsilon_solvent; /* dielectric coeff. of implicit solvent */
+ real gb_obc_alpha; /* 1st scaling factor for Bashford-Case GB */
+ real gb_obc_beta; /* 2nd scaling factor for Bashford-Case GB */
+ real gb_obc_gamma; /* 3rd scaling factor for Bashford-Case GB */
+ real gb_dielectric_offset; /* Dielectric offset for Still/HCT/OBC */
+ int sa_algorithm; /* Algorithm for SA part of GBSA */
+ real sa_surface_tension; /* Energy factor for SA part of GBSA */
+ int vdwtype; /* Type of Van der Waals treatment */
+ int vdw_modifier; /* Modify the VdW interaction */
+ real rvdw_switch; /* Van der Waals switch range start (nm) */
+ real rvdw; /* Van der Waals cutoff (nm) */
+ int eDispCorr; /* Perform Long range dispersion corrections */
+ real tabext; /* Extension of the table beyond the cut-off, *
+ * as well as the table length for 1-4 interac. */
+ real shake_tol; /* tolerance for shake */
+ int efep; /* free energy calculations */
+ t_lambda *fepvals; /* Data for the FEP state */
+ gmx_bool bSimTemp; /* Whether to do simulated tempering */
+ t_simtemp *simtempvals; /* Variables for simulated tempering */
+ gmx_bool bExpanded; /* Whether expanded ensembles are used */
+ t_expanded *expandedvals; /* Expanded ensemble parameters */
+ int eDisre; /* Type of distance restraining */
+ real dr_fc; /* force constant for ta_disre */
+ int eDisreWeighting; /* type of weighting of pairs in one restraints */
+ gmx_bool bDisreMixed; /* Use comb of time averaged and instan. viol's */
+ int nstdisreout; /* frequency of writing pair distances to enx */
+ real dr_tau; /* time constant for memory function in disres */
+ real orires_fc; /* force constant for orientational restraints */
+ real orires_tau; /* time constant for memory function in orires */
+ int nstorireout; /* frequency of writing tr(SD) to enx */
+ real dihre_fc; /* force constant for dihedral restraints (obsolete) */
+ real em_stepsize; /* The stepsize for updating */
+ real em_tol; /* The tolerance */
+ int niter; /* Number of iterations for convergence of */
+ /* steepest descent in relax_shells */
+ real fc_stepsize; /* Stepsize for directional minimization */
+ /* in relax_shells */
+ int nstcgsteep; /* number of steps after which a steepest */
+ /* descents step is done while doing cg */
+ int nbfgscorr; /* Number of corrections to the hessian to keep */
+ int eConstrAlg; /* Type of constraint algorithm */
+ int nProjOrder; /* Order of the LINCS Projection Algorithm */
+ real LincsWarnAngle; /* If bond rotates more than %g degrees, warn */
+ int nLincsIter; /* Number of iterations in the final Lincs step */
+ gmx_bool bShakeSOR; /* Use successive overrelaxation for shake */
+ real bd_fric; /* Friction coefficient for BD (amu/ps) */
+ int ld_seed; /* Random seed for SD and BD */
+ int nwall; /* The number of walls */
+ int wall_type; /* The type of walls */
+ real wall_r_linpot; /* The potentail is linear for r<=wall_r_linpot */
+ int wall_atomtype[2]; /* The atom type for walls */
+ real wall_density[2]; /* Number density for walls */
+ real wall_ewald_zfac; /* Scaling factor for the box for Ewald */
+ int ePull; /* Type of pulling: no, umbrella or constraint */
+ t_pull *pull; /* The data for center of mass pulling */
+ gmx_bool bRot; /* Calculate enforced rotation potential(s)? */
+ t_rot *rot; /* The data for enforced rotation potentials */
+ real cos_accel; /* Acceleration for viscosity calculation */
+ tensor deform; /* Triclinic deformation velocities (nm/ps) */
+ int userint1; /* User determined parameters */
int userint2;
int userint3;
int userint4;
* To help us fund GROMACS development, we humbly ask that you cite
* the research papers on the package. Check out http://www.gromacs.org.
*/
+#ifndef GMX_LEGACYHEADERS_TOPOLOGY_H
+#define GMX_LEGACYHEADERS_TOPOLOGY_H
#include "atoms.h"
#include "idef.h"
enum {
egcTC, egcENER, egcACC, egcFREEZE,
- egcUser1, egcUser2, egcVCM, egcXTC,
+ egcUser1, egcUser2, egcVCM, egcCompressedX,
egcORFIT, egcQMMM,
egcNR
};
#ifdef __cplusplus
}
#endif
+
+#endif
t_graph **graph, t_mdatoms *mdatoms, gmx_global_stat_t *gstat,
gmx_vsite_t *vsite, gmx_constr_t constr,
int nfile, const t_filenm fnm[],
- gmx_mdoutf_t **outf, t_mdebin **mdebin)
+ gmx_mdoutf_t *outf, t_mdebin **mdebin)
{
int start, homenr, i;
real dvdl_constr;
if (mdebin != NULL)
{
/* Init bin for energy stuff */
- *mdebin = init_mdebin((*outf)->fp_ene, top_global, ir, NULL);
+ *mdebin = init_mdebin(mdoutf_get_fp_ene(*outf), top_global, ir, NULL);
}
clear_rvec(mu_tot);
calc_shifts(ems->s.box, fr->shift_vec);
}
-static void finish_em(t_commrec *cr, gmx_mdoutf_t *outf,
+static void finish_em(t_commrec *cr, gmx_mdoutf_t outf,
gmx_walltime_accounting_t walltime_accounting,
gmx_wallcycle_t wcycle)
{
}
static void write_em_traj(FILE *fplog, t_commrec *cr,
- gmx_mdoutf_t *outf,
+ gmx_mdoutf_t outf,
gmx_bool bX, gmx_bool bF, const char *confout,
gmx_mtop_t *top_global,
t_inputrec *ir, gmx_int64_t step,
{
mdof_flags |= MDOF_F;
}
- write_traj(fplog, cr, outf, mdof_flags,
- step, (double)step,
- &state->s, state_global, state->f, f_global);
+ mdoutf_write_to_trajectory_files(fplog, cr, outf, mdof_flags,
+ top_global, step, (double)step,
+ &state->s, state_global, state->f, f_global);
if (confout != NULL && MASTER(cr))
{
gmx_bool do_log = FALSE, do_ene = FALSE, do_x, do_f;
tensor vir, pres;
int number_steps, neval = 0, nstcg = inputrec->nstcgsteep;
- gmx_mdoutf_t *outf;
+ gmx_mdoutf_t outf;
int i, m, gf, step, nminstep;
real terminate = 0;
NULL, NULL, vir, pres, NULL, mu_tot, constr);
print_ebin_header(fplog, step, step, s_min->s.lambda[efptFEP]);
- print_ebin(outf->fp_ene, TRUE, FALSE, FALSE, fplog, step, step, eprNORMAL,
+ print_ebin(mdoutf_get_fp_ene(outf), TRUE, FALSE, FALSE, fplog, step, step, eprNORMAL,
TRUE, mdebin, fcd, &(top_global->groups), &(inputrec->opts));
}
where();
{
print_ebin_header(fplog, step, step, s_min->s.lambda[efptFEP]);
}
- print_ebin(outf->fp_ene, do_ene, FALSE, FALSE,
+ print_ebin(mdoutf_get_fp_ene(outf), do_ene, FALSE, FALSE,
do_log ? fplog : NULL, step, step, eprNORMAL,
TRUE, mdebin, fcd, &(top_global->groups), &(inputrec->opts));
}
if (!do_ene || !do_log)
{
/* Write final energy file entries */
- print_ebin(outf->fp_ene, !do_ene, FALSE, FALSE,
+ print_ebin(mdoutf_get_fp_ene(outf), !do_ene, FALSE, FALSE,
!do_log ? fplog : NULL, step, step, eprNORMAL,
TRUE, mdebin, fcd, &(top_global->groups), &(inputrec->opts));
}
gmx_bool do_log, do_ene, do_x, do_f, foundlower, *frozen;
tensor vir, pres;
int start, end, number_steps;
- gmx_mdoutf_t *outf;
+ gmx_mdoutf_t outf;
int i, k, m, n, nfmax, gf, step;
int mdof_flags;
/* not used */
NULL, NULL, vir, pres, NULL, mu_tot, constr);
print_ebin_header(fplog, step, step, state->lambda[efptFEP]);
- print_ebin(outf->fp_ene, TRUE, FALSE, FALSE, fplog, step, step, eprNORMAL,
+ print_ebin(mdoutf_get_fp_ene(outf), TRUE, FALSE, FALSE, fplog, step, step, eprNORMAL,
TRUE, mdebin, fcd, &(top_global->groups), &(inputrec->opts));
}
where();
mdof_flags |= MDOF_F;
}
- write_traj(fplog, cr, outf, mdof_flags,
- step, (real)step, state, state, f, f);
+ mdoutf_write_to_trajectory_files(fplog, cr, outf, mdof_flags,
+ top_global, step, (real)step, state, state, f, f);
/* Do the linesearching in the direction dx[point][0..(n-1)] */
{
print_ebin_header(fplog, step, step, state->lambda[efptFEP]);
}
- print_ebin(outf->fp_ene, do_ene, FALSE, FALSE,
+ print_ebin(mdoutf_get_fp_ene(outf), do_ene, FALSE, FALSE,
do_log ? fplog : NULL, step, step, eprNORMAL,
TRUE, mdebin, fcd, &(top_global->groups), &(inputrec->opts));
}
}
if (!do_ene || !do_log) /* Write final energy file entries */
{
- print_ebin(outf->fp_ene, !do_ene, FALSE, FALSE,
+ print_ebin(mdoutf_get_fp_ene(outf), !do_ene, FALSE, FALSE,
!do_log ? fplog : NULL, step, step, eprNORMAL,
TRUE, mdebin, fcd, &(top_global->groups), &(inputrec->opts));
}
t_graph *graph;
real stepsize, constepsize;
real ustep, fnormn;
- gmx_mdoutf_t *outf;
+ gmx_mdoutf_t outf;
t_mdebin *mdebin;
gmx_bool bDone, bAbort, do_x, do_f;
tensor vir, pres;
upd_mdebin(mdebin, FALSE, FALSE, (double)count,
mdatoms->tmass, enerd, &s_try->s, inputrec->fepvals, inputrec->expandedvals,
s_try->s.box, NULL, NULL, vir, pres, NULL, mu_tot, constr);
- print_ebin(outf->fp_ene, TRUE,
+ print_ebin(mdoutf_get_fp_ene(outf), TRUE,
do_per_step(steps_accepted, inputrec->nstdisreout),
do_per_step(steps_accepted, inputrec->nstorireout),
fplog, count, count, eprNORMAL, TRUE,
gmx_walltime_accounting_t walltime_accounting)
{
const char *NM = "Normal Mode Analysis";
- gmx_mdoutf_t *outf;
+ gmx_mdoutf_t outf;
int natoms, atom, d;
int nnodes, node;
rvec *f_global;
t_nrnb *nrnb, gmx_mtop_t *mtop,
gmx_update_t *upd,
int nfile, const t_filenm fnm[],
- gmx_mdoutf_t **outf, t_mdebin **mdebin,
+ gmx_mdoutf_t *outf, t_mdebin **mdebin,
tensor force_vir, tensor shake_vir, rvec mu_tot,
gmx_bool *bSimAnn, t_vcm **vcm, unsigned long Flags)
{
{
*outf = init_mdoutf(nfile, fnm, Flags, cr, ir, mtop, oenv);
- *mdebin = init_mdebin((Flags & MD_APPENDFILES) ? NULL : (*outf)->fp_ene,
- mtop, ir, (*outf)->fp_dhdl);
+ *mdebin = init_mdebin((Flags & MD_APPENDFILES) ? NULL : mdoutf_get_fp_ene(*outf),
+ mtop, ir, mdoutf_get_fp_dhdl(*outf));
}
if (ir->bAdress)
cmp_int(fp, "inputrec->nstfout", -1, ir1->nstfout, ir2->nstfout);
cmp_int(fp, "inputrec->nstcalcenergy", -1, ir1->nstcalcenergy, ir2->nstcalcenergy);
cmp_int(fp, "inputrec->nstenergy", -1, ir1->nstenergy, ir2->nstenergy);
- cmp_int(fp, "inputrec->nstxtcout", -1, ir1->nstxtcout, ir2->nstxtcout);
+ cmp_int(fp, "inputrec->nstxout_compressed", -1, ir1->nstxout_compressed, ir2->nstxout_compressed);
cmp_double(fp, "inputrec->init_t", -1, ir1->init_t, ir2->init_t, ftol, abstol);
cmp_double(fp, "inputrec->delta_t", -1, ir1->delta_t, ir2->delta_t, ftol, abstol);
- cmp_real(fp, "inputrec->xtcprec", -1, ir1->xtcprec, ir2->xtcprec, ftol, abstol);
+ cmp_real(fp, "inputrec->x_compression_precision", -1, ir1->x_compression_precision, ir2->x_compression_precision, ftol, abstol);
cmp_real(fp, "inputrec->fourierspacing", -1, ir1->fourier_spacing, ir2->fourier_spacing, ftol, abstol);
cmp_int(fp, "inputrec->nkx", -1, ir1->nkx, ir2->nkx);
cmp_int(fp, "inputrec->nky", -1, ir1->nky, ir2->nky);
#include "gromacs/fileio/tpxio.h"
#include "gromacs/fileio/trnio.h"
#include "gromacs/fileio/futil.h"
+#include "gromacs/fileio/tngio_for_tools.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
#include "gromacs/linearalgebra/mtxio.h"
#include "gromacs/linearalgebra/sparsematrix.h"
close_xtc(xd);
}
+/* Callback used by list_tng_for_gmx_dump. */
+void list_tng_inner(const char *fn,
+ gmx_bool bFirstFrame,
+ gmx_bool bXVG,
+ real *values,
+ gmx_int64_t step,
+ double frame_time,
+ gmx_int64_t n_values_per_frame,
+ gmx_int64_t n_atoms,
+ real prec,
+ gmx_int64_t nframe,
+ char *block_name)
+{
+ char buf[256];
+ int indent = 0;
+
+ if (bXVG)
+ {
+ gmx_int64_t j;
+ int d;
+
+ if (bFirstFrame)
+ {
+ fprintf(stdout, "%g", (real)frame_time);
+ }
+ for (j = 0; j < n_atoms; j++)
+ {
+ for (d = 0; d < DIM; d++)
+ {
+ fprintf(stdout, " %g", values[j * DIM + d]);
+ }
+ }
+ fprintf(stdout, "\n");
+ }
+ else
+ {
+ if (bFirstFrame)
+ {
+ sprintf(buf, "%s frame %" GMX_PRId64, fn, nframe);
+ indent = 0;
+ indent = pr_title(stdout, indent, buf);
+ pr_indent(stdout, indent);
+ fprintf(stdout, "natoms=%10" GMX_PRId64 " step=%10" GMX_PRId64 " time=%12.7e",
+ n_atoms, step, frame_time);
+ if (prec > 0)
+ {
+ fprintf(stdout, " prec=%10g", prec);
+ }
+ fprintf(stdout, "\n");
+ }
+ pr_reals_of_dim(stdout, indent, block_name, values, n_atoms, n_values_per_frame);
+ }
+}
+
void list_trx(const char *fn, gmx_bool bXVG)
{
int ftp;
{
list_trn(fn);
}
+ else if (ftp == efTNG)
+ {
+ list_tng_for_gmx_dump(fn, bXVG);
+ }
else
{
fprintf(stderr, "File %s is of an unsupported type. Try using the command\n 'less %s'\n",
#ifndef GMX_TOOLS_DUMP_H
#define GMX_TOOLS_DUMP_H
+#include "gromacs/legacyheaders/types/simple.h"
+
#ifdef __cplusplus
extern "C" {
#endif
*/
int gmx_dump(int argc, char *argv[]);
+/*! \brief Callback used by list_tng_for_gmx_dump.
+ *
+ * This keeps TNG-related stuff in a TNG-related file, and
+ * dumping-related stuff in the dumping file. */
+void list_tng_inner(const char *fn,
+ gmx_bool bFirstFrame,
+ gmx_bool bXVG,
+ real *values,
+ gmx_int64_t step,
+ double frame_time,
+ gmx_int64_t n_values_per_frame,
+ gmx_int64_t n_atoms,
+ real prec,
+ gmx_int64_t nframe,
+ char *block_name);
+
#ifdef __cplusplus
}
#endif
unsigned long Flags,
gmx_walltime_accounting_t walltime_accounting)
{
- gmx_mdoutf_t *outf;
+ gmx_mdoutf_t outf = NULL;
gmx_int64_t step, step_rel;
double elapsed_time;
double t, t0, lam0[efptNR];
if (bRerunMD)
{
- ir->nstxtcout = 0;
+ ir->nstxout_compressed = 0;
}
groups = &top_global->groups;
nrnb, wcycle, graph, groups,
shellfc, fr, bBornRadii, t, mu_tot,
&bConverged, vsite,
- outf->fp_field);
+ mdoutf_get_fp_field(outf));
tcount += count;
if (bConverged)
state->box, state->x, &state->hist,
f, force_vir, mdatoms, enerd, fcd,
state->lambda, graph,
- fr, vsite, mu_tot, t, outf->fp_field, ed, bBornRadii,
+ fr, vsite, mu_tot, t, mdoutf_get_fp_field(outf), ed, bBornRadii,
(bNS ? GMX_FORCE_NS : 0) | force_flags);
}
* coordinates at time t. We must output all of this before
* the update.
*/
- do_trajectory_writing(fplog, cr, nfile, fnm, step, step_rel, t,
- ir, state, state_global, top_global, fr, upd,
- outf, mdebin, ekind, f, f_global,
- wcycle, mcrng, &nchkpt,
- bCPT, bRerunMD, bLastStep, (Flags & MD_CONFOUT),
- bSumEkinhOld);
+ do_md_trajectory_writing(fplog, cr, nfile, fnm, step, step_rel, t,
+ ir, state, state_global, top_global, fr, upd,
+ outf, mdebin, ekind, f, f_global,
+ wcycle, mcrng, &nchkpt,
+ bCPT, bRerunMD, bLastStep, (Flags & MD_CONFOUT),
+ bSumEkinhOld);
/* kludge -- virial is lost with restart for NPT control. Must restart */
if (bStartingFromCpt && bVV)
do_dr = do_per_step(step, ir->nstdisreout);
do_or = do_per_step(step, ir->nstorireout);
- print_ebin(outf->fp_ene, do_ene, do_dr, do_or, do_log ? fplog : NULL,
+ print_ebin(mdoutf_get_fp_ene(outf), do_ene, do_dr, do_or, do_log ? fplog : NULL,
step, t,
eprNORMAL, bCompact, mdebin, fcd, groups, &(ir->opts));
}
{
if (ir->nstcalcenergy > 0 && !bRerunMD)
{
- print_ebin(outf->fp_ene, FALSE, FALSE, FALSE, fplog, step, t,
+ print_ebin(mdoutf_get_fp_ene(outf), FALSE, FALSE, FALSE, fplog, step, t,
eprAVER, FALSE, mdebin, fcd, groups, &(ir->opts));
}
}
done_mdoutf(outf);
-
debug_gmx();
if (ir->nstlist == -1 && nlh.nns > 0 && fplog)
t_filenm fnm[] = {
{ efTPX, NULL, NULL, ffREAD },
{ efTRN, "-o", NULL, ffWRITE },
- { efXTC, "-x", NULL, ffOPTWR },
+ { efCOMPRESSED, "-x", NULL, ffOPTWR },
{ efCPT, "-cpi", NULL, ffOPTRD },
{ efCPT, "-cpo", NULL, ffOPTWR },
{ efSTO, "-c", "confout", ffWRITE },
${exename}
# files with code for tests
rerun.cpp
- xtc_output.cpp
+ trajectory_writing.cpp
+ compressed_x_output.cpp
# files with code for test fixtures
moduletest.cpp
# pseudo libraries for code for grompp and mdrun
{
//! Test fixture for mdrun -x
-class XtcOutputTest : public gmx::test::MdrunTestFixture,
+class CompressedXOutputTest : public gmx::test::MdrunTestFixture,
public testing::WithParamInterface<const char*>
{
};
/* Among other things, this test ensures mdrun can write a compressed trajectory. */
-TEST_P(XtcOutputTest, ExitsNormally)
+TEST_P(CompressedXOutputTest, ExitsNormally)
{
std::string mdpFile("cutoff-scheme = Group\n"
"nsteps = 1\n"
- "nstxtcout = 1\n");
+ "nstxout-compressed = 1\n");
mdpFile += GetParam();
useStringAsMdpFile(mdpFile.c_str());
useTopGroAndNdxFromDatabase("spc2");
ASSERT_EQ(0, callGrompp());
- xtcFileName = fileManager_.getTemporaryFilePath(".xtc");
+ reducedPrecisionTrajectoryFileName = fileManager_.getTemporaryFilePath(".xtc");
ASSERT_EQ(0, callMdrun());
::gmx::test::CommandLine checkCaller;
checkCaller.append("check");
- checkCaller.addOption("-f", xtcFileName);
+ checkCaller.addOption("-f", reducedPrecisionTrajectoryFileName);
ASSERT_EQ(0, gmx_check(checkCaller.argc(), checkCaller.argv()));
}
#pragma warning( disable : 177 )
#endif
-INSTANTIATE_TEST_CASE_P(WithDifferentMdpOptions, XtcOutputTest,
+INSTANTIATE_TEST_CASE_P(WithDifferentMdpOptions, CompressedXOutputTest,
::testing::Values
- ( // Test writing the whole system to XTC via
+ ( // Test writing the whole system via
// the default behaviour
"",
- // Test writing the whole system to XTC
+ // Test writing the whole system
// explicitly
- "xtc-grps = System\n",
+ "compressed-x-grps = System\n",
- // Test writing part of the system to XTC.
+ // Test writing only part of the system.
// It would be nice to check that this test
// writes 3 atoms and the others write 6, but
- // that's not yet easy
- "xtc-grps = SecondWaterMolecule\n"
+ // that's not yet easy.
+ "compressed-x-grps = SecondWaterMolecule\n"
));
} // namespace
MdrunTestFixture::MdrunTestFixture() :
topFileName(),
groFileName(),
- trrFileName(),
+ fullPrecisionTrajectoryFileName(),
ndxFileName(),
mdpInputFileName(fileManager_.getTemporaryFilePath("input.mdp")),
mdpOutputFileName(fileManager_.getTemporaryFilePath("output.mdp")),
void
MdrunTestFixture::useStringAsMdpFile(const char *mdpString)
+{
+ useStringAsMdpFile(std::string(mdpString));
+}
+
+void
+MdrunTestFixture::useStringAsMdpFile(const std::string &mdpString)
{
gmx::File::writeFileFromString(mdpInputFileName, mdpString);
}
caller.addOption("-g", logFileName);
caller.addOption("-e", edrFileName);
- caller.addOption("-o", trrFileName);
- caller.addOption("-x", xtcFileName);
+ caller.addOption("-o", fullPrecisionTrajectoryFileName);
+ caller.addOption("-x", reducedPrecisionTrajectoryFileName);
+
+ caller.addOption("-deffnm", fileManager_.getTemporaryFilePath("state"));
#ifdef GMX_THREAD_MPI
caller.addOption("-nt", numThreads);
void useEmptyMdpFile();
//! Use a string as -f input to grompp
void useStringAsMdpFile(const char *mdpString);
+ //! Use a string as -f input to grompp
+ void useStringAsMdpFile(const std::string &mdpString);
//! Use a string as -n input to grompp
void useStringAsNdxFile(const char *ndxString);
//! Use a standard .top and .gro file as input to grompp
*/
std::string topFileName;
std::string groFileName;
- std::string trrFileName;
- std::string xtcFileName;
+ std::string fullPrecisionTrajectoryFileName;
+ std::string reducedPrecisionTrajectoryFileName;
std::string ndxFileName;
std::string mdpInputFileName;
std::string mdpOutputFileName;
{
//! Test fixture for mdrun -rerun
-typedef gmx::test::MdrunTestFixture RerunTest;
+class MdrunRerun : public gmx::test::MdrunTestFixture,
+ public ::testing::WithParamInterface<const char *>
+{
+};
/* Among other things, this test ensures mdrun can read a trajectory. */
-TEST_F(RerunTest, RerunExitsNormally)
+TEST_P(MdrunRerun, WithDifferentInputFormats)
{
useEmptyMdpFile();
useTopGroAndNdxFromDatabase("spc2");
EXPECT_EQ(0, callGrompp());
- std::string rerunFileName = fileManager_.getInputFilePath("spc2.trr");
+ std::string rerunFileName = fileManager_.getInputFilePath(GetParam());
::gmx::test::CommandLine rerunCaller;
rerunCaller.append("mdrun");
ASSERT_EQ(0, callMdrun(rerunCaller));
}
+/*! \brief Helper array of input files present in the source repo
+ * database. These all have two identical frames of two SPC water
+ * molecules, which were generated via trjconv from the .gro
+ * version. */
+const char *trajectoryFileNames[] = {
+ "../../../gromacs/gmxana/legacytests/spc2-traj.trr",
+#ifdef GMX_USE_TNG
+ "../../../gromacs/gmxana/legacytests/spc2-traj.tng",
+#endif
+ "../../../gromacs/gmxana/legacytests/spc2-traj.xtc",
+ "../../../gromacs/gmxana/legacytests/spc2-traj.gro",
+ "../../../gromacs/gmxana/legacytests/spc2-traj.pdb",
+ "../../../gromacs/gmxana/legacytests/spc2-traj.g96"
+};
+// TODO later. Find a better way to manage this file database and
+// these string arrays that index it
+
+#ifdef __INTEL_COMPILER
+#pragma warning( disable : 177 )
+#endif
+
+INSTANTIATE_TEST_CASE_P(NoFatalErrorFrom,
+ MdrunRerun,
+ ::testing::ValuesIn(gmx::ArrayRef<const char*>(trajectoryFileNames)));
+
/*! \todo Add other tests for mdrun -rerun, e.g.
*
* - RerunReproducesRunWhenRunOnlyWroteEnergiesOnNeighborSearchSteps
--- /dev/null
+
+ 6
+ 1MeOH Me1 1 1.970 1.460 1.209 -0.8587 -0.1344 -0.0643
+ 1MeOH O2 2 1.978 1.415 1.082 0.0623 -0.1787 0.0036
+ 1MeOH H3 3 1.905 1.460 1.030 -0.5020 -0.9564 0.0997
+ 2SOL OW 4 1.555 1.511 0.703 0.869 1.245 1.665
+ 2SOL HW1 5 1.498 1.495 0.784 0.169 0.275 1.565
+ 2SOL HW2 6 1.496 1.521 0.623 0.269 2.275 1.465
+ 3.01000 3.01000 3.01000
--- /dev/null
+[ System ]
+ 1 2 3 4 5 6
+[ Methanol ]
+ 1 2 3
+[ SOL ]
+ 4 5 6
--- /dev/null
+#include "gromos43a1.ff/forcefield.itp"
+#include "gromos43a1.ff/methanol.itp"
+#include "gromos43a1.ff/spc.itp"
+
+[ system ]
+; Name
+spc-and-methanol
+
+[ molecules ]
+; Compound #mols
+Methanol 1
+SOL 1
--- /dev/null
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2013, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+
+/*! \internal \file
+ * \brief
+ * Tests for the .mdp nst*out functionality
+ *
+ * \author Mark Abraham <mark.j.abraham@gmail.com>
+ * \ingroup module_mdrun
+ */
+#include <gtest/gtest.h>
+#include "gromacs/legacyheaders/string2.h"
+#include "moduletest.h"
+#include "gromacs/options/filenameoption.h"
+#include "gromacs/utility/stringutil.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+namespace
+{
+
+// TODO configure these tests so they test all formats for mdrun trajectory writing
+#ifdef GMX_USE_TNG
+
+//! Test fixture for mdrun trajectory writing
+class TrajectoryWritingTest :
+ public gmx::test::MdrunTestFixture,
+ public ::testing::WithParamInterface<const char *>
+{
+ public:
+ //! The file name of the MDP file
+ std::string theMdpFile;
+
+ //! Execute the trajectory writing test
+ void runTest()
+ {
+ useStringAsMdpFile(theMdpFile);
+ useTopGroAndNdxFromDatabase("spc-and-methanol");
+ EXPECT_EQ(0, callGrompp());
+
+ fullPrecisionTrajectoryFileName = fileManager_.getTemporaryFilePath("spc-and-methanol.tng");
+ reducedPrecisionTrajectoryFileName = fileManager_.getTemporaryFilePath("spc-and-methanol-reduced.tng");
+ ASSERT_EQ(0, callMdrun());
+ // TODO When there is a way to sense something like the
+ // output of gmx check, compare the result with that from
+ // writing .trr and .xtc and assert the behaviour is
+ // correct. Note that TNG will always write the box, even
+ // when constant - this will be a source of
+ // trajectory-file differences.
+ }
+};
+
+//! Helper typedef for naming test cases like sentences
+typedef TrajectoryWritingTest Trajectories;
+
+/* This test ensures mdrun can write various quantities at various
+ frequencies */
+TEST_P(Trajectories, ThatDifferInNstxout)
+{
+ theMdpFile = gmx::formatString("integrator = md\n"
+ "nsteps = 6\n"
+ "nstxout = %s\n"
+ "nstvout = 2\n"
+ "nstfout = 4\n"
+ "nstxout-compressed = 5\n"
+ "tcoupl = v-rescale\n"
+ "tc-grps = System\n"
+ "tau-t = 1\n"
+ "ref-t = 298\n"
+ "compressed-x-grps = Sol\n",
+ GetParam());
+ runTest();
+}
+
+//! Helper typedef for naming test cases like sentences
+typedef TrajectoryWritingTest NptTrajectories;
+
+/* This test ensures mdrun can write trajectories in TNG format from NPT ensembles. */
+TEST_P(NptTrajectories, WithDifferentPcoupl)
+{
+ theMdpFile = gmx::formatString("integrator = md\n"
+ "nsteps = 2\n"
+ "nstxout = 2\n"
+ "nstvout = 1\n"
+ "pcoupl = %s\n"
+ "tau-p = 1\n"
+ "ref-p = 1\n"
+ "compressibility = 4.5e-5\n"
+ "tcoupl = v-rescale\n"
+ "tc-grps = System\n"
+ "tau-t = 1\n"
+ "ref-t = 298\n",
+ GetParam());
+ runTest();
+}
+
+#ifdef __INTEL_COMPILER
+#pragma warning( disable : 177 )
+#endif
+
+// TODO Consider spamming more of the parameter space when we don't
+// have to write .mdp and .tpr files to do it.
+INSTANTIATE_TEST_CASE_P(CanWrite,
+ Trajectories,
+ ::testing::Values("1", "2", "3"));
+
+INSTANTIATE_TEST_CASE_P(CanWrite,
+ NptTrajectories,
+ ::testing::Values("no", "Berendsen", "Parrinello-Rahman"));
+
+#endif
+
+} // namespace