From b6931ebde5ac615890ebc48f86fc6ffa74df9ab9 Mon Sep 17 00:00:00 2001 From: Magnus Lundborg Date: Mon, 16 Jun 2014 17:15:08 +0200 Subject: [PATCH] Bumped the TNG library to the latest version. This is commit f7083045c6f7d23bac47b8302e413becd53fc030 in the TNG repository. Change-Id: I1f5a9edbaf1588b6d1cee6cf86a7ea254aad23a1 --- src/external/tng_io/CMakeLists.txt | 10 +- src/external/tng_io/include/tng_io.h | 9 +- src/external/tng_io/include/tng_io.hpp | 2 - src/external/tng_io/include/tng_io_fwd.h | 2 - src/external/tng_io/include/version.h.in | 7 + .../tng_io/src/compression/CMakeLists.txt | 11 +- src/external/tng_io/src/lib/CMakeLists.txt | 31 +- src/external/tng_io/src/lib/tng_io.c | 6054 +++++++++-------- src/external/tng_io/src/lib/tng_io_fortran.c | 2 - src/external/tng_io/src/tests/md_openmp.c | 2 +- .../tng_io/src/tests/md_openmp_util.c | 2 +- .../tng_io/src/tests/tng_io_read_pos.c | 2 - .../tng_io/src/tests/tng_io_read_pos_util.c | 2 - .../tng_io/src/tests/tng_io_testing.c | 40 +- .../tng_io/src/tests/tng_parallel_read.c | 2 - 15 files changed, 3449 insertions(+), 2729 deletions(-) create mode 100644 src/external/tng_io/include/version.h.in diff --git a/src/external/tng_io/CMakeLists.txt b/src/external/tng_io/CMakeLists.txt index 41eb1551de..06f3f7d53b 100644 --- a/src/external/tng_io/CMakeLists.txt +++ b/src/external/tng_io/CMakeLists.txt @@ -1,7 +1,12 @@ cmake_minimum_required(VERSION 2.8) project(TNG_IO) -set(PROJECT_VERSION "1.0") +set(PROJECT_VERSION "1.5") +set(API_VERSION "5") + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/version.h.in + ${CMAKE_BINARY_DIR}/include/version.h ) +include_directories(${CMAKE_BINARY_DIR}/include) if("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wall") @@ -47,5 +52,8 @@ if(TNG_BUILD_DOCUMENTATION) 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. + + install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Documentation/ + DESTINATION share/tng/doc) endif() diff --git a/src/external/tng_io/include/tng_io.h b/src/external/tng_io/include/tng_io.h index 45cb1d8d2d..5b89cd6357 100644 --- a/src/external/tng_io/include/tng_io.h +++ b/src/external/tng_io/include/tng_io.h @@ -1,9 +1,7 @@ /* This code is part of the tng binary trajectory format. - * - * VERSION 1.5 * * Written by Magnus Lundborg - * Copyright (c) 2012-2013, The GROMACS development team. + * Copyright (c) 2012-2014, The GROMACS development team. * Check out http://www.gromacs.org for more information. * * @@ -343,10 +341,6 @@ typedef unsigned __int64 uint64_t; #endif /* USE_WINDOWS */ #endif /* DECLSPECDLLEXPORT */ - -/** The version of this TNG build */ -#define TNG_VERSION 5 /* TNG_VERSION 4 => Api version 1.5 */ - /** Flag to indicate frame dependent data. */ #define TNG_FRAME_DEPENDENT 1 /** Flag to indicate particle dependent data. */ @@ -419,6 +413,7 @@ typedef enum {TNG_NON_TRAJECTORY_BLOCK, TNG_TRAJECTORY_BLOCK} tng_block_type; #define TNG_TRAJ_B_FACTORS 0x0000000010000006LL #define TNG_TRAJ_ANISOTROPIC_B_FACTORS 0x0000000010000007LL #define TNG_TRAJ_OCCUPANCY 0x0000000010000008LL +#define TNG_TRAJ_GENERAL_COMMENTS 0x0000000010000009LL /** @} */ diff --git a/src/external/tng_io/include/tng_io.hpp b/src/external/tng_io/include/tng_io.hpp index f3bc32abea..12172e5515 100644 --- a/src/external/tng_io/include/tng_io.hpp +++ b/src/external/tng_io/include/tng_io.hpp @@ -1,6 +1,4 @@ /* This code is part of the tng binary trajectory format. - * - * VERSION 1.5 * * Written by Anders Gärdenäs * Copyright (c) 2012-2013, The GROMACS development team. diff --git a/src/external/tng_io/include/tng_io_fwd.h b/src/external/tng_io/include/tng_io_fwd.h index 34ddd87bad..8b63a9a55e 100644 --- a/src/external/tng_io/include/tng_io_fwd.h +++ b/src/external/tng_io/include/tng_io_fwd.h @@ -1,6 +1,4 @@ /* This code is part of the tng binary trajectory format. - * - * VERSION 1.5 * * Written by Magnus Lundborg * Copyright (c) 2012-2013, The GROMACS development team. diff --git a/src/external/tng_io/include/version.h.in b/src/external/tng_io/include/version.h.in new file mode 100644 index 0000000000..840e454fe8 --- /dev/null +++ b/src/external/tng_io/include/version.h.in @@ -0,0 +1,7 @@ +#ifndef VERSION_CONFIG_H +#define VERSION_CONFIG_H + +/* define the API version */ +#define TNG_API_VERSION @API_VERSION@ + +#endif diff --git a/src/external/tng_io/src/compression/CMakeLists.txt b/src/external/tng_io/src/compression/CMakeLists.txt index 267a45a8ac..3efd6bbf4d 100644 --- a/src/external/tng_io/src/compression/CMakeLists.txt +++ b/src/external/tng_io/src/compression/CMakeLists.txt @@ -1,11 +1,12 @@ -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) +set(source_files 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) + +add_library(tng_compress ${source_files}) + +# Append the required library dependencies if(UNIX) -target_link_libraries(tng_compress m) + 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) diff --git a/src/external/tng_io/src/lib/CMakeLists.txt b/src/external/tng_io/src/lib/CMakeLists.txt index c760f57539..81b5843e87 100644 --- a/src/external/tng_io/src/lib/CMakeLists.txt +++ b/src/external/tng_io/src/lib/CMakeLists.txt @@ -1,18 +1,18 @@ +set(source_files tng_io.c md5.c) 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) + list(APPEND source_files tng_io_fortran.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}) +add_library(tng_io ${source_files}) -install(TARGETS tng_io - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib) +# Now add source-file compilation properties to the source-file +# targets if(HAVE_INTTYPES_H) - set_property(TARGET tng_io APPEND PROPERTY COMPILE_DEFINITIONS USE_STD_INTTYPES_H) + set_property(SOURCE tng_io.c APPEND PROPERTY COMPILE_DEFINITIONS USE_STD_INTTYPES_H) +endif() +if(TNG_BUILD_WITH_ZLIB) + set_property(SOURCE tng_io.c APPEND PROPERTY COMPILE_DEFINITIONS USE_ZLIB) endif() # This test is for md5. The TNG library itself determines the actual byte order - @@ -20,12 +20,15 @@ endif() 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) + set_property(SOURCE md5.c APPEND PROPERTY COMPILE_DEFINITIONS TNG_INTEGER_BIG_ENDIAN) endif() +# Append the required library dependencies +target_link_libraries(tng_io tng_compress) if(TNG_BUILD_WITH_ZLIB) - 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) + target_link_libraries(tng_io ${ZLIB_LIBRARIES}) endif() + +install(TARGETS tng_io + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib) diff --git a/src/external/tng_io/src/lib/tng_io.c b/src/external/tng_io/src/lib/tng_io.c index b6c6f22227..252cbb2901 100644 --- a/src/external/tng_io/src/lib/tng_io.c +++ b/src/external/tng_io/src/lib/tng_io.c @@ -1,9 +1,7 @@ /* This code is part of the tng binary trajectory format. - * - * VERSION 1.5 * * Written by Magnus Lundborg - * Copyright (c) 2012-2013, The GROMACS development team. + * Copyright (c) 2012-2014, The GROMACS development team. * Check out http://www.gromacs.org for more information. * * @@ -27,6 +25,7 @@ #include "../../include/tng_io.h" #include "../../include/md5.h" #include "../../include/compression/tng_compress.h" +#include "../include/version.h" struct tng_bond { @@ -190,6 +189,7 @@ struct tng_trajectory_frame_set { }; /* FIXME: Should there be a pointer to a tng_gen_block from each data block? */ +/* FIXME: Make only one data block struct */ 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 */ @@ -248,7 +248,7 @@ struct tng_non_particle_data { /** 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 */ + /** If storing character data store it in a 2-dimensional array */ char ***strings; }; @@ -352,9 +352,6 @@ struct tng_trajectory { * 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; @@ -746,7 +743,7 @@ static tng_function_status tng_block_init(struct tng_gen_block **block_p) /* 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->block_version = TNG_API_VERSION; block->header_contents = 0; block->header_contents_size = 0; block->block_contents = 0; @@ -797,8 +794,9 @@ static tng_function_status tng_block_destroy(struct tng_gen_block **block_p) /** 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. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE(1) if a minor + * error has occured (not able to read the header size, thus skipping + * the block) 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) @@ -821,6 +819,12 @@ static tng_function_status tng_block_header_read return(TNG_CRITICAL); } + if(block->header_contents_size == 0) + { + block->id = -1; + return(TNG_FAILURE); + } + /* If this was the size of the general info block check the endianness */ if(ftell(tng_data->input_file) < 9) { @@ -1030,56 +1034,64 @@ static tng_function_status tng_block_header_read // } */ -static tng_function_status tng_reread_frame_set_at_file_pos - (tng_trajectory_t tng_data, - const int64_t pos) +/** 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) { - tng_gen_block_t block; - tng_function_status stat; - - tng_block_init(&block); + if(block->block_contents) + { + free(block->block_contents); + } - fseek(tng_data->input_file, pos, SEEK_SET); - if(pos > 0) + block->block_contents = malloc(block->block_contents_size); + if(!block->block_contents) { - 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", pos, - __FILE__, __LINE__); - tng_block_destroy(&block); - return(TNG_FAILURE); - } + fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n", + block->block_contents_size, __FILE__, __LINE__); + return(TNG_CRITICAL); + } - if(tng_block_read_next(tng_data, block, - TNG_SKIP_HASH) != TNG_SUCCESS) - { - tng_block_destroy(&block); - return(TNG_CRITICAL); - } + 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_destroy(&block); + 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); } -/** Write the header of a data block, regardless of its type +/** 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 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. + * @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_block_header_write - (tng_trajectory_t tng_data, - tng_gen_block_t block, - const char hash_mode) +static tng_function_status tng_header_pointers_update + (tng_trajectory_t tng_data, const char hash_mode) { - int name_len, offset = 0; - - TNG_ASSERT(block != 0, "TNG library: Trying to write uninitialized block (NULL pointer)."); + 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) { @@ -1088,101 +1100,54 @@ static tng_function_status tng_block_header_write 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; - } + tng_data->input_file = tng_data->output_file; - name_len = tng_min_i((int)strlen(block->name) + 1, TNG_MAX_STR_LEN); + tng_block_init(&block); - if(hash_mode == TNG_USE_HASH) + 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) { - tng_block_md5_hash_generate(block); + 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); } - /* 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; + contents_start_pos = ftell(tng_data->output_file); - if(block->header_contents) - { - free(block->header_contents); - } + fseek(tng_data->output_file, (long)block->block_contents_size - 5 * + sizeof(int64_t), SEEK_CUR); - 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); - } + tng_data->input_file = temp; - /* 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); + pos = tng_data->first_trajectory_frame_set_output_file_pos; - 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->input_endianness_swap_func_64) { - if(tng_data->output_endianness_swap_func_64(tng_data, - (int64_t *)block->header_contents+offset) + 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__); } } - 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(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1) { - 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__); - } + tng_block_destroy(&block); + return(TNG_CRITICAL); } - 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; + pos = tng_data->last_trajectory_frame_set_output_file_pos; - memcpy(block->header_contents+offset, &block->block_version, - sizeof(block->block_version)); - if(tng_data->output_endianness_swap_func_64) + if(tng_data->input_endianness_swap_func_64) { - if(tng_data->output_endianness_swap_func_64(tng_data, - (int64_t *)block->header_contents+offset) + if(tng_data->input_endianness_swap_func_64(tng_data, + &pos) != TNG_SUCCESS) { fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", @@ -1190,70 +1155,1044 @@ static tng_function_status tng_block_header_write } } - if(fwrite(block->header_contents, block->header_contents_size, - 1, tng_data->output_file) != 1) + if(fwrite(&pos, + sizeof(int64_t), 1, tng_data->output_file) != 1) { - fprintf(stderr, "TNG library: Could not write all header data. %s: %d\n", __FILE__, __LINE__); + 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); } -/** Read a general info block. This is the first block of a TNG file. - * Populate the fields in tng_data. +/** 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 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. + * @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_general_info_block_read - (tng_trajectory_t tng_data, tng_gen_block_t block, - const char hash_mode) +static tng_function_status tng_frame_set_pointers_update + (tng_trajectory_t tng_data, 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)"); + tng_gen_block_t block; + tng_trajectory_frame_set_t frame_set; + FILE *temp = tng_data->input_file; + int64_t pos, output_file_pos, contents_start_pos; - if(tng_input_file_init(tng_data) != 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); } - 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; + tng_block_init(&block); + output_file_pos = ftell(tng_data->output_file); - /* 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); - } + tng_data->input_file = tng_data->output_file; - /* FIXME: Does not check if the size of the contents matches the expected - * size or if the contents can be read. */ + frame_set = &tng_data->current_trajectory_frame_set; - if(hash_mode == TNG_USE_HASH) + pos = tng_data->current_trajectory_frame_set_output_file_pos; + + /* Update next frame set */ + if(frame_set->next_frame_set_file_pos > 0) { - 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. " + fseek(tng_data->output_file, (long)frame_set->next_frame_set_file_pos, + SEEK_SET); + + 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 - (5 * + sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR); + + 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->next_frame_set_file_pos, + contents_start_pos); + } + fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET); + } + /* Update previous frame set */ + if(frame_set->prev_frame_set_file_pos > 0) + { + fseek(tng_data->output_file, (long)frame_set->prev_frame_set_file_pos, + SEEK_SET); + + 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); + + 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->prev_frame_set_file_pos, + contents_start_pos); + } + fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET); + } + + /* Update the frame set one medium stride step after */ + if(frame_set->medium_stride_next_frame_set_file_pos > 0) + { + fseek(tng_data->output_file, + (long)frame_set->medium_stride_next_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 - (3 * + sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR); + + 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_next_frame_set_file_pos, + contents_start_pos); + } + } + /* Update the frame set one medium stride step before */ + if(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); + + 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 after */ + if(frame_set->long_stride_next_frame_set_file_pos > 0) + { + fseek(tng_data->output_file, + (long)frame_set->long_stride_next_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 - (1 * + sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR); + + 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_next_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 > 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); + + 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); +} + +static tng_function_status tng_reread_frame_set_at_file_pos + (tng_trajectory_t tng_data, + const int64_t pos) +{ + tng_gen_block_t block; + tng_function_status stat; + + tng_block_init(&block); + + fseek(tng_data->input_file, pos, SEEK_SET); + if(pos > 0) + { + 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", pos, + __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_FAILURE); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + } + + tng_block_destroy(&block); + + return(TNG_SUCCESS); +} + +static tng_function_status tng_file_pos_of_subsequent_trajectory_block_get + (tng_trajectory_t tng_data, + int64_t *pos) +{ + int64_t orig_pos, curr_frame_set_pos; + tng_gen_block_t block; + tng_function_status stat; + tng_trajectory_frame_set_t frame_set = + &tng_data->current_trajectory_frame_set; + + orig_pos = ftell(tng_data->input_file); + curr_frame_set_pos = tng_data->current_trajectory_frame_set_input_file_pos; + + *pos = tng_data->first_trajectory_frame_set_input_file_pos; + + if(*pos <= 0) + { + return(TNG_SUCCESS); + } + + fseek(tng_data->input_file, *pos, SEEK_SET); + + tng_block_init(&block); + /* 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", *pos, + __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_FAILURE); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + /* Read all frame set blocks (not the blocks between them) */ + while(frame_set->next_frame_set_file_pos > 0) + { + fseek(tng_data->input_file, frame_set->next_frame_set_file_pos, SEEK_SET); + 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", *pos, + __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + if(stat != TNG_SUCCESS || block->id != TNG_TRAJECTORY_FRAME_SET) + { + return(TNG_FAILURE); + } + + stat = tng_block_read_next(tng_data, block, TNG_SKIP_HASH); + if(stat != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(stat); + } + /* Update *pos if this is the earliest frame set so far (after orig_pos) */ + if(tng_data->current_trajectory_frame_set_input_file_pos < *pos && + tng_data->current_trajectory_frame_set_input_file_pos > orig_pos) + { + *pos = tng_data->current_trajectory_frame_set_input_file_pos; + } + } + + /* Re-read the frame set that used to be the current one */ + tng_reread_frame_set_at_file_pos(tng_data, curr_frame_set_pos); + + fseek(tng_data->input_file, orig_pos, SEEK_SET); + + tng_block_destroy(&block); + + return(TNG_SUCCESS); +} + +static tng_function_status tng_frame_set_complete_migrate + (tng_trajectory_t tng_data, + int64_t block_start_pos, + int64_t block_len, + int64_t new_pos) +{ + int64_t i; + tng_bool updated = TNG_FALSE; + + char *contents; + + if(tng_input_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + + fseek(tng_data->input_file, block_start_pos, SEEK_SET); + + contents = malloc(block_len); + if(!contents) + { + fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n", + block_len, __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + if(fread(contents, block_len, 1, tng_data->input_file) == 0) + { + fprintf(stderr, "TNG library: Cannot read data from file when migrating data. %s: %d\n", + __FILE__, __LINE__); + free(contents); + return(TNG_CRITICAL); + } + fseek(tng_data->output_file, new_pos, SEEK_SET); + + if(fwrite(contents, block_len, 1, tng_data->output_file) != 1) + { + fprintf(stderr, "TNG library: Could not write data to file when migrating data. %s: %d\n", + __FILE__, __LINE__); + free(contents); + return(TNG_CRITICAL); + } + + tng_data->current_trajectory_frame_set_output_file_pos = new_pos; + + tng_frame_set_pointers_update(tng_data, TNG_USE_HASH); + + /* Update the general info block if needed */ + if(block_start_pos == tng_data->first_trajectory_frame_set_output_file_pos) + { + tng_data->first_trajectory_frame_set_output_file_pos = new_pos; + updated = TNG_TRUE; + } + if(block_start_pos == tng_data->last_trajectory_frame_set_output_file_pos) + { + tng_data->last_trajectory_frame_set_output_file_pos = new_pos; + updated = TNG_TRUE; + } + if(updated) + { + tng_header_pointers_update(tng_data, TNG_USE_HASH); + } + + /* Fill the block with NULL to avoid confusion. */ + for(i = 0; i < block_len; i++) + { + contents[i] = '\0'; + } + fseek(tng_data->output_file, block_start_pos, SEEK_SET); + + /* FIXME: casting block_len to size_t is dangerous */ + fwrite(contents, 1, block_len, tng_data->output_file); + + free(contents); + + return(TNG_SUCCESS); +} + +static tng_function_status tng_length_of_current_frame_set_contents_get + (tng_trajectory_t tng_data, + int64_t *len) +{ + int64_t orig_pos, pos, curr_frame_set_pos; + tng_gen_block_t block; + tng_function_status stat; + + orig_pos = ftell(tng_data->input_file); + curr_frame_set_pos = pos = tng_data->current_trajectory_frame_set_input_file_pos; + + *len = 0; + + fseek(tng_data->input_file, curr_frame_set_pos, SEEK_SET); + + tng_block_init(&block); + /* 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", + curr_frame_set_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_FAILURE); + } + + /* Read the headers of all blocks in the frame set (not the actual contents of them) */ + while(stat == TNG_SUCCESS) + { + fseek(tng_data->input_file, block->block_contents_size, SEEK_CUR); + *len += block->header_contents_size + block->block_contents_size; + pos += block->header_contents_size + block->block_contents_size; + if(pos >= tng_data->input_file_len) + { + break; + } + stat = tng_block_header_read(tng_data, block); + if(block->id == TNG_TRAJECTORY_FRAME_SET) + { + break; + } + } + + /* Re-read the frame set that used to be the current one */ + tng_reread_frame_set_at_file_pos(tng_data, curr_frame_set_pos); + + fseek(tng_data->input_file, orig_pos, SEEK_SET); + + tng_block_destroy(&block); + + return(TNG_SUCCESS); +} + +/** Migrate blocks in the file to make room for new data in a block. This + * is required e.g. when adding data to a block or extending strings in a + * block. + * @param tng_data is a trajectory data container. + * @param start_pos is the position from which to start moving data, usually + * the byte after the end of the block to which data was added. + * @param offset is the number of bytes that were inserted. + * @details Trajectory blocks (frame sets and their related blocks) are moved + * to the end of the file (if needed) in order to make room for non-trajectory + * data. + */ +static tng_function_status tng_migrate_data_in_file + (tng_trajectory_t tng_data, + int64_t start_pos, + int64_t offset) +{ + int64_t traj_start_pos, empty_space, orig_file_pos, frame_set_length; + tng_gen_block_t block; + tng_function_status stat; + FILE *temp; + + if(offset <= 0) + { + return(TNG_SUCCESS); + } + + temp = tng_data->input_file; + + stat = tng_file_pos_of_subsequent_trajectory_block_get(tng_data, &traj_start_pos); + if(stat != TNG_SUCCESS) + { + tng_data->input_file = temp; + return(stat); + } + + tng_data->current_trajectory_frame_set_input_file_pos = traj_start_pos; + + empty_space = traj_start_pos - (start_pos - 1); + + if(empty_space >= offset) + { + return(TNG_SUCCESS); + } + + orig_file_pos = ftell(tng_data->input_file); + tng_block_init(&block); + + while(empty_space < offset) + { + fseek(tng_data->input_file, traj_start_pos, SEEK_SET); + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL) + { + fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n", + __FILE__, __LINE__); + tng_block_destroy(&block); + tng_data->input_file = temp; + return(TNG_CRITICAL); + } + if(stat != TNG_SUCCESS || block->id != TNG_TRAJECTORY_FRAME_SET) + { + tng_data->input_file = temp; + tng_block_destroy(&block); + return(TNG_FAILURE); + } + stat = tng_length_of_current_frame_set_contents_get(tng_data, &frame_set_length); + if(stat != TNG_SUCCESS) + { + tng_data->input_file = temp; + tng_block_destroy(&block); + return(stat); + } + stat = tng_frame_set_complete_migrate(tng_data, traj_start_pos, + frame_set_length, tng_data->input_file_len); + if(stat != TNG_SUCCESS) + { + tng_data->input_file = temp; + tng_block_destroy(&block); + return(stat); + } + + empty_space += frame_set_length; + } + fseek(tng_data->input_file, orig_file_pos, SEEK_SET); + tng_block_destroy(&block); + + return(TNG_SUCCESS); +} + +static tng_function_status tng_block_header_len_calculate + (const tng_trajectory_t tng_data, + tng_gen_block_t block, + int64_t *len) +{ + int name_len; + (void)tng_data; + + /* If the string is unallocated allocate memory for just string + * termination */ + 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); + + /* Calculate the size of the header to write */ + *len = sizeof(block->header_contents_size) + + sizeof(block->block_contents_size) + + sizeof(block->id) + + sizeof(block->block_version) + + TNG_MD5_HASH_LEN + + name_len; + + 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(tng_block_header_len_calculate(tng_data, block, &block->header_contents_size) != + TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot calculate length of block header. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + if(hash_mode == TNG_USE_HASH) + { + tng_block_md5_hash_generate(block); + } + + 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); + } + + name_len = tng_min_i((int)strlen(block->name) + 1, TNG_MAX_STR_LEN); + + /* 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); +} + +static tng_function_status tng_general_info_block_len_calculate + (tng_trajectory_t tng_data, + int64_t *len) +{ + 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; + + /* 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; + } + + 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); + + *len = 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; + + 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); */ @@ -1502,131 +2441,29 @@ static tng_function_status tng_general_info_block_read /** 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) + * 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) { - 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; + return(TNG_CRITICAL); } + fseek(tng_data->output_file, 0, SEEK_SET); + tng_block_init(&block); name_len = (int)strlen("GENERAL INFO"); @@ -1643,6 +2480,15 @@ static tng_function_status tng_general_info_block_write strcpy(block->name, "GENERAL INFO"); block->id = TNG_GENERAL_INFO; + if(tng_general_info_block_len_calculate(tng_data, &block->block_contents_size) != + TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot calculate length of general info block. %s: %d\n", + __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + 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, @@ -1662,24 +2508,6 @@ static tng_function_status tng_general_info_block_write 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); @@ -1758,8 +2586,8 @@ static tng_function_status tng_general_info_block_write 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)); + &tng_data->first_trajectory_frame_set_output_file_pos, + sizeof(tng_data->first_trajectory_frame_set_output_file_pos)); if(tng_data->output_endianness_swap_func_64) { if(tng_data->output_endianness_swap_func_64(tng_data, @@ -1770,11 +2598,11 @@ static tng_function_status tng_general_info_block_write __FILE__, __LINE__); } } - offset += sizeof(tng_data->first_trajectory_frame_set_input_file_pos); + offset += sizeof(tng_data->first_trajectory_frame_set_output_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)); + &tng_data->last_trajectory_frame_set_output_file_pos, + sizeof(tng_data->last_trajectory_frame_set_output_file_pos)); if(tng_data->output_endianness_swap_func_64) { if(tng_data->output_endianness_swap_func_64(tng_data, @@ -1785,7 +2613,7 @@ static tng_function_status tng_general_info_block_write __FILE__, __LINE__); } } - offset += sizeof(tng_data->last_trajectory_frame_set_input_file_pos); + offset += sizeof(tng_data->last_trajectory_frame_set_output_file_pos); memcpy(block->block_contents+offset, &tng_data->medium_stride_length, sizeof(tng_data->medium_stride_length)); @@ -2145,6 +2973,136 @@ static tng_function_status tng_atom_data_write(tng_trajectory_t tng_data, return(TNG_SUCCESS); } +static tng_function_status tng_molecules_block_len_calculate + (const tng_trajectory_t tng_data, + int64_t *len) +{ + int64_t i, j; + tng_molecule_t molecule; + tng_chain_t chain; + tng_residue_t residue; + tng_atom_t atom; + tng_bond_t bond; + + *len = 0; + + 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 = 0; 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 = 0; 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 = 0; 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 = 0; j < molecule->n_bonds; j++) + { + *len += sizeof(bond->from_atom_id) + sizeof(bond->to_atom_id); + } + } + *len += 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; + + if(!tng_data->var_num_atoms_flag) + { + *len += tng_data->n_molecules * sizeof(int64_t); + } + + 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. @@ -2210,7 +3168,7 @@ static tng_function_status tng_molecules_block_read if(tng_data->molecules) { - for(i=tng_data->n_molecules; i--;) + for(i=0; in_molecules; i++) { tng_molecule_destroy(tng_data, &tng_data->molecules[i]); } @@ -2438,7 +3396,7 @@ static tng_function_status tng_molecules_block_read if(molecule->n_chains > 0) { /* Read the chains of the molecule */ - for(j=molecule->n_chains; j--;) + for(j=0; jn_chains; j++) { chain->molecule = molecule; @@ -2448,7 +3406,7 @@ static tng_function_status tng_molecules_block_read residue = chain->residues; /* Read the residues of the chain */ - for(k=chain->n_residues; k--;) + for(k=0; kn_residues; k++) { residue->chain = chain; @@ -2456,7 +3414,7 @@ static tng_function_status tng_molecules_block_read residue->atoms_offset = atom - molecule->atoms; /* Read the atoms of the residue */ - for(l=residue->n_atoms; l--;) + for(l=0; ln_atoms; l++) { atom->residue = residue; @@ -2473,7 +3431,7 @@ static tng_function_status tng_molecules_block_read { if(molecule->n_residues > 0) { - for(k=molecule->n_residues; k--;) + for(k=0; kn_residues; k++) { residue->chain = 0; @@ -2481,7 +3439,7 @@ static tng_function_status tng_molecules_block_read residue->atoms_offset = atom - molecule->atoms; /* Read the atoms of the residue */ - for(l=residue->n_atoms; l--;) + for(l=0; ln_atoms; l++) { atom->residue = residue; @@ -2494,7 +3452,7 @@ static tng_function_status tng_molecules_block_read } else { - for(l=molecule->n_atoms; l--;) + for(l=0; ln_atoms; l++) { atom->residue = 0; @@ -2548,7 +3506,7 @@ static tng_function_status tng_molecules_block_read bond = molecule->bonds; - for(j=molecule->n_bonds; j--;) + for(j=0; jn_bonds; j++) { memcpy(&bond->from_atom_id, block->block_contents+offset, sizeof(bond->from_atom_id)); @@ -2615,108 +3573,6 @@ static tng_function_status tng_molecules_block_write 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"); @@ -2733,19 +3589,13 @@ static tng_function_status tng_molecules_block_write 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) + if(tng_molecules_block_len_calculate(tng_data, &block->block_contents_size) != + TNG_SUCCESS) { - block->block_contents_size += tng_data->n_molecules * sizeof(int64_t); + fprintf(stderr, "TNG library: Cannot calculate length of molecules block. %s: %d\n", + __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); } block->block_contents = malloc(block->block_contents_size); @@ -2869,17 +3719,17 @@ static tng_function_status tng_molecules_block_write if(molecule->n_chains > 0) { chain = molecule->chains; - for(j = molecule->n_chains; j--;) + for(j = 0; j < molecule->n_chains; j++) { tng_chain_data_write(tng_data, block, chain, &offset); residue = chain->residues; - for(k = chain->n_residues; k--;) + for(k = 0; 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--;) + for(l = 0; l < residue->n_atoms; l++) { tng_atom_data_write(tng_data, block, atom, &offset); @@ -2895,12 +3745,12 @@ static tng_function_status tng_molecules_block_write if(molecule->n_residues > 0) { residue = molecule->residues; - for(k = molecule->n_residues; k--;) + for(k = 0; 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--;) + for(l = 0; l < residue->n_atoms; l++) { tng_atom_data_write(tng_data, block, atom, &offset); @@ -2912,7 +3762,7 @@ static tng_function_status tng_molecules_block_write else { atom = molecule->atoms; - for(l = molecule->n_atoms; l--;) + for(l = 0; l < molecule->n_atoms; l++) { tng_atom_data_write(tng_data, block, atom, &offset); @@ -2936,7 +3786,7 @@ static tng_function_status tng_molecules_block_write offset += sizeof(molecule->n_bonds); bond = molecule->bonds; - for(j = molecule->n_bonds; j--;) + for(j = 0; j < molecule->n_bonds; j++) { memcpy(block->block_contents+offset, &bond->from_atom_id, sizeof(bond->from_atom_id)); @@ -2992,6 +3842,20 @@ static tng_function_status tng_molecules_block_write return(TNG_SUCCESS); } +static tng_function_status tng_frame_set_block_len_calculate + (const tng_trajectory_t tng_data, + int64_t *len) +{ + *len = sizeof(int64_t) * 8; + *len += sizeof(double) * 2; + + if(tng_data->var_num_atoms_flag) + { + *len += sizeof(int64_t) * tng_data->n_molecules; + } + 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. @@ -3272,7 +4136,14 @@ static tng_function_status tng_frame_set_block_read tng_data->time_per_frame = -1; } - frame_set->n_written_frames = frame_set->n_frames; + /* If the output file and the input files are the same the number of + * frames in the file are the same number as has just been read. + * This is updated here to later on see if there have been new frames + * added and thereby the frame set needs to be rewritten. */ + if(tng_data->output_file == tng_data->input_file) + { + frame_set->n_written_frames = frame_set->n_frames; + } return(TNG_SUCCESS); } @@ -3320,12 +4191,12 @@ static tng_function_status tng_frame_set_block_write 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) + if(tng_frame_set_block_len_calculate(tng_data, &block->block_contents_size) != + TNG_SUCCESS) { - block->block_contents_size += sizeof(int64_t) * tng_data->n_molecules; + fprintf(stderr, "TNG library: Cannot calculate length of frame set block. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); } if(block->block_contents) @@ -3524,6 +4395,16 @@ static tng_function_status tng_frame_set_block_write return(TNG_SUCCESS); } +static tng_function_status tng_trajectory_mapping_block_len_calculate + (const tng_trajectory_t tng_data, + const int64_t n_particles, + int64_t *len) +{ + (void)tng_data; + *len = sizeof(int64_t) * (2 + n_particles); + + return(TNG_SUCCESS); +} /** Read an atom mappings block (translating between real atom indexes and how * the atom info is written in this frame set). @@ -3725,7 +4606,15 @@ static tng_function_status tng_trajectory_mapping_block_write strcpy(block->name, "PARTICLE MAPPING"); block->id = TNG_PARTICLE_MAPPING; - block->block_contents_size = sizeof(int64_t) * (2 + mapping->n_particles); + if(tng_trajectory_mapping_block_len_calculate(tng_data, + mapping->n_particles, + &block->block_contents_size) != + TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot calculate length of atom mapping block. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } if(block->block_contents) { @@ -4280,624 +5169,273 @@ static tng_function_status tng_gzip_compress(tng_trajectory_t tng_data, 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); - if(!dest) - { - fprintf(stderr, "TNG library: Cannot allocate memory (%lud bytes). %s: %d\n", - uncompressed_len, __FILE__, __LINE__); - return(TNG_CRITICAL); - } - - 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); + 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_data_find - (tng_trajectory_t tng_data, - const int64_t id, - tng_non_particle_data_t *data) +static tng_function_status tng_gzip_uncompress(tng_trajectory_t tng_data, + tng_gen_block_t block, + void *start_pos, + unsigned long uncompressed_len) { - int64_t block_index, i; - tng_trajectory_frame_set_t frame_set = &tng_data-> - current_trajectory_frame_set; - char block_type_flag; + Bytef *dest; + char *temp; + unsigned long stat; + int offset; + (void)tng_data; - 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 + offset = (char *)start_pos - (char *)block->block_contents; + + dest = malloc(uncompressed_len); + if(!dest) { - block_type_flag = TNG_NON_TRAJECTORY_BLOCK; + fprintf(stderr, "TNG library: Cannot allocate memory (%lud bytes). %s: %d\n", + uncompressed_len, __FILE__, __LINE__); + return(TNG_CRITICAL); } - block_index = -1; - if(block_type_flag == TNG_TRAJECTORY_BLOCK) + stat = uncompress(dest, &uncompressed_len, (Bytef *) start_pos, + block->block_contents_size - offset); + + if(stat != Z_OK) { - for(i = frame_set->n_data_blocks; i-- ;) + free(dest); + if(stat == (unsigned long)Z_MEM_ERROR) { - *data = &frame_set->tr_data[i]; - if((*data)->block_id == id) - { - block_index = i; - break; - } + fprintf(stderr, "TNG library: Not enough memory. "); } - if(block_index == -1) + else if(stat == (unsigned long)Z_BUF_ERROR) { - for(i = tng_data->n_data_blocks; i-- ;) - { - *data = &tng_data->non_tr_data[i]; - if((*data)->block_id == id) - { - block_index = i; - break; - } - } + fprintf(stderr, "TNG library: Destination buffer too small. "); } - } - else - { - for(i = tng_data->n_data_blocks; i-- ;) + else if(stat == (unsigned long)Z_DATA_ERROR) { - *data = &tng_data->non_tr_data[i]; - if((*data)->block_id == id) - { - block_index = i; - break; - } + fprintf(stderr, "TNG library: Data corrupt. "); } + fprintf(stderr, "TNG library: Error uncompressing gzipped data. %s: %d\n", __FILE__, + __LINE__); + return(TNG_FAILURE); } - if(block_index == -1) + + + block->block_contents_size = uncompressed_len + offset; + + temp = realloc(block->block_contents, uncompressed_len + offset); + if(!temp) { - return(TNG_FAILURE); + 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 -/** Read the values of a particle data block +/** 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 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. + * @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_particle_data_read +static tng_function_status tng_allocate_particle_data_mem (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, + tng_particle_data_t data, int64_t n_frames, - const int64_t n_values, - const int64_t codec_id, - const double multiplier) + int64_t stride_length, + const int64_t n_particles, + const int64_t n_values_per_frame) { - 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."); + void ***values; + int64_t i, j, k, size, frame_alloc; + (void)tng_data; - switch(datatype) + if(n_particles == 0 || n_values_per_frame == 0) { - 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); + return(TNG_FAILURE); } - /* If the block does not exist, create it */ - if(tng_particle_data_find(tng_data, block->id, &data) != TNG_SUCCESS) + if(data->strings && data->datatype == TNG_CHAR_DATA) { - 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) + for(i = 0; i < data->n_frames; i++) { - fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", - (int)strlen(block->name)+1, __FILE__, __LINE__); - return(TNG_CRITICAL); + for(j = 0; j < n_particles; j++) + { + for(k = 0; 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]); } - 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; + 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; - n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length; - - if(codec_id != TNG_UNCOMPRESSED) + if(data->datatype == TNG_CHAR_DATA) { - data_size = (unsigned long)(n_frames_div * size * n_particles * n_values); - switch(codec_id) + data->strings = malloc(sizeof(char ***) * frame_alloc); + for(i = 0; i < frame_alloc; i++) { - 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) + data->strings[i] = malloc(sizeof(char **) * + n_particles); + if(!data->strings[i]) { - fprintf(stderr, "TNG library: Could not read tng compressed block data. %s: %d\n", - __FILE__, __LINE__); + fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n", + sizeof(union data_values *) * n_particles, + __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) + for(j = 0; j < n_particles; j++) { - fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__, - __LINE__); - return(TNG_CRITICAL); + 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 = 0; k < n_values_per_frame; k++) + { + data->strings[i][j][k] = 0; + } } -/* 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) + else { - if(tng_allocate_particle_data_mem(tng_data, data, n_frames, - stride_length, - tot_n_particles, n_values) != - TNG_SUCCESS) + switch(data->datatype) { - fprintf(stderr, "TNG library: Cannot allocate memory for particle data. %s: %d\n", + 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); +} - data->first_frame_with_data = first_frame_with_data; +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(datatype == TNG_CHAR_DATA) + if(tng_data->current_trajectory_frame_set_input_file_pos > 0 || + tng_data->current_trajectory_frame_set_output_file_pos > 0) { - for(i = 0; i < n_frames_div; i++) + 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 = 0; i < frame_set->n_particle_data_blocks; i++) { - first_dim_values = data->strings[i]; - for(j = num_first_particle; j < num_first_particle + n_particles; - j++) + *data = &frame_set->tr_particle_data[i]; + if((*data)->block_id == id) { - 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; - } + block_index = i; + break; } } } 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) + for(i = 0; i < tng_data->n_particle_data_blocks; i++) { - 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) + *data = &tng_data->non_tr_particle_data[i]; + if((*data)->block_id == id) { - 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__); - } - } + block_index = i; + break; } - break; - case TNG_CHAR_DATA: - break; } } + if(block_index == -1) + { + return(TNG_FAILURE); + } 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 +static tng_function_status tng_data_find (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) + const int64_t id, + tng_non_particle_data_t *data) { - 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; + int64_t block_index, i; + tng_trajectory_frame_set_t frame_set = &tng_data-> + current_trajectory_frame_set; 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) + 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; } @@ -4906,28 +5444,71 @@ static tng_function_status tng_particle_data_block_write block_type_flag = TNG_NON_TRAJECTORY_BLOCK; } - if(tng_output_file_init(tng_data) != TNG_SUCCESS) + block_index = -1; + if(block_type_flag == TNG_TRAJECTORY_BLOCK) { - return(TNG_CRITICAL); + for(i = 0; 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 = 0; 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_type_flag == TNG_TRAJECTORY_BLOCK) + else { - 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) + for(i = 0; i < tng_data->n_data_blocks; i++) { - return(TNG_SUCCESS); + *data = &tng_data->non_tr_data[i]; + if((*data)->block_id == id) + { + block_index = i; + break; + } } - - stride_length = tng_max_i64(1, data->stride_length); } - else + if(block_index == -1) { - data = &tng_data->non_tr_particle_data[block_index]; - stride_length = 1; + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +static tng_function_status tng_data_block_len_calculate + (const tng_trajectory_t tng_data, + const tng_particle_data_t data, + const tng_bool is_particle_data, + const int64_t n_frames, + const int64_t frame_step, + const int64_t stride_length, + const int64_t num_first_particle, + const int64_t n_particles, + const char dependency, + int64_t *data_start_pos, + int64_t *len) +{ + int size; + int64_t i, j, k; + char ***first_dim_values, **second_dim_values; + (void)tng_data; + + if(data == 0) + { + return(TNG_SUCCESS); } switch(data->datatype) @@ -4946,841 +5527,720 @@ static tng_function_status tng_particle_data_block_write 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 + *len = sizeof(char) * 2 + sizeof(data->n_values_per_frame) + + sizeof(data->codec_id); + if(is_particle_data) { - num_first_particle = 0; - if(tng_data->var_num_atoms_flag) - { - n_particles = frame_set->n_particles; - } - else - { - n_particles = tng_data->n_particles; - } + *len += sizeof(num_first_particle) + sizeof(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); + *len += sizeof(data->first_frame_with_data) + + sizeof(data->stride_length); } if(data->codec_id != TNG_UNCOMPRESSED) { - block->block_contents_size += sizeof(data->compression_multiplier); + *len += 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); + *len += sizeof(char); } - data_start_pos = block->block_contents_size; + *data_start_pos = *len; if(data->datatype == TNG_CHAR_DATA) { - for(i = n_frames; i--;) + if(is_particle_data) { - first_dim_values = data->strings[i]; - for(j = num_first_particle; j < num_first_particle + n_particles; - j++) + for(i = 0; i < n_frames; i++) { - second_dim_values = first_dim_values[j]; - for(k = data->n_values_per_frame; k--;) + first_dim_values = data->strings[i]; + for(j = num_first_particle; j < num_first_particle + n_particles; + j++) { - block->block_contents_size += - strlen(second_dim_values[k]) + 1; + second_dim_values = first_dim_values[j]; + for(k = 0; k < data->n_values_per_frame; k++) + { + *len += 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; + for(i = 0; i < n_frames; i++) + { + second_dim_values = ((tng_non_particle_data_t)data)->strings[i]; + for(j = 0; j < data->n_values_per_frame; j++) + { + *len += strlen(second_dim_values[j]) + 1; + } + } } - 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) + else { - 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__); - } + *len += size * frame_step * n_particles * data->n_values_per_frame; } - 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); + return(TNG_SUCCESS); +} - if(data->codec_id != TNG_UNCOMPRESSED) +/** 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) { - 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); + 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(data->n_frames > 0 && stride_length > 1) + /* If the block does not exist, create it */ + if(tng_particle_data_find(tng_data, block->id, &data) != TNG_SUCCESS) { - /* FIXME: first_frame_with_data is not reliably set */ - if(data->first_frame_with_data == 0) + if(tng_data->current_trajectory_frame_set_input_file_pos > 0) { - data->first_frame_with_data = frame_set->first_frame; + block_type_flag = TNG_TRAJECTORY_BLOCK; } - memcpy(block->block_contents+offset, &data->first_frame_with_data, - sizeof(data->first_frame_with_data)); - if(tng_data->output_endianness_swap_func_64) + else { - 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__); - } + block_type_flag = TNG_NON_TRAJECTORY_BLOCK; } - 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_particle_data_block_create(tng_data, block_type_flag) != + TNG_SUCCESS) { - 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__); - } + fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); } - 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) + if(block_type_flag == TNG_TRAJECTORY_BLOCK) { - fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", - __FILE__, __LINE__); + data = &frame_set->tr_particle_data[frame_set-> + n_particle_data_blocks - 1]; } - } - offset += sizeof(num_first_particle); + else + { + data = &tng_data->non_tr_particle_data[tng_data-> + n_particle_data_blocks - 1]; + } + data->block_id = block->id; - 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) + data->block_name = malloc(strlen(block->name) + 1); + if(!data->block_name) { - fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", - __FILE__, __LINE__); + 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; } - offset += sizeof(n_particles); - if(data->datatype == TNG_CHAR_DATA) + if(/*block_type_flag == TNG_TRAJECTORY_BLOCK &&*/ + tng_data->current_trajectory_frame_set_input_file_pos > 0 && + tng_data->var_num_atoms_flag) { - 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; - } - } - } - } + tot_n_particles = frame_set->n_particles; } - else if(data->values) + else { - memcpy(block->block_contents + offset, data->values, - block->block_contents_size - offset); + tot_n_particles = tng_data->n_particles; + } - switch(data->datatype) + 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_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__); - } - } - } - } + case TNG_XTC_COMPRESSION: + fprintf(stderr, "TNG library: XTC compression not implemented yet.\n"); break; - case TNG_INT_DATA: - if(tng_data->input_endianness_swap_func_64) + 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) { - 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__); - } - } + 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; - case TNG_DOUBLE_DATA: - if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION || - data->codec_id == TNG_TNG_COMPRESSION) +#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) { - 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__); - } - } - } + fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__, + __LINE__); + return(TNG_CRITICAL); } - else +/* 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++) { - multiplier = data->compression_multiplier; - if(fabs(multiplier - 1.0) > 0.00001 || - tng_data->input_endianness_swap_func_64) + second_dim_values = first_dim_values[j]; + for(k = 0; k < n_values; k++) { - for(i = offset; i < block->block_contents_size; i+=size) + len = tng_min_i((int)strlen(block->block_contents+*offset) + 1, + TNG_MAX_STR_LEN); + if(second_dim_values[k]) { - *(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__); - } + 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; } } - 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) + 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_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) + case TNG_FLOAT_DATA: + if(tng_data->input_endianness_swap_func_32) { - fprintf(stderr, "TNG library: Could not write tng compressed block data. %s: %d\n", - __FILE__, __LINE__); - if(stat == TNG_CRITICAL) + for(i = 0; i < (block->block_contents_size - *offset); i+=size) { - return(TNG_CRITICAL); + 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__); + } } - /* 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) + case TNG_INT_DATA: + case TNG_DOUBLE_DATA: + if(tng_data->input_endianness_swap_func_64) { - fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__, - __LINE__); - if(stat == TNG_CRITICAL) + for(i = 0; i < (block->block_contents_size - *offset); i+=size) { - return(TNG_CRITICAL); + 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__); + } } - /* 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 + case TNG_CHAR_DATA: + break; } } - - 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 +/** Write a 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) + * @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_data_block_create +static tng_function_status tng_particle_data_block_write (tng_trajectory_t tng_data, - const char block_type_flag) + tng_gen_block_t block, + const int64_t block_index, + const tng_particle_mapping_t mapping, + const char hash_mode) { - tng_trajectory_frame_set_t frame_set = - &tng_data->current_trajectory_frame_set; + 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_non_particle_data_t data; + 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) { - frame_set->n_data_blocks++; - data = realloc(frame_set->tr_data, sizeof(struct tng_non_particle_data) * - frame_set->n_data_blocks); - if(!data) + 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) { - 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); + return(TNG_SUCCESS); } - frame_set->tr_data = data; + + stride_length = tng_max_i64(1, data->stride_length); } 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) + 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 (%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; + fprintf(stderr, "TNG library: Cannot allocate memory (%lud bytes). %s: %d\n", len, + __FILE__, __LINE__); + free(block->name); + block->name = 0; return(TNG_CRITICAL); } - tng_data->non_tr_data = data; + block->name = temp_name; } + strncpy(block->name, data->block_name, len); + block->id = data->block_id; - return(TNG_SUCCESS); -} + /* 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); -/* 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(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; - if(n_values_per_frame == 0) + /* 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) { - return(TNG_FAILURE); + data->compression_multiplier = tng_data->compression_precision; } - - if(data->strings && data->datatype == TNG_CHAR_DATA) + /* 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) { - 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->compression_multiplier = 1.0; } - 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) + if(mapping && mapping->n_particles != 0) { - 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; - } - } + n_particles = mapping->n_particles; + num_first_particle = mapping->num_first_particle; } else { - switch(data->datatype) + num_first_particle = 0; + if(tng_data->var_num_atoms_flag) { - 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_particles = frame_set->n_particles; } - - values = realloc(data->values, - size * frame_alloc * - n_values_per_frame); - if(!values) + else { - 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); + n_particles = tng_data->n_particles; } - data->values = values; } - return(TNG_SUCCESS); -} + if(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0) + { + dependency = TNG_FRAME_DEPENDENT + TNG_PARTICLE_DEPENDENT; + } + else + { + dependency = TNG_PARTICLE_DEPENDENT; + } -/** 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; + if(tng_data_block_len_calculate(tng_data, data, TNG_TRUE, n_frames, + frame_step, stride_length, num_first_particle, + n_particles, dependency, &data_start_pos, + &block->block_contents_size) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot calculate length of particle data block. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } - TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer."); + 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); + } -/* fprintf(stderr, "TNG library: %s\n", block->name);*/ - switch(datatype) + 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) { - 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(stride_length > 1) + { + temp = 1; + } + else + { + temp = 0; + } + memcpy(block->block_contents+offset, &temp, sizeof(char)); + offset += sizeof(char); } - /* If the block does not exist, create it */ - if(tng_data_find(tng_data, block->id, &data) != TNG_SUCCESS) + 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->current_trajectory_frame_set_input_file_pos > 0) + if(tng_data->output_endianness_swap_func_64(tng_data, + (int64_t *)block->header_contents+offset) + != TNG_SUCCESS) { - block_type_flag = TNG_TRAJECTORY_BLOCK; + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); } - else + } + 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) { - block_type_flag = TNG_NON_TRAJECTORY_BLOCK; + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); } + } + offset += sizeof(data->codec_id); - if(tng_data_block_create(tng_data, block_type_flag) != - TNG_SUCCESS) + 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) { - fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n", - __FILE__, __LINE__); - return(TNG_CRITICAL); + 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(block_type_flag == TNG_TRAJECTORY_BLOCK) + 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 = &frame_set->tr_data[frame_set->n_data_blocks - 1]; + data->first_frame_with_data = frame_set->first_frame; } - else + memcpy(block->block_contents+offset, &data->first_frame_with_data, + sizeof(data->first_frame_with_data)); + if(tng_data->output_endianness_swap_func_64) { - data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1]; + 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__); + } } - data->block_id = block->id; + offset += sizeof(data->first_frame_with_data); - data->block_name = malloc(strlen(block->name) + 1); - if(!data->block_name) + memcpy(block->block_contents+offset, &stride_length, + sizeof(stride_length)); + if(tng_data->output_endianness_swap_func_64) { - fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", - (int)strlen(block->name)+1, __FILE__, __LINE__); - return(TNG_CRITICAL); + 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__); + } } - 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; + offset += sizeof(stride_length); } - n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length; - if(codec_id != TNG_UNCOMPRESSED) + memcpy(block->block_contents+offset, &num_first_particle, + sizeof(num_first_particle)); + if(tng_data->output_endianness_swap_func_64) { - switch(codec_id) + if(tng_data->output_endianness_swap_func_64(tng_data, + (int64_t *)block->header_contents+offset) + != TNG_SUCCESS) { -#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 + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); } } + offset += sizeof(num_first_particle); - /* Allocate memory */ - if(!data->values || data->n_frames != n_frames || - data->n_values_per_frame != n_values) + memcpy(block->block_contents+offset, &n_particles, sizeof(n_particles)); + if(tng_data->output_endianness_swap_func_64) { - if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length, - n_values) != - TNG_SUCCESS) + if(tng_data->output_endianness_swap_func_64(tng_data, + (int64_t *)block->header_contents+offset) + != TNG_SUCCESS) { - fprintf(stderr, "TNG library: Cannot allocate memory for data. %s: %d\n", - __FILE__, __LINE__); - return(TNG_CRITICAL); + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); } } + offset += sizeof(n_particles); - data->first_frame_with_data = first_frame_with_data; - - if(datatype == TNG_CHAR_DATA) + if(data->datatype == TNG_CHAR_DATA) { - for(i = 0; i < n_frames_div; i++) + if(data->strings) { - for(j = 0; j < n_values; j++) + for(i = 0; i < frame_step; i++) { - 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]) + first_dim_values = data->strings[i]; + for(j = num_first_particle; j < num_first_particle + n_particles; + j++) { - fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", - len, __FILE__, __LINE__); - return(TNG_CRITICAL); + 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; + } } - strncpy(data->strings[i][j], block->block_contents+*offset, - len); - *offset += len; } } } - else + else if(data->values) { - memcpy(data->values, block->block_contents + *offset, - block->block_contents_size - *offset); - switch(datatype) + memcpy(block->block_contents + offset, data->values, + block->block_contents_size - offset); + + switch(data->datatype) { case TNG_FLOAT_DATA: - if(tng_data->input_endianness_swap_func_32) + if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION || + data->codec_id == TNG_TNG_COMPRESSION) { - for(i = 0; i < (block->block_contents_size - *offset); i+=size) + if(tng_data->input_endianness_swap_func_32) { - if(tng_data->input_endianness_swap_func_32(tng_data, - (int32_t *)((char *)data->values + i)) - != TNG_SUCCESS) + for(i = offset; i < block->block_contents_size; i+=size) { - fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", - __FILE__, __LINE__); + 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: - case TNG_DOUBLE_DATA: if(tng_data->input_endianness_swap_func_64) { - for(i = 0; i < (block->block_contents_size - *offset); i+=size) + for(i = offset; i < block->block_contents_size; i+=size) { if(tng_data->input_endianness_swap_func_64(tng_data, - (int64_t *)((char *)data->values + i)) - != TNG_SUCCESS) + (int64_t *)(block->block_contents + i)) + != TNG_SUCCESS) { fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", __FILE__, __LINE__); @@ -5788,375 +6248,478 @@ static tng_function_status tng_data_read(tng_trajectory_t tng_data, } } 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); } -/** Write a non-particle data block +/* TEST: */ +/** Create 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. + * @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_write(tng_trajectory_t tng_data, - tng_gen_block_t block, - const int64_t block_index, - const char hash_mode) +static tng_function_status tng_data_block_create + (tng_trajectory_t tng_data, + const char block_type_flag) { - 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) + frame_set->n_data_blocks++; + data = realloc(frame_set->tr_data, sizeof(struct tng_non_particle_data) * + frame_set->n_data_blocks); + if(!data) { - return(TNG_SUCCESS); + 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); } - - stride_length = tng_max_i64(1, data->stride_length); + frame_set->tr_data = data; } 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) + 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 (%d bytes). %s: %d\n", len+1, - __FILE__, __LINE__); - free(block->name); - block->name = 0; + 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); } - 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); + tng_data->non_tr_data = data; } - 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; - } + return(TNG_SUCCESS); +} - block->block_contents_size = sizeof(char) * 2 + - sizeof(data->n_values_per_frame) + - sizeof(data->codec_id); +/* 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(stride_length > 1) + if(n_values_per_frame == 0) { - block->block_contents_size += sizeof(data->first_frame_with_data) + - sizeof(data->stride_length); + return(TNG_FAILURE); } - if(data->codec_id != TNG_UNCOMPRESSED) + if(data->strings && data->datatype == TNG_CHAR_DATA) { - block->block_contents_size += sizeof(data->compression_multiplier); + for(i = 0; i < data->n_frames; i++) + { + for(j = 0; 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(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0) + if(data->datatype == TNG_CHAR_DATA) { - dependency = TNG_FRAME_DEPENDENT; + data->strings = malloc(sizeof(char **) * frame_alloc); + for(i = 0; 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 = 0; j < n_values_per_frame; j++) + { + data->strings[i][j] = 0; + } + } } else { - dependency = 0; - } - if(dependency & TNG_FRAME_DEPENDENT) - { - block->block_contents_size += sizeof(char); + 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 - data_start_pos = block->block_contents_size; + 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; - 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; - } + TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer."); - if(block->block_contents) - { - free(block->block_contents); - } - block->block_contents = malloc(block->block_contents_size); - if(!block->block_contents) +/* fprintf(stderr, "TNG library: %s\n", block->name);*/ + + switch(datatype) { - fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n", - block->block_contents_size, __FILE__, __LINE__); - return(TNG_CRITICAL); + 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); } - - 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 the block does not exist, create it */ + if(tng_data_find(tng_data, block->id, &data) != TNG_SUCCESS) { - if(stride_length > 1) + if(tng_data->current_trajectory_frame_set_input_file_pos > 0) { - temp = 1; + block_type_flag = TNG_TRAJECTORY_BLOCK; } else { - temp = 0; + block_type_flag = TNG_NON_TRAJECTORY_BLOCK; } - 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) + if(tng_data_block_create(tng_data, block_type_flag) != + TNG_SUCCESS) { - fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", - __FILE__, __LINE__); + fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); } - } - 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) + if(block_type_flag == TNG_TRAJECTORY_BLOCK) { - fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", - __FILE__, __LINE__); + data = &frame_set->tr_data[frame_set->n_data_blocks - 1]; } - } - 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) + else { - 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__); - } + data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1]; } - offset += sizeof(data->compression_multiplier); - } + data->block_id = block->id; - 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) + data->block_name = malloc(strlen(block->name) + 1); + if(!data->block_name) { - 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__); - } + fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", + (int)strlen(block->name)+1, __FILE__, __LINE__); + return(TNG_CRITICAL); } - offset += sizeof(data->first_frame_with_data); + strcpy(data->block_name, block->name); - memcpy(block->block_contents+offset, &stride_length, - sizeof(data->stride_length)); - if(tng_data->output_endianness_swap_func_64) + 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) { - if(tng_data->output_endianness_swap_func_64(tng_data, - (int64_t *)block->header_contents+offset) - != TNG_SUCCESS) +#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: Cannot swap byte order. %s: %d\n", - __FILE__, __LINE__); + 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 } - offset += sizeof(data->stride_length); } - if(data->datatype == TNG_CHAR_DATA) + /* Allocate memory */ + if(!data->values || data->n_frames != n_frames || + data->n_values_per_frame != n_values) { - if(data->strings) + if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length, + n_values) != + TNG_SUCCESS) { - 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; - } - } + fprintf(stderr, "TNG library: Cannot allocate memory for data. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); } } - else if(data->values) + + data->first_frame_with_data = first_frame_with_data; + + if(datatype == TNG_CHAR_DATA) { - memcpy(block->block_contents + offset, data->values, - block->block_contents_size - offset); - switch(data->datatype) + for(i = 0; i < n_frames_div; i++) { - case TNG_FLOAT_DATA: - if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION || - data->codec_id == TNG_TNG_COMPRESSION) + for(j = 0; j < n_values; j++) { - if(tng_data->input_endianness_swap_func_32) + len = tng_min_i((int)strlen(block->block_contents+*offset) + 1, + TNG_MAX_STR_LEN); + if(data->strings[i][j]) { - 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__); - } - } + free(data->strings[i][j]); } - } - else - { - multiplier = data->compression_multiplier; - if(fabs(multiplier - 1.0) > 0.00001 || - tng_data->input_endianness_swap_func_32) + data->strings[i][j] = malloc(len); + if(!data->strings[i][j]) { - 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__); - } - } + 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; } - break; - case TNG_INT_DATA: - if(tng_data->input_endianness_swap_func_64) + } + } + 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 = offset; i < block->block_contents_size; i+=size) + for(i = 0; i < (block->block_contents_size - *offset); i+=size) { - if(tng_data->input_endianness_swap_func_64(tng_data, - (int64_t *)(block->block_contents + i)) - != TNG_SUCCESS) + 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__); @@ -6164,41 +6727,18 @@ static tng_function_status tng_data_block_write(tng_trajectory_t tng_data, } } break; + case TNG_INT_DATA: 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 + if(tng_data->input_endianness_swap_func_64) { - multiplier = data->compression_multiplier; - if(fabs(multiplier - 1.0) > 0.00001 || - tng_data->input_endianness_swap_func_64) + for(i = 0; i < (block->block_contents_size - *offset); i+=size) { - 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)) + 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__); - } + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); } } } @@ -6207,687 +6747,742 @@ static tng_function_status tng_data_block_write(tng_trajectory_t tng_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, data_start_pos; + int64_t i, j; + int offset = 0, size; + unsigned int len; +#ifdef USE_ZLIB + 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 { - memset(block->block_contents+offset, 0, block->block_contents_size - offset); + block_type_flag = TNG_NON_TRAJECTORY_BLOCK; } - frame_set->n_written_frames += frame_set->n_unwritten_frames; - frame_set->n_unwritten_frames = 0; + if(tng_output_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } - if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0) + if(block_type_flag == TNG_TRAJECTORY_BLOCK) { - switch(data->codec_id) + 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) { -#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 + return(TNG_SUCCESS); } + + stride_length = tng_max_i64(1, data->stride_length); + } + else + { + data = &tng_data->non_tr_data[block_index]; + stride_length = 1; } - if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS) + switch(data->datatype) { - fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n", - tng_data->output_file_path, __FILE__, __LINE__); - return(TNG_CRITICAL); + 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(fwrite(block->block_contents, block->block_contents_size, 1, - tng_data->output_file) != 1) + len = (unsigned int)strlen(data->block_name) + 1; + + if(!block->name || strlen(block->name) < len) { - fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", - __FILE__, __LINE__); - return(TNG_CRITICAL); + 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; - return(TNG_SUCCESS); -} + /* 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); -/** 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_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); - if(block->block_contents) + 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) { - contents = block->block_contents; + 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(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0) + { + dependency = TNG_FRAME_DEPENDENT; } 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__); - } + dependency = 0; + } + + if(tng_data_block_len_calculate(tng_data, (tng_particle_data_t)data, TNG_FALSE, n_frames, + frame_step, stride_length, 0, + 1, dependency, &data_start_pos, + &block->block_contents_size) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot calculate length of non-particle data block. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } - 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); - } + 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(datatype, contents+*offset, - sizeof(*datatype)); - *offset += sizeof(*datatype); - memcpy(dependency, contents+*offset, - sizeof(*dependency)); - *offset += sizeof(*dependency); + memcpy(block->block_contents, &data->datatype, sizeof(char)); + offset += sizeof(char); - if(*dependency & TNG_FRAME_DEPENDENT) + memcpy(block->block_contents+offset, &dependency, sizeof(char)); + offset += sizeof(char); + + if(dependency & TNG_FRAME_DEPENDENT) { - memcpy(sparse_data, contents+*offset, - sizeof(*sparse_data)); - *offset += sizeof(*sparse_data); + if(stride_length > 1) + { + temp = 1; + } + else + { + temp = 0; + } + memcpy(block->block_contents+offset, &temp, sizeof(char)); + offset += sizeof(char); } - memcpy(n_values, contents+*offset, - sizeof(*n_values)); - if(tng_data->input_endianness_swap_func_64) + 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->input_endianness_swap_func_64(tng_data, - n_values) + 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_values); + offset += sizeof(data->n_values_per_frame); - memcpy(codec_id, contents+*offset, - sizeof(*codec_id)); - if(tng_data->input_endianness_swap_func_64) + memcpy(block->block_contents+offset, &data->codec_id, + sizeof(data->codec_id)); + if(tng_data->output_endianness_swap_func_64) { - if(tng_data->input_endianness_swap_func_64(tng_data, - codec_id) + 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(*codec_id); + offset += sizeof(data->codec_id); - if(*codec_id != TNG_UNCOMPRESSED) + if(data->codec_id != TNG_UNCOMPRESSED) { - memcpy(multiplier, contents+*offset, - sizeof(*multiplier)); - if(tng_data->input_endianness_swap_func_64) + memcpy(block->block_contents+offset, &data->compression_multiplier, + sizeof(data->compression_multiplier)); + if(tng_data->output_endianness_swap_func_64) { - if(tng_data->input_endianness_swap_func_64(tng_data, - (int64_t *) multiplier) + 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(*multiplier); - } - else - { - *multiplier = 1; + offset += sizeof(data->compression_multiplier); } - if(*dependency & TNG_FRAME_DEPENDENT) + if(data->n_frames > 0 && stride_length > 1) { - if(*sparse_data) + /* FIXME: first_frame_with_data is not reliably set */ + if(data->first_frame_with_data == 0) { - memcpy(first_frame_with_data, contents+*offset, - sizeof(*first_frame_with_data)); - if(tng_data->input_endianness_swap_func_64) + 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) { - 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__); - } + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); } - *offset += sizeof(*first_frame_with_data); + } + offset += sizeof(data->first_frame_with_data); - memcpy(stride_length, contents+*offset, - sizeof(*stride_length)); - if(tng_data->input_endianness_swap_func_64) + 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) { - 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__); - } + 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; + offset += sizeof(data->stride_length); } - if (*dependency & TNG_PARTICLE_DEPENDENT) + if(data->datatype == TNG_CHAR_DATA) { - memcpy(num_first_particle, contents+*offset, - sizeof(*num_first_particle)); - if(tng_data->input_endianness_swap_func_64) + if(data->strings) { - if(tng_data->input_endianness_swap_func_64(tng_data, - num_first_particle) - != TNG_SUCCESS) + for(i = 0; i < frame_step; i++) { - fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", - __FILE__, __LINE__); + 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; + } } } - *offset += sizeof(*num_first_particle); - - memcpy(block_n_particles, contents+*offset, - sizeof(*block_n_particles)); - if(tng_data->input_endianness_swap_func_64) + } + else if(data->values) + { + memcpy(block->block_contents + offset, data->values, + block->block_contents_size - offset); + switch(data->datatype) { - if(tng_data->input_endianness_swap_func_64(tng_data, - block_n_particles) - != TNG_SUCCESS) + 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 { - fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", - __FILE__, __LINE__); + 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; } - *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) + else { - fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__); - return(TNG_CRITICAL); + memset(block->block_contents+offset, 0, block->block_contents_size - offset); } - /* FIXME: Does not check if the size of the contents matches the expected - * size or if the contents can be read. */ + frame_set->n_written_frames += frame_set->n_unwritten_frames; + frame_set->n_unwritten_frames = 0; - if(hash_mode == TNG_USE_HASH) + if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0) { - tng_md5_hash_match_verify(block, &same_hash); - if(same_hash != TNG_TRUE) + switch(data->codec_id) { - fprintf(stderr, "TNG library: '%s' data block contents corrupt. Hashes do not match. %s: %d\n", - block->name, __FILE__, __LINE__); - /* return(TNG_FAILURE); */ +#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_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); - if(!block->block_contents) + if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS) { - fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n", - block->block_contents_size, __FILE__, __LINE__); + fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n", + tng_data->output_file_path, __FILE__, __LINE__); return(TNG_CRITICAL); } - 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) + if(fwrite(block->block_contents, block->block_contents_size, 1, + tng_data->output_file) != 1) { - fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__); + fprintf(stderr, "TNG library: Could not write all block data. %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 +/** Read the meta information of a data block (particle or non-particle data). * @param tng_data is a trajectory data container. - * @param hash_mode specifies whether to update the block md5 hash when - * updating the pointers. + * @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_header_pointers_update - (tng_trajectory_t tng_data, const char hash_mode) +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) { - tng_gen_block_t block; - FILE *temp = tng_data->input_file; - int64_t output_file_pos, pos, contents_start_pos; + int meta_size; + char *contents; - if(tng_output_file_init(tng_data) != TNG_SUCCESS) + if(block->block_contents) { - fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n", - __FILE__, __LINE__); - return(TNG_CRITICAL); + contents = block->block_contents; } - - 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) + else { - 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); - } + 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__); + } - contents_start_pos = ftell(tng_data->output_file); + 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); + } + } - fseek(tng_data->output_file, (long)block->block_contents_size - 5 * - sizeof(int64_t), SEEK_CUR); + memcpy(datatype, contents+*offset, + sizeof(*datatype)); + *offset += sizeof(*datatype); - tng_data->input_file = temp; + memcpy(dependency, contents+*offset, + sizeof(*dependency)); + *offset += sizeof(*dependency); - pos = tng_data->first_trajectory_frame_set_output_file_pos; + 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, - &pos) + n_values) != TNG_SUCCESS) { fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", __FILE__, __LINE__); } } + *offset += sizeof(*n_values); - 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; - + 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, - &pos) + codec_id) != TNG_SUCCESS) { fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", __FILE__, __LINE__); } } + *offset += sizeof(*codec_id); - 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) + if(*codec_id != TNG_UNCOMPRESSED) { - 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; - + memcpy(multiplier, contents+*offset, + sizeof(*multiplier)); if(tng_data->input_endianness_swap_func_64) { if(tng_data->input_endianness_swap_func_64(tng_data, - &pos) + (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(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1) + if(*dependency & TNG_FRAME_DEPENDENT) + { + if(*sparse_data) { - tng_data->input_file = temp; - tng_block_destroy(&block); - return(TNG_CRITICAL); - } + 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); - if(hash_mode == TNG_USE_HASH) + 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 { - tng_md5_hash_update(tng_data, block, header_start_pos, - contents_start_pos); + *first_frame_with_data = 0; + *stride_length = 1; + *n_frames = tng_data->current_trajectory_frame_set.n_frames; } - 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) + else { - 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; + *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, - &pos) + num_first_particle) != TNG_SUCCESS) { fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", __FILE__, __LINE__); } } + *offset += sizeof(*num_first_particle); - 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) + memcpy(block_n_particles, contents+*offset, + sizeof(*block_n_particles)); + if(tng_data->input_endianness_swap_func_64) { - tng_md5_hash_update(tng_data, block, - frame_set->medium_stride_prev_frame_set_file_pos, - contents_start_pos); + 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); } - /* 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) + if(!block->block_contents) { - fseek(tng_data->output_file, - (long)frame_set->long_stride_prev_frame_set_file_pos, - SEEK_SET); + free(contents); + } + return(TNG_SUCCESS); +} - 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 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; - contents_start_pos = ftell(tng_data->output_file); + if(tng_input_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } - fseek(tng_data->output_file, (long)block->block_contents_size - (2 * - sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR); + if(block->block_contents) + { + free(block->block_contents); + } - pos = tng_data->current_trajectory_frame_set_output_file_pos; + 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); + } - 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__); - } - } + /* 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); + } - if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1) - { - tng_data->input_file = temp; - tng_block_destroy(&block); - 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) + if(hash_mode == TNG_USE_HASH) + { + tng_md5_hash_match_verify(block, &same_hash); + if(same_hash != TNG_TRUE) { - tng_md5_hash_update(tng_data, block, - frame_set->long_stride_prev_frame_set_file_pos, - contents_start_pos); + fprintf(stderr, "TNG library: '%s' data block contents corrupt. Hashes do not match. %s: %d\n", + block->name, __FILE__, __LINE__); + /* return(TNG_FAILURE); */ } } - fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET); - - tng_data->input_file = temp; - - tng_block_destroy(&block); + 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); + } - return(TNG_SUCCESS); + 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)); + } } + /* // ** 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 @@ -7262,29 +7857,19 @@ tng_function_status DECLSPECDLLEXPORT tng_molecule_add const char *name, tng_molecule_t *molecule) { - int64_t id, i; - tng_bool found_id = TNG_TRUE; + int64_t id; 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) + /* Set ID to the ID of the last molecule + 1 */ + if(tng_data->n_molecules) { - 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++; - } + id = tng_data->molecules[tng_data->n_molecules-1].id + 1; + } + else + { + id = 1; } return(tng_molecule_w_id_add(tng_data, name, id, molecule)); @@ -7297,7 +7882,7 @@ tng_function_status DECLSPECDLLEXPORT tng_molecule_w_id_add tng_molecule_t *molecule) { tng_molecule_t new_molecules; - int64_t *new_molecule_cnt_list, i; + int64_t *new_molecule_cnt_list; tng_function_status stat = TNG_SUCCESS; TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); @@ -7343,17 +7928,6 @@ tng_function_status DECLSPECDLLEXPORT tng_molecule_w_id_add /* 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++; @@ -7365,29 +7939,19 @@ tng_function_status DECLSPECDLLEXPORT tng_molecule_existing_add (tng_trajectory_t tng_data, tng_molecule_t *molecule_p) { - tng_bool found_id = TNG_TRUE; + int64_t *new_molecule_cnt_list, id; 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) + /* Set ID to the ID of the last molecule + 1 */ + if(tng_data->n_molecules) { - 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++; - } + id = tng_data->molecules[tng_data->n_molecules-1].id + 1; + } + else + { + id = 1; } new_molecules = realloc(tng_data->molecules, @@ -7506,12 +8070,12 @@ tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_get 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--;) + for(i = 0; i < tng_data->n_molecules; i++) { if(&tng_data->molecules[i] == molecule) { index = i; - i = 0; + break; } } if(index == -1) @@ -7532,12 +8096,12 @@ tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_set TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); - for(i = tng_data->n_molecules; i--;) + for(i = 0; i < tng_data->n_molecules; i++) { if(&tng_data->molecules[i] == molecule) { index = i; - i = 0; + break; } } if(index == -1) @@ -7580,7 +8144,7 @@ tng_function_status DECLSPECDLLEXPORT tng_molecule_find n_molecules = tng_data->n_molecules; - for(i = 0; i < n_molecules; i++) + for(i = n_molecules - 1; i >= 0; i--) { *molecule = &tng_data->molecules[i]; if(name[0] == 0 || strcmp(name, (*molecule)->name) == 0) @@ -7858,7 +8422,7 @@ tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_find n_chains = molecule->n_chains; - for(i = 0; i < n_chains; i++) + for(i = n_chains - 1; i >= 0; i--) { *chain = &molecule->chains[i]; if(name[0] == 0 || strcmp(name, (*chain)->name) == 0) @@ -7881,11 +8445,23 @@ tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_add const char *name, tng_chain_t *chain) { + int64_t id; + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); TNG_ASSERT(name, "TNG library: name must not be a NULL pointer."); + /* Set ID to the ID of the last chain + 1 */ + if(molecule->n_chains) + { + id = molecule->chains[molecule->n_chains-1].id + 1; + } + else + { + id = 1; + } + return(tng_molecule_chain_w_id_add(tng_data, molecule, name, - molecule->n_chains + 1, chain)); + id, chain)); } tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_w_id_add @@ -7895,7 +8471,6 @@ tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_w_id_add const int64_t id, tng_chain_t *chain) { - int64_t i; tng_chain_t new_chains; tng_function_status stat = TNG_SUCCESS; @@ -7926,16 +8501,6 @@ tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_w_id_add (*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; @@ -7950,21 +8515,9 @@ tng_function_status DECLSPECDLLEXPORT tng_molecule_bond_add 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)); @@ -8006,7 +8559,7 @@ tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_find n_atoms = molecule->n_atoms; - for(i = 0; i < n_atoms; i++) + for(i = n_atoms - 1; i >= 0; i--) { *atom = &molecule->atoms[i]; if(name[0] == 0 || strcmp(name, (*atom)->name) == 0) @@ -8124,7 +8677,7 @@ tng_function_status DECLSPECDLLEXPORT tng_chain_residue_find n_residues = chain->n_residues; - for(i = 0; i < n_residues; i++) + for(i = n_residues - 1; i >= 0; i--) { *residue = &chain->residues[i]; if(name[0] == 0 || strcmp(name, (*residue)->name) == 0) @@ -8147,11 +8700,23 @@ tng_function_status DECLSPECDLLEXPORT tng_chain_residue_add const char *name, tng_residue_t *residue) { + int64_t id; + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); TNG_ASSERT(name, "TNG library: name must not be a NULL pointer."); + /* Set ID to the ID of the last residue + 1 */ + if(chain->n_residues) + { + id = chain->residues[chain->n_residues-1].id + 1; + } + else + { + id = 0; + } + return(tng_chain_residue_w_id_add(tng_data, chain, name, - chain->n_residues + 1, residue)); + id, residue)); } tng_function_status DECLSPECDLLEXPORT tng_chain_residue_w_id_add @@ -8161,7 +8726,7 @@ tng_function_status DECLSPECDLLEXPORT tng_chain_residue_w_id_add const int64_t id, tng_residue_t *residue) { - int64_t i, curr_index; + int64_t curr_index; tng_residue_t new_residues, temp_residue, last_residue; tng_molecule_t molecule = chain->molecule; tng_function_status stat = TNG_SUCCESS; @@ -8223,6 +8788,10 @@ tng_function_status DECLSPECDLLEXPORT tng_chain_residue_w_id_add { chain->residues = *residue; } + else + { + chain->residues = &molecule->residues[curr_index]; + } (*residue)->name = 0; tng_residue_name_set(tng_data, *residue, name); @@ -8231,16 +8800,6 @@ tng_function_status DECLSPECDLLEXPORT tng_chain_residue_w_id_add (*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++; @@ -8355,13 +8914,24 @@ tng_function_status DECLSPECDLLEXPORT tng_residue_atom_add const char *atom_type, tng_atom_t *atom) { + int64_t id; + 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."); + /* Set ID to the ID of the last atom + 1 */ + if(residue->chain->molecule->n_atoms) + { + id = residue->chain->molecule->atoms[residue->chain->molecule->n_atoms-1].id + 1; + } + else + { + id = 0; + } + return(tng_residue_atom_w_id_add(tng_data, residue, atom_name, atom_type, - residue->chain->molecule->n_atoms + 1, - atom)); + id, atom)); } tng_function_status DECLSPECDLLEXPORT tng_residue_atom_w_id_add @@ -8372,7 +8942,6 @@ tng_function_status DECLSPECDLLEXPORT tng_residue_atom_w_id_add 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; @@ -8410,16 +8979,6 @@ tng_function_status DECLSPECDLLEXPORT tng_residue_atom_w_id_add (*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++; @@ -8492,7 +9051,7 @@ tng_function_status DECLSPECDLLEXPORT tng_molecule_destroy(const tng_trajectory_ if(molecule->chains) { - for(i = molecule->n_chains; i--;) + for(i = 0; i < molecule->n_chains; i++) { if(molecule->chains[i].name) { @@ -8507,7 +9066,7 @@ tng_function_status DECLSPECDLLEXPORT tng_molecule_destroy(const tng_trajectory_ if(molecule->residues) { - for(i = molecule->n_residues; i--;) + for(i = 0; i < molecule->n_residues; i++) { if(molecule->residues[i].name) { @@ -8522,7 +9081,7 @@ tng_function_status DECLSPECDLLEXPORT tng_molecule_destroy(const tng_trajectory_ if(molecule->atoms) { - for(i = molecule->n_atoms; i--;) + for(i = 0; i < molecule->n_atoms; i++) { tng_atom_destroy(&molecule->atoms[i]); } @@ -9095,7 +9654,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_particle_mapping_free(tng_tr if(frame_set->n_mapping_blocks && frame_set->mappings) { - for(i = frame_set->n_mapping_blocks; i--;) + for(i = 0; i < frame_set->n_mapping_blocks; i++) { mapping = &frame_set->mappings[i]; if(mapping->real_particle_numbers) @@ -9165,7 +9724,6 @@ tng_function_status DECLSPECDLLEXPORT tng_trajectory_init(tng_trajectory_t *tng_ 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; @@ -9303,6 +9861,11 @@ tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *t if(tng_data->input_file) { + if(tng_data->output_file == tng_data->input_file) + { + tng_frame_set_finalize(tng_data, TNG_USE_HASH); + tng_data->output_file = 0; + } fclose(tng_data->input_file); tng_data->input_file = 0; } @@ -9394,7 +9957,7 @@ tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *t if(tng_data->non_tr_particle_data) { - for(i = tng_data->n_particle_data_blocks; i--; ) + for(i = 0; i < tng_data->n_particle_data_blocks; i++) { if(tng_data->non_tr_particle_data[i].values) { @@ -9408,11 +9971,11 @@ tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *t n_values_per_frame; if(tng_data->non_tr_particle_data[i].strings[0]) { - for(j = n_particles; j--;) + for(j = 0; j < n_particles; j++) { if(tng_data->non_tr_particle_data[i].strings[0][j]) { - for(k = n_values_per_frame; k--;) + for(k = 0; k < n_values_per_frame; k++) { if(tng_data->non_tr_particle_data[i]. strings[0][j][k]) @@ -9447,7 +10010,7 @@ tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *t if(tng_data->non_tr_data) { - for(i = tng_data->n_data_blocks; i--;) + for(i = 0; i < tng_data->n_data_blocks; i++) { if(tng_data->non_tr_data[i].values) { @@ -9461,7 +10024,7 @@ tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *t n_values_per_frame; if(tng_data->non_tr_data[i].strings[0]) { - for(j = n_values_per_frame; j--;) + for(j = 0; j < n_values_per_frame; j++) { if(tng_data->non_tr_data[i].strings[0][j]) { @@ -9502,7 +10065,7 @@ tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *t if(frame_set->tr_particle_data) { - for(i = frame_set->n_particle_data_blocks; i--; ) + for(i = 0; i < frame_set->n_particle_data_blocks; i++) { if(frame_set->tr_particle_data[i].values) { @@ -9514,16 +10077,16 @@ tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *t { 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--;) + for(j = 0; j < frame_set->tr_particle_data[i].n_frames; j++) { if(frame_set->tr_particle_data[i].strings[j]) { - for(k = n_particles; k--;) + for(k = 0; k < n_particles; k++) { if(frame_set->tr_particle_data[i]. strings[j][k]) { - for(l = n_values_per_frame; l--;) + for(l = 0; l < n_values_per_frame; l++) { if(frame_set->tr_particle_data[i]. strings[j][k][l]) @@ -9560,7 +10123,7 @@ tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *t if(frame_set->tr_data) { - for(i = frame_set->n_data_blocks; i--;) + for(i = 0; i < frame_set->n_data_blocks; i++) { if(frame_set->tr_data[i].values) { @@ -9572,11 +10135,11 @@ tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *t { n_values_per_frame = frame_set->tr_data[i]. n_values_per_frame; - for(j = frame_set->tr_data[i].n_frames; j--;) + for(j = 0; j < frame_set->tr_data[i].n_frames; j++) { if(frame_set->tr_data[i].strings[j]) { - for(k = n_values_per_frame; k--;) + for(k = 0; k < n_values_per_frame; k++) { if(frame_set->tr_data[i].strings[j][k]) { @@ -9607,7 +10170,7 @@ tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *t if(tng_data->molecules) { - for(i=tng_data->n_molecules; i--;) + for(i = 0; i < tng_data->n_molecules; i++) { tng_molecule_destroy(tng_data, &tng_data->molecules[i]); } @@ -9692,7 +10255,6 @@ tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_from_src(tng_trajector 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; @@ -9896,6 +10458,7 @@ tng_function_status DECLSPECDLLEXPORT tng_output_append_file_set tng_data->output_file_path, __FILE__, __LINE__); return(TNG_CRITICAL); } + tng_data->input_file = tng_data->output_file; return(TNG_SUCCESS); } @@ -10831,7 +11394,7 @@ tng_function_status DECLSPECDLLEXPORT tng_num_molecules_get return(TNG_FAILURE); } - for(i = tng_data->n_molecules; i --;) + for(i = 0; i < tng_data->n_molecules; i++) { cnt += cnt_list[i]; } @@ -11172,7 +11735,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find } if(tng_block_read_next(tng_data, block, - TNG_SKIP_HASH) != TNG_SUCCESS) + TNG_SKIP_HASH) != TNG_SUCCESS) { tng_block_destroy(&block); return(TNG_CRITICAL); @@ -11912,11 +12475,55 @@ static TNG_INLINE tng_function_status tng_particle_mapping_get_real_particle } */ +static tng_function_status tng_file_headers_len_get + (tng_trajectory_t tng_data, + int64_t *len) +{ + int64_t orig_pos; + tng_gen_block_t block; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + if(tng_input_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + + *len = 0; + + orig_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); + + tng_block_init(&block); + /* Read through the headers of non-trajectory blocks (they come before the + * trajectory blocks in the file) */ + while (*len < tng_data->input_file_len && + tng_block_header_read(tng_data, block) != TNG_CRITICAL && + block->id != -1 && + block->id != TNG_TRAJECTORY_FRAME_SET) + { + *len += block->header_contents_size + block->block_contents_size; + fseek(tng_data->input_file, block->block_contents_size, SEEK_CUR); + } + + fseek(tng_data->input_file, orig_pos, SEEK_SET); + + tng_block_destroy(&block); + + return(TNG_SUCCESS); +} + tng_function_status DECLSPECDLLEXPORT tng_file_headers_read (tng_trajectory_t tng_data, const char hash_mode) { - int cnt = 0, prev_pos = 0; + int64_t prev_pos = 0; tng_gen_block_t block; TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); @@ -11932,8 +12539,8 @@ tng_function_status DECLSPECDLLEXPORT tng_file_headers_read { 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); } + fseek(tng_data->input_file, 0, SEEK_SET); tng_block_init(&block); /* Non trajectory blocks (they come before the trajectory @@ -11943,11 +12550,7 @@ tng_function_status DECLSPECDLLEXPORT tng_file_headers_read block->id != -1 && block->id != TNG_TRAJECTORY_FRAME_SET) { - if(tng_block_read_next(tng_data, block, - hash_mode) == TNG_SUCCESS) - { - cnt++; - } + tng_block_read_next(tng_data, block, hash_mode); prev_pos = ftell(tng_data->input_file); } @@ -11967,7 +12570,9 @@ tng_function_status DECLSPECDLLEXPORT tng_file_headers_write const char hash_mode) { int i; - tng_gen_block_t data_block; + int64_t len, orig_len, tot_len = 0, data_start_pos; + tng_function_status stat; + tng_gen_block_t block; TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); @@ -11976,6 +12581,69 @@ tng_function_status DECLSPECDLLEXPORT tng_file_headers_write return(TNG_CRITICAL); } + if(tng_data->n_trajectory_frame_sets > 0) + { + stat = tng_file_headers_len_get(tng_data, &orig_len); + if(stat != TNG_SUCCESS) + { + return(stat); + } + + tng_block_init(&block); + block->name = malloc(TNG_MAX_STR_LEN); + if(!block->name) + { + fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", + TNG_MAX_STR_LEN, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + strcpy(block->name, "GENERAL INFO"); + tng_block_header_len_calculate(tng_data, block, &len); + tot_len += len; + tng_general_info_block_len_calculate(tng_data, &len); + tot_len += len; + strcpy(block->name, "MOLECULES"); + tng_block_header_len_calculate(tng_data, block, &len); + tot_len += len; + tng_molecules_block_len_calculate(tng_data, &len); + tot_len += len; + + for(i = 0; i < tng_data->n_data_blocks; i++) + { + strcpy(block->name, tng_data->non_tr_data[i].block_name); + tng_block_header_len_calculate(tng_data, block, &len); + tot_len += len; + tng_data_block_len_calculate(tng_data, + (tng_particle_data_t)&tng_data->non_tr_data[i], + TNG_FALSE, 1, 1, 1, 0, + 1, 0, &data_start_pos, + &len); + tot_len += len; + } + for(i = 0; i < tng_data->n_particle_data_blocks; i++) + { + strcpy(block->name, tng_data->non_tr_particle_data[i].block_name); + tng_block_header_len_calculate(tng_data, block, &len); + tot_len += len; + tng_data_block_len_calculate(tng_data, + &tng_data->non_tr_particle_data[i], + TNG_TRUE, 1, 1, 1, 0, + tng_data->n_particles, TNG_PARTICLE_DEPENDENT, + &data_start_pos, + &len); + tot_len += len; + } + tng_block_destroy(&block); + + if(tot_len > orig_len) + { + tng_migrate_data_in_file(tng_data, orig_len+1, tot_len - orig_len); + } + + tng_data->current_trajectory_frame_set_output_file_pos = -1; + } + /* 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. */ @@ -11998,22 +12666,22 @@ tng_function_status DECLSPECDLLEXPORT tng_file_headers_write /* FIXME: Currently writing non-trajectory data blocks here. * Should perhaps be moved. */ - tng_block_init(&data_block); + tng_block_init(&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, + block->id = tng_data->non_tr_data[i].block_id; + tng_data_block_write(tng_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, + block->id = tng_data->non_tr_particle_data[i].block_id; + tng_particle_data_block_write(tng_data, block, i, 0, hash_mode); } - tng_block_destroy(&data_block); + tng_block_destroy(&block); return(TNG_SUCCESS); } @@ -12077,7 +12745,8 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_read /* 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) + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET || + block->id == -1) { fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n", file_pos, __FILE__, __LINE__); @@ -12096,7 +12765,8 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_read 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) + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) { stat = tng_block_read_next(tng_data, block, hash_mode); @@ -12211,7 +12881,8 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_current_only_data_from_ 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) + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) { if(block->id == block_id) { @@ -12545,8 +13216,8 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_new /* 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); + fseek(tng_data->output_file, (long)block->block_contents_size - (6 * + sizeof(int64_t) + 2 * sizeof(double)), 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) @@ -12601,8 +13272,8 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_new /* 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); + fseek(tng_data->output_file, (long)block->block_contents_size - (6 * + sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR); tng_block_destroy(&block); @@ -13396,7 +14067,8 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_data_write stat = tng_block_header_read(tng_data, block); while(file_pos < output_file_len && stat != TNG_CRITICAL && - block->id != TNG_TRAJECTORY_FRAME_SET) + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) { if(block->id == TNG_PARTICLE_MAPPING) { @@ -13464,7 +14136,8 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_data_write while(file_pos < output_file_len && stat != TNG_CRITICAL && block->id != block_id && - block->id != TNG_TRAJECTORY_FRAME_SET) + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) { fseek(tng_data->output_file, (long)block->block_contents_size, SEEK_CUR); file_pos = ftell(tng_data->output_file); @@ -13824,7 +14497,8 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_particle_data_write stat = tng_block_header_read(tng_data, block); while(file_pos < output_file_len && stat != TNG_CRITICAL && - block->id != TNG_TRAJECTORY_FRAME_SET) + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) { if(block->id == TNG_PARTICLE_MAPPING) { @@ -13903,7 +14577,8 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_particle_data_write stat = tng_block_header_read(tng_data, block); while(file_pos < output_file_len && stat != TNG_CRITICAL && - block->id != TNG_TRAJECTORY_FRAME_SET) + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) { if(block->id == TNG_PARTICLE_MAPPING) { @@ -13964,7 +14639,8 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_particle_data_write stat != TNG_CRITICAL && block->id != block_id && block->id != TNG_PARTICLE_MAPPING && - block->id != TNG_TRAJECTORY_FRAME_SET) + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) { fseek(tng_data->output_file, (long)block->block_contents_size, SEEK_CUR); file_pos = ftell(tng_data->output_file); @@ -14319,7 +14995,7 @@ static tng_function_status tng_data_values_alloc } - for(i = n_frames; i--;) + for(i = 0; i < n_frames; i++) { (*values)[i] = malloc(sizeof(union data_values) * n_values_per_frame); @@ -14355,7 +15031,7 @@ tng_function_status DECLSPECDLLEXPORT tng_data_values_free { if(type == TNG_CHAR_DATA) { - for(j = n_values_per_frame; j--;) + for(j = 0; j < n_values_per_frame; j++) { if(values[i][j].c) { @@ -14413,7 +15089,7 @@ static tng_function_status tng_particle_data_values_alloc } - for(i = n_frames; i--;) + for(i = 0; i < n_frames; i++) { (*values)[i] = malloc(sizeof(union data_values *) * n_particles); @@ -14426,7 +15102,7 @@ static tng_function_status tng_particle_data_values_alloc *values = 0; return(TNG_CRITICAL); } - for(j = n_particles; j--;) + for(j = 0; j < n_particles; j++) { (*values)[i][j] = malloc(sizeof(union data_values) * n_values_per_frame); @@ -14468,7 +15144,7 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_data_values_free { if(type == TNG_CHAR_DATA) { - for(k = n_values_per_frame; k--;) + for(k = 0; k < n_values_per_frame; k++) { if(values[i][j][k].c) { @@ -14526,7 +15202,8 @@ tng_function_status DECLSPECDLLEXPORT tng_data_get 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) + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) { /* Use hash by default */ stat = tng_block_read_next(tng_data, block, @@ -14548,7 +15225,7 @@ tng_function_status DECLSPECDLLEXPORT tng_data_get return(stat); } - for(i = frame_set->n_data_blocks; i-- ;) + for(i = 0; i < frame_set->n_data_blocks; i++) { data = &frame_set->tr_data[i]; if(data->block_id == block_id) @@ -14581,9 +15258,9 @@ tng_function_status DECLSPECDLLEXPORT tng_data_get switch(*type) { case TNG_CHAR_DATA: - for(i=*n_frames; i--;) + for(i = 0; i < *n_frames; i++) { - for(j=*n_values_per_frame; j--;) + for(j = 0; j < *n_values_per_frame; j++) { len = strlen(data->strings[i][j]) + 1; (*values)[i][j].c = malloc(len); @@ -14593,9 +15270,9 @@ tng_function_status DECLSPECDLLEXPORT tng_data_get break; case TNG_INT_DATA: size = sizeof(int); - for(i=*n_frames; i--;) + for(i = 0; i < *n_frames; i++) { - for(j=*n_values_per_frame; j--;) + for(j = 0; j < *n_values_per_frame; j++) { (*values)[i][j].i = *(int *)((char *)data->values + size * (i*(*n_values_per_frame) + j)); @@ -14604,9 +15281,9 @@ tng_function_status DECLSPECDLLEXPORT tng_data_get break; case TNG_FLOAT_DATA: size = sizeof(float); - for(i=*n_frames; i--;) + for(i = 0; i < *n_frames; i++) { - for(j=*n_values_per_frame; j--;) + for(j = 0; j < *n_values_per_frame; j++) { (*values)[i][j].f = *(float *)((char *)data->values + size * (i*(*n_values_per_frame) + j)); @@ -14616,9 +15293,9 @@ tng_function_status DECLSPECDLLEXPORT tng_data_get case TNG_DOUBLE_DATA: default: size = sizeof(double); - for(i=*n_frames; i--;) + for(i = 0; i < *n_frames; i++) { - for(j=*n_values_per_frame; j--;) + for(j = 0; j < *n_values_per_frame; j++) { (*values)[i][j].d = *(double *)((char *)data->values + size * (i*(*n_values_per_frame) + j)); @@ -14666,7 +15343,8 @@ tng_function_status tng_data_vector_get(tng_trajectory_t tng_data, 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) + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) { /* Use hash by default */ stat = tng_block_read_next(tng_data, block, @@ -14688,7 +15366,7 @@ tng_function_status tng_data_vector_get(tng_trajectory_t tng_data, return(stat); } - for(i = frame_set->n_data_blocks; i-- ;) + for(i = 0; i < frame_set->n_data_blocks; i++) { data = &frame_set->tr_data[i]; if(data->block_id == block_id) @@ -14794,7 +15472,8 @@ tng_function_status DECLSPECDLLEXPORT tng_data_interval_get 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) + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) { stat = tng_block_read_next(tng_data, block, hash_mode); @@ -14819,7 +15498,7 @@ tng_function_status DECLSPECDLLEXPORT tng_data_interval_get /* 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-- ;) + for(i = 0; i < frame_set->n_data_blocks; i++) { data = &frame_set->tr_data[i]; if(data->block_id == block_id) @@ -14868,7 +15547,7 @@ tng_function_status DECLSPECDLLEXPORT tng_data_interval_get } current_frame_pos = 0; } - for(j=*n_values_per_frame; j--;) + for(j = 0; j < *n_values_per_frame; j++) { len = strlen(data->strings[current_frame_pos][j]) + 1; (*values)[i][j].c = malloc(len); @@ -14890,7 +15569,7 @@ tng_function_status DECLSPECDLLEXPORT tng_data_interval_get } current_frame_pos = 0; } - for(j=*n_values_per_frame; j--;) + for(j = 0; j < *n_values_per_frame; j++) { (*values)[i][j].i = *(int *)((char *)data->values + size * (current_frame_pos * @@ -14912,7 +15591,7 @@ tng_function_status DECLSPECDLLEXPORT tng_data_interval_get } current_frame_pos = 0; } - for(j=*n_values_per_frame; j--;) + for(j = 0; j < *n_values_per_frame; j++) { (*values)[i][j].f = *(float *)((char *)data->values + size * (current_frame_pos * @@ -14935,7 +15614,7 @@ tng_function_status DECLSPECDLLEXPORT tng_data_interval_get } current_frame_pos = 0; } - for(j=*n_values_per_frame; j--;) + for(j = 0; j < *n_values_per_frame; j++) { (*values)[i][j].d = *(double *)((char *)data->values + size * (current_frame_pos * @@ -15013,7 +15692,8 @@ tng_function_status DECLSPECDLLEXPORT tng_data_vector_interval_get 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) + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) { if(block->id == block_id) { @@ -15236,7 +15916,8 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_data_get 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) + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) { /* Use hash by default */ stat = tng_block_read_next(tng_data, block, @@ -15258,7 +15939,7 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_data_get return(stat); } - for(i = frame_set->n_particle_data_blocks; i-- ;) + for(i = 0; i < frame_set->n_particle_data_blocks; i++) { data = &frame_set->tr_particle_data[i]; if(data->block_id == block_id) @@ -15316,12 +15997,12 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_data_get switch(*type) { case TNG_CHAR_DATA: - for(i=*n_frames; i--;) + for(i = 0; i < *n_frames; i++) { - for(j=*n_particles; j--;) + for(j = 0; j < *n_particles; j++) { tng_particle_mapping_get_real_particle(frame_set, j, &mapping); - for(k=*n_values_per_frame; k--;) + for(k = 0; k < *n_values_per_frame; k++) { len = strlen(data->strings[i][j][k]) + 1; (*values)[i][mapping][k].c = malloc(len); @@ -15334,12 +16015,12 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_data_get case TNG_INT_DATA: size = sizeof(int); i_step = (*n_particles) * (*n_values_per_frame); - for(i=*n_frames; i--;) + for(i = 0; i < *n_frames; i++) { - for(j=*n_particles; j--;) + for(j = 0; j < *n_particles; j++) { tng_particle_mapping_get_real_particle(frame_set, j, &mapping); - for(k=*n_values_per_frame; k--;) + for(k = 0; k < *n_values_per_frame; k++) { (*values)[i][mapping][k].i = *(int *) ((char *)data->values + size * @@ -15352,12 +16033,12 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_data_get case TNG_FLOAT_DATA: size = sizeof(float); i_step = (*n_particles) * (*n_values_per_frame); - for(i=*n_frames; i--;) + for(i = 0; i < *n_frames; i++) { - for(j=*n_particles; j--;) + for(j = 0; j < *n_particles; j++) { tng_particle_mapping_get_real_particle(frame_set, j, &mapping); - for(k=*n_values_per_frame; k--;) + for(k = 0; k < *n_values_per_frame; k++) { (*values)[i][mapping][k].f = *(float *) ((char *)data->values + size * @@ -15371,12 +16052,12 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_data_get default: size = sizeof(double); i_step = (*n_particles) * (*n_values_per_frame); - for(i=*n_frames; i--;) + for(i = 0; i < *n_frames; i++) { - for(j=*n_particles; j--;) + for(j = 0; j < *n_particles; j++) { tng_particle_mapping_get_real_particle(frame_set, j, &mapping); - for(k=*n_values_per_frame; k--;) + for(k = 0; k < *n_values_per_frame; k++) { (*values)[i][mapping][k].d = *(double *) ((char *)data->values + size * @@ -15431,7 +16112,8 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_get 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) + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) { /* Use hash by default */ stat = tng_block_read_next(tng_data, block, @@ -15453,7 +16135,7 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_get return(stat); } - for(i = frame_set->n_particle_data_blocks; i-- ;) + for(i = 0; i < frame_set->n_particle_data_blocks; i++) { data = &frame_set->tr_particle_data[i]; if(data->block_id == block_id) @@ -15534,9 +16216,9 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_get else { i_step = (*n_particles) * (*n_values_per_frame); - for(i = *n_frames; i--;) + for(i = 0; i < *n_frames; i++) { - for(j = *n_particles; j--;) + for(j = 0; j < *n_particles; j++) { tng_particle_mapping_get_real_particle(frame_set, j, &mapping); memcpy(((char *)*values) + size * (i * i_step + mapping * @@ -15601,7 +16283,8 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get 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) + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) { stat = tng_block_read_next(tng_data, block, hash_mode); @@ -15686,10 +16369,10 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get } current_frame_pos = 0; } - for(j=*n_particles; j--;) + for(j = 0; j < *n_particles; j++) { tng_particle_mapping_get_real_particle(frame_set, j, &mapping); - for(k=*n_values_per_frame; k--;) + for(k = 0; k < *n_values_per_frame; k++) { len = strlen(data->strings[current_frame_pos][j][k]) + 1; (*values)[i][mapping][k].c = malloc(len); @@ -15713,10 +16396,10 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get } current_frame_pos = 0; } - for(j=*n_particles; j--;) + for(j = 0; j < *n_particles; j++) { tng_particle_mapping_get_real_particle(frame_set, j, &mapping); - for(k=*n_values_per_frame; k--;) + for(k = 0; k < *n_values_per_frame; k++) { (*values)[i][mapping][k].i = *(int *) ((char *)data->values + size * @@ -15742,10 +16425,10 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get } current_frame_pos = 0; } - for(j=*n_particles; j--;) + for(j=0; j<*n_particles; j++) { tng_particle_mapping_get_real_particle(frame_set, j, &mapping); - for(k=*n_values_per_frame; k--;) + for(k=0; k<*n_values_per_frame; k++) { (*values)[i][mapping][k].f = *(float *) ((char *)data->values + size * @@ -15772,10 +16455,10 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get } current_frame_pos = 0; } - for(j=*n_particles; j--;) + for(j=0; j<*n_particles; j++) { tng_particle_mapping_get_real_particle(frame_set, j, &mapping); - for(k=*n_values_per_frame; k--;) + for(k=0; k<*n_values_per_frame; k++) { (*values)[i][mapping][k].d = *(double *) ((char *)data->values + size * @@ -15857,7 +16540,8 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_interval_get 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) + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) { if(block->id == block_id || block->id == TNG_PARTICLE_MAPPING) { @@ -16182,6 +16866,11 @@ tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_open } else if(mode == 'a') { + if((*tng_data_p)->output_file) + { + fclose((*tng_data_p)->output_file); + } + (*tng_data_p)->output_file = (*tng_data_p)->input_file; fseek((*tng_data_p)->input_file, (long)(*tng_data_p)->last_trajectory_frame_set_input_file_pos, SEEK_SET); @@ -16192,6 +16881,7 @@ tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_open fprintf(stderr, "TNG library: Cannot read frame set and related blocks. %s: %d\n", __FILE__, __LINE__); } + (*tng_data_p)->output_file = 0; (*tng_data_p)->first_trajectory_frame_set_output_file_pos = (*tng_data_p)->first_trajectory_frame_set_input_file_pos; @@ -16199,9 +16889,6 @@ tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_open (*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); @@ -18375,19 +19062,18 @@ tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_next_frame_present_dat } } - /* If no data blocks have been found in the frame set check what data blocks - * are present. If they have already been found do not read them again. */ + /* Check for data blocks only if they have not already been found. */ if(frame_set->n_particle_data_blocks <= 0 && frame_set->n_data_blocks <= 0) { file_pos = ftell(tng_data->input_file); - /* Read all blocks until next frame set block */ if(file_pos < tng_data->input_file_len) { tng_block_init(&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) + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) { stat = tng_block_read_next(tng_data, block, TNG_USE_HASH); diff --git a/src/external/tng_io/src/lib/tng_io_fortran.c b/src/external/tng_io/src/lib/tng_io_fortran.c index baceef75d1..d53d15b07b 100644 --- a/src/external/tng_io/src/lib/tng_io_fortran.c +++ b/src/external/tng_io/src/lib/tng_io_fortran.c @@ -1,6 +1,4 @@ /* This code is part of the tng binary trajectory format. - * - * VERSION 1.5 * * Written by Magnus Lundborg * Copyright (c) 2012-2013, The GROMACS development team. diff --git a/src/external/tng_io/src/tests/md_openmp.c b/src/external/tng_io/src/tests/md_openmp.c index b57eff41c8..fd9f4b0e77 100644 --- a/src/external/tng_io/src/tests/md_openmp.c +++ b/src/external/tng_io/src/tests/md_openmp.c @@ -5,7 +5,7 @@ # include # include # include -# include "tng_io.h" +#include "../../include/tng_io.h" int main (); void compute ( int np, int nd, double pos[], double vel[], diff --git a/src/external/tng_io/src/tests/md_openmp_util.c b/src/external/tng_io/src/tests/md_openmp_util.c index 34b8964144..8c332f32ee 100644 --- a/src/external/tng_io/src/tests/md_openmp_util.c +++ b/src/external/tng_io/src/tests/md_openmp_util.c @@ -5,7 +5,7 @@ # include # include # include -# include "tng_io.h" +#include "../../include/tng_io.h" int main (); void compute ( int np, int nd, float pos[], float vel[], diff --git a/src/external/tng_io/src/tests/tng_io_read_pos.c b/src/external/tng_io/src/tests/tng_io_read_pos.c index 079cad7e48..2a0bb09741 100644 --- a/src/external/tng_io/src/tests/tng_io_read_pos.c +++ b/src/external/tng_io/src/tests/tng_io_read_pos.c @@ -1,6 +1,4 @@ /* 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. diff --git a/src/external/tng_io/src/tests/tng_io_read_pos_util.c b/src/external/tng_io/src/tests/tng_io_read_pos_util.c index 64df9df278..1667bae2d8 100644 --- a/src/external/tng_io/src/tests/tng_io_read_pos_util.c +++ b/src/external/tng_io/src/tests/tng_io_read_pos_util.c @@ -2,8 +2,6 @@ * * 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. diff --git a/src/external/tng_io/src/tests/tng_io_testing.c b/src/external/tng_io/src/tests/tng_io_testing.c index 973ac4fb7b..dd13d925d3 100644 --- a/src/external/tng_io/src/tests/tng_io_testing.c +++ b/src/external/tng_io/src/tests/tng_io_testing.c @@ -1,9 +1,7 @@ /* 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. + * Copyright (c) 2012-2014, The GROMACS development team. * Check out http://www.gromacs.org for more information. * * @@ -149,6 +147,9 @@ static tng_function_status tng_test_write_and_read_traj(tng_trajectory_t *traj) tng_medium_stride_length_set(*traj, 10); tng_long_stride_length_set(*traj, 100); + tng_first_user_name_set(*traj, "User1"); + tng_first_program_name_set(*traj, "tng_testing"); + /* Create molecules */ if(tng_test_setup_molecules(*traj) == TNG_CRITICAL) { @@ -212,7 +213,7 @@ static tng_function_status tng_test_write_and_read_traj(tng_trajectory_t *traj) /* 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, + if(tng_data_block_add(*traj, TNG_TRAJ_GENERAL_COMMENTS, "COMMENTS", TNG_CHAR_DATA, TNG_NON_TRAJECTORY_BLOCK, 1, 1, 1, TNG_UNCOMPRESSED, annotation) != TNG_SUCCESS) { @@ -569,6 +570,26 @@ tng_function_status tng_test_get_positions_data(tng_trajectory_t traj) return(TNG_SUCCESS); } + +tng_function_status tng_test_append(tng_trajectory_t traj) +{ + tng_function_status stat; + + stat = tng_util_trajectory_open(TNG_EXAMPLE_FILES_DIR "tng_test.tng", 'a', &traj); + if(stat != TNG_SUCCESS) + { + return(stat); + } + + tng_last_user_name_set(traj, "User2"); + tng_last_program_name_set(traj, "tng_testing"); + tng_file_headers_write(traj, TNG_USE_HASH); + + stat = tng_util_trajectory_close(&traj); + + return(stat); +} + int main() { tng_trajectory_t traj; @@ -683,6 +704,17 @@ int main() printf("Test Utility function close:\t\t\tSucceeded.\n"); } + if(tng_test_append(traj) != TNG_SUCCESS) + { + printf("Test Append:\t\t\t\t\tFailed. %s: %d.\n", + __FILE__, __LINE__); + exit(1); + } + else + { + printf("Test Append:\t\t\t\t\tSucceeded.\n"); + } + printf("Tests finished\n"); exit(0); diff --git a/src/external/tng_io/src/tests/tng_parallel_read.c b/src/external/tng_io/src/tests/tng_parallel_read.c index 95d1c9a3fc..e2e23c6b4f 100644 --- a/src/external/tng_io/src/tests/tng_parallel_read.c +++ b/src/external/tng_io/src/tests/tng_parallel_read.c @@ -1,8 +1,6 @@ #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. -- 2.22.0