diff options
| -rw-r--r-- | include/tng_io.h | 95 | ||||
| -rw-r--r-- | src/lib/tng_io.c | 404 | 
2 files changed, 481 insertions, 18 deletions
| diff --git a/include/tng_io.h b/include/tng_io.h index dd344ed..9a6cfa7 100644 --- a/include/tng_io.h +++ b/include/tng_io.h @@ -2040,7 +2040,7 @@ tng_function_status DECLSPECDLLEXPORT tng_block_read_next                   const char hash_mode);  /** - * @brief Read one (the next) frame set, including mapping and related data blocks + * @brief Read one (the next) frame set, including particle mapping and related data blocks   * from the input_file of tng_data.   * @param tng_data is a trajectory data container.   * @details  tng_data->input_file_path specifies @@ -2059,6 +2059,27 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next                   const char hash_mode);  /** + * @brief Read one (the next) frame set, including particle mapping and data blocks with a + * specific block id from the input_file of tng_data. + * @param tng_data is a trajectory data container. + * @details  tng_data->input_file_path specifies + * which file to read from. If the file (input_file) is not open it will be + * opened. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be + * compared to the md5 hash of the read contents to ensure valid data. + * @param block_id is the ID number of the blocks that should be read from file. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next_only_data_from_block_id +                (tng_trajectory_t tng_data, +                 const char hash_mode, +                 const int64_t block_id); + +/**   * @brief Write one frame set, including mapping and related data blocks   * to the output_file of tng_data.   * @param tng_data is a trajectory data container. @@ -2925,6 +2946,78 @@ tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read                   int64_t *stride_length);  /** + * @brief High-level function for reading the next frame of particle-dependent + * data of a specific type. + * @param tng_data is the trajectory to read from. + * @param block_id is the ID number of the block containing the data of interest. + * @param values will be set to point at a 1-dimensional array containing the + * requested data. The variable may point at already allocated memory or be a + * NULL pointer. The memory must be freed afterwards. + * @param data_type will be pointing to a character indicating the size of the + * data of the returned values, e.g. TNG_INT_DATA, TNG_FLOAT_DATA or TNG_DOUBLE_DATA. + * @param retrieved_frame_number will be pointing at the frame number of the + * returned frame. + * @param retrieved_time will be pointing at the time stamp of the returned + * frame. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code values != 0 \endcode The pointer to the values array + * must not be a NULL pointer. + * @pre \code data_type != 0 \endcode The pointer to the data type of the + * returned data must not be a NULL pointer. + * @pre \code retrieved_frame_number != 0 \endcode The pointer to the frame + * number of the returned data must not be a NULL pointer. + * @pre \code retrieved_time != 0 \endcode The pointer to the time of the + * returned data must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_particle_data_next_frame_read +                (tng_trajectory_t tng_data, +                 const int64_t block_id, +                 void **values, +                 char *data_type, +                 int64_t *retrieved_frame_number, +                 double *retrieved_time); + +/** + * @brief High-level function for reading the next frame of non-particle-dependent + * data of a specific type. + * @param tng_data is the trajectory to read from. + * @param block_id is the ID number of the block containing the data of interest. + * @param values will be set to point at a 1-dimensional array containing the + * requested data. The variable may point at already allocated memory or be a + * NULL pointer. The memory must be freed afterwards. + * @param data_type will be pointing to a character indicating the size of the + * data of the returned values, e.g. TNG_INT_DATA, TNG_FLOAT_DATA or TNG_DOUBLE_DATA. + * @param retrieved_frame_number will be pointing at the frame number of the + * returned frame. + * @param retrieved_time will be pointing at the time stamp of the returned + * frame. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code values != 0 \endcode The pointer to the values array + * must not be a NULL pointer. + * @pre \code data_type != 0 \endcode The pointer to the data type of the + * returned data must not be a NULL pointer. + * @pre \code retrieved_frame_number != 0 \endcode The pointer to the frame + * number of the returned data must not be a NULL pointer. + * @pre \code retrieved_time != 0 \endcode The pointer to the time of the + * returned data must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_non_particle_data_next_frame_read +                (tng_trajectory_t tng_data, +                 const int64_t block_id, +                 void **values, +                 char *data_type, +                 int64_t *retrieved_frame_number, +                 double *retrieved_time); + +/**   * @brief High-level function for reading the positions of all particles   * from a specific range of frames.   * @param tng_data is the trajectory to read from. diff --git a/src/lib/tng_io.c b/src/lib/tng_io.c index 29cf246..492b463 100644 --- a/src/lib/tng_io.c +++ b/src/lib/tng_io.c @@ -210,6 +210,8 @@ struct tng_particle_data {      int64_t stride_length;      /** ID of the CODEC used for compression 0 == no compression. */      int64_t codec_id; +    /** If reading one frame at a time this is the last read frame */ +    int64_t last_retrieved_frame;      /** The multiplier used for getting integer values for compression */      double compression_multiplier;      /** A 1-dimensional array of values of length @@ -238,6 +240,8 @@ struct tng_non_particle_data {      int64_t stride_length;      /** ID of the CODEC used for compression. 0 == no compression. */      int64_t codec_id; +    /** If reading one frame at a time this is the last read frame */ +    int64_t last_retrieved_frame;      /** Compressed data is stored as integers. This compression multiplier is       *  the multiplication factor to convert from integer to float/double */      double compression_multiplier; @@ -4616,6 +4620,8 @@ static tng_function_status tng_particle_data_read      }      n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length; +     +    data->last_retrieved_frame = -1;      if(codec_id != TNG_UNCOMPRESSED)      { @@ -5541,6 +5547,8 @@ static tng_function_status tng_data_read(tng_trajectory_t tng_data,      n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length; +    data->last_retrieved_frame = -1; +      if(codec_id != TNG_UNCOMPRESSED)      {          switch(codec_id) @@ -11036,8 +11044,9 @@ tng_function_status DECLSPECDLLEXPORT tng_block_read_next(tng_trajectory_t tng_d  } -tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next(tng_trajectory_t tng_data, -                                            const char hash_mode) +tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next +                (tng_trajectory_t tng_data, +                 const char hash_mode)  {      long file_pos;      tng_gen_block_t block; @@ -11130,6 +11139,115 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next(tng_trajectory_t t      return(TNG_SUCCESS);  } +tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next_only_data_from_block_id +                (tng_trajectory_t tng_data, +                 const char hash_mode, +                 const int64_t block_id) +{ +    long file_pos; +    tng_gen_block_t block; +    tng_function_status stat; + +    TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + +    if(tng_input_file_init(tng_data) != TNG_SUCCESS) +    { +        return(TNG_CRITICAL); +    } + +    file_pos = (long)tng_data->current_trajectory_frame_set.next_frame_set_file_pos; + +    if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0) +    { +        file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos; +    } + +    if(file_pos > 0) +    { +        fseek(tng_data->input_file, +              file_pos, +              SEEK_SET); +    } +    else +    { +        return(TNG_FAILURE); +    } + +    tng_block_init(&block); + +    if(!tng_data->input_file_len) +    { +        fseek(tng_data->input_file, 0, SEEK_END); +        tng_data->input_file_len = ftell(tng_data->input_file); +        fseek(tng_data->input_file, file_pos, SEEK_SET); +    } + +    /* Read block headers first to see what block is found. */ +    stat = tng_block_header_read(tng_data, block); +    if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) +    { +        printf("TNG library: Cannot read block header at pos %ld. %s: %d\n", +               file_pos, __FILE__, __LINE__); +        tng_block_destroy(&block); +        return(TNG_CRITICAL); +    } + +    tng_data->current_trajectory_frame_set_input_file_pos = file_pos; + +    if(tng_block_read_next(tng_data, block, +                           hash_mode) == TNG_SUCCESS) +    { +        tng_data->n_trajectory_frame_sets++; +        file_pos = ftell(tng_data->input_file); +        /* Read only blocks of the requested ID +         * until next frame set block */ +        stat = tng_block_header_read(tng_data, block); +        while(file_pos < tng_data->input_file_len && +              stat != TNG_CRITICAL && +              block->id != TNG_TRAJECTORY_FRAME_SET) +        { +            if(block->id == block_id) +            { +                stat = tng_block_read_next(tng_data, block, +                                        hash_mode); +                if(stat != TNG_CRITICAL) +                { +                    file_pos = ftell(tng_data->input_file); +                    if(file_pos < tng_data->input_file_len) +                    { +                        stat = tng_block_header_read(tng_data, block); +                    } +                } +            } +            else +            { +                file_pos += block->block_contents_size + block->header_contents_size; +                fseek(tng_data->input_file, block->block_contents_size, SEEK_CUR); +                if(file_pos < tng_data->input_file_len) +                { +                    stat = tng_block_header_read(tng_data, block); +                } +            } +        } +        if(stat == TNG_CRITICAL) +        { +            printf("TNG library: Cannot read block header at pos %ld. %s: %d\n", +                   file_pos, __FILE__, __LINE__); +            tng_block_destroy(&block); +            return(stat); +        } + +        if(block->id == TNG_TRAJECTORY_FRAME_SET) +        { +            fseek(tng_data->input_file, file_pos, SEEK_SET); +        } +    } + +    tng_block_destroy(&block); + +    return(TNG_SUCCESS); +} +  tng_function_status tng_frame_set_write(tng_trajectory_t tng_data,                                          const char hash_mode)  { @@ -13127,6 +13245,8 @@ tng_function_status DECLSPECDLLEXPORT tng_data_get              }          }      } +     +    data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;      return(TNG_SUCCESS);  } @@ -13242,6 +13362,8 @@ tng_function_status tng_data_vector_get(tng_trajectory_t tng_data,      *values = temp;      memcpy(*values, data->values, data_size); +     +    data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;      return(TNG_SUCCESS);  } @@ -13443,6 +13565,8 @@ tng_function_status DECLSPECDLLEXPORT tng_data_interval_get          }      } +    data->last_retrieved_frame = end_frame_nr; +          return(TNG_SUCCESS);  } @@ -13468,7 +13592,7 @@ tng_function_status DECLSPECDLLEXPORT tng_data_vector_interval_get      tng_function_status stat;      TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); -    TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr."); +    TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than the end_frame_nr.");      TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");      TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");      TNG_ASSERT(type, "TNG library: type must not be a NULL pointer."); @@ -13482,23 +13606,45 @@ tng_function_status DECLSPECDLLEXPORT tng_data_vector_interval_get          return(stat);      } -    /* Do not re-read the frame set. */ +    /* Do not re-read the frame set and only need the requested block. */ +    /* TODO: Test that blocks are read correctly now that now all of them are read at the same time. */ +    stat = tng_data_find(tng_data, block_id, &np_data);      if(first_frame != frame_set->first_frame || -       frame_set->n_data_blocks <= 0) +       stat != TNG_SUCCESS)      {          tng_block_init(&block); +        if(stat != TNG_SUCCESS) +        { +            fseek(tng_data->input_file, +                  tng_data->current_trajectory_frame_set_input_file_pos, +                  SEEK_SET); +            stat = tng_block_header_read(tng_data, block); +            fseek(tng_data->input_file, block->block_contents_size, SEEK_CUR); +        }          file_pos = ftell(tng_data->input_file); -        /* Read all blocks until next frame set block */ +        /* Read until next frame set block */          stat = tng_block_header_read(tng_data, block);          while(file_pos < tng_data->input_file_len &&              stat != TNG_CRITICAL &&              block->id != TNG_TRAJECTORY_FRAME_SET)          { -            stat = tng_block_read_next(tng_data, block, -                                    hash_mode); -            if(stat != TNG_CRITICAL) +            if(block->id == block_id)              { -                file_pos = ftell(tng_data->input_file); +                stat = tng_block_read_next(tng_data, block, +                                        hash_mode); +                if(stat != TNG_CRITICAL) +                { +                    file_pos = ftell(tng_data->input_file); +                    if(file_pos < tng_data->input_file_len) +                    { +                        stat = tng_block_header_read(tng_data, block); +                    } +                } +            } +            else +            { +                file_pos += block->block_contents_size + block->header_contents_size; +                fseek(tng_data->input_file, block->block_contents_size, SEEK_CUR);                  if(file_pos < tng_data->input_file_len)                  {                      stat = tng_block_header_read(tng_data, block); @@ -13652,6 +13798,8 @@ tng_function_status DECLSPECDLLEXPORT tng_data_vector_interval_get          free(current_values);      } +    np_data->last_retrieved_frame = end_frame_nr; +          return(TNG_SUCCESS);  } @@ -13852,6 +14000,8 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_data_get          }      } +    data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1; +          return(TNG_SUCCESS);  } @@ -14011,6 +14161,8 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_get          }      } +    data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1; +          return(TNG_SUCCESS);  } @@ -14249,6 +14401,8 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get          }      } +    data->last_retrieved_frame = end_frame_nr; +          return(TNG_SUCCESS);  } @@ -14289,23 +14443,45 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_interval_get          return(stat);      } -    /* Do not re-read the frame set. */ +    /* Do not re-read the frame set and only need the requested block + particle mapping blocks. */ +    /* TODO: Test that blocks are read correctly now that now all of them are read at the same time. */ +    stat = tng_particle_data_find(tng_data, block_id, &p_data);      if(first_frame != frame_set->first_frame || -       frame_set->n_particle_data_blocks <= 0) +       stat != TNG_SUCCESS)      {          tng_block_init(&block); +        if(stat != TNG_SUCCESS) +        { +            fseek(tng_data->input_file, +                  tng_data->current_trajectory_frame_set_input_file_pos, +                  SEEK_SET); +            stat = tng_block_header_read(tng_data, block); +            fseek(tng_data->input_file, block->block_contents_size, SEEK_CUR); +        }          file_pos = ftell(tng_data->input_file); -        /* Read all blocks until next frame set block */ +        /* Read until next frame set block */          stat = tng_block_header_read(tng_data, block);          while(file_pos < tng_data->input_file_len &&              stat != TNG_CRITICAL &&              block->id != TNG_TRAJECTORY_FRAME_SET)          { -            stat = tng_block_read_next(tng_data, block, -                                       hash_mode); -            if(stat != TNG_CRITICAL) +            if(block->id == block_id || block->id == TNG_PARTICLE_MAPPING)              { -                file_pos = ftell(tng_data->input_file); +                stat = tng_block_read_next(tng_data, block, +                                        hash_mode); +                if(stat != TNG_CRITICAL) +                { +                    file_pos = ftell(tng_data->input_file); +                    if(file_pos < tng_data->input_file_len) +                    { +                        stat = tng_block_header_read(tng_data, block); +                    } +                } +            } +            else +            { +                file_pos += block->block_contents_size + block->header_contents_size; +                fseek(tng_data->input_file, block->block_contents_size, SEEK_CUR);                  if(file_pos < tng_data->input_file_len)                  {                      stat = tng_block_header_read(tng_data, block); @@ -14458,6 +14634,8 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_interval_get          free(current_values);      } +    p_data->last_retrieved_frame = end_frame_nr; +          return(TNG_SUCCESS);  } @@ -14847,6 +15025,198 @@ tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read      return(stat);  } +tng_function_status DECLSPECDLLEXPORT tng_util_particle_data_next_frame_read +                (tng_trajectory_t tng_data, +                 const int64_t block_id, +                 void **values, +                 char *data_type, +                 int64_t *retrieved_frame_number, +                 double *retrieved_time) +{ +    tng_particle_data_t data; +    tng_function_status stat; +    int size; +    int64_t i, data_size, n_particles; +    void *temp; +     +    TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); +    TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer"); +    TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer"); +    TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer"); +    TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer"); +     +    stat = tng_particle_data_find(tng_data, block_id, &data); +    if(stat != TNG_SUCCESS) +    { +        stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id); +        if(stat != TNG_SUCCESS) +        { +            return(stat); +        } +        stat = tng_particle_data_find(tng_data, block_id, &data); +        if(stat != TNG_SUCCESS) +        { +            return(TNG_FAILURE); +        } +    } +    if(data->last_retrieved_frame < 0) +    { +        i = data->first_frame_with_data; +    } +    else +    { +        i = data->last_retrieved_frame + data->stride_length; +        if(i >= data->n_frames) +        { +            stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id); +            if(stat != TNG_SUCCESS) +            { +                return(stat); +            } +            i = data->first_frame_with_data; +        } +    } +    data->last_retrieved_frame = i; +    *retrieved_frame_number = i; +    *retrieved_time = tng_data->current_trajectory_frame_set.first_frame_time +  +                      (i - tng_data->current_trajectory_frame_set.first_frame) * +                      tng_data->time_per_frame; +     +    i = (i - data->first_frame_with_data) / data->stride_length; +     +    tng_num_particles_get(tng_data, &n_particles); +     +    *data_type = data->datatype; +     +    switch(*data_type) +    { +    case TNG_CHAR_DATA: +        return(TNG_FAILURE); +    case TNG_INT_DATA: +        size = sizeof(int64_t); +        break; +    case TNG_FLOAT_DATA: +        size = sizeof(float); +        break; +    case TNG_DOUBLE_DATA: +    default: +        size = sizeof(double); +    } +     +    data_size = size * n_particles * data->n_values_per_frame; + +    temp = realloc(*values, data_size); +    if(!temp) +    { +        printf("TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n", +               data_size, __FILE__, __LINE__); +        free(*values); +        *values = 0; +        return(TNG_CRITICAL); +    } +     +    *values = temp; +     +    memcpy(*values, (char *)data->values + i * data_size, data_size); +     +    return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_non_particle_data_next_frame_read +                (tng_trajectory_t tng_data, +                 const int64_t block_id, +                 void **values, +                 char *data_type, +                 int64_t *retrieved_frame_number, +                 double *retrieved_time) +{ +    tng_non_particle_data_t data; +    tng_function_status stat; +    int size; +    int64_t i, data_size; +    void *temp; +     +    TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); +    TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer"); +    TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer"); +    TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer"); +    TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer"); +     +    stat = tng_data_find(tng_data, block_id, &data); +    if(stat != TNG_SUCCESS) +    { +        stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id); +        if(stat != TNG_SUCCESS) +        { +            return(stat); +        } +        stat = tng_data_find(tng_data, block_id, &data); +        if(stat != TNG_SUCCESS) +        { +            return(TNG_FAILURE); +        } +    } +    if(data->last_retrieved_frame < 0) +    { +        i = data->first_frame_with_data; +    } +    else +    { +        i = data->last_retrieved_frame + data->stride_length; +        if(i >= data->n_frames) +        { +            stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id); +            if(stat != TNG_SUCCESS) +            { +                return(stat); +            } +            i = data->first_frame_with_data; +        } +    } +    data->last_retrieved_frame = i; +    *retrieved_frame_number = i; +    *retrieved_time = tng_data->current_trajectory_frame_set.first_frame_time +  +                      (i - tng_data->current_trajectory_frame_set.first_frame) * +                      tng_data->time_per_frame; +     +    i = (i - data->first_frame_with_data) / data->stride_length; +     +    *data_type = data->datatype; +     +    switch(*data_type) +    { +    case TNG_CHAR_DATA: +        return(TNG_FAILURE); +    case TNG_INT_DATA: +        size = sizeof(int64_t); +        break; +    case TNG_FLOAT_DATA: +        size = sizeof(float); +        break; +    case TNG_DOUBLE_DATA: +    default: +        size = sizeof(double); +    } +     +    data_size = size * data->n_values_per_frame; + +    temp = realloc(*values, data_size); +    if(!temp) +    { +        printf("TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n", +               data_size, __FILE__, __LINE__); +        free(*values); +        *values = 0; +        return(TNG_CRITICAL); +    } +     +    *values = temp; +     +    memcpy(*values, (char *)data->values + i * data_size, data_size); +     +    return(TNG_SUCCESS); +} +  tng_function_status DECLSPECDLLEXPORT tng_util_pos_read_range                  (tng_trajectory_t tng_data,                   const int64_t first_frame, | 
